Search

EKS - External Secrets Operator를 활용한 AWS Secret manager 연동

EKS - External Secrets Operator를 활용한 AWS Secret manager 연동

개요

Helm을 사용하나 Manifest를 사용하나, Github에 올라가는 순간 노출되면 안되는 정보가 존재합니다.
우리는 EKS 환경 내에서 AWS Secret manager를 활용하여 해당 정보를 숨기는 방법을 알아볼 것입니다.
External Secrets Operator(ESO)를 사용하여 AWS Secrets Manager와 연동하는 전체 과정을 설명합니다
전체적인 Flow 사전 점검
1. AWS Secrets Manager에 Secret 생성:
먼저 AWS Secrets Manager에 필요한 비밀 정보를 저장합니다.
2. IRSA (IAM Roles for Service Accounts) 설정:
EKS 클러스터에서 Secrets Manager에 접근할 수 있는 IAM 역할을 생성하고, 이를 Kubernetes 서비스 계정과 연결합니다.
3. External Secrets Operator 설치:
Kubernetes에서 AWS Secrets Manager의 정보를 가져올 수 있게 해주는 External Secrets Operator를 설치합니다.
4. SecretStore 리소스 생성:
External Secrets Operator가 AWS Secrets Manager에 접근할 수 있도록 SecretStore 리소스를 생성합니다.
5. ExternalSecret 리소스 생성:
AWS Secrets Manager의 특정 시크릿을 Kubernetes Secret으로 동기화하는 ExternalSecret 리소스를 생성합니다.
6. 애플리케이션에서 사용:
생성된 Kubernetes Secret을 Pod의 환경 변수나 볼륨으로 마운트하여 사용합니다.
이 방식을 사용하면 민감한 정보를 GitOps 저장소나 K8s 매니페스트에 직접 포함시키지 않고도 안전하게 관리할 수 있습니다
주로 아래와 같은 장점을 가지게 됩니다.
AWS Secrets Manager의 값이 자동으로 K8s Secret과 동기화
refreshInterval로 동기화 주기 설정 가능
JSON 형식의 시크릿에서 특정 필드만 선택적으로 추출 가능
여러 Secret을 하나의 K8s Secret으로 통합 가능
주의 사항
네임스페이스별로 접근 제어 가능
IAM Role은 최소 권한 원칙에 따라 설정
Secret은 필요한 네임스페이스에만 생성
주기적인 시크릿 로테이션 구현 권장

External Secrets Operator 설치

External Secrets Operator(ESO)는 쿠버네티스 환경에서 외부 시크릿 관리 시스템과의 통합을 관리하는 쿠버네티스 오퍼레이터
External Secrets Operator의 주요 기능
자동 동기화: 외부 시크릿 변경 시 자동 업데이트
템플릿 지원: 시크릿 값 변환/가공 가능
다중 공급자: 여러 시크릿 저장소 동시 사용 가능
네임스페이스/클러스터 범위 지원
클러스터 레벨에서 작동하는 오퍼레이터이므로, 하나의 네임스페이스(일반적으로 external-secrets)에만 설치하면 됩니다. 각 애플리케이션의 네임스페이스에 설치할 필요가 없습니다.
시크릿 검증 및 모니터링
지원하는 외부 시크릿 저장소
- AWS Secrets Manager - AWS Parameter Store - HashiCorp Vault - Google Secrets Manager - Azure Key Vault - IBM Cloud Secrets Manager 등 다양한 외부 시크릿 저장소 지원
Plain Text
복사
# Helm repo 추가 helm repo add external-secrets https://charts.external-secrets.io # ESO 설치 helm install external-secrets \ external-secrets/external-secrets \ -n external-secrets \ --create-namespace
YAML
복사
Secret manager이 생성이 되어 있다면, IRSA를 진행해보겠습니다.
IRSA를 위해 IAM Role이 필요합니다.
eksctl create iamserviceaccount \ --cluster=eks-cluster \ --name external-secrets-sa \ --namespace external-secrets \ --attach-policy-arn=arn:aws:iam::xxx:policy/xxxx \ --override-existing-serviceaccounts \ --approve \ --region=ap-northeast-2
YAML
복사
eksctl get iamserviceaccount --cluster eks-cluster --namespace external-secrets --region ap-northeast-2
YAML
복사
IAM Role 설정
apiVersion: v1 kind: ServiceAccount metadata: name: external-secrets-sa namespace: external-secrets annotations: eks.amazonaws.com/role-arn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/external-secrets-role
YAML
복사
IAM Role 정책:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret" ], "Resource": "*" } ] }
JSON
복사

SecretStore 생성

External Secrets Operator가 AWS Secrets Manager에 접근할 수 있도록 SecretStore 리소스를 생성합니다.
apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: aws-secret-store namespace: default spec: provider: aws: service: SecretsManager region: ap-northeast-2 auth: jwt: serviceAccountRef: name: external-secrets-sa
YAML
복사
ClusterSecretStore 사용 (클러스터 전체)
apiVersion: external-secrets.io/v1beta1 kind: ClusterSecretStore metadata: name: "cluster-secret-store" spec: provider: aws: service: SecretsManager region: $AWS_REGION auth: jwt: serviceAccountRef: name: "external-secrets-sa" namespace: "external-secrets"
YAML
복사
ClusterSecretStore 상태 확인:
kubectl get clustersecretstore kubectl describe clustersecretstore cluster-secret-store
YAML
복사

ExternalSecret 생성

ExternalSecret: External Secrets Operator의 핵심 Custom Resource로, 외부 시크릿 저장소의 시크릿을 쿠버네티스 Secret으로 동기화하는 역할
주요 속성
spec: refreshInterval: 1h # 동기화 주기 target: creationPolicy: Owner # Secret 생성 정책 (Owner/Orphan/Merge) deletionPolicy: Delete # Secret 삭제 정책 template: # 템플릿 설정 immutable: false # Secret 불변성 설정 dataFrom: # 전체 시크릿 동기화 data: # 개별 키-값 동기화
YAML
복사
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: my-secret spec: refreshInterval: 1h # 동기화 주기 secretStoreRef: # SecretStore 참조 name: aws-secret-store kind: SecretStore # SecretStore 또는 ClusterSecretStore target: name: app-secret # 생성될 K8s Secret 이름 data: - secretKey: DB_PASSWORD # K8s Secret의 키 remoteRef: key: prod/app/database # AWS Secret 이름 property: password # JSON 키 (선택사항) - secretKey: API_KEY remoteRef: key: prod/app/api property: key
YAML
복사
externalsecret 조회
kubectl get externalsecret kubectl describe externalsecret test-secret
YAML
복사
여러가지 유스 케이스들 소개
1.
템플릿 사용 시
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: template-example spec: target: template: data: config.yaml: | username: {{ .username }} password: {{ .password }} data: - secretKey: username remoteRef: key: my-secret property: username
YAML
복사
2.
여러 시크릿 병합:
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret spec: target: name: combined-secret data: - secretKey: db-creds remoteRef: key: database/credentials - secretKey: api-key remoteRef: key: api/key
YAML
복사
3.
데이터 변환(Rewrite):
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: transform-secret spec: target: name: transformed-secret data: - secretKey: DATABASE_URL remoteRef: key: db-secret property: url transforms: - regexp: source: "postgres://(.*)" target: "postgresql://$1"
YAML
복사
4.
조건부 동기화:
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: conditional-secret spec: target: name: result-secret dataFrom: - extract: key: prod/config rewrite: - regexp: source: "password" target: "DB_PASSWORD" condition: match: secretRef: name: condition-secret key: environment matchValue: "production"
YAML
복사
5.
JSON의 모든 필드를 자동으로 개별 키로 가져오는 방법:
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: conditional-secret spec: refreshInterval: 1h secretStoreRef: name: cluster-secret-store kind: ClusterSecretStore target: name: result-secret dataFrom: - extract: key: /키/이름/
YAML
복사
6. 모니터링 및 문제 해결:
# ESO 상태 확인 kubectl get externalsecrets -A # ESO 로그 확인 kubectl logs -n external-secrets \ -l app.kubernetes.io/name=external-secrets # Secret 동기화 상태 확인 kubectl get externalsecret my-secret -o yaml
Shell
복사

애플리케이션에서 사용

생성된 Kubernetes Secret을 Pod의 환경 변수나 볼륨으로 마운트하여 사용합니다.
이 방법을 사용하면 민감한 정보를 Kubernetes 매니페스트 파일에 직접 포함시키지 않고, AWS Secret manager에서 가져와 사용이 가능합니다.
위에서 external secret을 아래와 같이 설정
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: my-secret spec: refreshInterval: 1h secretStoreRef: name: aws-secret-store kind: SecretStore target: name: app-secret # 생성될 K8s Secret 이름
YAML
복사
ConfigMap에서 Secret 사용
apiVersion: v1 kind: ConfigMap metadata: name: app-config data: config.yaml: | database: password: ${app-secret:DB_PASSWORD} api: key: ${app-secret:API_KEY}
YAML
복사
Secret에서 참조:
apiVersion: v1 kind: Secret metadata: name: another-secret type: Opaque stringData: credentials.yaml: | dbPassword: ${app-secret:DB_PASSWORD} apiKey: ${app-secret:API_KEY}
YAML
복사
Deployment에서 사용:
apiVersion: apps/v1 kind: Deployment metadata: name: app spec: template: spec: containers: - name: app image: app:1.0 env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: app-secret key: DB_PASSWORD - name: API_KEY valueFrom: secretKeyRef: name: app-secret key: API_KEY
YAML
복사

참고