ConfigMap·Secret 이란?
12-factor 원칙의 핵심은 "설정을 코드(이미지)에서 분리"하는 것입니다. 쿠버네티스는 두 리소스로 이를 구현합니다.
- ConfigMap: 비민감 설정(앱 옵션, URL, 기능 플래그 등)을 키-값으로 저장
- Secret: 비밀번호, 토큰, 인증서 등 민감정보를 저장 (base64 인코딩 + 접근 제어)
둘 다 환경변수나 볼륨 파일로 컨테이너에 주입할 수 있어, 같은 이미지를 dev/stage/prod에서 서로 다른 설정으로 재사용할 수 있습니다.
Secret의 기본 인코딩은 암호화가 아니라 base64입니다. 누구나 디코딩할 수 있으므로 "Secret이니까 안전하다"는 착각은 금물입니다. 진짜 보호는 RBAC + etcd 암호화 + 외부 비밀 관리 도구로 완성됩니다.
ConfigMap 만들기
명령형(리터럴/파일)
# 키-값 직접
kubectl create configmap app-config \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONN=100
# 파일 통째로 (--from-file)
kubectl create configmap nginx-conf --from-file=./nginx.conf
# .env 형식 일괄 (--from-env-file)
kubectl create configmap app-env --from-env-file=./app.env선언형(YAML) — 권장
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
MAX_CONN: "100"
# 파일 형태 설정도 통째로 넣을 수 있음
application.yaml: |
server:
port: 8080
feature:
newUI: truekubectl apply -f configmap.yaml
kubectl get cm app-config -o yamlSecret 만들기
# 일반 비밀값
kubectl create secret generic db-secret \
--from-literal=DB_USER=admin \
--from-literal=DB_PASS='S3cr3t!23'
# TLS 인증서
kubectl create secret tls web-tls --cert=tls.crt --key=tls.key
# 프라이빗 레지스트리 인증
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=ci --docker-password='token'YAML로 쓸 때는 값이 base64여야 합니다. 평문을 그대로 쓰려면 stringData를 사용하세요.
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData: # 평문 입력 → 저장 시 자동 base64
DB_USER: admin
DB_PASS: "S3cr3t!23"Secret의 주요 타입은 다음과 같습니다.
| type | 용도 |
|---|---|
Opaque | 임의 키-값 (기본) |
kubernetes.io/tls | TLS 인증서/키 |
kubernetes.io/dockerconfigjson | 레지스트리 인증 |
kubernetes.io/service-account-token | SA 토큰 |
컨테이너에 주입하기 — 환경변수
개별 키 주입
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: DB_PASS
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASS전체 일괄 주입 (envFrom)
envFrom:
- configMapRef: { name: app-config }
- secretRef: { name: db-secret }환경변수로 주입한 값은 Pod가 만들어질 때 한 번 박힙니다. ConfigMap을 수정해도 이미 떠 있는 Pod의 환경변수는 갱신되지 않습니다. 반영하려면 롤링 재시작이 필요합니다.
컨테이너에 주입하기 — 볼륨 마운트
ConfigMap/Secret을 파일로 마운트하면, 환경변수와 달리 ConfigMap 변경 시 마운트된 파일이 자동 갱신됩니다(수십 초 지연).
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: config-vol
mountPath: /etc/app # /etc/app/application.yaml 로 생성됨
readOnly: true
- name: secret-vol
mountPath: /etc/secret
readOnly: true
volumes:
- name: config-vol
configMap:
name: app-config
items: # 특정 키만 선택 마운트
- key: application.yaml
path: application.yaml
- name: secret-vol
secret:
secretName: db-secret
defaultMode: 0400 # 권한 제한| 방식 | 자동 갱신 | 적합한 경우 |
|---|---|---|
| 환경변수 (env/envFrom) | 아니오 | 단순 값, 12-factor 앱 |
| 볼륨 마운트 | 예(파일 갱신) | 설정 파일, 인증서, 핫리로드 앱 |
설정 변경 시 자동 롤링 재시작
환경변수 주입은 자동 반영이 안 되므로, 설정 변경 시 Deployment를 다시 굴려야 합니다. 흔한 패턴은 ConfigMap 내용의 해시를 어노테이션에 박는 것입니다.
spec:
template:
metadata:
annotations:
# 내용이 바뀌면 이 값을 갱신 → Pod 템플릿 변경 → 롤링 재시작
checksum/config: "a1b2c3..."수동으로는 다음 명령으로 즉시 롤링합니다.
kubectl rollout restart deployment/myappkubectl edit 또는 apply로 불변(immutable) ConfigMap을 만들면(immutable: true) 실수 변경을 막고 API 서버 부하도 줄일 수 있습니다. 단, 변경하려면 삭제 후 재생성해야 합니다.
보안 강화 — Secret 진짜로 보호하기
1) etcd 저장 시 암호화
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
providers:
- aescbc:
keys:
- name: key1
secret: <base64-32byte-key>
- identity: {}API 서버 기동 옵션에 --encryption-provider-config를 추가하면 Secret이 etcd에 암호문으로 저장됩니다.
2) RBAC로 접근 제한
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: prod
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["db-secret"] # 특정 Secret만
verbs: ["get"]3) 외부 비밀 관리 연동
운영에서는 평문 Secret을 git에 두지 않고 다음을 권장합니다.
- External Secrets Operator: AWS Secrets Manager, Vault 등에서 동기화
- Sealed Secrets: 암호문 형태로 git 커밋 가능, 클러스터 내에서만 복호화
- SOPS: 키만 KMS로 관리하며 파일 암호화
검증과 디버깅
# Secret 값 디코딩 확인
kubectl get secret db-secret -o jsonpath='{.data.DB_PASS}' | base64 -d; echo
# Pod 안에서 실제 주입된 환경변수 확인
kubectl exec deploy/myapp -- env | grep -E 'LOG_LEVEL|DB_'
# 마운트된 설정 파일 확인
kubectl exec deploy/myapp -- cat /etc/app/application.yaml| 증상 | 원인 |
|---|---|
| CreateContainerConfigError | 참조한 ConfigMap/Secret/key가 존재하지 않음 |
| 값이 빈 문자열 | key 이름 오타 또는 대소문자 불일치 |
| 파일이 안 보임 | mountPath가 기존 디렉터리를 덮어씀(전체 교체됨) |
정리
| 항목 | ConfigMap | Secret |
|---|---|---|
| 대상 | 비민감 설정 | 비밀번호/토큰/인증서 |
| 저장 | 평문 | base64 (암호화 아님) |
| 주입 | env / envFrom / volume | 동일 |
| 자동 갱신 | volume 마운트만 | volume 마운트만 |
| 보안 | RBAC | RBAC + etcd 암호화 + 외부도구 |
| 변경 반영 | rollout restart | 동일 |
설정과 코드의 분리가 ConfigMap/Secret의 본질입니다. 핫리로드가 필요하면 볼륨 마운트, 단순 값은 환경변수를 쓰고, Secret은 base64일 뿐임을 잊지 말고 etcd 암호화·RBAC·외부 비밀관리로 실질적 보호를 갖추세요.
이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.
질문 & 답변 (Q&A)
이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.