콘텐츠로 이동

M5. ConfigMap·Secret·환경변수 주입

NKS로 옮길 web-app, api-service, ai-service가 환경별 주소·log level을 image에 굽거나 API token을 manifest에 적으면 같은 image를 재사용하기 어렵고 유출 범위도 커집니다. ConfigMap과 Secret의 역할, env 주입 시점, 변경 후 rollout 필요 여부를 구분해야 AI가 제안한 배포 변경을 안전하게 리뷰할 수 있습니다.

개념 정의의 정본은 Kubernetes BasicsSecrets Management입니다. 원본 경로는 각각 content/topics/L5/kubernetes-basics.mdx, content/topics/L3/secrets-management.mdx이며, 이 모듈은 M4의 안정된 Service 경로 위에서 설정·민감값을 process env로 전달하는 실행 경계만 검증합니다.

객체 변경과 process env snapshot의 경계
flowchart LR
Image["동일한 container image"] --> Template["Deployment Pod template"]
CM["ConfigMap: 비민감 설정"] --> Ref["configMapKeyRef"]
Secret["Secret: 민감값 전달 객체"] --> SRef["secretKeyRef"]
Ref --> Template
SRef --> Template
Template -->|"Pod 시작 시 kubelet이 주입"| Env["process env snapshot"]
Source["ConfigMap/Secret 값 변경"] -->|"실행 중 env는 그대로"| Stale["기존 Pod: old value"]
Source --> Restart["rollout restart"]
Restart --> NewPod["새 Pod: latest value"]
구분담을 값 예시이 랩에서 보는 증거
ConfigMapAPP_MODE, LOG_LEVEL평문 설정과 configMapKeyRef
SecretAPI token, DB password값은 출력하지 않고 key·길이·주입 여부만 확인
env[].valueFrom필요한 key만 다른 env 이름으로 주입source object·key를 명시적으로 리뷰
envFromobject의 유효한 key를 한꺼번에 주입편하지만 충돌·불필요한 값 노출 범위가 커짐
실행 중 process envPod 시작 시 받은 snapshotsource 변경 뒤에도 old value 유지
rollout 뒤 새 process env최신 source로 만든 새 snapshotPod 교체와 최신 revision 확인

ConfigMap은 비민감 설정을 image와 분리하는 API object이며 secrecy나 encryption을 제공하지 않습니다. Secret은 민감 데이터를 전달하기 위한 별도 object지만 data의 base64는 encoding일 뿐 encryption이 아닙니다. Secret을 쓴다는 사실만으로 저장 시 암호화, 최소 RBAC, audit, rotation과 소비자 갱신이 자동 완성되지는 않습니다.

환경변수로 주입한 ConfigMap·Secret 값은 process가 시작할 때 정해집니다. source object를 바꿔도 기존 process env는 바뀌지 않으며, 새 Pod가 생기면 그 Pod만 최신 값을 받을 수 있어 의도하지 않은 old/new 혼합 상태가 생길 수 있습니다. 이 모듈은 명시적인 rollout과 검증으로 한 version에 수렴시킵니다. Volume projection의 갱신·subPath 예외와 application hot reload는 심화 범위입니다.

Infisical을 도입해도 남는 Kubernetes 경계
flowchart LR
Store["Infisical project"] --> Identity["Machine identity + auth"]
Identity --> Operator["Infisical Operator controller"]
CRD["InfisicalStaticSecret CRD"] --> Operator
Operator --> Native["namespace의 Kubernetes Secret"]
Native --> Pod["Pod env 또는 volume"]
Update["rotation / sync"] --> Operator
Operator --> Reload["Deployment reload 정책"]

Infisical Operator를 사용해도 최종 Kubernetes Secret의 namespace, RBAC, Pod 전달 방식과 reload 정책은 남습니다. 외부 저장소가 source of truth인지, native Secret의 lifecycle owner가 누구인지, sync 실패 때 기존 값 유지와 rollout을 어떻게 관찰할지 함께 결정해야 합니다.

시점 의존 설명은 2026-07-15에 다음 공식 1차 자료로 확인했습니다.

  • ConfigMaps: 비민감 데이터, configMapKeyRef·envFrom, env 갱신에는 Pod restart 필요
  • Secrets: Secret 사용 경계, secretKeyRef, base64가 confidentiality를 제공하지 않는다는 주의
  • Updating Configuration via a ConfigMap: 기존 env 유지, rollout 뒤 최신 값, rollout 전 old/new 혼합 가능성
  • Infisical Kubernetes Operator: v1beta1 CRD, InfisicalStaticSecret, sync와 Deployment reload 기능·지원 범위

현재 Infisical 공식 문서가 표시하는 Operator 지원 Kubernetes minor는 1.29~1.33이며 NKS는 검증된 배포판 목록에 없습니다. 이 랩의 K3s 1.36.2에 Operator를 설치하지 않고 official-doc-only로만 다룹니다. M7에서 Helm과 release rollback을 학습한 뒤에도 실제 도입은 승인된 non-production NKS에서 Kubernetes compatibility, namespace-scoped RBAC, 인증 방식, sync·reload failure를 별도로 검증해야 합니다.

개념비유비유의 경계
ConfigMap제품과 분리해 갈아 끼우는 비민감 설정표비밀 금고가 아니며 읽기 권한 통제는 별도입니다.
Secret열람자를 제한해야 하는 봉투base64 표기는 자물쇠가 아니고 저장 암호화도 보장하지 않습니다.
process env 주입출발할 때 한 번 인쇄된 탑승 정보원본을 고쳐도 이미 출발한 process에는 다시 인쇄되지 않습니다.
Infisical Operator중앙 금고 값을 namespace 봉투로 동기화하는 담당자downstream Secret·RBAC·reload 판단까지 없애지 않습니다.
항목검증값
기준일2026-07-15
hostmacOS arm64
Docker client / engine29.6.1 / 29.6.1
k3d5.9.0
K3s image / API serverrancher/k3s:v1.36.2-k3s1 / v1.36.2+k3s1
kubectl1.36.1
Helm4.2.3 — 이 모듈에서는 사용하지 않음
container imagebusybox:1.37.0 + Setup의 고정 multi-platform digest
evidence 환경local-cluster; 고정 context + k8s-wb-m5-<UTC run ID>

모든 shell 명령 묶음은 executed-local입니다. 실제 production credential, NKS encryption at rest, RBAC·audit 설정과 Infisical 설치·연동은 승인된 provider 환경이 없으므로 각각 excluded 또는 official-doc-only이며 예상 출력을 제시하지 않습니다.

  • 저장소 root에서 실행하며 M0~M4를 완료한 상태여야 합니다.
  • Docker Desktop과 M2의 cs-study-workbook cluster가 실행 중이어야 합니다.
  • 모든 workload API 명령은 --context k3d-cs-study-workbook과 고유 namespace를 명시합니다.
  • fixture token은 실행마다 host의 권한 제한 파일에서 생성하고 값 자체를 stdout, evidence, manifest에 출력하지 않습니다. 실제 credential이 아닙니다.
  • 예상 소요 시간은 95분입니다.

Secret 값은 명령행 literal이나 YAML에 적지 않습니다. 임시 파일 권한을 600으로 제한하고 --from-file로 전송한 직후 host 파일을 지웁니다.

Terminal window
set -euo pipefail
rm -rf /tmp/k8s-wb-m5
mkdir -p /tmp/k8s-wb-m5
chmod 700 /tmp/k8s-wb-m5
node automation/k8s-workbook/preflight.mjs --require-cluster
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="k8s-wb-m5-$(date -u +%Y%m%d%H%M%S)"
printf '%s' "$NS" > /tmp/k8s-wb-m5/namespace
if kubectl --context k3d-cs-study-workbook get namespace "$NS" >/dev/null 2>&1; then
echo "namespace collision: $NS" >&2
exit 1
fi
kubectl --context k3d-cs-study-workbook create namespace "$NS"
kubectl --context k3d-cs-study-workbook -n "$NS" create configmap app-runtime \
--from-literal=APP_MODE=preview \
--from-literal=LOG_LEVEL=info \
--dry-run=client -o yaml \
| kubectl --context k3d-cs-study-workbook -n "$NS" apply -f -
umask 077
trap 'rm -f /tmp/k8s-wb-m5/api-token' EXIT
openssl rand -hex 16 | tr -d '\n' > /tmp/k8s-wb-m5/api-token
test "$(wc -c < /tmp/k8s-wb-m5/api-token | tr -d ' ')" = "32"
kubectl --context k3d-cs-study-workbook -n "$NS" create secret generic app-credentials \
--from-file=API_TOKEN=/tmp/k8s-wb-m5/api-token \
--from-literal=TOKEN_REVISION=rev1 \
--dry-run=client -o yaml \
| kubectl --context k3d-cs-study-workbook -n "$NS" apply -f -
rm -f /tmp/k8s-wb-m5/api-token
trap - EXIT
kubectl --context k3d-cs-study-workbook -n "$NS" apply -f - <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
spec:
replicas: 1
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
spec:
terminationGracePeriodSeconds: 3
containers:
- name: app
image: busybox:1.37.0@sha256:9532d8c39891ca2ecde4d30d7710e01fb739c87a8b9299685c63704296b16028
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "sleep 3600"]
env:
- name: APP_MODE
valueFrom:
configMapKeyRef:
name: app-runtime
key: APP_MODE
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-runtime
key: LOG_LEVEL
- name: API_TOKEN
valueFrom:
secretKeyRef:
name: app-credentials
key: API_TOKEN
- name: TOKEN_REVISION
valueFrom:
secretKeyRef:
name: app-credentials
key: TOKEN_REVISION
YAML
kubectl --context k3d-cs-study-workbook -n "$NS" \
rollout status deployment/api-service --timeout=90s >/dev/null
test ! -e /tmp/k8s-wb-m5/api-token
echo 'fixture=configmap,secret,deployment ready=true token_file=absent'

예상 출력:

PASS platform: darwin/arm64
PASS architecture: arm64
PASS docker-cli: v29.6.1
PASS docker-engine: v29.6.1
PASS k3d: v5.9.0
PASS kubectl-skew: v1.36.1
PASS helm: v4.2.3
PASS context: k3d-cs-study-workbook
PASS kubernetes-server: v1.36.2+k3s1
namespace/k8s-wb-m5-<UTC 14자리 run ID> created
configmap/app-runtime created
secret/app-credentials created
deployment.apps/api-service created
fixture=configmap,secret,deployment ready=true token_file=absent

host architecture, Docker patch version과 namespace run ID는 변동 필드입니다. token 값은 변동값이지만 출력하지 않으며 길이와 전달 성공만 확인합니다.

Lab 1 — source reference와 안전한 주입 증거 확인하기

섹션 제목: “Lab 1 — source reference와 안전한 주입 증거 확인하기”
Terminal window
set -euo pipefail
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="$(cat /tmp/k8s-wb-m5/namespace)"
MODE="$(kubectl --context k3d-cs-study-workbook -n "$NS" get configmap app-runtime \
-o jsonpath='{.data.APP_MODE}')"
LEVEL="$(kubectl --context k3d-cs-study-workbook -n "$NS" get configmap app-runtime \
-o jsonpath='{.data.LOG_LEVEL}')"
SECRET_TYPE="$(kubectl --context k3d-cs-study-workbook -n "$NS" get secret app-credentials \
-o jsonpath='{.type}')"
TOKEN_BYTES="$(kubectl --context k3d-cs-study-workbook -n "$NS" get secret app-credentials \
-o jsonpath='{.data.API_TOKEN}' | base64 -d | wc -c | tr -d ' ')"
test "$TOKEN_BYTES" = "32"
POD="$(kubectl --context k3d-cs-study-workbook -n "$NS" get pod -l app=api-service \
-o jsonpath='{.items[0].metadata.name}')"
kubectl --context k3d-cs-study-workbook -n "$NS" exec "$POD" -- sh -c '
test "$APP_MODE" = preview
test "$LOG_LEVEL" = info
test "$TOKEN_REVISION" = rev1
test "${#API_TOKEN}" = 32
printf "process_env mode=%s log_level=%s token_revision=%s token_present=true token_length=%s\n" \
"$APP_MODE" "$LOG_LEVEL" "$TOKEN_REVISION" "${#API_TOKEN}"
'
printf 'configmap mode=%s log_level=%s\n' "$MODE" "$LEVEL"
printf 'secret type=%s keys=API_TOKEN,TOKEN_REVISION token_length=%s value_printed=false\n' \
"$SECRET_TYPE" "$TOKEN_BYTES"
printf 'references=configMapKeyRef,secretKeyRef explicit=true\n'

예상 출력:

process_env mode=preview log_level=info token_revision=rev1 token_present=true token_length=32
configmap mode=preview log_level=info
secret type=Opaque keys=API_TOKEN,TOKEN_REVISION token_length=32 value_printed=false
references=configMapKeyRef,secretKeyRef explicit=true

Secret의 base64를 decode해 화면에 출력하지 않습니다. byte count는 fixture 전달 여부의 증거이지 실제 credential을 검증하는 방식이 아닙니다.

Lab 2 — source를 바꿔도 기존 process env가 그대로인지 보기

섹션 제목: “Lab 2 — source를 바꿔도 기존 process env가 그대로인지 보기”
Terminal window
set -euo pipefail
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="$(cat /tmp/k8s-wb-m5/namespace)"
OLD_POD="$(kubectl --context k3d-cs-study-workbook -n "$NS" get pod -l app=api-service \
-o jsonpath='{.items[0].metadata.name}')"
printf '%s' "$OLD_POD" > /tmp/k8s-wb-m5/pod-before
kubectl --context k3d-cs-study-workbook -n "$NS" patch configmap app-runtime \
--type=merge -p '{"data":{"APP_MODE":"live"}}' >/dev/null
umask 077
trap 'rm -f /tmp/k8s-wb-m5/api-token' EXIT
openssl rand -hex 16 | tr -d '\n' > /tmp/k8s-wb-m5/api-token
kubectl --context k3d-cs-study-workbook -n "$NS" create secret generic app-credentials \
--from-file=API_TOKEN=/tmp/k8s-wb-m5/api-token \
--from-literal=TOKEN_REVISION=rev2 \
--dry-run=client -o yaml \
| kubectl --context k3d-cs-study-workbook -n "$NS" apply -f - >/dev/null
rm -f /tmp/k8s-wb-m5/api-token
trap - EXIT
OBJECT_MODE="$(kubectl --context k3d-cs-study-workbook -n "$NS" get configmap app-runtime \
-o jsonpath='{.data.APP_MODE}')"
OBJECT_REVISION="$(kubectl --context k3d-cs-study-workbook -n "$NS" get secret app-credentials \
-o jsonpath='{.data.TOKEN_REVISION}' | base64 -d)"
test "$OBJECT_MODE" = "live"
test "$OBJECT_REVISION" = "rev2"
kubectl --context k3d-cs-study-workbook -n "$NS" exec "$OLD_POD" -- sh -c '
test "$APP_MODE" = preview
test "$TOKEN_REVISION" = rev1
printf "running_pod mode=%s token_revision=%s stale=true\n" "$APP_MODE" "$TOKEN_REVISION"
'
printf 'source_objects mode=%s token_revision=%s updated=true\n' \
"$OBJECT_MODE" "$OBJECT_REVISION"

예상 출력:

running_pod mode=preview token_revision=rev1 stale=true
source_objects mode=live token_revision=rev2 updated=true

source object와 process env가 동시에 다른 값을 가진 실측 결과입니다. 이 상태에서 replica를 늘리면 새 Pod만 최신 값을 받아 old/new 설정이 섞일 수 있습니다.

Lab 3 — rollout으로 새 env snapshot에 수렴시키기

섹션 제목: “Lab 3 — rollout으로 새 env snapshot에 수렴시키기”
Terminal window
set -euo pipefail
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="$(cat /tmp/k8s-wb-m5/namespace)"
OLD_POD="$(cat /tmp/k8s-wb-m5/pod-before)"
kubectl --context k3d-cs-study-workbook -n "$NS" \
rollout restart deployment/api-service
kubectl --context k3d-cs-study-workbook -n "$NS" \
rollout status deployment/api-service --timeout=90s >/dev/null
kubectl --context k3d-cs-study-workbook -n "$NS" \
wait --for=delete "pod/$OLD_POD" --timeout=90s >/dev/null
POD_COUNT="$(kubectl --context k3d-cs-study-workbook -n "$NS" get pod -l app=api-service \
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | sed '/^$/d' | wc -l | tr -d ' ')"
test "$POD_COUNT" = "1"
NEW_POD="$(kubectl --context k3d-cs-study-workbook -n "$NS" get pod -l app=api-service \
-o jsonpath='{.items[0].metadata.name}')"
test "$NEW_POD" != "$OLD_POD"
kubectl --context k3d-cs-study-workbook -n "$NS" exec "$NEW_POD" -- sh -c '
test "$APP_MODE" = live
test "$LOG_LEVEL" = info
test "$TOKEN_REVISION" = rev2
test "${#API_TOKEN}" = 32
printf "new_process mode=%s log_level=%s token_revision=%s token_present=true token_length=%s\n" \
"$APP_MODE" "$LOG_LEVEL" "$TOKEN_REVISION" "${#API_TOKEN}"
'
printf 'pod_replaced old=%s new=%s latest_snapshot=true\n' "$OLD_POD" "$NEW_POD"

예상 출력:

deployment.apps/api-service restarted
new_process mode=live log_level=info token_revision=rev2 token_present=true token_length=32
pod_replaced old=api-service-<이전 hash>-<suffix> new=api-service-<새 hash>-<suffix> latest_snapshot=true

Pod 이름은 변동값입니다. source 변경 자체가 아니라 Pod template annotation을 바꾼 rollout이 새 process를 만들었다는 점을 구분합니다.

Lab 4 — 없는 key로 CreateContainerConfigError 재현하기

섹션 제목: “Lab 4 — 없는 key로 CreateContainerConfigError 재현하기”

optional: false가 기본이므로 typo를 조용히 빈 문자열로 바꾸지 않고 container 시작 전에 막습니다.

Terminal window
set -euo pipefail
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="$(cat /tmp/k8s-wb-m5/namespace)"
kubectl --context k3d-cs-study-workbook -n "$NS" apply -f - <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: broken-env
spec:
terminationGracePeriodSeconds: 3
containers:
- name: app
image: busybox:1.37.0@sha256:9532d8c39891ca2ecde4d30d7710e01fb739c87a8b9299685c63704296b16028
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "sleep 3600"]
env:
- name: APP_MODE
valueFrom:
configMapKeyRef:
name: app-runtime
key: DOES_NOT_EXIST
YAML
REASON=""
for _ in $(seq 1 30); do
REASON="$(kubectl --context k3d-cs-study-workbook -n "$NS" get pod broken-env \
-o jsonpath='{.status.containerStatuses[0].state.waiting.reason}')"
test "$REASON" = "CreateContainerConfigError" && break
sleep 1
done
test "$REASON" = "CreateContainerConfigError"
set +e
kubectl --context k3d-cs-study-workbook -n "$NS" \
wait --for=condition=Ready pod/broken-env --timeout=5s \
> /tmp/k8s-wb-m5/broken-ready.log 2>&1
READY_EXIT=$?
set -e
test "$READY_EXIT" = "1"
grep -q 'timed out waiting for the condition' /tmp/k8s-wb-m5/broken-ready.log
printf 'pod=broken-env reason=%s ready=false exit=%s\n' "$REASON" "$READY_EXIT"
exit 1

예상 출력과 exit code:

pod/broken-env created
pod=broken-env reason=CreateContainerConfigError ready=false exit=1

전체 예상 exit code는 1입니다. image pull이나 application crash 전에 kubelet이 참조 key를 찾지 못해 container 구성을 만들지 못한 상태입니다.

복구 — typo를 실제 key로 고쳐 새 Pod 만들기

섹션 제목: “복구 — typo를 실제 key로 고쳐 새 Pod 만들기”

Pod의 핵심 container env는 in-place 수정하지 않습니다. 실패한 Pod를 지우고 올바른 spec으로 다시 만듭니다.

Terminal window
set -euo pipefail
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="$(cat /tmp/k8s-wb-m5/namespace)"
kubectl --context k3d-cs-study-workbook -n "$NS" delete pod broken-env --wait=true >/dev/null
kubectl --context k3d-cs-study-workbook -n "$NS" apply -f - <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: broken-env
spec:
terminationGracePeriodSeconds: 3
containers:
- name: app
image: busybox:1.37.0@sha256:9532d8c39891ca2ecde4d30d7710e01fb739c87a8b9299685c63704296b16028
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "sleep 3600"]
env:
- name: APP_MODE
valueFrom:
configMapKeyRef:
name: app-runtime
key: APP_MODE
YAML
kubectl --context k3d-cs-study-workbook -n "$NS" \
wait --for=condition=Ready pod/broken-env --timeout=90s >/dev/null
MODE="$(kubectl --context k3d-cs-study-workbook -n "$NS" exec broken-env -- \
sh -c 'printf %s "$APP_MODE"')"
test "$MODE" = "live"
printf 'recovery=correct-key pod=Ready mode=%s\n' "$MODE"

예상 출력:

pod/broken-env created
recovery=correct-key pod=Ready mode=live
Terminal window
set -euo pipefail
test "$(kubectl config current-context)" = "k3d-cs-study-workbook"
NS="$(cat /tmp/k8s-wb-m5/namespace)"
kubectl --context k3d-cs-study-workbook delete namespace "$NS" --wait=false >/dev/null
kubectl --context k3d-cs-study-workbook wait --for=delete "namespace/$NS" --timeout=120s >/dev/null
if kubectl --context k3d-cs-study-workbook get namespace "$NS" >/dev/null 2>&1; then
echo "cleanup failed: namespace remains" >&2
exit 1
fi
rm -rf /tmp/k8s-wb-m5
test ! -e /tmp/k8s-wb-m5
READY_NODES="$(kubectl --context k3d-cs-study-workbook get nodes --no-headers \
| awk '$2 == "Ready" {count++} END {print count+0}')"
test "$READY_NODES" = "2"
printf 'cleanup namespace=0 fixture=0 secret_files=0 nodes_ready=%s cluster_retained=true\n' \
"$READY_NODES"

예상 출력:

cleanup namespace=0 fixture=0 secret_files=0 nodes_ready=2 cluster_retained=true
실행 뒤실제 변화운영 판단
ConfigMap·Secret 생성설정 object와 민감값 전달 object가 image 밖에 존재object 종류만으로 RBAC·암호화·rotation이 끝나지 않습니다.
명시적 key 주입필요한 4개 env만 process에 존재envFrom보다 review할 노출 범위가 작습니다.
source object 갱신object는 live/rev2, 기존 process는 preview/rev1running env는 자동 갱신되지 않습니다.
rollout restartPod 교체 뒤 live/rev2로 수렴실제 process 값을 안전한 marker로 확인합니다.
없는 ConfigMap keyCreateContainerConfigError, Ready 실패image나 app log보다 object name·key·event를 먼저 봅니다.
cleanupM5 object·host token file 0, 공유 cluster 유지민감 fixture를 host에도 남기지 않습니다.

Q1. APP_MODE를 바꾼 뒤 replica 3개 중 1개만 새 값입니다. ConfigMap이 고장난 걸까요?

섹션 제목: “Q1. APP_MODE를 바꾼 뒤 replica 3개 중 1개만 새 값입니다. ConfigMap이 고장난 걸까요?”

먼저 각 Pod의 생성 시각과 실제 env marker를 비교합니다. ConfigMap env는 기존 process에 자동 반영되지 않으므로 우연히 새로 생긴 Pod만 최신 값을 받았을 가능성이 큽니다. Pod template에 의도한 version을 반영하거나 승인된 rollout을 수행하고, 모든 replica가 같은 marker에 수렴했는지 검증합니다.

Q2. AI가 “Secret도 base64로 보이니 API token을 ConfigMap에 넣어도 같다”고 제안했습니다. 받아들여도 될까요?

섹션 제목: “Q2. AI가 “Secret도 base64로 보이니 API token을 ConfigMap에 넣어도 같다”고 제안했습니다. 받아들여도 될까요?”

안 됩니다. base64가 encryption이 아니라는 지적과 ConfigMap을 쓰자는 결론은 별개입니다. 민감값은 Secret 또는 승인된 외부 secret delivery 경로로 분리하고, 최소 RBAC·저장 시 암호화, audit·rotation·소비자 갱신을 함께 검토합니다. Secret 값이나 decoded 결과를 PR·terminal log에 남기지 않습니다.

Q3. Infisical Operator를 바로 NKS에 cluster-wide로 설치하자는 PR이 왔습니다. 무엇이 먼저인가요?

섹션 제목: “Q3. Infisical Operator를 바로 NKS에 cluster-wide로 설치하자는 PR이 왔습니다. 무엇이 먼저인가요?”

현재 지원 Kubernetes version과 NKS compatibility를 공식 문서·vendor에 확인하고, M7의 Helm release·rollback 기준을 세운 뒤 non-production에서 검증합니다. namespace-scoped RBAC, Machine Identity 권한, native Secret owner, sync 실패 시 기존 값 유지, rotation 후 Deployment reload와 rollback을 확인하기 전에는 production 설치를 승인하지 않습니다.

함정 1. base64를 암호화로 생각하기

섹션 제목: “함정 1. base64를 암호화로 생각하기”

Secret data는 쉽게 decode할 수 있습니다. kubectl get secret -o yaml, shell tracing, printenv, application log로 값을 노출하지 말고 API read 권한·etcd encryption at rest·audit와 rotation을 별도 제어로 봅니다.

함정 2. source object 변경이 실행 중 env를 바꾼다고 가정하기

섹션 제목: “함정 2. source object 변경이 실행 중 env를 바꾼다고 가정하기”

ConfigMap·Secret env는 process 시작 시 snapshot입니다. 변경 뒤 rollout하지 않고 scale만 하면 old/new 값이 섞일 수 있습니다. rollout trigger와 소비자 수렴 검증을 배포 계약에 포함합니다.

함정 3. optional: true로 typo를 숨기기

섹션 제목: “함정 3. optional: true로 typo를 숨기기”

필수 key가 없을 때 startup을 막는 편이 잘못된 설정으로 요청을 처리하는 것보다 안전할 수 있습니다. 정말 optional인 feature만 기본값·관측 신호와 함께 optional로 설계합니다.

실제 production Secret 처리, production NKS 변경, control plane·etcd 운영, KMS·NCP IAM 상세, Terraform과 Infisical 설치는 제외합니다. Secret volume·CSI·sidecar/agent injection, immutable ConfigMap·Secret과 automatic reloader는 심화 범위입니다.

M6에서는 이 Pod template에 label·selector, requests·limits와 toleration을 더해 어떤 node pool에 배치할지와 배치 실패를 판단합니다.