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
복사