쿠버네티스 마스터 노트 시리즈 5편. ConfigMap이 12-Factor의 'config in environment'를 K8s에 적용한 방식, Secret이 base64만 인코딩이고 암호화 X인 진실, Pod에 주입하는 4가지 방법(env·envFrom·volume·subPath), 운영 환경에서 Secret 평문 위험과 Sealed Secrets·External Secrets·Vault 통합 패턴까지.
이 글은 쿠버네티스 마스터 노트 시리즈의 다섯 번째 편입니다. 4편(Services)까지 Pod 외부 접근이었다면, 이번엔 Pod 안 설정·민감 정보 — ConfigMap과 Secret.
코드 안 비밀번호 박는 건 안티패턴. 환경 변수로? 어디서 관리? K8s가 그 답 — ConfigMap·Secret. 다만 Secret은 암호화 X 함정이 있습니다.
처음 ConfigMap·Secret이 어렵게 느껴지는 이유
처음 이 단원이 어렵게 느껴지는 이유는 두 가지예요. 첫째, 둘이 어떻게 다른지 막연합니다. 같은 키-값인데 왜 두 종류? 둘째, Pod에 주입하는 방법이 4가지 — env·envFrom·volume·subPath 헷갈립니다.
해결법은 한 가지예요. "ConfigMap = 일반 / Secret = 민감" 한 줄. 이름만 다르고 동작은 거의 같음. 다만 Secret은 평문 base64일 뿐 암호화 X — 이 함정만 인식하면 운영 안전.
12-Factor App — Config in Environment
환경별 다른 값 (DB 호스트·API 키·로그 레벨) →
코드에 박지 말고 → 환경 변수 또는 외부 설정으로
K8s에서 = ConfigMap (일반) + Secret (민감).
ConfigMap — 일반 설정
생성 방법 4종
# 1. CLI로 직접
kubectl create configmap app-config \
--from-literal=DB_HOST=postgres \
--from-literal=LOG_LEVEL=info
# 2. 파일에서
kubectl create configmap app-config \
--from-file=config.properties
# 3. 디렉토리 전체
kubectl create configmap app-config \
--from-file=./config-dir/
# 4. YAML
kubectl apply -f configmap.yaml
YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_HOST: "postgres"
DB_PORT: "5432"
LOG_LEVEL: "info"
config.properties: |
server.port=8080
spring.profiles.active=production
Pod에 주입 4종
1. 단일 환경 변수 (env.valueFrom)
spec:
containers:
- name: app
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
2. 모든 키를 환경 변수로 (envFrom)
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config
ConfigMap의 모든 키-값이 환경 변수로 주입.
3. Volume Mount (파일)
spec:
containers:
- name: app
volumeMounts:
- name: config
mountPath: /etc/config
volumes:
- name: config
configMap:
name: app-config
/etc/config/DB_HOST, /etc/config/config.properties 등 파일로.
4. SubPath (특정 파일만)
volumeMounts:
- name: config
mountPath: /etc/myapp/config.properties
subPath: config.properties
특정 파일 하나만 마운트. 디렉토리 덮어쓰기 회피.
여기서 정말 중요한 시험 함정 — ConfigMap 변경 시 Pod 자동 갱신:
- env / envFrom = 자동 갱신 X (Pod 재시작 필요)
- Volume Mount = 자동 갱신 O (수십 초 후)
설정 변경이 잦으면 Volume 권장. 단 메모리에서 갱신은 앱 코드 책임.
Secret — 민감 정보
# CLI
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password=s3cr3t
# YAML
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: YWRtaW4= # base64
password: czNjcjN0
Secret 타입
| Type | 용도 |
|---|---|
| Opaque | 일반 (기본) |
| kubernetes.io/dockerconfigjson | Docker registry |
| kubernetes.io/tls | TLS 인증서 |
| kubernetes.io/service-account-token | ServiceAccount |
TLS Secret
kubectl create secret tls my-tls \
--cert=cert.pem \
--key=key.pem
Ingress 등에서 사용.
Pod 주입 — ConfigMap과 동일
env:
- name: DB_PASS
valueFrom:
secretKeyRef:
name: db-secret
key: password
envFrom:
- secretRef:
name: db-secret
volumeMounts:
- name: secret
mountPath: /etc/secret
volumes:
- name: secret
secret:
secretName: db-secret
Secret의 결정적 함정 — 암호화 X
> kubectl get secret db-secret -o yaml
data:
password: czNjcjN0 # base64
> echo "czNjcjN0" | base64 -d
s3cr3t # 평문 노출!
여기서 정말 중요한 시험 함정 — K8s Secret은 base64 인코딩만, 암호화 X. etcd에 그대로 저장. RBAC 권한 있는 사람은 즉시 평문 조회 가능. 운영 환경엔 추가 보호 필수.
운영 Secret 관리 패턴
1. EncryptionConfiguration — etcd 암호화
# /etc/kubernetes/encryption.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: [secrets]
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
API Server가 etcd 쓰기 전 암호화. 기본 활성 X — 명시 설정.
2. Sealed Secrets
# 클라이언트 도구
kubeseal < secret.yaml > sealed-secret.yaml
# 결과 — 클러스터 안 전용 키로 암호화된 SealedSecret 객체
# Git에 커밋해도 안전
GitOps 환경 표준. Bitnami가 만듦.
3. External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-secret
spec:
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-secret
data:
- secretKey: password
remoteRef:
key: secret/data/db
property: password
Vault·AWS Secrets Manager·GCP Secret Manager 등 외부 시스템에서 자동 동기화.
4. CSI Secret Store Driver
Pod 시작 시 외부 시스템에서 직접 마운트. K8s Secret 객체 거치지 않음.
여기서 정말 중요한 시험 함정 — 운영 Secret 관리 = 외부 도구 거의 필수:
- 작은 환경 = Sealed Secrets
- 엔터프라이즈 = External Secrets + Vault
- 클라우드 네이티브 = 클라우드 Secret Manager
ConfigMap vs Secret — 결정 기준
| 데이터 | 선택 |
|---|---|
| DB 호스트·포트 | ConfigMap |
| 로그 레벨·기능 플래그 | ConfigMap |
| 일반 설정 파일 | ConfigMap |
| DB 비밀번호·API 키 | Secret |
| TLS 인증서·키 | Secret (tls 타입) |
| OAuth 토큰 | Secret |
동시 사용
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config # 일반
- secretRef:
name: db-secret # 민감
환경별 분리
configmap-dev.yaml
configmap-staging.yaml
configmap-prod.yaml
Helm·Kustomize로 환경별 관리 (9편).
또는 namespace로 분리:
ns: dev
ConfigMap app-config (개발 값)
ns: prod
ConfigMap app-config (운영 값)
ConfigMap 크기 제한
여기서 시험 함정이 하나 있어요. ConfigMap·Secret 한 객체 ≤ 1MB. etcd 한계. 큰 설정 파일은 분리 또는 외부 저장소.
ConfigMap 자동 갱신
Volume mount 시 자동 갱신:
1. ConfigMap 수정 (kubectl apply)
2. ~수십 초 후 Pod 안 파일 자동 갱신
3. 앱이 파일 변경 감지·재로드 (앱 코드 책임)
여기서 시험 함정이 하나 있어요. 앱이 파일 watch 안 하면 갱신 무용. Spring Boot Refresh Scope 또는 inotify 같은 메커니즘 필요.
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 5편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.
- ConfigMap = 일반 설정 / Secret = 민감 정보
- 동작 거의 같음, 이름만 다름
- ConfigMap 생성 —
--from-literal/--from-file/ 디렉토리 / YAML - Pod 주입 4종 — env (단일) / envFrom (전체) / Volume / subPath
- env / envFrom = 자동 갱신 X (Pod 재시작)
- Volume Mount = 자동 갱신 O (수십 초)
- 앱이 파일 watch 안 하면 무용
- Secret = base64만, 암호화 X (가장 큰 함정)
- etcd에 평문 저장
- 운영 환경 = 추가 보호 필수
- Secret 타입 — Opaque / dockerconfigjson / tls / service-account-token
- EncryptionConfiguration = etcd 암호화 (기본 비활성)
- Sealed Secrets = GitOps 환경 표준 (Bitnami)
- External Secrets Operator = Vault·AWS Secrets Manager 동기화
- CSI Secret Store Driver = Pod 직접 마운트
- 운영 — Sealed Secrets / External Secrets+Vault / 클라우드 SM
- ConfigMap·Secret ≤ 1MB (etcd 한계)
- 환경별 분리 — Helm·Kustomize 또는 namespace
시리즈 다른 편
- 1편 — 아키텍처·Control Plane
- 2편 — Pod
- 3편 — Workloads
- 4편 — Services·Networking
- 5편 — ConfigMap·Secret (현재 글)
- 6편 — Storage
- 7편 — Scaling·Scheduling
- 8편 — Security
- 9편 — Helm
- 10편 — 실전 (매니지드·GitOps·Observability)
공식 문서: Kubernetes ConfigMap / Secret 에서 더 깊이.
다음 글(6편)에서는 Storage — Volume·PV·PVC·StorageClass·CSI까지 풀어 갑니다.