플랫폼, 데브옵스와 클라우드

ConfigMap과 Secret

meellon 2026. 6. 25. 05:40

학습 목표

ConfigMapSecret으로 설정·자격증명을 이미지·manifest와 분리할 수 있다.

환경변수·볼륨 마운트·envFrom 주입 방식 차이를 설명할 수 있다.

Secret의 저장·전송·RBAC·rotation 개요를 설명할 수 있다.

12-factor config 원칙과 K8s 설정 리소스 매핑을 설명할 수 있다.

문제 상황

  • DB URL·API 키를 Dockerfile ENV에 박아두었다
    • 이미지 재빌드 없이 dev/stage/prod 전환 불가
  • Deployment YAML에 비밀번호가 평문으로 있다
    • Git에 올리면 유출, 감사·로테이션도 어렵다
  • 설정 JSON 하나 바꿨는데 Pod 50개 이미지를 다시 빌드했다
    • 설정 변경 = 재배포만 하면 되는데 빌드 파이프라인을 탔다
  • ConfigMap을 바꿨는데 실행 중 Pod에 반영이 안 된다
    • 주입 방식·재시작 필요 여부를 모른다
  • Secret을 kubectl get -o yaml 했더니 base64 — 암호화가 아니다
    • etcd encryption at rest·RBAC·외부 vault 연동이 별도다

앞서 Pod·Deployment·Service를 봤다. ConfigMap·Secret은 워크로드에 설정을 붙이는 K8s 네이티브 방법이다.

1. 설정 분리 — 12-factor config

III. Config — 설정은 환경마다 다르고, 코드·이미지와 분리한다.

단계 설정 위치 K8s
Build 없음 (이미지에 env별 값 금지) Dockerfile — ARG만, prod URL 금지
Release release마다 config 묶음 ConfigMap·Secret apply
Run 프로세스 환경으로 주입 Pod env·volumeMount
  • immutable image — 같은 이미지를 dev·prod에, 다른 ConfigMap으로
  • GitOps — manifest + ConfigMap/Secret을 repo·환경별 overlay로 관리
  • Helm values·Kustomize — 환경별 config 패치 (14편 GitOps에서 심화)

2. ConfigMap

ConfigMap비민감 설정(key-value 또는 파일)을 K8s API 객체로 저장.

apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
data:
  LOG_LEVEL: info
  APP_ENV: production
  app.properties: |
    server.port=8080
    cache.ttl=300
주입 방식 동작 config 변경 시
env 키 하나 → 환경변수 Pod 재시작 필요
envFrom ConfigMap 전체 → env Pod 재시작 필요
volume 파일로 마운트 kubelet 주기적 sync (앱이 reload해야 반영)
command args $() 치환 (구버전) 거의 env/volume 사용
# env + envFrom
env:
  - name: LOG_LEVEL
    valueFrom:
      configMapKeyRef:
        name: api-config
        key: LOG_LEVEL
envFrom:
  - configMapRef:
      name: api-config
      optional: false
# volume — file as config
volumes:
  - name: config
    configMap:
      name: api-config
      items:
        - key: app.properties
          path: app.properties
volumeMounts:
  - name: config
    mountPath: /etc/config
    readOnly: true
  • subPath — 단일 파일만 마운트 (디렉터리 덮어쓰기 방지)
  • defaultMode — volume 마운트 파일 권한 (Secret은 0400 등)
  • immutable ConfigMap — 생성 후 수정 불가, 실수·드리프트 방지

3. Secret

Secret민감 데이터(password, token, TLS cert). API상 base64 인코딩일 뿐 암호화 아님.

  ConfigMap Secret
용도 로그 레벨, feature flag, URL(공개) DB password, API key, TLS key
타입 Opaque(기본) Opaque, kubernetes.io/tls, docker-registry
저장 etcd (평문) etcd — encryption at rest 권장
표시 kubectl get 값 노출 data 필드 base64, describe 제한
RBAC configmaps secrets더 좁게
apiVersion: v1
kind: Secret
metadata:
  name: api-db
type: Opaque
stringData:          # apply 시 base64 자동 (권장)
  DB_USER: app
  DB_PASSWORD: s3cr3t
# Pod — Secret as env
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: api-db
        key: DB_PASSWORD
# TLS Secret for Ingress (앞서 shop-tls)
apiVersion: v1
kind: Secret
metadata:
  name: shop-tls
type: kubernetes.io/tls
data:
  tls.crt: <base64>
  tls.key: <base64>
  • stringData — YAML에 평문 작성, API 저장 시 인코딩
  • Git에 Secret 평문 금지 — Sealed Secrets, External Secrets, SOPS, vault (Security 13편)
  • ServiceAccount token Secret — legacy; bound token·projected volume 권장

4. Pod에 함께 쓰기

실무 API Pod는 ConfigMap(설정) + Secret(자격증명) 조합.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: app
          image: my/api:1.2.0
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: api-config
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: api-db
                  key: DB_PASSWORD
          volumeMounts:
            - name: config
              mountPath: /etc/config
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: api-config
규칙 이유
Secret은 env 또는 readOnly volume 파일 권한·최소 노출
ConfigMap 크기 1MiB 제한 큰 설정은 별도 스토리지·init container
optional: true config 없어도 기동 (로컬·테스트)
probe·Service는 변경 없음 설정만 바뀌고 포트·label 동일

전체 manifest는 code/configmap-secret.yaml 참고.

5. 변경 반영과 reload

방식 ConfigMap 수정 후
env / envFrom 값은 Pod 생성 시 고정 → rollout restart
volume kubelet이 파일 업데이트 (수 분) → 앱 SIGHUP/reload 필요
immutable 새 ConfigMap 이름 + Deployment patch
kubectl apply -f code/configmap-secret.yaml
kubectl rollout restart deployment/api
kubectl exec deploy/api -- cat /etc/config/app.properties
# Stakater Reloader 등 — ConfigMap/Secret 변경 시 자동 rollout
# annotation: configmap.reloader.stakater.com/reload: "api-config"
  • downward API — Pod metadata·resource limit을 env로 (별도 주제)
  • projected volume — ConfigMap + Secret + SA token 한 volume

6. Secret rotation 개요

단계 내용
듀얼 credential DB user 두 개, 번갈아 rotate
새 Secret 버전 api-db-v2 apply → Deployment env ref 변경 → rollout
External Secrets Operator Vault/AWS SM → K8s Secret 동기화
cert-manager TLS Certificate → Secret 자동 갱신 (앞서 Ingress)
  • rotation 중 구·신 credential 동시 유효 기간 확보
  • zero-downtime — readiness 통과 후 old credential 폐기
  • 플랫폼 팀은 주입 경로 표준화, 앱 팀은 reload 계약

7. 보안·운영 체크리스트

항목 권장
Git Secret 평문 커밋 금지, Sealed/External Secrets
RBAC Secret get/list 최소 권한, namespace 분리
etcd EncryptionConfiguration at rest
audit Secret 접근 audit log
ConfigMap 민감 정보 넣지 않기 — Secret으로
네임스페이스 dev/prod ConfigMap 이름·overlay 분리
kubectl get configmap,secret
kubectl describe configmap api-config
kubectl get secret api-db -o jsonpath='{.data}'   # still encoded — not for logs

8. 정리

  • ConfigMap — 비민감 설정, Secret — 자격증명·TLS
  • 12-factor — 설정은 release/run에, 이미지와 분리
  • env vs volume — 재시작 vs 파일 reload 트레이드오프
  • Secret base64 ≠ 암호화 — RBAC·etcd encryption·외부 vault
  • rollout restart·Reloader로 config 변경 반영

다음에 다룰 것

  • PV·PVC·StorageClass
  • StatefulSet과 stable identity

해당 내용은 Kubernetes Documentation (kubernetes.io) 의 내용을 기반으로 합니다.

'플랫폼, 데브옵스와 클라우드' 카테고리의 다른 글

스케줄링과 리소스  (0) 2026.06.27
스토리지와 StatefulSet  (0) 2026.06.26
Service와 Ingress  (0) 2026.06.24
Pod와 Deployment  (0) 2026.06.23
Kubernetes 개요  (0) 2026.06.22