안녕하세요?
AEWS 6주차 과제로 AWS Secrets Manager로 Kubernetes Secret 관리하기라는 내용을 다뤄보겠습니다.
학습자료는 EKS Workshop의 Managing Secrets with AWS Secrets Manager 를 참고하였습니다.
Kubernetes Secret의 관리에 대해서
Kubernetes Secret이 뭔가요?
Secrets | Kubernetes 해당 공식 문서를 참고하겠습니다.
시크릿은 암호, 토큰 또는 키와 같은 소량의 중요한 데이터를 포함하는 오브젝트이다.
이를 사용하지 않으면 중요한 정보가 파드 명세나 컨테이너 이미지에 포함될 수 있다.
시크릿을 사용한다는 것은 사용자의 기밀 데이터를 애플리케이션 코드에 넣을 필요가 없음을 뜻한다.
Secret을 통해서 암호, 토큰, 키를 애플리케이션 파드와 독립적으로 관리할 수 있습니다.
예를 들어 이런 형태의 Secret 매니페스트를 통해 생성할 수 있습니다.
Key:Value 쌍으로 저장되는 형태인 것을 볼 수 있습니다.
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
USER_NAME: YWRtaW4=
PASSWORD: MWYyZDFlMmU2N2Rm
위와 같이 USER_NAME, PASSWORD를 따로 정의하면 Pod에 주입할 수 있게 됩니다.
아래와 같이 생성한 secret을 Pod에 바인딩하는 형태로 동작합니다.
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: mysecret
restartPolicy: Never
Secret을 사용하는 방법은 3가지가 있습니다.
- Pod에 직접적으로 마운트해서 파일 처럼 사용하기
- 마운트해서 환경 변수로 사용하기
- Pod image를 가져올 때 Kubelet이 pull할 때 필요한 Credential을 Secret으로 제공해서 Private repo에 접근하기
이렇게보면 Secret을 사용해서 편리하게 암호들을 관리할 수 있을 것 같습니다만,
문제가 있습니다.
Secret은 Kubernets 는 etcd에 저장되는데, base64 로 인코딩된 값이 평문으로 그대로 저장되기 때문입니다.
또한 Secret 매니페스트를 관리하기 위해서 GitOps등을 사용할 때, 이 값이 리포지토리에 그대로 노출된다는 문제도 있습니다.
그래서 클러스터 외부에서 Secret에 대한 값을 주입해줄 필요가 있습니다.
AWS Secret Manager가 뭔가요?
AWS Secrets Manager란 무엇인가요? - AWS Secrets Manager 해당 문서를 참고하겠습니다.
AWS Secrets Manager 는 수명 주기 전반에 걸쳐 데이터베이스 자격 증명, 애플리케이션 자격 증명,
OAuth 토큰, API 키 및 기타 보안 암호를 관리, 검색 및 교체하는 데 도움이 됩니다.
많은 AWS 서비스가 Secrets Manager에 보안 암호를 저장하고 사용합니다.
Secrets Manager를 사용하면 더 이상 애플리케이션 소스 코드에 하드 코딩된 보안 인증 정보가 필요하지 않으므로
보안 태세를 개선할 수 있습니다.
Secrets Manager에 보안 인증 정보를 저장하면 애플리케이션 또는 구성 요소를 조사할 수 있는 누군가로 인해
손상될 가능성을 방지할 수 있습니다.
하드 코딩된 보안 인증 정보를 Secrets Manager 서비스에 대한 런타임 호출로 대체하여 필요할 때
동적으로 보안 인증 정보를 검색합니다.
Secrets Manager를 사용하면 암호에 대한 자동 교체 일정을 구성할 수 있습니다.
따라서 단기 보안 암호로 장기 보안 암호를 교체할 수 있어 손상 위험이 크게 줄어듭니다.
보안 인증 정보가 더 이상 애플리케이션에 저장되지 않으므로 보안 인증 정보를 교체할 때
더 이상 애플리케이션을 업데이트하거나 애플리케이션 클라이언트에 변경 사항을 배포하지 않아도 됩니다.
위에서 언급한 Kubernetes의 문제 때문에 별도로 암호, 토큰 등을 관리해야 할 필요성이 있습니다.
그래서 AWS SecretManager를 통해 별도로 관리를 하고 이를 Kubernetes Pod에 주입시키는 방법을 사용하면 Secret을 Git Repo에서 관리하는 것보다 좀 더 안전할 것입니다.
그리고 AWS Secret Manager에서 우리가 사용할 암호나 토큰 등을 저장했다면 이것을 Kubernetes Secret과 동기화 할 방법이 필요합니다.
그 중 하나가 아래 설명할 External Secret Operator입니다.
External Secret Operator가 뭔가요?
External Secret Operator 공식문서
External Secret Operator를 이용하면 AWS Secret Manager와 Kubernetes의 Secret을 통합할 수 있습니다.
이 Operator는 추상화 계층을 통해 전체 라이프사이클을 관리하면서 AWS Secret Manager의 Secret을 Kubernetes의 Secret으로 동기화합니다.
이 Operator를 사용하면 자동으로 시크릿 매니저의 값을 Kubernetes Secret에 주입할 수 있습니다.
SecretStore, ExternalSecret이라는 2개의 CRD를 정의합니다.
- SecretStore : secret provider 정보 정의
- ExternalSecret : SecretStore에서 가져온 정보 관리
External Secret Operator로 AWS SecretManager 연동해보기
권한 설정
Secret Manager의 secret에 접근하기 위한 권한을 생성합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": [
"arn:aws:secretsmanager:us-weset-2:xxxxxxxxxxxxx:secret:your/secret/credentials*"
]
}
]
}
Service Account를 통해 AWS IAM Role을 사용할 수 있도록 IAM Role을 생성합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::xxxxxxxxx:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/xxxxxxxxxxxxxx"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-west-2.amazonaws.com/id/xxxxxxxxxxxxxx:sub": "system:serviceaccount:external-secrets:external-secrets"
}
}
}
]
}
External Secret Operator 설치
설치 방식은 공식 문서를 참고하겠습니다.
Getting started - External Secrets Operator
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
# --set installCRDs=false
helm value에는 IRSA를 위한 annotation 정보도 포함해줘야 합니다.
위에서 생성한 Role 정보를 넣어줍니다.
serviceAccount:
create: true
name: external-secrets
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxxxx:role/eks-external-secrets-role
그러면 관련 Pod 들이 생성된 것을 볼 수 있습니다.
k get pod -A | grep external-secret
external-secrets external-secrets-xxxxxxxx 1/1 Running 0 5m
external-secrets external-secrets-xxxxxxxx 1/1 Running 0 5m
external-secrets external-secrets-cert-controller-xxxxxxxx 1/1 Running 0 5m
external-secrets external-secrets-cert-controller-xxxxxxxx 1/1 Running 0 5m
external-secrets external-secrets-webhook-xxxxxxxx 1/1 Running 0 5m
external-secrets external-secrets-webhook-xxxxxxxx 1/1 Running 0 5m
그리고 AWS Secret Manager에 Secret을 하나 등록합니다.
key value 형태로 값을 등록해볼 수 있습니다.
your/secret/credential 이라는 이름으로 생성했다고 가정하겠습니다.
k -n external-secrets get sa | grep external
external-dns 0 20m
external-secrets 0 20m
external-secrets-cert-controller 0 20m
external-secrets-webhook 0 20m
Cluster Secret Store를 생성합니다.
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: "cluster-secret-store"
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: "external-secrets"
namespace: "external-secrets"
kubectl get clustersecretstores.external-secrets.io
kubectl get clustersecretstores.external-secrets.io cluster-secret-store -o yaml | yq '.spec'
provider:
aws:
auth:
jwt:
serviceAccountRef:
name: external-secrets
namespace: external-secrets
region: us-east-1
service: SecretsManager
ClusterSecretStore는 서비스 계정으로 참조되는 JSON 웹 토큰(JWT)을 사용하여 AWS Secret Manager로 인증합니다.
그 다음, AWS Secret Manager에서 어떤 데이터를 가져와야 하는지, 그리고 그 데이터를 어떻게 Kubernetes Secret 으로 변환해야 하는지를 정의하는 ExternalSecret을 생성해야 합니다.
예를 들어 아래와 같은 Application의 Key를 저장했다고 해보겠습니다.
생성한 cluster-secret-store를 참조합니다.
그리고 생성 대상이 되는 secret을 target에 넣어줍니다.
secret에 들어가는 데이터는 AWS SecreManager에 입력한 값입니다.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: example-db-secret
spec:
secretStoreRef:
kind: ClusterSecretStore
name: cluster-secret-store
target:
name: db-secret
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: your/secret/credential
property: username
- secretKey: password
remoteRef:
key: your/secret/credential
property: password
그러면 입력한 내용과 같이 아래와 같은 secret이 생성됩니다.
이 secret을 처음 소개했던 내용과 같이 pod에 바인딩해서 사용할 수 있습니다.
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: default
type: Opaque
data:
username: ZGJ1c2Vy
password: c3VwZXJzZWNyZXQxMjMh
'Kubernetes' 카테고리의 다른 글
Kubernetes Scheduling과 Scheduling plugins 파보기 (0) | 2025.03.20 |
---|---|
Karpenter + Keda로 특정 시간에 Autoscaling 걸기 (0) | 2025.03.16 |
Datadog Agent로 Traefik pod의 로그를 Datadog으로 전송하기 (0) | 2025.02.26 |
Mountpoint for Amazon S3로 EKS Pod에 S3 mount하기 (0) | 2025.02.18 |
Traefik API Gateway 사용시 AWS EKS의 NLB에서 Backend까지의 Flow (0) | 2025.02.16 |