IT/DevSecOps

External Secrets Operator vs SOPS, 1년 같이 써본 후기

gfrog 2026. 5. 12. 06:41
반응형

작년 봄에 시크릿 관리 체계를 갈아엎으면서 ESO(External Secrets Operator)랑 SOPS를 둘 다 도입했다. 처음엔 하나로 통일하자는 의견이 강했는데, 1년 굴려보니 둘 중 하나만으로는 답이 안 나오더라. 결국 우리 팀은 둘을 역할로 갈라놓고 쓰는 쪽으로 정착했다.

최근에 신규 팀 합류한 사람한테 이 구조를 설명할 일이 있었는데, 막상 글로 정리해두니 우리도 모호하게 쓰고 있던 부분이 꽤 보였다. 그래서 한번 정리해본다.

우리 환경 간단히

  • EKS 클러스터 4개 (dev/stage/prod 2개 — 리전 분리)
  • ArgoCD 기반 GitOps
  • AWS Secrets Manager, Parameter Store 둘 다 사용 중
  • 코드 저장소는 GitHub Enterprise

원래는 sealed-secrets 쓰고 있었는데, 클러스터 키 백업이 자꾸 새는 게 운영상 부담이었다. 클러스터를 한번 갈아엎으면 시크릿이 통째로 못 풀려서 매번 백업 키 복원 절차를 밟아야 했다. 이게 싫어서 갈아엎은 거다.

ESO를 먼저 도입한 이유

처음엔 ESO만 도입하려고 했다. AWS Secrets Manager에 모든 시크릿을 몰아넣고 ESO가 ExternalSecret CR로 동기화하는 그림. 깔끔해 보였다.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-db-creds
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: app-db-creds
    creationPolicy: Owner
  data:
    - secretKey: password
      remoteRef:
        key: prod/app/db
        property: password

이게 좋은 점: 시크릿 본체는 AWS Secrets Manager에 있고, Git에는 "어디서 가져올지"만 적힌다. 시크릿 로테이션도 AWS 콘솔이나 Lambda로 돌리면 ESO가 알아서 다시 끌어와서 워크로드를 재시작시킨다. IAM과 IRSA(혹은 Pod Identity) 권한으로 fine-grained 액세스 컨트롤이 된다. 진짜로 이건 강력하다.

그런데 한 두 달 굴려보니 ESO만으로는 안 되는 영역이 슬슬 보였다.

ESO가 잘 안 맞았던 영역

인프라 시크릿

Terraform에서 쓰는 시크릿 — Cloudflare API 토큰, Datadog API 키, 외부 SaaS 웹훅 URL — 이건 ESO 영역이 아니다. ESO는 클러스터 안에서 도는 컨트롤러니까, Terraform이 plan 돌리는 시점에는 등장하지 못한다.

물론 AWS Secrets Manager에 넣고 data "aws_secretsmanager_secret_version"으로 끌어 쓰면 되긴 하는데, 그러면 Terraform 실행자가 항상 그 시크릿에 read 권한이 있어야 하고, 신규 시크릿을 추가할 때마다 AWS 콘솔이나 CLI를 거쳐야 한다. PR 리뷰 흐름이 끊긴다.

부트스트랩 시크릿

ESO 자체를 깔려면 AWS 자격증명이 필요하다. IRSA를 쓰면 ServiceAccount 어노테이션으로 풀리는데, 이걸 위한 OIDC provider 설정이나 초기 admin 시크릿은 어디서 오나? 닭과 달걀 문제다. 처음엔 매뉴얼 kubectl로 때려 박았는데, 신규 클러스터 만들 때마다 사람이 손으로 해야 한다는 게 거슬렸다.

dev 환경의 더미 시크릿

dev 환경에서 쓰는 더미 토큰, 테스트용 API 키. 이거 하나하나 AWS Secrets Manager에 등록하는 건 오버킬이었다. AWS Secrets Manager는 시크릿당 월 0.4 USD가 붙는다. dev에서만 쓰는 30개 시크릿이 매달 12불씩 나간다는 게 좀 그랬다. 비용 자체보다는 "왜 이걸 굳이 외부에 둬야 하지"가 더 컸다.

그래서 SOPS를 같이 깔았다

SOPS는 정반대 철학이다. 시크릿을 Git에 직접 두되, 암호화해서 둔다. AWS KMS를 키 백엔드로 쓰면 IAM 권한으로 누가 풀 수 있는지 통제된다.

sops --encrypt --kms arn:aws:kms:ap-northeast-2:123:key/abcd \
  --encrypted-regex '^(data|stringData)$' \
  dev-secret.yaml > dev-secret.enc.yaml

ArgoCD에서는 argocd-vault-plugin이나 helm-secrets 플러그인으로 디크립트해서 적용. Terraform에서는 sops_file 데이터 소스로 바로 읽음. 같은 SOPS 파일을 Terraform이랑 ArgoCD가 다른 진입점에서 같이 본다는 게 의외로 좋았다.

장점은 명확하다. PR에 시크릿 추가가 그냥 코드 변경이다. 누가 언제 어떤 시크릿을 추가했는지 git blame이 다 잡아준다. 부트스트랩 시점에도 KMS 권한만 있으면 풀린다.

근데 단점도 있다. 시크릿 로테이션이 진짜 귀찮다. 값 하나 바꾸려면 SOPS로 디크립트 → 편집 → 재암호화 → 커밋 → PR → 머지 → ArgoCD sync 까지 가야 한다. AWS Secrets Manager에서 콘솔로 한 줄 바꾸는 거랑 비교 안 된다. 또 fine-grained 액세스 컨트롤이 사실상 KMS 키 레벨 분리로만 가능하다. 시크릿마다 다른 사람한테 읽기 권한 주는 건 어렵다.

우리 팀 분기 기준

1년 굴려보고 정리한 분기 기준이다. 절대적인 룰은 아니고 우리 팀 컨텍스트 기준.

ESO로 가는 케이스

  • 운영 환경 워크로드의 런타임 시크릿 (DB 비번, 외부 API 키)
  • 로테이션 빈도가 높은 시크릿 (RDS 마스터 비번 자동 로테이션 등)
  • 시크릿 값 자체를 절대 Git에 두면 안 되는 컴플라이언스 항목
  • 시크릿당 다른 IAM 정책으로 액세스 통제가 필요한 경우

SOPS로 가는 케이스

  • Terraform이 plan/apply 시점에 직접 읽어야 하는 시크릿
  • 클러스터 부트스트랩 시점 시크릿 (ESO 깔리기 전 단계)
  • dev/sandbox 환경의 더미 또는 저민감도 시크릿
  • 인프라 코드와 시크릿이 한 PR로 묶여야 하는 경우 (예: 신규 SaaS 연동 시 토큰과 Terraform 리소스 동시 추가)

이 분기를 명시적으로 README에 적어두니까 신규 팀원이 헷갈리는 일이 확 줄었다. "이거 어디다 넣어요?" 질문이 거의 안 나온다.

한 가지 더 — 모니터링 갭

ESO는 본인 메트릭을 노출한다. externalsecret_sync_calls_total 같은 거. 우리는 sync 실패가 30분 이상 지속되면 알람 나가게 해놨다. Secrets Manager 권한이 실수로 빠지거나 키 자체가 삭제되는 경우를 잡는다.

SOPS는 이런 메트릭이 없다. ArgoCD가 plugin에서 디크립트 실패하면 sync 실패가 뜨긴 하는데, 메시지가 모호하다. KMS 권한 빠진 건지 키가 지워진 건지 파일 포맷이 깨진 건지 한참 봐야 안다. 이게 SOPS 쪽의 운영 부담을 가중시키는 부분이다.

그래서 결론

둘 다 쓰는 게 정답이다... 라고 말하긴 좀 게으른 결론 같지만, 실제로 그렇다. 한쪽을 버리면 그 영역에서 우회 절차가 늘어나고, 우회 절차는 결국 휴먼 에러로 돌아온다.

다만 "둘 다 쓴다"가 "아무거나 편한 거 쓴다"가 되면 안 된다. 분기 기준을 글로 박아놓고, PR 리뷰에서 잘못된 도구를 골랐을 때 짚어주는 문화가 같이 따라와야 한다. 우리는 이 분기 기준이 자리잡는 데 한 4개월 걸렸다.

혹시 ESO에서 SOPS로 가거나 그 반대 마이그레이션을 고민 중인 분들 있으면 댓글로 상황 좀 알려주세요. 케이스 보고 추가로 정리해볼게요.

반응형