메인 콘텐츠로 이동하기
  1. Posts/

[K3s-06] GitOps에서 안전하게 Git에 secret을 등록하는 방법

·612 자
K3s

누구나 Kubernetes에 대해 조금이라도 알고 있다면 Kubernetes의 secrets가 실제로 안전하지 않다는 것을 알 것입니다. 이것은 단지 base64로 인코딩된 것일 뿐입니다. 따라서 git에 저장하거나 공개적으로 노출시키는 것은 안전하지 않습니다. 이를 안전하게 만드는 여러가지 방법이 있습니다만, 이 글에서는 가장 간단한 방법 위주로 소개하고자 합니다.

Kubernetes secrets를 안전하게 보관하기 위한 방법들:

  1. Sealed Secrets
  2. External Secrets Operator (예: Hashicorp Vault)

Sealed Secret #

Kubeseal 작동방식 #

sealed-secret-diagram
Auth0 블로그로의 Sealed Secret 아키텍쳐

How sealed secret or kubeseal works is very straightforward. I won’t explain what public key encryption in detail in this post, but to be simple for understanding, it is just encrypting the secret with public key and decrypting it with private key.

sealed secret 또는 kubeseal의 작동 방식은 매우 간단합니다. 이 게시물에서 공개 키 암호화에 대해 자세히 설명하지는 않겠지만, 쉽게 말하자면 공개 키를 사용하여 시크릿을 암호화하여 Git에 해당 정보를 저장하고, 클러스터에 있는 개인 키를 사용하여 해독하여 쿠버네티스 secret으로 활용합니다.

클러스터에 설치된 Sealed Secret Controller는 클러스터에 있는 개인 키를 활용하여 sealed secrets을 k8s secret으로 만듭니다. 그렇기에, sealed secret은 git에 쿠버네티스 secret manifest를 저장하기에 조금 더 안전한 수단을 제공할 뿐, 클러스터에 접근 권한이 있다면, 여전히 secret의 값을 볼 수 있음을 인지하고 있어야합니다.

Kubeseal 사용법 #

kubeseal 명령어 설치: https://github.com/bitnami-labs/sealed-secrets#kubeseal

# K3s에 kubeseal 컨트롤러 설치
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm repo update

helm install sealed-secrets -n kube-system --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets

helm status -n kube-system sealed-secrets

먼저, kubectl 명령어로 예제 시크릿을 생성하고, mysecret-1.yaml이라는 파일을 만듭니다.

  • dbpassword: password
  • secondkey: secondValue
  • thirdkey: thirdValue
kubectl create secret generic mysecret-1 --dry-run=client --from-literal=dbpassword=password --from-literal=secondkey=secondValue --from-literal=thirdkey=thirdValue -o yaml > mysecret-1.yaml

kubeseal 명령어를 사용할 때는, kubectl 명령어를 이용하기 때문에, 해당 권한이 설정되어 있는 개발환경이 준비되어있어야 한다. 그러면, 클러스터에 있는 공개키를 받아와서, sealed secret manifest를 생성합니다.

kubeseal --controller-name=sealed-secrets-controller --controller-namespace=kube-system --format yaml --secret-file mysecret-1.yaml --sealed-secret-file mysealedsecret-1.yaml

아니면 해당 공개키를 직접 받아와서, 로컬 환경에 따로 저장도 가능합니다. --cert mycert.pem 매개변수가 kubeseal 명령에 추가되면 암호화에 로컬 인증서를 사용합니다.

# install certificate
kubeseal \
      --controller-name=sealed-secrets-controller \
      --controller-namespace=kube-system \
      --fetch-cert > mycert.pem

# encrypt using mycert.pem
kubeseal \
	  --controller-name=sealed-secrets-controller \
	  --controller-namespace=kube-system \
	  --secret-file mysecret-1.yaml \
	  --format yaml --cert mycert.pem > mysealedsecret-1.yaml

생성된 암호화된 mysealedsecret-1.yaml 파일은 다음과 같습니다. 암호화되어 있기 때문에 base64로 디코드할 수 없으며, git에 저장하는 것도 안전합니다.

---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: mysecret-1
  namespace: default
spec:
  encryptedData:
    dbpassword: AgBpKKeEP7xHvP1oj/5Bc/6kzCTf91+xBl+LzZLsTrzwKkwDIXE2nuCRt/eSeSl04CvD8EOiZsmlPemZ3dbN6JXrLtilYdSL/QDWv0/6ijGfce5NC+zneGFrY+f9skqJWzhG4hQcwGvwJ/NpEO5TlPy9DVEmhXHouAK7/jSZMzO60GVP+dNgMAIknXWZFx4oVk9wbVUmmTCJG/LdFAaNCNxKtpVc1NCr6PxPE9pugroZ3BtpsAwdd7juDHYWqyVw9MW+fWNOw9ZRcScpxX1LXc5vQS9o3CuZpKTsJXe/fGxRAl9gsa+QOXK1bp2Yh7ODhCJBpM6GW7kxOncspn/O0ATiKoq4M3HiXOmsE6pJWx6K5cesW5Tf1/BGUMzkba8cglEo3GrP9acVot59+oT0mwNLnArPygR0ZRQyLX4e+eFv3rkKFm7Z2wFq+5YrATZ+LO/0qTzbdztk/iUwcLXg4kPK3df8vZlw36wsQ175jo33alkI+B6XwBvSjJVlK9nWTp5Bz4dthbEvsU8Jm78FMspF/6uxoF/Sa8Rf0u473aJawRAUYuBvw7Ay3y6K9WhIkf814Yenw4gYIQ+O+zHEbCT+0gTNWttApEqqBTPwLQtorhjnJUCmDQxECbuzUxehoO/948xTEULu6f+sC5IBbkPM9KNY3hu+f39DfRC6+M44QKaiUzyE8FXgt2D7xgvB0UTCzRSXpj55FQ==
    secondkey: AgAdg/xWDmTWfT11DdAbMvD19R9/tCL96P1iAws/0+KZaTVEc4+yuZrCHqgIwoc4fbkIOl9n9lzYn7CuRcptt9s+zXUHg/7RR22XHUmS0TuLmjv1mnqdVST3L2BZfBzLb6tXy0SVPFohe+c9G6UbOavMNrELhTYd1RMqicg88kGSVb5vp4kOUQ6E9DLEls/G9O8WyoQSowqVK5tA0vPSMjdTjV7fcfaaiR1a4uKSxUWvLf+eloEOWTsW3bPW06YwQ6hkLNX/hlQ2/NpOih0OxhOr8FqKfBTlHfri6xzPXQ38qXSvZFjDCYdCFQ7R7InW1jJWoqISNMHG5NK77G33wCaQ2Zp+k12d8YWBh/lWNoLTIzO560HvRUr414KtSOMnxg+HEZgkLMUWus/JULVMB8lCtk+5eXHuhFIwM9s4pCCbQBobv9Jltm+Og5ppTk/LFQLAUoLqQyMQVmaz4ugV/peiXAT5jw4T5aIwqS9AQx/kiUD5b+1mXSapl1lsyEypCkTNjkGpAleRJUvzjU66nRV/nJBLdNT23c1sFgJ9ZJZ3IAb9MBGi6ix62qlN1FEQsXLMEckX99jDKw2dpZJNQyERwNOB9CzkjM4cYAsjXqCYfAS7rsHin+VybZKcez3wkPKl9PXswEzqjOfTbVS8fISU7ZvWn4rRqC9Yrcg7JWC0Abv+f2yO8x524fw/hGTvJ4SubQe6HD+H9Md7yg==
    thirdkey: AgB0BNkNJ6Iop5GEUTkFs7G7WberMH6EKzvjcbb4KaSMcTA0vR093srJueifK81ZJoKDqlJJQJoETrcmopZhRATW9xMx+ANYPcWhvthNMEYfPSENgvUHtRR7rJHhfkwGfWfWdrGV1WYz61uLSHL6gxAOa4NNiWF373VX52NyT9EZAFIjSw1M2BKW9C0kJ+MO5ziDstkfYx8a0VJfvLJ5s4bKhj86SNAWPisCgRzUCCbQfIKBS1w7XTU5jTDISdnnmVVOqb4icqLBxi6TNKhDeCqGJtOcwMNVh36H5nNub/1GW64uNvnHGpP1tNbI3MlsBGJ3FNkoR18GKTKIgrQwatQzTKJZdILzo7WCtnn+SwwXbKS54wPTqGX3ZQak/l3kbqlkJixWOEIz4EF6UbsLuldFlZFy32HBdVO8+Nurb8b4bXVapEef6Ik739ykKKMzFioxuEnp3BZjKUNbKfvoDdH3+gpObF0FmKRFMB2AU+OZZV2aaJHBMR0C3nrGyKDvbvlt7J0IIwgrd/RaOTZas+mLAKY5DXMuy9S8nvWyF2C7asntbnmpjI3YZ46LGiDEYihexJUpcJTHyIMQ2hpKGKNxR9RIZf4AUvz4T6Osn+vIbd0slos7aibiObDY2e8iVjfVtUPGe6HsOh4BJ1mc/YL3+0App8EV6FIxxe4fo+nchUff8iKA44RrRDf5MSvQFFQhptmwvk16JM9t
  template:
    metadata:
      creationTimestamp: null
      name: mysecret-1
      namespace: default

그런 다음 클러스터에 비밀을 생성합니다.

kubectl create -f mysealedsecret-1.yaml

또는 아래와 같이 한 명령어로 봉인된 비밀을 생성할 수 있습니다.

kubectl create secret generic mysecret-1 --namespace=default --dry-run=client --from-literal=dbpassword=password --from-literal=secondkey=secondValue --from-literal=thirdkey=thirdValue -o yaml | \
    kubeseal \
      --controller-name=sealed-secrets-controller \
      --controller-namespace=kube-system \
      --format yaml > mysealedsecret-1.yaml

# you can check decrypted secret also
kubectl get secret mysecret-1 -o yaml

Sealed secret은 암호화되어 있으므로 Git에 업로드할 수 있습니다. 그리고 K3s에 생성되면 평소처럼 base64로 인코딩된 일반 비밀로 생성됩니다. obviously, 클러스터에 직접 접근할 경우 base64로도 디코드할 수 있습니다. 기존 비밀은 Deploymentsspec.containers.envFrom.secretRef에 주입될 수 있습니다.

Vault #

Vault 작동방식 (WIP) #

external-secret-diagram
Auth0 블로그의 External Secret 아키텍쳐

External Secrets Operator(ESO)를 사용하는 것은 클러스터에서 비밀을 저장하는 더 나은 방법입니다. 가장 잘 알려진 예는 Hashicorp Vault를 사용하는 것입니다.

ESO는 비밀을 관리하기 위해 네 개의 CRD를 제공합니다. ExternalSecretClusterExternalSecret CRD는 가져와야 할 데이터와 변환 방법을 정의합니다. SecretStoreClusterSecretStore CRD는 외부 비밀 저장소에 대한 연결 세부 정보를 정의합니다.

이는 다음과 같이 작동합니다:

  1. 외부 비밀 저장소에 대한 연결 세부 정보를 정의하는 SecretStore CRD를 생성합니다.
  2. 외부 비밀 저장소에 비밀을 생성합니다.
  3. 외부 비밀 저장소에서 가져와야 할 데이터를 정의하는 ExternalSecret CRD를 생성합니다.
  4. 대상 클러스터에 CRD를 배포합니다.
  5. ESO 컨트롤러는 외부 비밀 저장소에서 데이터를 가져와 Kubernetes 비밀을 생성합니다.

Kubernetes 비밀 주입기로서 Vault가 정확히 어떻게 작동하는지에 대한 설명은 훨씬 더 자세한 설명이 필요합니다. 이 섹션은 이후에 계속하여 업데이트할 예정입니다.

Vault 사용법 (WIP) #

Vault 설정 및 사용법 또한, 이후에 업데이트할 예정입니다.

Reference #