External Secrets Operator 란?
Kubernetes 환경에서 Secret 관리는 보안과 운영 측면에서 매우 중요하다. 하지만 Secret을 직접 관리하는 것은 번거롭고 보안상의 위험을 초래할 수 있다. External Secrets Operator(이하 ESO)를 사용하면 이러한 문제를 해결하고, 비밀 정보를 보다 안전하고 효율적으로 관리할 수 있다.
ESO는 AWS Secrets Manager, HashiCorp Vault, Google Secrets Manager 등 다양한 외부 비밀 관리 시스템을 통해 Kubernetes 환경에서 Secret을 쉽게 관리할 수 있도록 도와주는 오픈소스 솔루션이다.
External Secrets Operator의 가장 큰 장점은 외부 API를 통해 비밀 정보를 자동으로 동기화하여 Kubernetes Secrets을 사용할 수 있다는 점이다. 이를 통해 외부 시스템에서 Secret이 변경되면, Kubernetes에서 자동으로 이를 반영할 수 있어 운영 부담을 크게 줄일 수 있다.
위 그림에서 ESO 관련 리소스들의 역할은 다음과 같다.
SecretStore
- 외부 비밀 관리 시스템과 연결하고, Secret 값을 가져올 수 있도록 인증 정보와 접근 방법을 정의하는 리소스.
- SecretStore는 네임스페이스에 종속적인 반면, ClusterSecretStore는 클러스터 수준에서 비밀 관리 시스템 설정을 제공한다.
ExternalSecret
- 외부 비밀 관리 시스템에서 어떤 Secret을 가져와 Kubernetes Secret으로 생성 또는 동기화할지 정의하는 리소스.
ESO(External Secrets Operator)
- 외부 비밀 관리 시스템과 Kubernetes 간의 Secret을 동기화하는 컨트롤러.
본 글에서는 실습을 통해 ESO를 구성하고, AWS Secrets Manager와 EKS 클러스터 내에서 Kubernetes Secrets을 동기화하는 과정을 다룬다.
구성 환경
- Amazon EKS v1.30
- Helm cli : 3.17.2
설치 버전
- ESO Helm Chart : 0.15.0
- ESO Helm APP : 0.15.0
전제 조건
- AWS 계정
- AWS Secrets Manager 생성
- AWS Iam Role 생성
- Amazon EKS 클러스터
1. External Secrets Operator 설치
Helm을 사용하여 설치한다.
$ helm repo add external-secrets https://charts.external-secrets.io
"external-secrets" has been added to your repositories
$ helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace
설치가 완료되면 ESO의 Custom Resource Definitions(CRD)가 생성된다.
$ kubectl get crds | grep external-secrets
ESO가 정상적으로 구동되었는지 확인하기 위해 external-secrets 네임스페이스의 Pod 상태를 조회한다.
$ kubectl get po -n external-secrets
NAME READY STATUS RESTARTS AGE
external-secrets-68655687d8-ztbk6 1/1 Running 0 62s
external-secrets-cert-controller-7fcdd69449-ccppg 1/1 Running 0 62s
external-secrets-webhook-5fcb64844c-nwtnx 1/1 Running 0 62s
2. AWS IRSA와 SecretStore 설정을 통한 AWS Secrets Manager 권한 획득
참고
AWS Secrets Manager와 IAM Role 생성 과정은 생략한다
ESO에서 AWS IAM Role을 사용하여 AWS Secrets Manager에 접근하려면 IRSA(AWS IAM Roles for Service Accounts) 설정이 필요하다.
먼저, AWS IAM Role과 AWS Secrets Manager를 생성한 후, 해당 IAM Role에 다음과 같은 정책을 추가한다.
이때, Resource 항목에는 각 환경에 맞는 AWS Secrets Manager의 ARN을 입력하면 된다.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"secretsmanager:ListSecrets",
"secretsmanager:BatchGetSecretValue"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetResourcePolicy",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
],
"Resource": [
"arn:aws:secretsmanager:ap-northeast-2:{account}:secret*"
]
}
]
}
앞에서 생성한 IAM Role에 다음과 같이 신뢰 관계(Trust Relationships)을 설정한다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{account}:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/XXXXXXX"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.ap-northeast-2.amazonaws.com/id/XXXXXXX:sub": "system:serviceaccount:external-secrets:external-secrets",
"oidc.eks.ap-northeast-2.amazonaws.com/id/XXXXXXX:aud": "sts.amazonaws.com"
}
}
}
]
}
external-secrets Pod가 IAM Role 권한을 얻을 수 있도록 해당 Pod가 사용하는 ServiceAccount에 IAM Role 정보를 추가한다.
$ kubectl edit sa -n external-secrets external-secrets
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
#... 추가
eks.amazonaws.com/role-arn: arn:aws:iam::{account}:role/external-secrets
#... 중략
AWS Secrets Manager와 연결을 위해 SecretStore 리소스를 배포한다.
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secretsmanager
namespace: external-secrets
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets
SecretStore 리소스가 AWS Secrets Manager와 정상적으로 연결되었는지 확인한다.
다음과 같이 STATUS가 Valid이고, READY가 True이면 정상적으로 연결된 것이다.
$ kubectl get secretstores.external-secrets.io -n external-secrets
NAME AGE STATUS CAPABILITIES READY
aws-secretsmanager 96m Valid ReadWrite True
3. ExternalSecret 설정 및 Kubernetes Secret 자동 생성
EKS에서 AWS Secrets Manager 기반으로 Kubernetes Secret을 생성할 수 있게 ExternalSecret을 생성한다.
주요 설정 내용은 다음과 같다.
- target
- name : EKS 클러스터 내에서 생성될 Kubernetes Secret 이름
- data
- secretKey : Kubernetes Secret 내에서 사용할 키 이름
- remoteRef
- key : AWS Secrets Manager Secret 이름
- property : AWS Secrets Manager에서 가져올 Secret key 이름
ExternalSecret의 YAML 내용을 다음과 같이 작성한 후 kubectl 명령어를 사용하여 적용한다.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: example
namespace: external-secrets
spec:
refreshInterval: 1m
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: awssecret
creationPolicy: Owner
data:
- secretKey: key
remoteRef:
key: {AWS Secrets Manager name}
property: {AWS Secrets Manager Secret key}
ExternalSecret을 적용 후 상태를 확인하면 "SecretSynced" 상태가 표시된다. 이 상태는 ExternalSecret 리소스가 정상적으로 AWS Secrets Manager에서 Secret을 가져와 Kubernetes Secret으로 동기화되었음을 의미한다.
$ kubectl get externalsecrets.external-secrets.io -n external-secrets
NAME STORETYPE STORE REFRESH INTERVAL STATUS READY
example SecretStore aws-secretsmanager 1m SecretSynced True
이전에 설정한 ExternalSecret의 spec에 따라 "awssecret" Kubernetes Secret이 정상적으로 생성되었는지 확인한다.
$ kubectl get secrets -n external-secrets awssecret
NAME TYPE DATA AGE
awssecret Opaque 1 13m
주의
만약 생성이 안된다면 Kubernetes RBAC 및 AWS Iam Role 권한을 확인한다.
기본적으로 설치 과정에서 ClusterRole, ClusterRoleBinding, Role, RoleBinding 리소스가 자동으로 설정된다.
AWS Secrets Manager에서 설정한 값과 같은지 확인하려면, kubectl 명령어로 생성된 Kubernetes Secret을 확인하고, AWS Secrets Manager에서 해당 Secret을 직접 확인하여 값을 비교할 수 있다.
- AWS Secrets Manasger
- Kubernetes Secret
$ kubectl get secrets -n external-secrets awssecret -ojsonpath="{.data.key}" | base64 -d
test
이제부터 AWS Secrets Manager에서 Secret 값을 변경하면 Kubernetes Secret의 값도 변경된다.
응용 1.
AWS Secrets Manager의 모든 Key-Value를 Kubernetes Secret으로 한 번에 가져오려면 다음과 같이 설정한다.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: example
namespace: external-secrets
spec:
refreshInterval: 1m
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: awssecret
creationPolicy: Owner
dataFrom:
- extract:
key: {AWS Secrets Manager name}
응용 2.
AWS Secrets Manager의 모든 Key 중 특정 Key만 선택해서 가져오려면 다음과 같이 설정한다.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: example
namespace: external-secrets
spec:
refreshInterval: 1m
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: awssecret
creationPolicy: Owner
template:
data:
key1: "{{ .key_name1 }}"
key2: "{{ .key_namme2 }}"
dataFrom:
- extract:
key: {AWS Secrets Manager name}
마무리
이번 글에서는 External Secrets Operator (ESO)를 사용하여 AWS Secrets Manager와 EKS 클러스터 간에 비밀 정보를 자동으로 동기화하는 방법을 실습해 보았다. 이와 같은 자동화된 비밀 관리 방식은 보안성과 운영 효율성을 크게 향상시키고, 비밀 정보의 갱신이 자동으로 이루어지기 때문에 관리의 부담을 줄이는 데 큰 도움이 된다.
ESO와 유사한 역할을 하는 도구로 VSO(Vault Secrets Operator)가 있다. VSO와 ESO는 비슷한 목적을 가진 도구지만, 주요 차이점은 VSO는 HashiCorp Vault와의 통합에 특화되어 있는 반면, ESO는 여러 외부 비밀 관리 시스템과의 연동을 지원한다는 점이다.
이러한 장점 덕분에 Kubernetes를 사용하는 환경에서 ESO 도입은 충분히 고려해 볼 만한 좋은 선택이 될 것이다.
'Orchestration > Kubernetes' 카테고리의 다른 글
Amazon EKS 환경에서 신규 Subnet 할당을 통한 Pod IP 부족 문제 해결하기 (0) | 2024.07.11 |
---|---|
K8sGPT 사용하여 Kubernetes 문제 해결하기 (0) | 2024.07.03 |
AWS EKS AutoScaling 속도 비교(Cluster Autoscaler vs Kerpenter) (0) | 2023.10.22 |
Karpenter로 AWS EKS 환경에 AutoScaling 구현하기 (0) | 2023.10.18 |
AWS EKS 노드그룹 자동 시작, 중지하기 (0) | 2023.10.17 |
댓글