Search

쿠버네티스 Helm Values Data 를 보호하기 위한 Helm Secret 과 Argo 연동

생성일
2024/08/13 14:24
Category
Kubernetes
태그
Kubernetes
Helm

개요

Helm 을 사용하면, 쿠버네티스 매니페스트들을 관리하고 배포하는 데 있어서 정말 효율적으로 관리할 수 있게 됩니다.
하지만, Helm Chart 를 만들다보면 어느 순간 고민 포인트가 하나 생길 수 있습니다.
바로 보안성 입니다.
Terraform 의 경우 민감한 값들을 data 나 aws secretsmanager, aws parameterstore 를 이용해서 안전하게 가져 올 수 있는 반면에,
Helm 으로 작성되는 모든 코드들은 평문으로 들어가는데요.
형상관리를 하는 Repository 가 Private 이라고 해도 민감한 값들을 평문으로 하드코딩 하게 되는 것은 권고 되는 사항이 아닐 것 입니다.
Helm 의 값들을 보호하기 위해서 검토한 내용은 아래와 같습니다.

검토한 내용

Helm Secret
Helm 값들을 보호하기 위해서는 Helm Secret 이라는 Plugin 이 필요합니다.

Helm Secret 사용 방법

Helm Secret 을 사용하기 위해서는 먼저 Helm Secret 을 설치 해줘야 합니다.
Helm Plugin 설치:
helm plugin install https://github.com/jkroepke/helm-secrets
Bash
복사
GPG + SOPS
그리고 Helm Secret 을 더 완전하게 사용하기 위해서는 GPGSOPS 가 필요합니다.
GPG
GPG{GNU Privacy Guard} 는 대칭 및 비대칭 암호화를 지원하며, 파일 암호화에 사용됩니다.
암호화 및 복호화: 데이터를 암호화하고 복호화 합니다.
전자 서명: 데이터에 디지털 서명을 추가하여 데이터의 무결성과 출처를 확인합니다.
키 관리: 공개 키와 비밀 키를 생성하고, 관리할 수 있습니다.
GPG 설치는 아래와 같습니다.
# Mac brew install gnupg # Amazon Linux 2023 sudo yum install gnupg2 -y --allowerasing
Bash
복사
키 생성:
gpg --full-generate-key --rfc4880
Bash
복사
키 목록 확인:
gpg --list-keys
Bash
복사
생성된 키 내보내기:
# 생성된 GPG 키를 내보내기 gpg --armor --export-secret-keys <your-key-id> > key.asc
YAML
복사
키 생성을 완료하면 Key-ID 를 획득할 수 있는데 이 Key-ID 를 잘 기록해둡니다.
SOPS
SOPS{Secrets OPeratioS} 는 Mozilla 에서 개발한 도구로서 JSON, YAML, ENV, INI 파일을 암호화 및 복호화할 때 사용합니다.
파일 암호화 및 복호화: YAML, JSON, INI, ENV 파일의 특정 필드를 암호화하고 복호화 합니다.
다중 백엔드 지원: AWS KMS, GCP KMS, Azure Key Vault, PGP 를 지원합니다.
자동 복호화: 설정 파일이 자동으로 복호화되어 애플리케이션에서 사용할 수 있습니다.
SOPS 설치는 아래와 같습니다.
# Mac brew install sops # Amazon Linux 2023 sudo yum install sops
Bash
복사
.sops.yaml 파일 생성:
.sops.yaml 파일을 생성하고, 위에서 생성했던 Key-ID 값을 넣어줘야 합니다.
creation_rules: - pgp: xxxxx
Bash
복사
보호할 값을 파일로 생성:
아래와 같이 arn 값을 평문으로 노출하지 않고 보호할 것이기 때문에 보호할 값을 넣고 파일로 생성합니다.
serviceAccount: annotations: eks.amazonaws.com/role-arn: "arn:aws:iam::123456:role/foo-role"
Bash
복사
암호화:
이제 값을 암호화해야 합니다. 위에서 만든 파일에 대해서 암호화를 진행 하겠습니다.
sops -e -i --pgp {key-id} secrets.yaml
Bash
복사
Secret 생성:
로컬 맥북에서 작업을 했다면 생성한 키로 Kubernetes Secret 을 생성해줘야 합니다.
만약 Bastion EC2 에서 kubernetes 접근이 가능하다면 Secret 생성은 Bastion EC2 에서 진행해줍니다.
kubectl -n argo create secret generic helm-secrets-private-keys --from-file=key.asc=key.asc
YAML
복사
이제 암호화가 완료 되었습니다.
복호화가 잘 되고, 값을 잘 적용 시키는지 확인을 해봐야 하는데 아래 helm cli 로 할 수 있습니다.
helm secrets template test {helm dir} -f {helm dir}/values.yaml -f {helm dir}/senstive.yaml
Bash
복사
여기까지 helm 에서 복호화된 값을 잘 적용시키는 것 까지 확인해 볼 수 있습니다.
하지만, 실제 운영 환경에서 배포를 할 때는 cli 로 배포를 하는 경우는 없습니다.
Argo 로 애플리케이션에 대한 배포를 하게 되는데 Argo 자체는 암호화 및 복호화에 대한 기능이 없습니다.
즉, Argo 로 안전하게 배포를 하기 위해서 연동을 시켜줘야 합니다.
아래는 Argo 와의 연동 방법 입니다.

Argo 연동을 위한 설정

Argo를 Helm Secret과 연동하는 방법에 대해 설명합니다.
위에서 마지막에 설명했던 것처럼 Argo 에서 Helm Secret 을 배포하려면 일반적인 배포 방식으로는 불가능 합니다.
우선 GPG 의 복호화를 위해서 argo-repo-server 를 커스터마이징해야 합니다.
argo-repo-server 커스터마이징
argo-repo-server 를 커스터마이징 하는 방법에는 두 가지가 있습니다.
1.
Dockerfile 사용자정의 이미지 생성
2.
Init Container 실행
여기서는 2번 방법에 대해서 설명 하겠습니다.
Init Container 를 실행하기 위해서는 Argo 의 Values 를 수정해줘야 합니다.
argo-repo-server 의 설정 값:
repoServer: env: - name: HELM_PLUGINS value: /custom-tools/helm-plugins/ - name: HELM_SECRETS_CURL_PATH value: /custom-tools/curl - name: HELM_SECRETS_SOPS_PATH value: /custom-tools/sops - name: HELM_SECRETS_VALS_PATH value: /custom-tools/vals - name: HELM_SECRETS_KUBECTL_PATH value: /custom-tools/kubectl - name: HELM_SECRETS_BACKEND value: sops - name: HELM_SECRETS_VALUES_ALLOW_SYMLINKS value: "false" - name: HELM_SECRETS_VALUES_ALLOW_ABSOLUTE_PATH value: "true" - name: HELM_SECRETS_VALUES_ALLOW_PATH_TRAVERSAL value: "false" - name: HELM_SECRETS_WRAPPER_ENABLED value: "true" - name: HELM_SECRETS_DECRYPT_SECRETS_IN_TMP_DIR value: "true" - name: HELM_SECRETS_HELM_PATH value: /usr/local/bin/helm - name: HELM_SECRETS_LOAD_GPG_KEYS value: /helm-secrets-private-keys/key.asc volumes: - name: custom-tools emptyDir: {} - name: helm-secrets-private-keys secret: secretName: helm-secrets-private-keys volumeMounts: - mountPath: /custom-tools name: custom-tools - mountPath: /usr/local/sbin/helm subPath: helm name: custom-tools - mountPath: /helm-secrets-private-keys/ name: helm-secrets-private-keys initContainers: - name: download-tools image: alpine:latest imagePullPolicy: IfNotPresent command: [sh, -ec] env: - name: HELM_SECRETS_VERSION value: "4.6.0" - name: KUBECTL_VERSION value: "1.30.1" - name: VALS_VERSION value: "0.37.1" - name: SOPS_VERSION value: "3.8.1" args: - | mkdir -p /custom-tools/helm-plugins wget -qO- https://github.com/jkroepke/helm-secrets/releases/download/v${HELM_SECRETS_VERSION}/helm-secrets.tar.gz | tar -C /custom-tools/helm-plugins -xzf-; wget -qO /custom-tools/curl https://github.com/moparisthebest/static-curl/releases/latest/download/curl-amd64 wget -qO /custom-tools/sops https://github.com/getsops/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux.amd64 wget -qO /custom-tools/kubectl https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl wget -qO- https://github.com/helmfile/vals/releases/download/v${VALS_VERSION}/vals_${VALS_VERSION}_linux_amd64.tar.gz | tar -xzf- -C /custom-tools/ vals; cp /custom-tools/helm-plugins/helm-secrets/scripts/wrapper/helm.sh /custom-tools/helm chmod +x /custom-tools/* volumeMounts: - mountPath: /custom-tools name: custom-tools
YAML
복사
ConfigMap 설정:
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cm namespace: argo data: helm.valuesFileSchemes: >- secrets+gpg-import, secrets+gpg-import-kubernetes, secrets+age-import, secrets+age-import-kubernetes, secrets,secrets+literal, https
YAML
복사
위 설정값을 포함한채로 Argo 를 재배포 해줍니다.

Helm

위에까지 완료되었다면, Helm Chart 에 두 개의 Values 파일이 존재하게 해야 합니다.
values.yaml ⇒ 기존 파일
secrets.yaml ⇒ 암호화한 파일
values.yaml
기존 파일에는 암호화하려는 값을 아래처럼 수정해줍니다.
serviceAccount: annotations: eks.amazonaws.com/role-arn: ""
YAML
복사
secrets.yaml
암호화한 파일에는 아래처럼 암호화되고, 이 파일은 기존 파일과 같은 위치에 넣어 줍니다.
serviceAccount: annotations: eks.amazonaws.com/role-arn: ENC[AES256_GCM,data:+zxxxxx==,type:str] sops: kms: [] gcp_kms: [] azure_kv: [] hc_vault: [] age: [] lastmodified: "2024-06-16T06:50:04Z" mac: ENC[AES256_GCM,data:xxxxx,type:str] pgp: - created_at: "2024-06-16T06:50:04Z" enc: |- -----BEGIN PGP MESSAGE----- xxxxxxxxxxxxxx//Qym6pkhh8Fg60ZEzTi7kbjwgeMT98qusyHRBr3nX0eJqxxx DWEwc82kWikjEDJ6aYGPJmcZh3Vjr4ftZrEJy+uRcEyifR6Ggh9/EwHLNc1o2IeF 7YR9zCABmSTtcg1o24vmXSTxxxxxxxxxxxxxxxxxxxxxxxxxxEH467IjBPhiIztO KbQwSNUDC1gj/HO00oNm3Bpl6iEKC30LZiIcVQ/vwBJT9zYc7HJ7Nh/M8ox7dYQB jroGq3Srse9xn2Oqa2TGcVIGBnHwNvWP4LXOkWHPoz56YFdU9emuay5WJJDUrtKL a392bo4MmQwW6xKTjdj8Rt2UZyy7kgOcw/e165rhaESkIlL0rn9yEXL7AMldKyd7 AJExYutEMaZycA6VV9DQTQNGr57i7g2DK8FTrtHkMRHXvNymrmAEidTmOcQ1fKkU sFl1koquLB8BGkE6994q7+9lxQGWf7cowLTSj9I9PT/BO5vekeC0T3il/D4su9KS GftaTFUHbDW5HXKHfatDg3lrRBOJ/ryoIy5I2AhMHJWhMcspb4MlYaCZbScukuv0 0rqIqKbg6vtaXCUc2uB+74LH6zeHq5AWJz323nqfrrQls89nb9tIz02yU7WZ4q3/ FrJ7I9w9Kp+RVP0dMyLQAFrUsZCCzROmkMI9djGPNouofMEI9uQfiNdykjrMPFPU ZgEJAhDbO/sE7PFyXPohisIbXXDObc90loDoM3iL15MxM67XLSBeRBkW9KYnRGK8 92nCxVD67Ex3+6kItwFiiO+xE0yUxxxxxxxxxxxxxx8txxxxxxxxxxxxxxxxxxxx htY+HvELog== =LRME -----END PGP MESSAGE----- fp: xxxxxxxxxx unencrypted_suffix: _unencrypted version: 3.8.1
YAML
복사

배포

이제 배포가 잘 되는지 확인해봅니다.
암호화 & 복호화가 잘 된다면 배포도 문제없이 잘 됩니다.
애플리케이션
Argo 의 Application 을 이용하여 배포를 해야하며, 코드는 아래와 같습니다.
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: seoul namespace: foobar spec: project: default source: repoURL: '{Repository url}' targetRevision: {브랜치} path: {경로} helm: valueFiles: - values.yaml - secrets://sensitive.yaml destination: server: 'https://kubernetes.default.svc' namespace: seoul syncPolicy: syncOptions: - CreateNamespace=false
YAML
복사