Search

Configure Secrets in Applications

Created
2023/10/02 01:59
Tags
k8s
CKA
Mumshad Mannambeth
Application Lifecycle Management

1) About

Secret은 사용 방법이나 동작 과정이 ConfigMap과 동일하지만, 민감한 정보를 그대로 노출하지 않겠다는 것에 목적이 있음
즉, ConfigMap처럼 값을 공개적으로 확인하는 것이 어렵게 유지하여, 역할 자체를 ConfigMap과 분리하는 것이 Secret 객체의 존재 의의
다만 Secret을 생성하는 과정에서 키와 값을 실제 값으로 어딘가에는 기재되어야 하는데, 만일 정의 파일로 객체를 운용하게 되면 해당 파일 내에 키와 값이 Plain Text로 저장되어 확인이 쉬워지는 문제가 있음
** 정의 파일의 경우 내부적으로 접근하는 요소인데, 이에 대한 접근도 쉽지 않아야됨
** 선언적 방식의 이용에는 파일이 별도로 남지 않으므로 별도 인코딩 없이 이용
따라서 Secret의 정의 파일로 운용하는 값에 대해선 아래와 같은 명령어를 이용하여 인코딩된 값을 기재해야함
echo -n ${TEXT} | base64
Secret으로 생성된 값을 확인하고 싶다면 번거로운 디코딩 과정을 거쳐서 접근해야함
kubectl get secret ${NAME} -o yaml
을 이용하여 인코딩된 값을 확인하고, 해당 값을
echo -n ${TEXT} | base64 —decode
로 값을 읽어냄
어디까지나 Secret 객체를 생성하기 위한 값은 암호화가 아닌, 인코딩된 것임을 잊으면 안 됨
내부 이용자의 접근성을 떨어뜨리기 위한 목적이지, 접근 자체를 막는 방법이 아님
따라서 Secret의 정의 파일이 노출되는 경우엔 값을 디코딩하는 것도 가능하여 보안 문제로 직결
따라서 진짜 내부 이용자의 접근을 제한하고 싶은 경우에는 RBAC (Role Based Access Control)에 대해서 고려해야하고, 공식 문서에 따라 암호화 설정에 대한 것도 고려해야함
** AWS, GCP 같은 클라우드를 이용한다면, 해당 업체에서 제공하는 Secret Store를 이용하여 주입 받는 것도 방법

2) Encryption

별도 암호화 설정이 없다면, ETCD의 API를 이용하여 쿠버네티스 내부에서 이용하는 Secret의 값을 Plain Text로 확인할 수 있게 됨 (etcdctl을 운용하려면 CA 관련 파일이 필요, /etc/kubernetes/pki/etcd 경로에 파일들이 있는지 확인)
apt-get install etcd-client ETCDCTL_API=3 etcdctl \ —cacert=/etc/kubernetes/pki/etcd/ca.crt \ —cert=/etc/kubernetes/pki/etcd/server.crt \ —key=/etc/kubernetes/pki/etcd/server.key \ get /registry/secretes/default/${SECRET_NAME} | hexdump -C
만일 암호화가 되어 있지 않다면, Kube API Server 실행에 —encryption-provider-config의 설정이 되어 있지 않은 것
** ps -aux | grep ‘kube-api’ | grep ‘encryption-provider-config' 출력 내용이 있는지 확인
** cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep ‘encryption-provider-config’ 출력 내용이 있는지 확인
만일 출력 내용이 없다면 별도 EncryptionConfiguration 객체를 만들어 이를 Kube API Server의 —encryption-provider-config 실행 옵션으로 기재해야함
이 때 EncryptionConfiguration의 resources라는 암호화의 대상은 Secret만이 아니라 다른 쿠버네티스 객체도 지정할 수 있는데 대체로 Secret만 지정하는 것이 좋으며, providers 항목에는 암호화 방식에 대해서 명시할 수 있음
이 때 providers의 첫 번째 요소가 암호화 방식임에 유의
** 아래 링크를 참고
providers에서 사용하는 암호화 방식에는 암호화에 사용할 키를 명시해야 되는데, 키는 아래 명령어로 생성 가능
head -c 32 /dev/urandom | base64
apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: ${RANDOM_VALUE_32_BYTES}
YAML
복사
위와 같은 파일을 /etc/kubernetes/enc 경로에 작성
vim /etc/kubernetes/manifests/kube-apiserver.yaml을 통해 Kube API Server를 아래와 같은 형태로 수정
apiVersion: v1 kind: Pod metadata: annotations: kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.20.30.40:443 creationTimestamp: null labels: app.kubernetes.io/component: kube-apiserver tier: control-plane name: kube-apiserver namespace: kube-system spec: containers: - command: - kube-apiserver ... # ADD BELOW WITH FILE NAME FROM HERE - --encryption-provider-config=/etc/kubernetes/enc/${ENCRYPTION_CONFIGURATION_FILE_NAME}.yaml # TO HERE volumeMounts: ... # ADD BELOW FROM HERE - name: enc mountPath: /etc/kubernetes/enc readOnly: true # TO HERE ... volumes: ... # ADD BELOW FROM HERE - name: enc hostPath: path: /etc/kubernetes/enc type: DirectoryOrCreate # TO HERE ...
YAML
복사
위 파일의 저장과 동시에 Kube API Server는 재실행 되는데, encryption-provider-config 옵션이 잘 적용 되었는지 확인하면됨
이전 과정과 마찬가지로 Secret 객체를 만들고, ETCD의 API를 이용하여 잘 암호화 되었다면 기능도 정상 동작
** 암호화 적용 이전에 생성한 Secret은 적용되지 않으므로, 아래와 같은 명령어를 이용해야함 (자세한 과정은 반드시 아래 링크 참고)
kubectl get secret -A -o json | kubectl replace -f -

3) Commands

Secret 역시 생성하기 위해 ConfigMap처럼 명령적인 방법과 선언적인 방법을 모두 사용할 수 있음
kubectl create secret generic ${NAME} —from-literal=${KEY}=${VALUE} —from-literal=${KEY}=${VALUE} …
리터럴을 명시하여 Secret을 생성
kubectl create secret generic ${NAME} —from-file=${FILE_NAME}
파일을 통해 Secret을 생성
kubectl create -f ${SECRET_NAME}.yaml
Secret 정의 파일로 생성
apiVersion: v1 kind: Secret metadata: name: sample-secret data: KEY: VALUE
YAML
복사
** 위에서 설명했던 것처럼 인코딩 된 값을 이용
kubectl get secret
Secret 객체 조회

4) YAML

Pod를 생성할 때 Secret을 이용하고 싶다면 아래와 같이 YAML을 작성하여 주입할 수 있음
apiVersion: v1 kind: Pod metadata: name: sample-pod labels: name: sample-pod spec: containers: - name: sample-pod image: sample-pod ports: - containerPort: 8080 envFrom: - secretRef: name: sample-secret
YAML
복사
** 위 예시는 sample-secret이라는 Secret 객체의 모든 키 값 쌍을 환경 변수로 주입
아래 예시는 Secret 객체에서 key에 해당하는 값을 찾아 단일 키에 환경 변수로 주입
env: - name: KEY valueFrom: secretKeyRef: name: sample-secret key: KEY
YAML
복사
심지어 Secret을 볼륨으로 마운트 하여 파일로 운용 가능 (키 이름이 파일 이름이고, 값이 파일의 내용)
volumes: - name: sample-volume secret: secretName: sample-secret
YAML
복사