반응형
0. 개요
- 개념과 차이: ConfigMap vs Secret
- 1-1. 목적·사용 시점
- 1-2. 보안·용량·인코딩 제약
- 생성과 업데이트: kubectl & YAML
- 2-1. ConfigMap 생성(from-literal/from-file/YAML)
- 2-2. Secret 생성(generic/docker-registry/tls)
- 애플리케이션 주입 패턴
- 3-1. 환경 변수(env/envFrom)
- 3-2. 볼륨 마운트(파일 주입·subPath)
- 보안과 암호화
- 4-1. etcd/리소스 암호화(KMS)
- 4-2. RBAC·감사·네임스페이스 격리
- 배포 도구와 환경 분리
- 5-1. Kustomize 오버레이(dev/stg/prod)
- 5-2. Helm 템플릿/values로 관리
- 고급: Sealed Secrets & External Secrets
- 6-1. Sealed Secrets 워크플로우
- 6-2. External Secrets Operator(AWS/GCP/Azure)
- 로테이션과 무중단 전략
- 7-1. DB/토큰 교체 롤링
- 7-2. 애플리케이션 재시작 정책
- 네임스페이스/라벨링/거버넌스
- 8-1. 네이밍·라벨·어노테이션 규칙
- 8-2. Immutable ConfigMap/Secret 전략
- 관측·디버깅·트러블슈팅
- 9-1. kubectl 필수 명령
- 9-2. 흔한 오류와 해결
- 체크리스트 & 베스트 프랙티스
- 10-1. 도입 전 점검
- 10-2. 운영 중 가이드
- FAQ
- base64는 암호화인가?
- 언제 Secret/ConfigMap을 나눌까?
- 결론 요약
Kubernetes에서 ConfigMap과 Secret 관리하기
백엔드 애플리케이션을 쿠버네티스에 배포하면 가장 먼저 부딪히는 주제가 “설정과 비밀을 어떻게 안전하게 주입할 것인가”입니다. 이 글은 ConfigMap/Secret의 차이에서 시작해 생성·주입·보안·배포 도구·로테이션까지, 바로 실전에 복붙 가능한 예제로 정리했습니다.
1. 개념과 차이: ConfigMap vs Secret
1-1. 목적·사용 시점
- ConfigMap: 코드와 분리된 비민감 설정값(예: 기능 플래그, 외부 API 엔드포인트, 포맷 문자열).
- Secret: 민감 데이터(예: DB 비밀번호, API 키, TLS 키/인증서). 접근과 감사가 중요합니다.
- 공통: 애플 이미지를 다시 빌드하지 않고도 설정을 바꿀 수 있게 해 주는 운영 레버입니다.
1-2. 보안·용량·인코딩 제약
- Secret 데이터는 API 상 base64 인코딩으로 저장됩니다(암호화와 다름). etcd 암호화와 RBAC으로 보호해야 합니다.
- 리소스 크기: 단일 오브젝트 수백 KB 수준을 권장(너무 큰 설정은 별도 스토리지/파일 서버 고려).
2. 생성과 업데이트: kubectl & YAML
2-1. ConfigMap 생성(from-literal/from-file/YAML)
# ① 즉석 키/값 kubectl create configmap app-config -n app \ --from-literal=APP_ENV=prod --from-literal=FEATURE_X=true
② 파일로부터
kubectl create configmap app-config -n app
--from-file=config.json=./config.prod.json
③ 선언형 YAML
apiVersion: v1
kind: ConfigMap
metadata: { name: app-config, namespace: app, labels: { app: demo } }
data:
APP_ENV: "prod"
API_BASE: "https://api.example.com
"
2-2. Secret 생성(generic/docker-registry/tls)
# ① generic: 문자열/파일 kubectl create secret generic db-secret -n app \ --from-literal=DB_USER=app --from-literal=DB_PASS='S3cr3t!'
② docker-registry: 프라이빗 레지스트리 인증
kubectl create secret docker-registry regcred -n app
--docker-server=registry.example.com --docker-username=alice
--docker-password='********' --docker-email=dev@example.com
③ tls: 인증서/키
kubectl create secret tls site-tls -n app
--cert=./tls.crt --key=./tls.key
④ 선언형 YAML (값은 base64로 인코딩)
apiVersion: v1
kind: Secret
metadata: { name: db-secret, namespace: app }
type: Opaque
data:
DB_USER: YXBw
DB_PASS: UzNjcjN0IQ==
3. 애플리케이션 주입 패턴
3-1. 환경 변수(env/envFrom)
# Deployment 발췌 env: - name: APP_ENV valueFrom: { configMapKeyRef: { name: app-config, key: APP_ENV } } - name: DB_PASS valueFrom: { secretKeyRef: { name: db-secret, key: DB_PASS } }
여러 키를 한 번에 주입
envFrom:
configMapRef: { name: app-config }
secretRef: { name: db-secret }
- 장점: 간단·프레임워크 친화적. 단점: 긴 구조/파일형 설정엔 불리.
3-2. 볼륨 마운트(파일 주입·subPath)
# Deployment 발췌 - 파일로 마운트 volumes: - name: cm configMap: { name: app-config, items: [ { key: "config.json", path: "config.json" } ] } - name: sec secret: { secretName: db-secret } containers: - name: api volumeMounts: - { name: cm, mountPath: /app/config, readOnly: true } - { name: sec, mountPath: /app/secret, readOnly: true }
subPath로 파일 한 개만 특정 경로에 마운트 가능. 애플 재시작 없이 파일 갱신을 폴링해 반영하는 전략과 궁합이 좋습니다.
4. 보안과 암호화
4-1. etcd/리소스 암호화(KMS)
# 컨트롤플레인(encryptionConfiguration) 예시 (관리형 K8s는 콘솔/플래그로 설정) apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: [ "secrets" ] providers: - kms: name: kms-provider endpoint: unix:///var/run/kmsplugin/socket.sock - identity: {}
- Secret은 전송/저장 모두 암호화가 기본값이 되도록 합니다(클라우드 매니지드 K8s는 옵션 제공).
4-2. RBAC·감사·네임스페이스 격리
# 읽기 전용 Role (특정 네임스페이스) kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: { name: secret-reader, namespace: app } rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get","list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: { name: alice-secret-rb, namespace: app } subjects: [ { kind: User, name: alice } ] roleRef: { kind: Role, name: secret-reader, apiGroup: rbac.authorization.k8s.io }
- 감사(오딧) 로그로 누가 언제 어떤 Secret을 읽었는지 추적 가능하게 합니다.
5. 배포 도구와 환경 분리
5-1. Kustomize 오버레이(dev/stg/prod)
# base/kustomization.yaml resources: [ deployment.yaml, service.yaml ] configMapGenerator: - name: app-config literals: [ APP_ENV=dev, API_BASE=https://dev.api.example.com ] generatorOptions: { disableNameSuffixHash: true }
overlays/prod/kustomization.yaml
bases: [ ../../base ]
configMapGenerator:
name: app-config
behavior: replace
literals: [ APP_ENV=prod, API_BASE=https://api.example.com
]
오버레이로 환경별 차이를 선언적으로 유지합니다. disableNameSuffixHash는 이름 해시를 끄고, 대신 롤아웃 트리거는 애노테이션으로 관리하는 패턴을 권장합니다.
5-2. Helm 템플릿/values로 관리
# templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: { name: {{ include "app.fullname" . }}-config } data: APP_ENV: "{{ .Values.app.env }}" API_BASE: "{{ .Values.app.apiBase }}"
# values-prod.yaml app: env: prod apiBase: https://api.example.com
6. 고급: Sealed Secrets & External Secrets
6-1. Sealed Secrets 워크플로우
- 컨트롤러의 공개키로 Secret을 암호화해 Git에 커밋 → 클러스터에서만 복호화되어 일반 Secret으로 생성.
# 암호화된 시크릿 예시(발췌) apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: { name: db-secret, namespace: app } spec: encryptedData: DB_PASS: AgBv...==
6-2. External Secrets Operator(AWS/GCP/Azure)
- 클라우드 시크릿 매니저(예: AWS Secrets Manager)에서 값을 동기화해 Kubernetes Secret으로 투영.
# AWS 예시 apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: { name: db-secret, namespace: app } spec: refreshInterval: 1h secretStoreRef: { name: aws-sm, kind: ClusterSecretStore } target: { name: db-secret, creationPolicy: Owner } data: - secretKey: DB_PASS remoteRef: { key: prod/db, property: password }
7. 로테이션과 무중단 전략
7-1. DB/토큰 교체 롤링
- Secret을 갱신하면 파드가 자동 재시작되진 않습니다. 애노테이션 해시를 파드 스펙에 포함해 롤아웃을 트리거하세요.
# Deployment 템플릿에 해시 주입(Helm 예) annotations: secret-hash: "{{ include (print $.Template.BasePath \"/secret.yaml\") . | sha256sum }}"
7-2. 애플리케이션 재시작 정책
- 구(RollingUpdate) 전략으로 파드를 순차 교체해 연결 중단을 최소화.
- DB 비밀번호 변경은 양쪽(구/신) 모두 허용되는 그레이스 기간을 두면 안전합니다.
8. 네임스페이스/라벨링/거버넌스
8-1. 네이밍·라벨·어노테이션 규칙
- 네이밍:
<팀>-<서비스>-<용도>(예:checkout-api-config). - 라벨:
app=checkout,tier=backend,managed-by=helm. - 어노테이션: 소유자/만료일/티켓 참조를 기록해 가시성↑.
8-2. Immutable ConfigMap/Secret 전략
- 기본 오브젝트는 불변 속성 제공이 제한적입니다. 해시가 붙은 이름/어노테이션 해시로 불변처럼 다루고, 변경 시 새 오브젝트를 생성해 롤아웃합니다.
9. 관측·디버깅·트러블슈팅
9-1. kubectl 필수 명령
kubectl -n app get cm,secret kubectl -n app describe cm app-config kubectl -n app get secret db-secret -o jsonpath='{.data.DB_PASS}' | base64 -d kubectl -n app rollout restart deploy/api kubectl -n app get events --sort-by=.lastTimestamp
9-2. 흔한 오류와 해결
- CrashLoopBackOff: 환경 변수 키 오타 →
describe이벤트로 키 누락 확인. - PermissionDenied: RBAC 정책 부족 → Role/RoleBinding 점검.
- 갱신 미반영: Secret 업데이트 후 파드 미재시작 →
rollout restart또는 해시 주입 전략 적용.
10. 체크리스트 & 베스트 프랙티스
10-1. 도입 전 점검
- 민감/비민감 경계 정의, 키 네이밍 규칙 수립.
- etcd 암호화/KMS·RBAC·감사 로깅 활성화.
- 환경 분리(Kustomize/Helm)와 Git 정책(승인/리뷰) 정의.
10-2. 운영 중 가이드
- Secret 로테이션 주기/소유자 명시, 만료 알림.
- 해시 기반 롤아웃, 릴리즈마다 설정 드리프트 검출.
- 가능하면 Sealed/External Secrets로 Git에 평문 무커밋.
11. FAQ
- base64는 암호화인가요?
아니요. 단순 인코딩입니다. 저장 시 etcd 암호화와 접근 제어(RBAC), 전송 시 TLS가 필수입니다.
- 언제 Secret·ConfigMap을 나누나요?
누출 시 피해가 있는 값(크리덴셜·토큰·키)은 Secret, 그 외 비민감 설정은 ConfigMap으로 분리하세요. 애매하면 일단 Secret로 시작해도 무방합니다.
12. 결론 요약
ConfigMap은 비밀을 제외한 설정을, Secret은 민감 정보를 안전하게 전달하는 도구입니다. 선언형(YAML)·도구(Kustomize/Helm)·보안(RBAC/KMS)·로테이션(해시/재시작)까지 표준을 정해두면 팀 전체의 배포와 운영 신뢰도가 급상승합니다. 처음엔 작은 서비스에 적용해 보고, Sealed/External Secrets로 Git 친화적·클라우드 네이티브한 비밀 관리를 완성해 보세요.
반응형
'Backend > Study' 카테고리의 다른 글
| [Tip] ChatGPT를 활용한 개발 업무 자동화 사례 (0) | 2025.11.04 |
|---|---|
| [Tip] Notion + GitHub로 개발 문서 자동화하기 (0) | 2025.11.03 |
| [DevOps] Kubernetes 초보자 가이드 (백엔드 개발자를 위한 입문) (0) | 2025.10.30 |
| [DevOps] GitLab CI/CD vs GitHub Actions 비교 (0) | 2025.10.29 |
| [DevOps]Jenkins CI/CD 파이프라인 구축 방법 (0) | 2025.10.28 |