- Published on
EKS에서 ExternalSecret이 0개만 생성될 때
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
EKS에서 External Secrets Operator(ESO)를 설치하고 ExternalSecret 리소스까지는 정상적으로 생성되는데, 정작 원하는 Kubernetes Secret이 하나도 만들어지지(= 0개) 않는 상황을 종종 만납니다. 이 경우 kubectl get externalsecret는 보이지만 kubectl get secret에는 아무 것도 없거나, 기대한 이름의 Secret이 생성되지 않습니다.
이 글은 “ExternalSecret이 0개만 생성”이라는 표현이 실제로는 ExternalSecret은 존재하지만(또는 여러 개 만들었지만) 결과물 Secret이 0개인 케이스로 이어지는 경우가 많다는 전제에서, 빠르게 원인을 좁히는 점검 루틴을 제공합니다.
> 참고: AWS Secrets Manager 권한/403 이슈가 의심된다면 아래 글도 함께 보세요. > - EKS Pod에서 AWS Secrets Manager 403 해결 가이드
증상 정의: “0개”가 의미하는 것
먼저 무엇이 0개인지 분리해야 합니다.
- ExternalSecret 리소스가 0개: YAML이 적용되지 않았거나 다른 네임스페이스에 생성됨.
- ExternalSecret은 있는데 생성된 Secret이 0개: ESO 컨트롤러가 동기화에 실패했거나, 동기화 대상이 “빈 결과”로 판단됨.
- Secret은 생성되었는데 데이터가 비어 있음:
dataFrom/property매핑이 잘못되어 값이 누락.
이 글의 핵심은 2번(가장 흔함)입니다.
가장 빠른 10분 점검 순서
1) ExternalSecret의 Status/Condition부터 확인
ESO는 동기화 결과를 status.conditions로 남깁니다.
kubectl -n <ns> get externalsecret <name> -o yaml
아래 항목을 특히 봅니다.
status.conditions[].type: Readystatus.conditions[].status: True/Falsestatus.conditions[].message(실패 이유가 거의 여기 나옵니다)status.refreshTime,status.syncedResourceVersion
또는 요약 출력:
kubectl -n <ns> describe externalsecret <name>
여기서 Ready=False인데 이벤트/메시지가 없다면, 다음 단계로 넘어가 ESO 컨트롤러 로그를 봐야 합니다.
2) ESO 컨트롤러 로그 확인(가장 결정적)
ESO는 보통 external-secrets 네임스페이스에 설치됩니다(환경에 따라 다름).
kubectl -n external-secrets get pods
kubectl -n external-secrets logs deploy/external-secrets -f
로그에서 흔히 보이는 패턴:
AccessDeniedException/403→ IAM(IRSA) 또는 리소스 정책 문제SecretStore ... not found→ store 참조 네임스페이스/이름 불일치could not get secret data from provider→ 키/프로퍼티 매핑 오류failed to create/update target secret→ RBAC/네임스페이스 권한 문제
3) SecretStore vs ClusterSecretStore 스코프 확인
ExternalSecret이 참조하는 store가 SecretStore인지 ClusterSecretStore인지가 중요합니다.
SecretStore: 네임스페이스 스코프ClusterSecretStore: 클러스터 스코프
ExternalSecret YAML에서:
spec:
secretStoreRef:
name: my-store
kind: SecretStore # 또는 ClusterSecretStore
점검 포인트:
kind: SecretStore인데 store가 다른 네임스페이스에 있으면 항상 못 찾습니다.kind를 생략하면 기본값이SecretStore로 해석되는 버전/설정이 있어, 실제로는ClusterSecretStore를 만들었는데 참조가 실패하는 경우가 있습니다.
확인 명령:
kubectl -n <ns> get secretstore
kubectl get clustersecretstore
4) ExternalSecret과 target Secret의 네임스페이스 불일치
ExternalSecret은 네임스페이스 리소스이며, 기본적으로 같은 네임스페이스에 Secret을 생성합니다.
kubectl -n <ns> get externalsecret
kubectl -n <ns> get secret | grep <target-secret-name>
자주 하는 실수:
kubectl apply -f를 다른 컨텍스트/네임스페이스로 실행- GitOps(Argo CD/Flux)에서
destination.namespace와 YAML의metadata.namespace가 다름 - Helm values로 namespace를 바꾸면서 store/externalsecret이 서로 다른 ns에 생성
5) target Secret 이름/정책 설정 확인
ExternalSecret은 어떤 이름의 Secret을 만들지 spec.target.name으로 결정됩니다.
spec:
target:
name: app-secrets
creationPolicy: Owner
deletionPolicy: Retain
점검 포인트:
spec.target.name을 안 적으면 ExternalSecret 이름을 기본값으로 쓰는 구성도 있습니다(차트/버전마다 차이).creationPolicy가None에 가까운 설정(또는 특정 정책 조합)으로 인해 생성이 안 되거나 업데이트만 시도하는 경우가 있습니다.
6) 리모트 키 매핑(data / dataFrom) 오류로 “빈 결과”가 되는 경우
AWS Secrets Manager를 예로 들면, 다음 두 방식이 있습니다.
(A) 개별 키 매핑(spec.data)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: demo
namespace: app
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-sm
kind: ClusterSecretStore
target:
name: demo-secret
data:
- secretKey: DB_PASSWORD
remoteRef:
key: prod/db
property: password
key: Secrets Manager의 secret name 또는 ARNproperty: JSON secret일 때 특정 필드
실수 포인트:
property가 존재하지 않으면 결과가 비거나 에러가 납니다(버전/설정에 따라 다름).- secret 값이 JSON이 아닌데
property를 지정함
(B) 전체 가져오기(spec.dataFrom)
spec:
dataFrom:
- extract:
key: prod/app
실수 포인트:
extract.key가 실제 secret 이름과 다름- secret이 JSON이 아닌 문자열인데
extract를 사용(이 경우data로 매핑해야 하는 경우가 많음)
7) IRSA/IAM 권한 문제(특히 AccessDenied)로 동기화 실패
ESO가 AWS API를 호출할 권한이 없으면 Secret 생성이 0개로 남습니다. 이때 ExternalSecret만 “존재”하고 결과가 없습니다.
핵심은 ESO 컨트롤러의 ServiceAccount가 올바른 IAM Role을 Assume하고 있는지입니다.
kubectl -n external-secrets get sa external-secrets -o yaml
아래 annotation 확인:
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account>:role/<role>
권한 정책 최소 예시(Secrets Manager 읽기):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:ap-northeast-2:<account>:secret:prod/*"
}
]
}
추가로 KMS CMK로 암호화된 secret이면 kms:Decrypt도 필요합니다.
권한 문제를 더 깊게 다루는 실전 체크는 아래 글이 도움이 됩니다.
8) ESO의 RBAC 부족으로 Secret 생성 자체가 실패
AWS에서 값을 가져오는 데는 성공했지만, Kubernetes Secret을 만들 권한이 없으면 생성이 0개가 됩니다.
컨트롤러 로그에 다음 류가 보입니다.
forbidden: User "system:serviceaccount:..." cannot create resource "secrets"
확인:
kubectl auth can-i create secrets \
--as=system:serviceaccount:external-secrets:external-secrets \
-n <target-ns>
no라면 Role/ClusterRole 및 Binding 구성이 설치 방식(Helm chart values, namespace scope)에 맞는지 재검토해야 합니다.
9) 네트워크/엔드포인트 문제로 AWS API 호출이 실패
프라이빗 서브넷 + NAT 미구성, VPC Endpoint 누락, DNS 문제 등으로 AWS Secrets Manager에 도달하지 못하면 동기화가 실패합니다.
이 경우 로그에 i/o timeout, no route to host, dial tcp 같은 메시지가 보입니다.
- 클러스터가 Private이고 NAT가 없다면 Secrets Manager VPC Endpoint(
com.amazonaws.<region>.secretsmanager)를 고려 - CoreDNS 장애/노드 네트워크 이슈 점검
네트워크가 전체적으로 불안정할 때는 503/502 증상과 함께 나타나는 경우도 많습니다. 아래 글의 “10분 진단” 체크리스트가 네트워크/인그레스/서비스 레벨 트러블슈팅 감각을 잡는 데 도움이 됩니다.
재현 가능한 최소 예제(정상 동작 기준)
아래는 ClusterSecretStore + ExternalSecret 조합의 최소 예시입니다.
ClusterSecretStore (AWS Secrets Manager)
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-sm
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets
namespace: external-secrets
ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-config
namespace: app
spec:
refreshInterval: 5m
secretStoreRef:
name: aws-sm
kind: ClusterSecretStore
target:
name: app-config
creationPolicy: Owner
data:
- secretKey: DATABASE_URL
remoteRef:
key: prod/app
property: database_url
적용 후 확인:
kubectl apply -f store.yaml
kubectl apply -f externalsecret.yaml
kubectl -n app get externalsecret
kubectl -n app describe externalsecret app-config
kubectl -n app get secret app-config -o yaml
“0개” 상황에서 자주 나오는 원인 TOP 7 정리
secretStoreRef.kind누락/오타로 SecretStore/ClusterSecretStore 스코프 불일치- store가 다른 네임스페이스에 있는데
SecretStore로 참조 - IRSA 미설정 또는 잘못된 role-arn, trust policy 오류
- IAM 정책에
GetSecretValue/DescribeSecret/kms:Decrypt누락 remoteRef.key/property오타 또는 JSON/문자열 타입 불일치- ESO 컨트롤러 RBAC 부족(특정 네임스페이스에 Secret 생성 불가)
- 프라이빗 네트워크에서 AWS API로 라우팅 불가(NAT/VPC Endpoint/DNS)
결론: Status → 로그 → 스코프 → 권한 순으로 좁혀라
ExternalSecret은 “리소스가 생성되었다”는 사실만으로는 성공을 의미하지 않습니다. status.conditions와 컨트롤러 로그가 정답에 가장 가깝고, 그 다음이 store 스코프(SecretStore vs ClusterSecretStore), 마지막이 AWS/IAM과 Kubernetes RBAC입니다.
특히 EKS에서는 IRSA/IAM이 얽히면서 403/AccessDenied가 가장 흔한 루트 원인이므로, 권한과 신뢰 정책(trust relationship)을 먼저 의심해보는 것이 시간을 크게 줄여줍니다.