민감한 정보를 저장하는 Secret

Created
April 10, 2022
Created by
D
DaEun Kim
Tags
Kubernetes
Property

  • 시크릿(Secret)은 SSH 키, 비밀번호와 같이 민감한 정보를 저장하기 위한 용도로 사용한다.
  • 네임스페이스에 종속된다.
  • 개별 시크릿의 크기는 1MiB로 제한된다.
  • 시크릿 볼륨 소스는 지정된 오브젝트 참조가 실제로 시크릿 유형의 오브젝트를 가리키는지 확인하기 위해 유효성을 검사한다. 따라서, 시크릿에 의존하는 모든 파드보다 먼저 시크릿을 만들어야 한다.
  • 시크릿을 생성하는 명령어는 3가지로 나뉘고 시크릿타입은 opaque, dockerconfigjson, tls 등이 있다.
$ ku create secret --help
Create a secret using specified subcommand.

Available Commands:
  docker-registry Create a secret for use with a Docker registry
  generic         Create a secret from a local file, directory, or literal value
  tls             Create a TLS secret

opaque 타입의 시크릿 생성하기

opaque 타입은 사용자가 정의하는 데이터를 저장할 수 있는 범용 시크릿이다.

my-password 라는 시크릿을 아래와 같이 생성한다.

시크릿도 컨피그맵처럼 —from-literal, —from-env-file 등의 옵션을 사용할 수 있다.

ubuntu@ip-10-220-12-225:~$ kubectl create secret generic my-password --from-literal password=1234
secret/my-password created

시크릿을 조회해보면 2개가 나온다. (default-token-nqqnl 시크릿은 ServiceAccount 라는 오브젝트에 의해 네임스페이스 별로 이미 만들어진 것이다.)

ubuntu@ip-10-220-12-225:~$ ku get secrets
NAME                  TYPE                                  DATA   AGE
default-token-nqqnl   kubernetes.io/service-account-token   3      40d
my-password           Opaque

직접 만든 my-password 라는 시크릿을 YAML 형식으로 조회해보면 password 키에 대응하는 값이 1234가 아닌 MTIzNA==으로 되어있다.

쿠버네티스가 기본적으로 시크릿 값을 base64 방식으로 인코딩하기 때문이다.

image
ubuntu@ip-10-220-12-225:~$ echo MTIzNA== | base64 -d
1234

따라서 YAML 파일로 시크릿을 생성할 때도 base64으로 인코딩된 문자열을 작성해야 한다.

파드에서 생성한 시크릿 불러오기

시크릿을 파드에서 환경변수로 사용하려면 아래와 같이 YAML을 작성하고 클러스터에 적용한다.

apiVersion: v1
kind: Pod
metadata:
  name: env-from-secret
spec:
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      envFrom:
        - secretRef:         # my-password 라는 시크릿에서 키/값을 불러옴
            name: my-password

apply 하면 디코딩된 값이 컨테이너의 환경변수에 들어간다. password=1234

image

valueFrom 으로 원하는 키/값만 선택해서 다른 이름으로 불러올 수도 있다. MY_PW=1234

apiVersion: v1
kind: Pod
metadata:
  name: value-from-secret
spec:
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      env:
        - name: MY_PW
          valueFrom:
             # my-password 라는 시크릿의 password 키/값을 가져와 MY_PW 라는 이름으로 바꿈.
            secretKeyRef:
              name: my-password
              key: password
image

시크릿을 파일로 마운트해서 불러올 수도 있다. (시크릿 키 이름으로 된 파일 내용이 시크릿 값으로 되어있음.)

apiVersion: v1
kind: Pod
metadata:
  name: volume-mount-secret
spec:
  volumes:
    # my-password 라는 시크릿을 컨테이너에 마운트하는 데 필요한 볼륨 정의
    - name: secret-volume
      secret:
        # 가져올 시크릿
        secretName: my-password
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      volumeMounts:
        # secret-volume 이 불러올 시크릿 값을 /etc/secret 에 마운트시킨다
        - name: secret-volume
          mountPath: /etc/secret
image
apiVersion: v1
kind: Pod
metadata:
  name: selective-volume-mount-secret
spec:
  volumes:
    # my-password 라는 시크릿을 컨테이너에 마운트하는 데 필요한 볼륨 정의
    - name: secret-volume
      secret:
        # 가져올 시크릿
        secretName: my-password
        # my-password 시크릿에 있는 password 키/값만 선택하고 값은 /etc/secret/mypw 에 저장함
        items:
          - key: password
            path: mypw
  containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      volumeMounts:
        # secret-volume 이 불러올 시크릿 키/값을 /etc/secret 에 마운트시킨다
        - name: secret-volume
          mountPath: /etc/secret
image

이미지 레지스트리 접근을 위한 dockerconfigjson 타입의 시크릿 생성하기

AWS ECR 같은 프라이빗 레지스트리에서 도커이미지를 받아오려면 레지스트리에 로그인을 해야 한다.

쿠버네티스에서는 docker login 명령어 대신에 레지스트리 접근에 필요한 인증 정보를 저장하는 시크릿을 생성한다.

레지스트리 인증을 위해 시크릿을 생성하는 방법은 2가지가 있다.

  1. docker login 명령어로 레지스트리에 로그인 할 때 도커가 만들어주는 ~/.docker/config.json 사용
  2. 시크릿 만들 때 직접 —-docker-username, —-docker-password 으로 인증 정보 명시
  1. ~/.docker/config.json 사용

~/.docker/config.json 을 아래와 같이 작성한다. (프라이빗 레지스트리로 AWS ECR 을 사용한다고 가정.)

{
  	"auths" : {
		"credHelpers": {
			"public.ecr.aws": "ecr-login",
			"<ECR 레지스트리 주소>": "ecr-login",
		}
  }
}

레지스트리에 로그인한다.

$ aws ecr get-login-password --profile ecr-user --region ap-northeast-2 \
| docker login --username AWS --password-stdin <레지스트리 주소>
Login Succeeded

~/.docker/config.json 내용이 아래와 같이 바뀐다. (auths.<ECR 레지스트리 주소>.auth 에 레지스트리 로그인에 필요한 토큰이 들어감.)

$ cat ~/.docker/config.json
{
        "auths": {
                "<ECR 레지스트리 주소>": {
                        "auth": "QVdTOmV5SndZW..."
                },
                "credHelpers": {}
        }
}

바뀐 ~/.docker/config.json 을 가지고 $ kubectl create secret generic 명령어로 시크릿을 생성한다.

이 때 시크릿 키 이름을 .dockerconfigjson 으로 명시하지 않으면 error: failed to create secret Secret "registry-auth-from-dockerconfigjson" is invalid: data[.dockerconfigjson]: Required value 에러가 발생한다.

$ kubectl create secret generic \
registry-auth-from-dockerconfigjson \
--from-file=.dockerconfigjson=/home/ubuntu/config.json \
--type=kubernetes.io/dockerconfigjson

생성된 시크릿을 조회해본다. .dockerconfigjson 을 키 이름으로 하고 토큰을 값으로 하는 kubernetes.io/dockerconfigjson 타입의 시크릿이 만들어졌다.

ubuntu@ip-10-220-12-225:~$ ku get secrets registry-auth-from-dockerconfigjson -o yaml
apiVersion: v1
data:
  .dockerconfigjson: ewogICAgICAgICJhdXRocyI6IHsKI...
kind: Secret
metadata:
  creationTimestamp: "2022-04-10T08:15:19Z"
  name: registry-auth-from-dockerconfigjson
  namespace: default
  resourceVersion: "4734200"
  uid: d7f7dc11-a609-48e6-ad5b-83a476469aba
type: kubernetes.io/dockerconfigjson
  1. —-docker-username, —-docker-password 으로 인증 정보 명시

$ kubectl create secret docker-registry 명령어에 —docker-username, —docker-password 옵션을 줘서 레지스트리 로그인 인증 정보를 명시하여 시크릿을 생성할 수 있다.

$ kubectl create secret docker-registry \
ecr-registry-auth-by-cmd \
--docker-username=AWS
--docker-password=$(aws ecr get-login-password --profile ecr-user --region ap-northeast-2)

~/.docker/config.json 으로 시크릿을 만들었을 때와 마찬가지로 .dockerconfigjson 을 키 이름으로 하고 로그인에 필요한 토큰을 값으로 하는 시크릿이 생성되었다.

$ ku get secrets ecr-registry-auth-by-cmd -o yaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJodHRw...
kind: Secret
metadata:
  creationTimestamp: "2022-04-10T07:56:42Z"
  name: ecr-registry-auth-by-cmd
  namespace: default
  resourceVersion: "4732710"
  uid: 7b00a93b-1cc1-4fcb-8f27-784cd9aefe1b
type: kubernetes.io/dockerconfigjson

프라이빗 레지스트리에서 이미지를 받아서 파드 생성하기

디플로이먼트를 아래와 같이 만들었다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-using-image-registry-secrets
spec:
  replicas: 3
  selector:
    matchLabels:  # matchLabels 에 있는 라벨이 붙은 파드들을 리플리카셋으로 묶음.
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
        - name: app
          image: <프라이빗 레지스트리 주소>:<이미지태그>
          ports:
            - containerPort: 8000
      imagePullSecrets:
        - name: ecr-registry-auth-by-cmd  # 레지스트리 인증에 사용할 시크릿 이름

$ kubectl apply -f 명령어로 디플로이먼트를 생성한다.

image

프라이빗 레지스트리에 있는 이미지로 파드가 생성된 것을 확인할 수 있다.

ubuntu@ip-10-220-12-225:~/k8s-practice$ ku describe pod deployment-using-image-registry-secrets-78f955769c-64k88
Name:         deployment-using-image-registry-secrets-78f955769c-64k88
Namespace:    default
Priority:     0
Node:         ip-10-220-6-77/10.220.6.77
Start Time:   Sun, 10 Apr 2022 09:47:45 +0000
Labels:       app=app
              pod-template-hash=78f955769c
Annotations:  <none>
Status:       Running
IP:           11.244.1.90
IPs:
  IP:           11.244.1.90
Controlled By:  ReplicaSet/deployment-using-image-registry-secrets-78f955769c
Containers:
  app:
    Container ID:   docker://12e7d7aba0ad6aa7f1890b36958b633e3b1c5288b3d8e1bf762b6c101d4bce8f
    Image:          <프라이빗 레지스트리 주소>:latest
    Image ID:       docker-pullable://<프라이빗 레지스트리 주소>@sha256:fcd06e50decc221bb316bdc2e44886391c2b5618ab6e0c38a2d7a36d16e78248

TLS 키를 저장할 수 있는 시크릿 생성하기

파드 내부의 애플리케이션이 SSL 인증서나 비밀키를 써야할 때 tls 시크릿을 생성한다.

  1. SSL 인증서 및 키 생성
$ openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 --subj "/CN=example.com" -keyout cert.key -out cert.crt
.........+..........+.....+......+.+..+...+....+........+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+..................+..+.+..+....+...........+....+...+......+.....+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+..............................+...+....+..+....+......+...+.....+................+...........+....+...........+....+.....+.+......+..............+......+...+....+...+.....+.............+......+..............+.......+...+.....+...............+.+..............+...................+...+............+..+...+...+....+...+...+...+..+...+......+...+.........................+........+.............+...........+...+............+.............+...+..+......+.......+...+..............+...+...............+....+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..+...+...+.+...+...+............+..+...+..........+........+...+.+...+...+.....+.........+..........+.....+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+.....+.........+...+.........+....+..+.......+.....+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+..+.+......+...+......+..+..........+...............+..+......+.+.........+......+...+........+...+......+.+........+.........+.+...........+....+.....+..........+.....+.+......+.........+.....+...+......+.+...+.....+......+.+.....+................+.....+..................+.......+.....+...+....+......+......+.....+......+.......+..+...+.......+...+..+.....................+....+.....+...+...............+..........+...+........+.......+..+..................+....+...+..+.+............+..+....+..+....+..............+....+......+.........+.....+.+......+...........+..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
$ ls -al | grep cert
-rw-rw-r-- 1 ubuntu ubuntu  1814 Apr 10 10:27 cert.crt
-rw------- 1 ubuntu ubuntu  3272 Apr 10 10:27 cert.key
  1. TLS 생성 (타입이 kubernetes.io/tls 으로 되어있다.)
$ ku create secret tls my-tls-secret --cert cert.crt --key cert.key
image

tls.cert 라는 키 이름에는 인증서가 인코딩 된 값으로 들어있고 tls.key 라는 키 이름에는 비밀키가 인코딩 되어 들어가있다.

$ ku get secret my-tls-secret -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0...=
  tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0t...=
kind: Secret
metadata:
  creationTimestamp: "2022-04-10T10:28:37Z"
  name: my-tls-secret
  namespace: default
  resourceVersion: "4746494"
  uid: e65f5dc2-715e-489c-a3ea-0bfa8418202b
type: kubernetes.io/tls

참고자료