🥞 BE
home

Ch11. 시크릿

목차
시크릿(secret)비밀번호, OAuth 토큰, ssh 키 같은 민감한 정보들을 저장하는 용도로 사용한다. 이런 정보들은 컨테이너 안에 저장해 두지 않고 별도로 보관해 두었다가 실제 포드가 실행할때 설정을 통해서 컨테이너에 제공해 준다.

11.1 시크릿 만들기

시크릿은 내장 시크릿(built-in)사용자 정의 시크릿 2가지 종류가 있다.
내장 시크릿은 쿠버네티스 클러스터 내부에서 API에 접근할때 사용된다. 클러스터 내부에서 사용되는 계정인 ServiceAccount를 생성하면 자동으로 관련 시크릿이 만들어진다. 이렇게 만들어진 시크릿을 이용해서 해당 ServiceAccount가 권한을 가지고 있는 API에 접근할 수 있다.
사용자 시크릿은 사용자가 만든 시크릿이다.
시크릿은 kubectl create secret 명령 or 다른 자원들처럼 yaml 파일을 이용해서 만들 수도 있다.

11.1.1 명령으로 시크릿 만들기

먼저 echo -n 명령으로 사용자 이름과 비밀번호를 설정하는 파일을 만든다. 이후 create 명령으로 user-pass-secret이라는 시크릿을 만든다.
$ echo -n 'username' > ./username.txt $ echo -n 'password' > ./password.txt $ kubectl create secret generic user-pass-secret --from-file=./username.txt --from-file=./password.txt
Shell
복사
만든 시크릿은 kubectl get secret <시크릿이름> -o yaml 명령으로 확인 가능.
이후, 아래의 명령어로 필드 값을 디코딩해보면 원래 값을 알 수 있다.
$ echo cGFzc3dvcmQ= | base64 --decode $ echo dXNlcm5hbWU= | base64 --decode
Shell
복사

11.1.2 템플릿으로 시크릿 만들기

apiVersion: v1 kind: Secret metadata: name: user-pass-yaml type: Opaque data: username: dXNlcm5hbWU= password: cGFzc3dvcmQ=
YAML
복사
secret/user-pass-yaml.yaml
.type 필드 값은 Opaque이다. 시크릿의 타입은 다음과 같다.
시크릿 타입
설명
Opaque
기본값임. 키-값 형식으로 임의의 데이터를 설정할 수 있음
kubernetes.io/service-account-token
쿠버네티스 인증 토큰을 저장함
kubernetes.io/dockercfg
도커 저장소 환경 설정 정보를 저장함
kubernetes.io/dockerconfigjson
도커 저장소 인증 정보를 저장함
kubernetes.io/basic-auth
기본 인증을 위한 자격 증명을 저장함
kubernetes.io/ssh-auth
SSH 접속을 위한 자격 증명을 저장함
kubernetes.io/tls
TLS 인증서를 저장함
bootstrap.kubernetes.io/token
부트스트랩 토큰 데이터 정보를 저장함
.data.username.data.password 필드 값을 설정할 때 주의해야 할 점은 base64 문자 인코딩값을 설정해야 한다는 점이다. base64 문자 인코딩값은 echo -n 명령으로 만든다.
$ echo -n "username" | base64 $ echo -n "password" | base64
Shell
복사
모든 설정 후, kubectl apply -f user-pass-yaml.yaml 명령을 실행하면 시크릿을 만들 수 있다.

11.2 시크릿 사용하기

시크릿은 파드의 환경변수나 볼륨을 이용해서 파일 형식으로 사용할 수도 있다.

11.2.1 파드의 환경 변수로 시크릿 사용하기

apiVersion: apps/v1 kind: Deployment metadata: name: secretapp labels: app: secretapp spec: replicas: 1 selector: matchLabels: app: secretapp template: metadata: labels: app: secretapp spec: containers: - name: testapp image: arisu1000/simple-container-app:latest ports: - containerPort: 8080 env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: user-pass-yaml key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: user-pass-yaml key: password --- apiVersion: v1 kind: Service metadata: labels: app: secretapp name: secretapp-svc namespace: default spec: ports: - nodePort: 30900 port: 8080 protocol: TCP targetPort: 8080 selector: app: secretapp type: NodePort
YAML
복사
secret/deployment-secret01.yaml
눈여겨봐야 할 부분은 .spec.template.sepc.containers[].env[] 이다.
.name 필드의 SECRET_USERNAME이라는 환경 변수를 보면, 하위의 .valueFrom 필드에 .secretKeyRef.name.key 라는 하위 필드를 설정해서 시크릿의 이름(user-pass-yaml)과 키 값(username, password)을 참조한다.
여기서 사용되는 시크릿은 미리 만들어져 있어야 한다. 만약 오타 등의 실수로 없는 시크릿을 참조하게 되면 에러가 나면서 파드가 실행되지 못한다. 좀 더 구체적으로는, apiserver에서는 통과가 되어서 스케쥴링이 되지만 실제 kubelet이 파드를 실행하면서 시크릿을 가져올 때 에러가 발생하게 된다. 그러면 kubelet은 계속해서 시크릿을 가져오려고 재시도한다. 이 때 시크릿을 제대로 만들어 주면 파드가 정상적으로 실행된다.
kubectl apply -f deployment-secret01.yaml 명령으로 클러스터에 적용 후, localhost:30900/env 에 접속한 후 JSON 뷰어 플러그인을 실행한다.

11.2.2 볼륨 형식으로 파드에 시크릿 제공하기

볼륨 형식을 이용해 파드에 시크릿을 제공할 때는 .spec.template.spec.containers[].env[] 필드 대신, .spec.template.spec.containers[].volumeMounts[] 필드와 .spec.template.spec.containers[].volumes[] 필드를 설정한다.
apiVersion: apps/v1 kind: Deployment metadata: name: secretapp labels: app: secretapp spec: replicas: 1 selector: matchLabels: app: secretapp template: metadata: labels: app: secretapp spec: containers: - name: testapp image: arisu1000/simple-container-app:latest ports: - containerPort: 8080 volumeMounts: - name: volume-secret mountPath: "/etc/volume-secret" readOnly: true volumes: - name: volume-secret secret: secretName: user-pass-yaml --- apiVersion: v1 kind: Service metadata: labels: app: secretapp name: secretapp-svc namespace: default spec: ports: - nodePort: 30900 port: 8080 protocol: TCP targetPort: 8080 selector: app: secretapp type: NodePort
YAML
복사
secret/deployment-secret02.yaml
.spec.template.spec.containers[].volumeMounts[].mountPath 필드 값으로 컨테이너의 /etc/volume-secret 디렉터리를 설정해 시크릿 설정 내용을 파일 형태로 저장한다.
.spec.template.spec.containers[].volumeMounts[].readOnly 필드 값으로는 true를 설정해 볼륨을 읽기 전용으로 사용한다.
.spec.template.spec.containers[].volumes[].secret 필드 값으로 user-pass-yaml 시크릿을 설정한다.
kubectl apply -f deployment-secret01.yaml 명령으로 클러스터에 적용 후, localhost:30900/env 에 접속한 후 JSON 뷰어 플러그인을 실행한다.
볼륨 형식으로 시크릿 설정을 불러왔는지 확인하려면 http://localhost:30900/volume-config?path=/etc/volume-secret/username 으로 접속한다.

11.2.3 프라이빗 컨테이너 이미지를 가져올 때 시크릿 사용하기

일반적으로 컨테이너 이미지를 pull할때는 대부분 공개되어 있는 이미지를 사용한다. 하지만 사설(private) 이미지를 이용할 때는 인증 정보가 필요하다. 데스크탑에서 개인용으로 사용할때는 데스크탑에 사설 이미지에 대한 권한을 가진 사용자 정보를 저장해두고 사용하지만 쿠버네티스 클러스터에서는 그렇게 설정해서 사용하면 보안상의 위험이 있기 때문에 그렇게 설정하지 않는다. 이때 사용자 정보를 시크릿으로 저장해두고 사용할 수 있다.
이를 위해서 create secret 의 하위 명령으로 도커저장소용 시크릿을 만들 수 있는 docker-registry 명령이 있다. 다음 명령으로 secret을 만든다.
kubectl create secret docker-registry dockersecret --docker-username=USERNAME --docker-password=PASSWORD --docker-email=EMAIL --docker-server=https://index.docker.io/v1/
Shell
복사
도커이미지 저장소를 직접 설치해서 사용하거나 공식 도커 허브가 아닌 다른 곳을 사용하고 있다면 그곳 주소로 docker-server 설정을 변경해 주어야 한다. 그외 USERNAME, PASSWORD, EMAIL부분에는 본인의 정보를 넣어 주어야 한다.
시크릿을 어떻게 사용하는지는 kubectl get secrets dockersecret -o yaml 명령어로 확인 가능하다.
기존과 다르게 .data 필드 아래 .dockerconfigjson이라는 필드와 앞에서 설정한 도커 인증 정보 값이 설정되어 있다. 또한 .type 필드 값은 kubernetes.io/dockerconfigjson 이다.
apiVersion: apps/v1 kind: Deployment metadata: name: secretapp labels: app: secretapp spec: replicas: 1 selector: matchLabels: app: secretapp template: metadata: labels: app: secretapp spec: containers: - name: testapp image: geonoo/private-test:latest ports: - containerPort: 8080 imagePullSecrets: - name: dockersecret --- apiVersion: v1 kind: Service metadata: labels: app: secretapp name: secretapp-svc namespace: default spec: ports: - nodePort: 30900 port: 8080 protocol: TCP targetPort: 8080 selector: app: secretapp type: NodePort
YAML
복사
secret/deployment-secret03.yaml
.spec.template.spec.containers[].image 필드 값으로 geonoo/private-test:latest를 설정해서 프라이빗 컨테이너 이미지를 사용하도록 변경했다.
.spec.template.spec.imagePullSecrets[].name 필드로 dockersecret을 추가했다.
대충 dockerfile 만들어서 docker hub private에 이미지를 push 했다.
kubectl apply -f deployment-secret03.yaml 명령으로 클러스터에 적용 후,
kubectl get pods 명령 실행

11.2.4 시크릿으로 TLS 인증서를 저장해 사용하기

시크릿을 https인증서를 저장하는 용도로도 사용할 수 있다. 일반적으로 인증서는 공인된 기관에서 발급받아서 사용해야 하지만 여기서는 테스트 목적이기 때문에 사설인증서를 만들어서 사용해 보자. 아래 명령으로 인증서 키과 crt 파일을 만든다.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=example.com”
Shell
복사
이렇게 만든 인증서 파일을 이용해서 다음처럼 시크릿을 만듭니다.
kubectl create secret tls tlssecret --key tls.key --cert tls.crt
Shell
복사

11.3 시크릿 데이터 용량 제한

시크릿 크기가 너무 커지면 쿠버네티스의 apiserver나 kubelet의 메모리를 많이 차지하게되기 때문에 개별 시크릿의 최대 크기는 1MB까지이다.
크기가 작은 시크릿을 너무 많이 만들어도 같은 이슈가 있을 수 있기 때문에 전체 시크릿에 제한을 두는 기능도 도입될 예정이다.
시크릿 데이터는 etcd에 암호화 되지 않은 평문으로 저장된다. 그래서 누군가 etcd에 직접 접근한다면 시크릿의 내용을 확인할 수 있다. etcd에는 이외에도 중요한 데이터가 많이 있기 때문에 중요한 서비스에 쿠버네티스를 사용중이라면 etcd에 대한 접근을 제한하는 것이 필요하다. etcd에 저장되는 시크릿을 암호화해서 저장하는 것도 가능하지만 그건 쿠버네티스 클러스터를 직접 설치해서 사용할 때 옵션으로 별도로 지정을 해주어야 한다.

Reference