Secret
민감한 정보를 저장하는 Kubernetes 리소스
민감한 정보를 저장하는 Kubernetes 리소스
Kubernetes Secret은 비밀번호, OAuth 토큰, SSH 키, TLS 인증서 등 민감한 정보를 저장하고 관리하는 리소스입니다. ConfigMap과 유사하지만, 민감한 데이터를 위해 설계되었으며 base64로 인코딩되어 저장됩니다.
Secret 타입:
Secret 사용 방식:
보안 고려사항:
기본 Secret은 etcd에 평문으로 저장됩니다. 프로덕션 환경에서는 다음을 권장합니다:
Secret vs ConfigMap: ConfigMap은 민감하지 않은 설정 데이터용이고, Secret은 민감한 데이터용입니다. Secret은 tmpfs에 마운트되어 디스크에 쓰이지 않고, 메모리에 로드됩니다.
# 1. kubectl로 Secret 생성 (권장)
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password='S3cur3P@ss!'
# 2. YAML 파일로 생성 (base64 인코딩 필요)
# echo -n 'admin' | base64 → YWRtaW4=
# echo -n 'S3cur3P@ss!' | base64 → UzNjdXIzUEBzcyE=
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: production
type: Opaque
data:
username: YWRtaW4= # base64 인코딩
password: UzNjdXIzUEBzcyE=
# 3. stringData 사용 (평문, 자동 인코딩)
apiVersion: v1
kind: Secret
metadata:
name: api-keys
type: Opaque
stringData:
api-key: "sk-1234567890abcdef"
webhook-secret: "whsec_abcdef123456"
---
# Pod에서 Secret 사용
apiVersion: v1
kind: Pod
metadata:
name: app-with-secrets
spec:
containers:
- name: app
image: my-app:latest
env:
# 개별 키를 환경변수로
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# 전체 Secret을 환경변수로
envFrom:
- secretRef:
name: api-keys
optional: false
# 파일로 마운트
volumeMounts:
- name: db-creds-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: db-creds-volume
secret:
secretName: db-credentials
defaultMode: 0400 # 읽기 전용 권한
# TLS Secret 생성
kubectl create secret tls my-tls-secret \
--cert=./tls.crt \
--key=./tls.key
# YAML 형식
apiVersion: v1
kind: Secret
metadata:
name: my-tls-secret
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # base64 인코딩된 인증서
tls.key: LS0tLS1CRUdJTi... # base64 인코딩된 개인키
---
# Ingress에서 TLS Secret 사용
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- my-app.example.com
secretName: my-tls-secret
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
# External Secrets Operator 설치
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace
# SecretStore 설정 (AWS Secrets Manager 연결)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secretsmanager
namespace: production
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
---
# ExternalSecret 정의 (AWS에서 동기화)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h # 1시간마다 동기화
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: db-credentials # 생성될 K8s Secret 이름
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: production/database # AWS Secret 이름
property: username
- secretKey: password
remoteRef:
key: production/database
property: password
# kubectl get externalsecret -n production
# NAME STORE REFRESH STATUS
# db-credentials aws-secretsmanager 1h SecretSynced
보안팀: "DB 비밀번호가 Git에 올라간 거 같은데요?"
개발자: "Secret YAML에 base64로 인코딩해서 올렸는데..."
보안팀: "base64는 암호화가 아니에요. 누구나 디코딩할 수 있어요. Sealed Secrets이나 External Secrets Operator를 써서 Git에는 암호화된 상태로만 저장하세요."
개발자: "알겠습니다. AWS Secrets Manager로 옮기고 External Secrets로 동기화하겠습니다."
면접관: "Kubernetes Secret의 보안 한계점은?"
지원자: "첫째, 기본적으로 etcd에 평문 저장됩니다. EncryptionConfiguration으로 저장 시 암호화를 활성화해야 해요. 둘째, base64는 인코딩일 뿐 암호화가 아닙니다. 셋째, Secret에 접근 가능한 모든 Pod와 사용자가 값을 볼 수 있어 RBAC 설정이 중요합니다."
면접관: "그래서 어떻게 개선하나요?"
지원자: "HashiCorp Vault나 AWS Secrets Manager 같은 전문 Secret 관리 도구를 사용합니다. External Secrets Operator로 외부 Secret을 K8s Secret으로 동기화하면 소스 저장소에 민감 정보를 저장하지 않아도 됩니다."
운영팀: "Secret 업데이트했는데 Pod에 반영이 안 돼요."
개발자: "환경변수로 주입한 Secret은 Pod 재시작이 필요해요. 볼륨 마운트 방식이면 kubelet이 주기적으로 업데이트하지만 기본 1분 정도 걸려요. 즉시 반영하려면 Pod를 롤링 재시작하세요."
운영팀: "자동으로 재시작되게 할 수 없나요?"
개발자: "Reloader 같은 컨트롤러를 설치하면 Secret 변경 시 자동으로 Deployment를 롤아웃해요. 아니면 Secret hash를 annotation에 넣어서 변경 시 Pod가 재생성되게 할 수도 있어요."