목차

Kubernetes Secret

비밀번호, OAuth 토큰, API 키, TLS 인증서, ssl키 와 같은 민감한 Credential이 요구 되는 데이터를 base64로 인코딩 하여 저장, 관리

  • 데이터 저장은 1MiB 이하로만 가능
  • Pod에 Secret 적용시 자동 Decoding되어 애플리케이션에서 바로 사용 가능
  • 기본 사용방법은 configMap와 동일 → Kubernetes configMap 확인
    • kubectl create cm → kubectl create secret
    • envFrom.configMapRef → envFrom.secretRef
    • name → secretName 로 바꿔 사용

Secret Pod

apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: sc-container
    image: busybox
    volumeMounts:
    - name: web-secret
      mountPath: /secrets
    envFrom:
    - secretRef:
        name: secret-sc
  volumes:
  - name: web-secret
    secret:
      secretName: secret-sc
      key: sc-source

ConfigMap Pod (비교)

apiVersion: v1
kind: Pod
metadata:
  name: cm-pod
spec:
  containers:
  - name: cm-container
    image: busybox
    volumeMounts:
    - name: cm-secret
      mountPath: /configmap
    envFrom:
    - configMapRef:
        name: secret-sc
  volumes:
  - name: web-cm
    configMap:
      name: configMap-cm
      key: cm-source
  • 쉽게 디코딩 되는 아쉬움 있음
$ echo 'kubernetes secret' | base64
a3ViZXJuZXRlcyBzZWNyZXQK

$ echo a3ViZXJuZXRlcyBzZWNyZXQK | base64 -d
kubernetes secret

#secret 생성
$ kubectl create secret generic secret-sc \
--from-literal=rootpw=k8sroot \
--from-literal=database=k8sdb \
--from-literal=user=k8suser \
--from-literal=password=k8suser

configMap secret 동시 사용 예제

apiVersion: v1
kind: Pod
metadata:
  name: sc-pod
spec:
  containers:
  - name: my-container
    image: busybox
    env:
    - name: ROOT_PASSWORD
      valueFrom:
        secretKeyRef:
          name: secret-sc
          key: rootpw
    - name: DATABASE_NAME
      valueFrom:
        configMapKeyRef:
          name: configmap-cm
          key: database

configMap secret 동시 사용 예제2

apiVersion: v1
kind: Pod
metadata:
  name: sc-pod
spec:
  containers:
  - name: my-container
    image: busybox
    envFrom:
    - configMapRef:
        name: configmap-cm
    - secretRef:
        name: secret-sc

  • Secret에 저장되는 값은 단순 base64인코딩 값이므로 쉽게 디코딩이 가능하다. 민감한 데이터는 쉽게 디코딩되어 노출될 위험이 높다.
  • SealedSecret 사용 시 클러스터에서 실행되는 Controller에 의해서만 암/복호화가 가능
    • SealedSecret Controller는 Kubernetes Secret으로 복호화를 수행
    • 복호화는 SealedSecret Controller내 저장된 인증서를 통해 처리
    • 실행되는 Controller가 문제가 생길경우 복호화가 불가능

    • 예기치 않은 상황에 대비해 내장된 인증서를 로컬에 저장하여 사용 가능함

#링크에서 릴리즈 버전 확인하여 설치 현재 0.26.2
$ KUBESEAL_VERSION='0.26.2'

$ wget "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION:?}/kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz"

$ tar -xvzf kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz kubeseal

#전역 사용 설정
$ sudo install -m 755 kubeseal /usr/local/bin/kubeseal

$ kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.26.2/controller.yaml
#또는 wget으로 다운받고 그 파일(controller.yaml) apply

#Pod 확인
$ kubectl get pods -n kube-system | grep sealed-secrets-controller
sealed-secrets-controller-7f4d55d696-56c9t   1/1     Running   0          22s

#base64기반 yaml 파일 생성
$ kubectl create secret generic secret-from-sealedsecret \
--dry-run=client --from-literal=superpwd=k8ssecret -o yaml > mysecret.yaml

#파일에서 vi mysecret.yaml에서 data 에 암호화된 부분 확인 ->azhzc2VjcmV0
$ echo azhzc2VjcmV0 | base64 -d
k8ssecret
#쉽게 디코딩

#SealedSecret controller가 보유한 인증서 암호화
$ cat mysecret.yaml | kubeseal -o yaml > mysecret-sealed.yaml

mysecret.yaml

apiVersion: v1
data:
  superpwd: azhzc2VjcmV0
kind: Secret
metadata:
  creationTimestamp: null
  name: secret-from-sealedsecret

mysecret-sealed.yaml

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: secret-from-sealedsecret
  namespace: default
spec:
  encryptedData:
    superpwd: AgB2DoUuu1job77bFv73W8ReEzpkYhaB9d15gGPpgGo16rGay5MyS/9WTa5CLyhfhHoowSKqSSRXFniGg692PgyeUCEVsOBh8k5J0B7jmb8OBa+OYHOebZguY4Gr4rNjV2QSqNlEIqzuBslBZSnyDsAgmDYq3qqvsnkuCQPFZzsTQcw8oPHdS5kI3MgvZp/Sh20LvjIfjki2BN7bjYrF74D3HKNukiw6X5M7F9dFneszeSO9Nv1LJ1sFMUqXwFouyvFsn6JTLbIjiKf/Gv9vdTaGRaPfT48RWLmOipnwI+qD2QaZdrO/Sjo96CSKLpHc76QmZR7QSLJu1LU0+92LxknTnBmi1o7dnhE3dScS4MooUG7LkB+jXlQpd1flJfXxRfEJmy6EJ0/HYUfo73rCBQvdzdllgJ33z569OAvoAwnLbDP/I0AhPTk8PRlPIeOz5frzbSCMfnCtddfhxMuF309FbJG36HPNn8siB9rKTkqVNSGlXvJwZvHv93bgrxgsJkp9ao5Xt4ITokC9rXl6GR0kzNy9mkuku64C6BZioxrnPtjnYhpEr6sQgo/3rDkkrTm5d/2A6yiRgzoXfJuIFeKuItj1RlkuMuwJH7ACRzlqf6hy0onhW6a+bucZ4Rjz9NE7BNPbBB97GFY/x4NCLaZQ38FiZIc9dQV4eBOCTOd1QE4ovqUO7+ihiT7OeMzprspCLR7svZruRAE=
  template:
    metadata:
      creationTimestamp: null
      name: secret-from-sealedsecret
      namespace: default
$ kubectl apply -f mysecret-sealed.yaml
sealedsecret.bitnami.com/secret-from-sealedsecret created

#확인
$ kubectl get sealedsecret
NAME                       AGE
secret-from-sealedsecret   13s

#secret를 통해서도 확인 가능
$ kubectl get secret
NAME                              TYPE                 DATA   AGE
...
secret-from-sealedsecret          Opaque               1      29s

#데이터 확인 mysecret.yaml의 base64 인코딩 값과 같음
$ kubectl get secret secret-from-sealedsecret -o jsonpath='{.data.superpwd}'
azhzc2VjcmV0

Controller가 보유한 인증서 저장

#mycert.pem으로 저장 'kubeseal --fetch-cert > mycert.pem'로도 가능
$ kubeseal --controller-name=sealed-secrets-controller \
--controller-namespace=kube-system --fetch-cert > mycert.pem

$ cat mycert.pem
-----BEGIN CERTIFICATE-----
MIIEzTCCArWgAwIBAgIRAPogo3H13Lz+gpZ0O3jpZoYwDQYJKoZIhvcNAQELBQAw
ADAeFw0yNDA0MTYwNDM0MTVaFw0zNDA0MTQwNDM0MTVaMAAwggIiMA0GCSqGSIb3
...

저장된 인증서로 SealedSecret 생성

$ kubectl create secret generic secret-from-localsealed \
--dry-run=client --from-literal=superpwd=k8ssecret -o yaml > lsecret.yaml

$ cat lsecret.yaml | kubeseal --controller-name=sealed-secrets-controller \
 --controller-namespace=kube-system --format yaml \
 --cert mycert.pem > lsecret-sealed-local.yaml

$ kubectl get secret secret-from-localsealed -o jsonpath='{.data.superpwd}'
azhzc2VjcmV0

암호화키 교체 (–re-encrypt)

#encryptedData 의 키값이 변경됨 결과값(azhzc2VjcmV0->k8ssecret)은 같음
$ kubeseal --re-encrypt < lsecret-sealed-local.yaml > tmp.yaml \
 && mv tmp.yaml lsecret-sealed-local.yaml

Private-key 백업/복원

  • 클러스터가 문제가 생길경우 private-key가 소실되어 암복호화가 불가능해지는 것을 방지 하기 위하여 별도로 백업. 새로운 클러스터 재구성시 private-key를 복원하여 seald-secret를 복호화 하여 secret를 얻을 수 있다.
#백업
$ kubectl get secret -n kube-system -l \
sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > main.key

#복원
$ kubectl apply -f main.key

# pod 재생성하여 pod 가 새로 업데이트된 key 값을 반영하도록 한다.
$ kubectl delete pod -n kube-system -l \
app.kubernetes.io/name=sealed-secrets