[Retry, k8s] 22. 컨피그 & 스토리지 API - 시크릿
카테고리: KUBERNETES
태그: kubernetes
🔔 시크릿
쿠버네티스의 시크릿은 암호, 토큰 또는 키와 같은 소량의 중요한 데이터를 포함하는 오브젝트
-
시크릿 리소에서는 하나의 시크릿 안에 여러 키-벨류 값이 저장된다.
-
하나의 시크릿당 저장 가능한 데이터 사이즈는 총 1MB로 제한된다.
| 종류 | 개요 |
|---|---|
| Qpaque | 범용 용도 |
| kubernetes.io/tls | TLS 인증서용 |
| kubernetes.io/basic | 기본 인증용 |
| kubernetes.io/dockerconfigjson | 도커 레지스트리 인증 정보용 |
| kubernetes.io/ssh-auth | SSH 인증 정보용 |
| kubernetes.io/service-account-token | 서비스 어카운트 토큰용 |
| bootstrap.kubernetes.io/token | Bootstrap 토큰용 |
(1) 시크릿 타입 - 범용 용도의 시크릿 (Qpaque)
일반 사용자명과 패스워드 같은 인증 정보 등의 임의의 사용자 정의 데이터를 저장하는데 사용되는 시크릿 타입
📜 kubectl로 파일에서 값을 참조하여 생성(–from-file)
-
파일명이 그대로 키가 되기 때문에 확장자는 붙이지 않는 것이 좋다.
-
확장자를 붙일 경우 “–from-file=username=username.txt” 등과 같이 지정한다.
# 파일 생성할 때 개행 코드가 들어가지 않도록 "echo -n" 출력 결과를 리다이렉트하여 파일에 쓰는 방법을 사용
$ echo -n "root" > ./username
$ echo -n "rootpasswd" > ./password
# 파일에서 값을 참조하여 시클릿 생성
$ kubectl create secret generic --save-config sample-db-auth \
--from-file=./username --from-file=./password
secret/sample-db-auth created
# 시크릿 확인
$ kubectl get secrets sample-db-auth -o json | jq .data
{
"password": "cm9vdHBhc3N3ZA==",
"username": "cm9vdA=="
}
# 보통은 base64로 인코드되어 있다.
$ kubectl get secret sample-db-auth -o json | jq -r .data.username
cm9vdA==
# 일반 텍스트로 변경하려면 base64로 디코드가 필요
$ kubectl get secret sample-db-auth -o json | jq -r .data.username | base64 --decode
root
📜 kubectl로 envfile에서 값을 참조하여 생성(–from-env-file)
$ cat env-secret.txt
username=root
password=rootpassword
$ kubectl create secret generic --save-config sample-db-auth \
--from-env-file ./env-secret.txt
secret/sample-db-auth created
📜 kubectl로 직접 값을 전달하여 생성(–from-literal)
$ kubectl create secret generic --save-config sample-db-auth \
--from-literal=username=root --from-literal=password=rootpassword
secret/sample-db-auth created
📜 매니페스트에서 생성(-f)
-
“data”는 base64로 인코딩된 문자열 값으로 받는다.
-
“stringData”는 필드는 임의의 문자열을 값으로 받는다.
$ cat <<EOF > sample-db-auth.yaml
apiVersion: v1
kind: Secret
metadata:
name: sample-db-auth
type: Opaque
data:
username: cm9vdA==
password: cm9vdHBhc3N3ZA=
EOF
$ cat <<EOF > sample-db-auth-nobase64.yaml
apiVersion: v1
kind: Secret
metadata:
name: sample-db-auth
type: Opaque
stringData:
username: root
password: rootpassword
EOF
(2) 시크릿 타입 - TLS 타입 시크릿 (kubernetes.io/tls)
TLS 연결을 위한 인증서와 개인 키를 저장하는 데 사용되는 시크릿 타입
-
TLS 타입의 시크릿은 인그레스 리소스 등에서 사용하는 것이 일반적이다.
-
TLS 타입의 시크릿은 매니페스트로 생성할 수 있지만, 기본적으로 비밀키와 인증서 파일로 생성하는 것을 추천한다.
# 자체 서명된 인증서 생성
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ~/tls.key -out ~/tls.crt -subj "/CN=sample1.example.com"
# 비밀키와 인증서 파일로 생성 (--key, --cert) - TLS 시크릿 생성
$ kubectl create secret tls --save-config tls-sample --key ~/tls.key --cert ~/tls.crt
(3) 시크릿 타입 - 도커 레지스트리 타입의 시크릿 (kubernetes.io/dockerconfigjson)
도커 레지스트리에 인증하기 위한 도커 구성 파일을 저장하는 데 사용되는 시크릿 타입
-
사용하고 있는 컨테이너 레지스트리가 프라이빗 저장소인 경우, 도커 이미지를 가져오려면 인증이 필요하다.
-
쿠버네티스에서는 이 인증 정보를 시클릿으로 정의하여 사용할 수 있다.
-
도커 레지스트리 인증용 시크릿도 매니페스트로 생성할 수 있지만, 형식이 특수하므로 kubectl로 직접 생성하는 것이 편하다.
-
이 타입의 시크릿은 ~/.docker/config.json 파일 대체용으로 사용한다.
📜 kubectl로 직접 생성
# 도커 레지스트리 인증 정보의 시크릿 생성
$ kubectl create secret docker-registry --save-config sample-registry-auth \
--docker-server=REGISTRY_SERVER \
--docker-username=REGISTRY_USER \
--docker-password=REGISTRY_USER_PASSWORD \
--docker-email=REGISTRY_USER_EMAIL
# base64로 인코드된 dockercfg 형식의 JSON 데이터
$ kubectl get secrets -o json sample-registry-auth | jq .data
{
".dockerconfigjson": "eyJhdXRocyI6eyJSRUdJU1RSWV9TRVJWRVIiOnsidXNlcm5hbWUiOiJSRUdJU1RSWV9VU0VSIiwicGFzc3dvcmQiOiJSRUdJU1RSWV9VU0VSX1BBU1NXT1JEIiwiZW1haWwiOiJSRUdJU1RSWV9VU0VSX0VNQUlMIiwiYXV0aCI6IlVrVkhTVk5VVWxsZlZWTkZVanBTUlVkSlUxUlNXVjlWVTBWU1gxQkJVMU5YVDFKRSJ9fX0="
}
# base64로 디코드한 dockercfg 형식의 JSON 데이터
$ kubectl get secrets sample-registry-auth -o yaml | grep "\.dockerconfigjson" | awk -F' ' '{print $2}' | base64 --decode
{"auths":{"REGISTRY_SERVER":{"username":"REGISTRY_USER","password":"REGISTRY_USER_PASSWORD","email":"REGISTRY_USER_EMAIL","auth":"UkVHSVNUUllfVVNFUjpSRUdJU1RSWV9VU0VSX1BBU1NXT1JE"}}}
📜 이미지 다운로드 시 시크릿 사용
- 인증이 필요한 도커 레지스트리의 프라이빗 저장소에서 이미지를 다운로드 하는 경우, 시크릿을 사전에 생성한 후, 파드의 정의 “spec.imagePullSecrets”에 docker-registry 타입의 시크릿을 지정해야 한다.
apiVersion: v1
kind: Pod
metadata:
name: sample-pull-secret
spec:
containers:
- name: secret-image-container
image: REGISTRY_NAME/secret-image:latest
imagePullSecrets:
- name: sample-registry-auth
(4) 시크릿 타입 - 기본 인증 타입의 시크릿 (kubernetes.io/basic-auth)
기본 인증을 위한 사용자 이름과 비밀번호를 저장하는데 사용되는 시크릿 타입
📜 kubectl로 직접 전달하여 생성 (–from-literal)
$ kubectl create secret generic --save-config sample-basic-auth \
--type kubernetes.io/basic-auth \
--from-literal=username=root --from-literal=password=rootpassword
📜 매니페스트에서 생성()
apiVersion: v1
kind: Secret
metadata:
name: sample-basic-auth
type: kubernetes.io/basic-auth
data:
username: cm9vdA==
password: cm9vdHBhc3N3ZA=
(5) 시크릿 타입 - SSH 인증 타입의 시크릿 (kubernetes.io/ssh-auth)
SSH를 위한 개인 키를 저장하는 데 사용되는 시크릿 타입
📜 kubectl로 파일에서 값을 참조하여 생성 (–from-file)
$ ssh-keygen -t rsa -b 2048 -f sample-key -C "sample"
$ kubectl create secret generic --save-config sample-ssh-auth \
--type kubernetes.io/ssh-auth
--from-file=ssh-privatekey=./sample-key
📜 매니페스트 생성
apiVersion: v1
kind: Secret
metadata:
name: sample-ssh-auth
type: kubernetes.io/ssh-auth
data:
ssh-privatekey: LS0tLS1CRUdJTIBPUEVOU1NIIFB...
(6) 시크릿 사용
시크릿을 컨테이너에서 사용할 경우 크게 두 가지 패턴으로 나룰 수 있다.
-
환경 변수로 전달
-
시크릿의 특정 키만
-
시크릿의 전체 키
-
-
볼륨으로 마운트
-
시크릿의 특정 키만
-
시크릿의 전체 키
-
📜 환경 변수로 전달
$ cat <<EOF > sample-db-auth-nobase64.yaml
apiVersion: v1
kind: Secret
metadata:
name: sample-db-auth
type: Opaque
stringData:
username: root
password: rootpassword
EOF
- env로 하나씩 정의하기 때문에 환경 변수명을 지정할 수 있는 것이 특징
# 특정 키만
$ cat <<EOF > sample-secret-single-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-single-env
spec:
containers:
- name: secret-container
image: nginx:1.16
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: sample-db-auth
key: username
EOF
# sample-secret-single-env 파드의 DB_USERNAME 환경 변수 확인
$ kubectl exec -it sample-secret-single-env -- env | grep DB_USERNAME
DB_USERNAME=root
- envFrom으로 시크릿 전체를 변수로 전달할 수 있어, 키마다 각각 설정할 필요 없으므로 매니페스트가 길어지지는 않지만 시크릿에 어떤 값이 저장되어 있는지 매니페스트 정의에서는 판단하기 힘들다.
# 전체 키
$ cat <<EOF > sample-secret-multi-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-multi-env
spec:
containers:
- name: secret-container
image: nginx:1.16
envFrom:
- secretRef:
name: sample-db-auth
EOF
# sample-secret-multi-env 파드의 환경 변수 확인
$ kubectl exec -it sample-secret-multi-env -- env
..(생략)..
password=rootpassword
username=root
..(생략)..
- envFrom에서 여러 시크릿을 가져오면 충돌할 가능성이 있다. 이런 경우에는 접두사를 붙여 충돌을 방지할 수 있다.
# 전체 키
$ cat <<EOF > sample-secret-prefix-env.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-prefix-env
spec:
containers:
- name: secret-container
image: nginx:1.16
envFrom:
- secretRef:
name: sample-db-auth
prefix: DB1_
- secretRef:
name: sample-db-auth
prefix: DB2_
EOF
# sample-secret-multi-env 파드의 환경 변수 확인
$ kubectl exec -it sample-secret-prefix-env -- env | grep ^DB
DB1_password=rootpassword
DB1_username=root
DB2_password=rootpassword
DB2_username=root
📜 볼륨으로 마운트
$ cat <<EOF > sample-db-auth-nobase64.yaml
apiVersion: v1
kind: Secret
metadata:
name: sample-db-auth
type: Opaque
stringData:
username: root
password: rootpassword
EOF
# 볼륨으로 마운트하는 경우에도 특정 키를 마운트 하는 경우
$ cat <<EOF > sample-secret-single-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-single-volume
spec:
containers:
- name: secret-container
image: nginx:1.16
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
secret:
secretName: sample-db-auth
items:
- key: username
path: username.txt
EOF
# sample-secret-single-volume 파드의 /config/username.txt 파일 확인
$ kubectl exec -it sample-secret-single-volume -- cat /config/username.txt
root
# 시크릿 전체를 마운트
$ cat <<EOF > sample-secret-multi-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: sample-secret-multi-volume
spec:
containers:
- name: secret-container
image: nginx:1.16
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
secret:
secretName: sample-db-auth
EOF
# 파드 내부의 /config 디렉터리 내용 확인
$ kubectl exec -it sample-secret-single-volume -- ls /config/
password username
📜 동적 시크릿 업데이트
-
볼륨 마운트를 사용한 시크릿에서는 일정 기간(기본 업데이트 주기 60초)마다 kube-apiserver로 변경을 확인하고 변경이 있을 경우 파일을 교체한다.
-
이 주기를 조정하려면 “kubelet의 –sync-frequency 옵션”을 지정해야 한다.
-
환경 변수를 사용한 시크릿의 경우 파드를 기동할 때 환경 변수가 정해지기 때문에 동적으로 변경할 수는 없다.

# 시크릿에 마운트된 디렉터리 확인
$ kubectl exec -it sample-secret-multi-volume -- ls -la /config
total 4
drwxrwxrwt 3 root root 120 Apr 8 09:06 .
drwxr-xr-x 1 root root 4096 Apr 8 09:06 ..
drwxr-xr-x 2 root root 80 Apr 8 09:06 ..2023_04_08_09_06_41.2801225511
lrwxrwxrwx 1 root root 32 Apr 8 09:06 ..data -> ..2023_04_08_09_06_41.2801225511
lrwxrwxrwx 1 root root 15 Apr 8 09:06 password -> ..data/password
lrwxrwxrwx 1 root root 15 Apr 8 09:06 username -> ..data/username
# 파드의 /config/username 파일 내용 확인
$ kubectl exec -it sample-secret-multi-volume -- cat /config/username
root
# 시크릿 변경 전 경과 시간(AGE) 확인
$ kubectl get pod sample-secret-multi-volume
NAME READY STATUS RESTARTS AGE
sample-secret-multi-volume 1/1 Running 0 11m
-
일정 기간(최대 60초)이 경과하면 볼륨에 마운트된 파일 값이 변경된 것을 확인할 수 있다.
-
파드가 다시 생성되지 않기 때문에 순단(순간 단절)도 발생하지 않는다.
# 시크릿 내용 업데이트
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: sample-db-auth
type: Opaque
data:
username: YWRtaW4=
EOF
secret/sample-db-auth configured
# 시크릿에 마운트된 디렉터리 확인
$ kubectl exec -it sample-secret-multi-volume -- ls -la /config
total 4
drwxrwxrwt 3 root root 120 Apr 8 09:20 .
drwxr-xr-x 1 root root 4096 Apr 8 09:06 ..
drwxr-xr-x 2 root root 80 Apr 8 09:20 ..2023_04_08_09_20_21.2388709565
lrwxrwxrwx 1 root root 32 Apr 8 09:20 ..data -> ..2023_04_08_09_20_21.2388709565
lrwxrwxrwx 1 root root 15 Apr 8 09:06 password -> ..data/password
lrwxrwxrwx 1 root root 15 Apr 8 09:06 username -> ..data/username
# root에서 amdin으로 변경
$ kubectl exec -it sample-secret-multi-volume -- cat /config/username
admin
# 동적으로 파일 변경된 후의 경과 시간을 확인
$ kubectl get pods sample-secret-multi-volume
NAME READY STATUS RESTARTS AGE
sample-secret-multi-volume 1/1 Running 0 15m
댓글 남기기