[CKA] Secret 구성

Secret 구성의 핵심 개념과 구성 방법, 실습 풀이를 정리합니다.

비밀번호나 민감한 정보를 일반 설정과 분리해 저장할 때 Secret을 사용합니다.
Secret의 data 값은 Base64로 인코딩될 뿐 암호화되지는 않습니다. 저장 시 암호화와 접근 제어는 별도로 구성해야 합니다.

생성 방식

명령형

# 일반적인 생성 방식
kubectl create secret generic <secret-name> --from-literal=<key>=<value>

#여러 literal을 사용한 방식
kubectl create secret generic \
    app-secret --from-literal=DB_Host=mysql \
    --from-literal=DB_User=root \
    --from-literal=DB_Password=paswrd
    
    
 # 파일로 분리
 # 파일의 이름이 secret 내의 키가 됩니다.
 # 파일의 내용이 해당 키의 값이 됩니다.
 kubectl create secret generic <secret-name> --from-file=<path-to-file>
 
 # 특정 파일을 사용한 방식
 kubectl create secret generic \
    app-secret --from-file=app_secret.properties

따로 인코딩 과정을 거치지 않습니다.

kubectl create secret generic db-secret \
  --from-literal=DB_Host=sql01 \
  --from-literal=DB_User=root \
  --from-literal=DB_Password=password123
secret/db-secret created

선언형

Secret의 data 필드에는 Base64로 인코딩한 값을 넣어야 합니다. Base64는 보안 수단이 아니며, YAML에 평문을 넣고 싶다면 stringData 필드를 사용할 수 있습니다.

echo -n 'mysql' | base64
echo -n 'root' | base64
echo -n 'paswrd' | base64

data에 평문을 넣으면 다음과 같은 오류가 발생합니다.

Error from server (BadRequest): error when creating "secret.yaml": Secret in version "v1" cannot be handled as a Secret: illegal base64 data at input byte 4

아래는 오류를 재현하는 잘못된 예시입니다.

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
data:
  DB_Host: mysql
  DB_User: root
  DB_Password: paswrd

올바른 선언형 예시는 평문을 받는 stringData를 사용할 수 있습니다.

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
stringData:
  DB_Host: mysql
  DB_User: root
  DB_Password: paswrd

view secrets

따로 값은 확인되지 않으며 이전에 인코딩된 옵션에서 디코딩하여 사용합니다.
echo -n 'cm9vdA==' | base64 --decode

kubectl get secrets
kubectl describe secrets

in Pods

envFrom:
  - secretRef:
      name: app-secret
env:
  - name: DB_Password
    valueFrom:
      secretKeyRef:
        name: app-secret
        key: DB_Password
volumes:
  - name: app-secret-volume
    secret:
      secretName: app-secret

Secret을 볼륨으로 연결하면 키별 파일로 읽을 수 있습니다. 컨테이너에서는 해당 볼륨을 volumeMounts로 마운트합니다.

주의사항

  1. Secrets는 완전히 암호화되지 않습니다.
    단순히 인코딩만 되어있으므로 외부에서 유출될 경우 디코딩되어 피해가 발생할 수 있습니다.
  2. etcd에서 또한 마찬가지로 암호화되어있지 않습니다.
    유휴 상태일 때 혹은 필요시 암호화 구성을 해야합니다.
  3. 네임스페이스에서 Pod나 Deployment를 생성할 권한이 있으면 그 네임스페이스의 Secret을 Pod에 연결해 읽을 수 있습니다.
    따라서 RBAC(역할 기반 접근 제어)를 구성하여 엑세스 제한이 필요합니다.
  4. 상황에 따라 특정 리소스만 엑세스할 수 있도록 설정 가능합니다.
  5. AWS, Azure 등 필요에 따라 외부 secret Provider를 구성해야합니다.

모범 사례

쿠버네티스가 비밀을 처리하는 방식입니다.