Secret을 사용해 자격 증명을 안전하게 배포하기
Secret을 사용해 자격 증명을 안전하게 배포하기 (Distribute Credentials Securely Using Secrets)
이 페이지는 비밀번호와 암호화 키 같은 민감한 데이터를 파드에 안전하게 주입하는 방법을 보여 줘요.
출처: 문서
본문
시작하기 전에
쿠버네티스 클러스터가 있어야 하고, kubectl 명령줄 도구가 클러스터와 통신하도록 구성되어 있어야 해요. 이 튜토리얼을 제어 플레인 호스트로 작동하지 않는 최소 두 개의 노드가 있는 클러스터에서 실행하는 것을 권장해요. 아직 클러스터가 없다면 minikube로 만들거나 다음 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있어요:
- iximiuz Labs
- Killercoda
- KodeKloud
시크릿 데이터를 base-64 표현으로 변환하기
my-app이라는 사용자 이름과 39528$vdg7Jb라는 비밀번호라는 두 개의 시크릿 데이터가 있다고 가정해 봐요. 먼저 base64 인코딩 도구를 사용해 사용자 이름과 비밀번호를 base64 표현으로 변환해요. 흔히 사용 가능한 base64 프로그램을 사용한 예시는 다음과 같아요:
echo -n 'my-app' | base64
echo -n '39528$vdg7Jb' | base64
출력은 사용자 이름의 base-64 표현이 bXktYXBw이고, 비밀번호의 base-64 표현이 Mzk1MjgkdmRnN0pi임을 보여 줘요.
Secret 만들기
사용자 이름과 비밀번호를 담는 Secret을 만들기 위해 사용할 수 있는 구성 파일은 다음과 같아요:
apiVersion: v1
kind: Secret
metadata:
name: test-secret
data:
username: bXktYXBw
password: Mzk1MjgkdmRnN0pi
- Secret 만들기
kubectl apply -f https://k8s.io/examples/pods/inject/secret.yaml
- Secret에 대한 정보 보기:
kubectl get secret test-secret
출력:
NAME TYPE DATA AGE
test-secret Opaque 2 1m
- Secret에 대한 더 자세한 정보 보기:
kubectl describe secret test-secret
출력:
Name: test-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 13 bytes
username: 7 bytes
kubectl로 Secret 직접 만들기
Base64 인코딩 단계를 건너뛰고 싶다면 kubectl create secret 명령으로 같은 Secret을 만들 수 있어요. 예를 들어:
kubectl create secret generic test-secret --from-literal='username=my-app' --from-literal='password=39528$vdg7Jb'
이것이 더 편리해요. 앞서 보여 준 자세한 접근 방식은 무슨 일이 일어나는지 보여 주기 위해 각 단계를 명시적으로 진행해요.
볼륨을 통해 시크릿 데이터에 접근할 수 있는 파드 만들기
파드를 만드는 데 사용할 수 있는 구성 파일은 다음과 같아요:
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
spec:
containers:
- name: test-container
image: nginx
volumeMounts:
# name must match the volume name below
- name: secret-volume
mountPath: /etc/secret-volume
readOnly: true
# The secret data is exposed to Containers in the Pod through a Volume.
volumes:
- name: secret-volume
secret:
secretName: test-secret
- 파드 만들기:
kubectl apply -f https://k8s.io/examples/pods/inject/secret-pod.yaml
- 파드가 실행 중인지 확인:
kubectl get pod secret-test-pod
출력:
NAME READY STATUS RESTARTS AGE
secret-test-pod 1/1 Running 0 42m
- 파드에서 실행 중인 컨테이너에 셸 접근하기:
kubectl exec -i -t secret-test-pod -- /bin/bash
- 시크릿 데이터는
/etc/secret-volume아래에 마운트된 볼륨을 통해 컨테이너에 노출돼요.
셸에서 /etc/secret-volume 디렉터리의 파일을 나열해 보세요:
# Run this in the shell inside the container
ls /etc/secret-volume
출력은 시크릿 데이터 각각에 대해 하나씩, 두 개의 파일을 보여 줘요:
password username
- 셸에서 username과 password 파일의 내용을 표시해요:
# Run this in the shell inside the container
echo "$( cat /etc/secret-volume/username )"
echo "$( cat /etc/secret-volume/password )"
출력은 여러분의 사용자 이름과 비밀번호예요:
my-app
39528$vdg7Jb
프로그램이 mountPath 디렉터리에서 파일을 찾도록 이미지나 명령줄을 수정하세요. Secret 데이터 맵의 각 키는 이 디렉터리의 파일 이름이 돼요.
Secret 키를 특정 파일 경로로 프로젝션하기
Secret 키가 프로젝션되는 볼륨 내 경로를 제어할 수도 있어요. .spec.volumes[].secret.items 필드를 사용해 각 키의 대상 경로를 변경해요:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
이 파드를 배포하면 다음이 일어나요:
mysecret의username키는/etc/foo/username이 아닌/etc/foo/my-group/my-username경로에서 컨테이너에 제공돼요.- 그 Secret 객체의
password키는 프로젝션되지 않아요.
.spec.volumes[].secret.items를 사용해 키를 명시적으로 나열한다면 다음을 고려해요:
items에 지정된 키만 프로젝션돼요.- Secret의 모든 키를 소비하려면 모두
items필드에 나열해야 해요. - 나열된 모든 키는 해당 Secret에 존재해야 해요. 그렇지 않으면 볼륨이 생성되지 않아요.
Secret 키에 대한 POSIX 권한 설정
단일 Secret 키에 대한 POSIX 파일 접근 권한 비트를 설정할 수 있어요. 권한을 지정하지 않으면 기본적으로 0644가 사용돼요. 전체 Secret 볼륨에 대한 기본 POSIX 파일 모드를 설정하고, 필요하면 키별로 재정의할 수도 있어요.
예를 들어 다음과 같이 기본 모드를 지정할 수 있어요:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
secret:
secretName: mysecret
defaultMode: 0400
Secret은 /etc/foo에 마운트되고; 시크릿 볼륨 마운트가 만든 모든 파일은 0400 권한을 가져요.
Secret 데이터를 사용해 컨테이너 환경 변수 정의하기
컨테이너의 환경 변수로 Secret의 데이터를 소비할 수 있어요.
컨테이너가 이미 환경 변수로 Secret을 소비한다면, 컨테이너가 재시작되지 않는 한 Secret 업데이트는 컨테이너에 보이지 않아요. 시크릿이 변경될 때 재시작을 트리거하는 서드파티 솔루션이 있어요.
단일 Secret의 데이터로 컨테이너 환경 변수 정의하기
- Secret에서 환경 변수를 키-값 쌍으로 정의해요:
kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
- Secret에 정의된
backend-username값을 파드 스펙의SECRET_USERNAME환경 변수에 할당해요.
apiVersion: v1
kind: Pod
metadata:
name: env-single-secret
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: backend-user
key: backend-username
- 파드 만들기:
kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
- 셸에서
SECRET_USERNAME컨테이너 환경 변수의 내용을 표시해요.
kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
출력은 다음과 비슷해요:
backend-admin
여러 Secret의 데이터로 컨테이너 환경 변수 정의하기
- 이전 예시와 마찬가지로 먼저 Secret을 만들어요.
kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
kubectl create secret generic db-user --from-literal=db-username='db-admin'
- 파드 스펙에서 환경 변수를 정의해요.
apiVersion: v1
kind: Pod
metadata:
name: envvars-multiple-secrets
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: BACKEND_USERNAME
valueFrom:
secretKeyRef:
name: backend-user
key: backend-username
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-user
key: db-username
- 파드 만들기:
kubectl create -f https://k8s.io/examples/pods/inject/pod-multiple-secret-env-variable.yaml
- 셸에서 컨테이너 환경 변수를 표시해요.
kubectl exec -i -t envvars-multiple-secrets -- /bin/sh -c 'env | grep _USERNAME'
출력은 다음과 비슷해요:
DB_USERNAME=db-admin
BACKEND_USERNAME=backend-admin
Secret의 모든 키-값 쌍을 컨테이너 환경 변수로 구성하기
- 여러 키-값 쌍을 포함하는 Secret 만들기
kubectl create secret generic test-secret --from-literal=username='my-app' --from-literal=password='39528$vdg7Jb'
envFrom을 사용해 Secret의 모든 데이터를 컨테이너 환경 변수로 정의해요. Secret의 키가 파드의 환경 변수 이름이 돼요.
apiVersion: v1
kind: Pod
metadata:
name: envfrom-secret
spec:
containers:
- name: envars-test-container
image: nginx
envFrom:
- secretRef:
name: test-secret
- 파드 만들기:
kubectl create -f https://k8s.io/examples/pods/inject/pod-secret-envFrom.yaml
- 셸에서 username과 password 컨테이너 환경 변수를 표시해요.
kubectl exec -i -t envfrom-secret -- /bin/sh -c 'echo "username: $username\npassword: $password\n"'
출력은 다음과 비슷해요:
username: my-app
password: 39528$vdg7Jb
예시: Secret을 사용해 prod/test 자격 증명을 파드에 제공하기
이 예시는 프로덕션 자격 증명을 포함하는 Secret을 소비하는 파드와, 테스트 환경 자격 증명이 있는 Secret을 소비하는 다른 파드를 보여 줘요.
- prod 환경 자격 증명용 Secret 만들기:
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
출력은 다음과 비슷해요:
secret "prod-db-secret" created
- test 환경 자격 증명용 Secret 만들기.
kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
출력은 다음과 비슷해요:
secret "test-db-secret" created
참고:
$, \, *, =, ! 같은 특수 문자는 셸에 의해 해석되며 이스케이프가 필요해요.
대부분의 셸에서 비밀번호를 이스케이프하는 가장 쉬운 방법은 단일 따옴표(')로 감싸는 것이에요. 예를 들어 실제 비밀번호가 S!B\*d$zDsb=라면 다음과 같이 명령을 실행해야 해요:
kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb='
파일에서 온 비밀번호(--from-file)의 특수 문자는 이스케이프할 필요가 없어요.
- 파드 매니페스트 만들기:
cat <<EOF > pod.yaml
apiVersion: v1
kind: List
items:
- kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: prod-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
- kind: Pod
apiVersion: v1
metadata:
name: test-db-client-pod
labels:
name: test-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
EOF
참고:
- 다음을 실행해 API 서버에 모든 객체를 적용해요:
kubectl create -f pod.yaml
두 컨테이너 모두 파일시스템에 각 컨테이너의 환경 값이 담긴 다음 파일들이 존재하게 돼요:
/etc/secret-volume/username
/etc/secret-volume/password
두 개의 서비스 계정을 사용해 기본 파드 스펙을 더 단순화할 수 있어요:
prod-db-secret이 있는prod-usertest-db-secret이 있는test-user
파드 스펙은 다음과 같이 짧아져요:
apiVersion: v1
kind: Pod
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
serviceAccount: prod-db-client
containers:
- name: db-client-container
image: myClientImage
참조 (References)
- Secret
- Volume
- Pod
더 알아보기 (Learn more)
- Secrets에 대해 더 배우기.
- Volumes에 대해 배우기.