웹 애플리케이션이 데이터베이스에 연결할 때는 보통 다음 정보가 필요합니다.
- DB Host
- DB Username
- DB Password
강의 예시처럼 MySQL에 붙는 간단한 Python 웹앱이 있고, 코드에 호스트/유저/비밀번호가 하드코딩되어 있다면 동작은 하겠지만 운영 관점에서는 좋지 않습니다. 값 변경이 어렵고, 무엇보다 비밀번호가 코드/이미지/레포에 남는 보안 사고로 이어지기 쉽습니다.
이전 글에서 ConfigMap으로 구성 데이터를 분리할 수 있다고 했지만, ConfigMap은 일반 텍스트로 저장되므로 비밀번호 저장처로 적합하지 않습니다. 그래서 등장하는 것이 Secret입니다.
1) Secret이 필요한 이유: ConfigMap은 평문, Secret은 민감 정보용
ConfigMap
- 일반 구성 데이터(예:
APP_COLOR,LOG_LEVEL,DB_HOST,DB_USER) - 기본적으로 평문 저장(보안 목적 아님)
Secret
- 비밀번호/토큰/키 같은 민감 정보
- ConfigMap과 비슷하게 “키-값”을 저장하지만
- 값은 보통 Base64 인코딩된 형태로 저장됩니다.
중요한 주의: Base64는 “암호화(encryption)”가 아니라 “인코딩(encoding)”입니다. 즉, 그대로 디코딩하면 원문이 나옵니다. Secret은 “평문 ConfigMap에 비해 의도/표준이 맞는 저장소”이지만, 보안은 RBAC, etcd 암호화, 외부 Secret 관리(Vault/Cloud KMS) 등과 함께 설계해야 합니다.
2) Secret 작업도 ConfigMap처럼 2단계
- Secret 생성
- Pod(또는 Deployment 등)에 주입
3) Secret 생성 방법 2가지: 명령형 vs 선언형
Secret도 ConfigMap과 동일하게 명령형(Imperative), 선언형(Declarative) 두 방식이 있습니다.
3-1) 명령형: kubectl create secret generic + --from-literal
강의의 흐름 그대로, 커맨드에서 키-값을 직접 넣어 Secret을 만들 수 있습니다.
kubectl create secret generic app-secret \
--from-literal=DB_HOST=mysql \
--from-literal=DB_USER=root \
--from-literal=DB_PASSWORD=passw0rd
generic: 일반적인 Key-Value Secret- 리터럴이 많아지면 커맨드가 길어지고 관리가 어려워질 수 있습니다.
3-2) 명령형: --from-file로 파일 기반 입력
비밀 데이터가 파일로 있을 때는 파일을 그대로 Secret에 담을 수 있습니다.
kubectl create secret generic app-secret \
--from-file=./db_password.txt
- 기본적으로 키 이름은 파일명
- 파일 내용이 Secret 값이 됩니다.
3-3) 선언형: Secret YAML로 생성 (Base64 인코딩 필요)
ConfigMap처럼 YAML로 Secret을 만들 수도 있습니다. 다만 Secret의 data에는 Base64로 인코딩된 값을 넣어야 합니다.
예: 평문이 mysql이라면 Base64로 변환해야 합니다.
(1) Base64 인코딩
echo -n 'mysql' | base64
echo -n 'root' | base64
echo -n 'passw0rd' | base64
-n을 붙여야 줄바꿈 문자(\n)가 같이 인코딩되는 실수를 피할 수 있습니다.
(2) Secret YAML 예시
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
DB_HOST: bXlzcWw=
DB_USER: cm9vdA==
DB_PASSWORD: cGFzc3cwcmQ=
적용:
kubectl apply -f secret.yaml
4) Secret 조회/확인: 값은 기본적으로 숨겨진다
목록 조회
kubectl get secrets
클러스터에는 쿠버네티스가 내부적으로 사용하는 Secret도 존재할 수 있습니다.
상세 조회(값은 숨김)
kubectl describe secret app-secret
- 키 목록은 보이지만 값은 노출되지 않습니다.
YAML로 보기(인코딩 값은 보임)
kubectl get secret app-secret -o yaml
- Base64 인코딩된 값이 보입니다.
디코딩(원문 확인)
echo 'bXlzcWw=' | base64 --decode
또는 kubectl로 바로 뽑아서 디코딩(실전에서 자주 씀):
kubectl get secret app-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 --decode
echo
5) Pod에 Secret 주입하기: 환경 변수로 쓰기
이제 2단계(주입)입니다. 강의처럼 “파드 정의 파일에 env를 추가하고, 각 env 항목이 secret의 키를 참조”하면 됩니다.
5-1) 단일 키를 환경 변수로 주입: secretKeyRef
apiVersion: v1
kind: Pod
metadata:
name: webapp-with-secret
spec:
containers:
- name: webapp
image: my-python-webapp:1.0
env:
- name: DB_HOST
valueFrom:
secretKeyRef:
name: app-secret
key: DB_HOST
- name: DB_USER
valueFrom:
secretKeyRef:
name: app-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: DB_PASSWORD
이렇게 하면 애플리케이션에서 DB_HOST, DB_USER, DB_PASSWORD 환경 변수를 읽어 DB 연결에 사용할 수 있습니다.
6) Pod에 Secret 주입하기: 다른 2가지 방식도 있다
강의에서 마지막에 언급한 것처럼 Secret 주입은 환경 변수 외에도 가능합니다.
6-1) Secret 전체를 한 번에 환경 변수로 주입: envFrom
envFrom:
- secretRef:
name: app-secret
- Secret의 모든 키가 환경 변수로 들어갑니다.
- 키 충돌/예상치 못한 주입을 피하려면 팀 규칙을 두는 게 좋습니다.
6-2) Secret을 볼륨으로 마운트: “키마다 파일 생성”
Secret을 볼륨으로 마운트하면, Secret의 각 키가 파일이 됩니다.
apiVersion: v1
kind: Pod
metadata:
name: webapp-secret-volume
spec:
containers:
- name: webapp
image: my-python-webapp:1.0
volumeMounts:
- name: secret-vol
mountPath: /etc/secret
readOnly: true
volumes:
- name: secret-vol
secret:
secretName: app-secret
결과:
/etc/secret/DB_HOST/etc/secret/DB_USER/etc/secret/DB_PASSWORD
처럼 파일이 생성되고, 예를 들어 DB_PASSWORD 파일 내용이 실제 비밀번호가 됩니다.
7) 핵심 정리
- 코드에 비밀번호를 하드코딩하는 것은 운영/보안적으로 위험
- ConfigMap은 평문 구성 데이터에 적합(비밀번호에는 부적절)
- Secret은 민감 정보를 저장/주입하기 위한 오브젝트(값은 Base64 형태로 저장)
- Secret 작업은 2단계:
- 생성(create/apply)
- Pod에 주입(env / envFrom / volume)
- 볼륨 마운트 시 Secret의 각 키는 “파일”이 된다
**Base64로 인코딩하는거면 사실상 디코딩이 쉬우니 ConfigMap과 별 다를 것 아닌것 아닌가?
-> Secret을 읽을 수 있다면 사실상 맞지만 일반적으로 대부분의 유저에게 Secret에 대해 접근 권한을 주지 않는 등으로 별도 관리하여 보안성을 높혀줌
Practice Test: https://uklabs.kodekloud.com/topic/practice-test-secrets-2/
'CKA' 카테고리의 다른 글
| Application Lifecycle Management - 멀티 컨테이터 파드 (1) | 2025.12.30 |
|---|---|
| Application Lifecycle Management - etcd에 저장되는 secret 암호화하기 (0) | 2025.12.30 |
| Application Lifecycle Management - ConfigMap (0) | 2025.12.30 |
| Application Lifecycle Management - Docker CMD/Entrypoint와 쿠버네티스 (0) | 2025.12.30 |
| Application Lifecycle Management - 배포전략 (0) | 2025.12.30 |