[GitOps]ArgoCD에 Vault 적용하기

Hoone·2021년 6월 5일
4
post-thumbnail

개요

GitOps 환경을 구성하기 위해 kubernetes 설정 파일을 git 저장소에 올려서 ArgoCD와 연동을 했었습니다.
하지만 configmap이나 secret 을 git 저장소에 올리기에는 보안상 문제가 있다고 생각했습니다.
물론 private한 저장소를 사용하는 방법을 사용하면 외부에 공유가 되지는 않지만
그래도 소스코드에 DB 패스워드 같은 정보가 들어있는게 부담이 되었습니다.

ArgoCD에서도 비밀관리에 대한 다양한 방법을 여기에 제시해 놓았습니다.

이 중 IBM에서 만든 HashiCorp Vault를 이용한 argocd-vault-plugin 방식이 마음에 들어 적용해 보았습니다.

Vault

VaultHashiCorp에 의해서 개발된 크로스플랫폼 패스워드 및 인증 관리 시스템이다. 공개되면 안되는 비밀번호, API 키, 토큰 등을 UI, CLI, HTTP API를 사용하여 저장하고 관리한다.

설치

vault 설치를 위한 다양한 방법이 있는데 전 Helm을 이용해 kubernetes에 설치하였습니다.

$ git clone https://github.com/hashicorp/vault-guides.git
$ cd vault-guides/operations/provision-vault/kubernetes/minikube/getting-started

Consul 설치

$ helm repo add hashicorp https://helm.releases.hashicorp.com
$ helm repo update
$ helm install consul hashicorp/consul --values helm-consul-values.yml

서버 및 클라이언트 Pod이 Running일 때까지 기다립니다.

Vault 설치

$ helm install vault hashicorp/vault --values helm-vault-values.yml

Vault 초기화 및 봉인해제

봉인해제 키를 가져옵니다.

$ kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
$ VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")

vault-0, vault-1, vault-2 Pod에서 봉인해제 합니다.

$ kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
$ kubectl exec vault-1 -- vault operator unseal $VAULT_UNSEAL_KEY
$ kubectl exec vault-2 -- vault operator unseal $VAULT_UNSEAL_KEY

Vault 비밀 설정

root token을 가져옵니다.

$ cat cluster-keys.json | jq -r ".root_token"

vault-0 에 접속

$ kubectl exec --stdin=true --tty=true vault-0 -- /bin/sh
/ $

Login 합니다.

/ $ vault login

kv-v2 비밀을 secret 경로에 활성화합니다.

/ $ vault secrets enable -path=secret kv-v2 

secret에 비밀을 생성합니다.

/ $ vault kv put secret/example-app/secret \
		db-user="example-app" \
		db-password="password" \
		db-root-password="root-password"

Kubernetes 인증 구성

kubernetes의 서비스 계정 토큰으로 vault 비밀에 접근하기 위해서 kubernetes 인증을 활성화 합니다.

/ $ vault auth enable kubernetes
/ $ vault write auth/kubernetes/config \
        token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
        kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
 	kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

example-app 비밀에 대한 read 권한을 생성합니다.

/ $ vault policy write example-app - <<EOF
path "secret/data/example-app/*" {
  capabilities = ["read"]
}
EOF

ArgoCD의 default 서비스 계정과 vault의 example-app 정책을 연결하는 역할을 만듭니다.
ArgoCD의 서비스 계정은 kubectl get sa -n argocd 명령으로 확인할 수 있습니다.

vault write auth/kubernetes/role/argocd \
    bound_service_account_names=default \
    bound_service_account_namespaces=argocd \
    policies=example-app \
    ttl=24h

policies는 위에서 생성한 example-app policy를 추가합니다.

argocd-vault-plugin

argocd-vault-plugin는 kubernetes 설정파일에서 <placeholder> 형식을 vault 값으로 변환해주는 역할을 합니다. <>안의 값은 vault의 실제 key입니다.
argocd-repo-server에 argocd-vault-plugin을 설치하고 vault 인증정보를 설정하면
ArgoCD에서 동기화할 때 vault 값을 kubernetes 설정 정보에 반영해서 적용합니다.

자세한 사용법은 여기를 참고하세요.

Vault 주소 확인

$ kubectl get svc vault
NAME    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
vault   ClusterIP   10.110.116.153   <none>        8200/TCP,8201/TCP   5d2h

vault 주소는 http://CLUSTER-IP:8200 입니다.
http://10.110.116.153:8200

Kubernetes Secret

argocd-repo-server에서 vault에 접근하기 위한 인증정보를 생성합니다.
VAULT_ADDR는 위에서 확인한 vault 주소입니다
AVP_K8S_ROLEKubernetes 인증 구성에서 만든 역할 이름 입니다. argocd

argocd-vault-plugin-credentials.yaml

kind: Secret
apiVersion: v1
metadata:
  name: argocd-vault-plugin-credentials
  namespace: argocd
type: Opaque
stringData:
  VAULT_ADDR: http://10.110.116.153:8200
  AVP_TYPE: vault
  AVP_AUTH_TYPE: k8s
  AVP_K8S_ROLE: argocd

secret를 argocd 네임스페이스에 적용합니다.

$ kubectl apply -n argocd -f argocd-vault-plugin-credentials.yaml

argocd-repo-server 설정 편집

$ kubectl edit deployment argocd-repo-server -n argocd -o yaml

아래 내용 추가 후 저장

# automountServiceAccountToken 추가
automountServiceAccountToken: true

  # custom-tools volume 추가
  volumes:
    - name: custom-tools
      emptyDir: {}

  # initContainer 추가
  initContainers:
    - name: download-tools
      image: alpine:3.8
      command: [sh, -c]
      args:
        - wget -O argocd-vault-plugin
        https://github.com/IBM/argocd-vault-plugin/releases/download/v1.0.0/argocd-vault-plugin_1.0.0_linux_amd64

        chmod +x argocd-vault-plugin && mv argocd-vault-plugin /custom-tools/
      volumeMounts:
        - mountPath: /custom-tools
          name: custom-tools

  # custom-tools mount 추가, env 추가
  containers:
    - name: argocd-repo-server
      volumeMounts:
        - name: custom-tools
          mountPath: /usr/local/bin/argocd-vault-plugin
          subPath: argocd-vault-plugin
      envFrom:
        - secretRef:
            name: argocd-vault-plugin-credentials

argocd-cm data 추가

$ kubectl edit configmap argocd-cm -n argocd -o yaml

아래 내용 추가 후 저장

data:
  configManagementPlugins: |
    - name: argocd-vault-plugin
      generate:
        command: ["argocd-vault-plugin"]
        args: ["generate", "./"]
    - name: argocd-vault-plugin-helm
      generate:
        command: ["sh", "-c"]
        args: ["helm template . > all.yaml && argocd-vault-plugin generate all.yaml"]
    - name: argocd-vault-plugin-kustomize
      generate:
        command: ["sh", "-c"]
        args: ["kustomize build . > all.yaml && argocd-vault-plugin generate all.yaml"]

ArgoCD plugin 연결

ArgoCD에서 앱 등록화면에서 Directory 를 클릭해서 Plugin을 선택합니다.

kustomize로 구성되어있어서 argocd-vault-plugin-kustomize를 선택하고 저장합니다.

애플리케이션 secret 수정

overlays/dev/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: example-app-secret
  labels:
    app: example-app
  annotations:
    avp.kubernetes.io/path: "secret/data/example-app/secret"
type: Opaque
data:
  DB_USERNAME: <db-user | base64encode>
  DB_PASSWORD: <db-password | base64encode>
  DB_ROOT_PASSWORD: <db-root-password | base64encode>

avp.kubernetes.io/path는 vault 비밀이 저장된 path를 입력한다. Vault 비밀 설정
secretexample-app사이에 data를 넣어야함.

Kubernetes Secret의 data는 base64로 인코딩된 값이어야하므로 | base64encode 키워드를 붙혀준다.

kustomization.yaml에 비밀 추가

overlays/dev/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: ghcr.io/wlgns5376/example-app
  newTag: e70be61b
patchesStrategicMerge:
- secret.yaml
resources:
- ../../base

이제 수정한 파일을 git에 push하고 ArgoCD에서 동기화가 잘되는지 확인하면 됩니다.

위에 코드들은 여기에 올려져 있습니다.

마치며

아주 Simple하게나마 GitOps라는걸 살짝 맛만 보았는데도 다양한 도구를 사용했네요.
GitHub + Kubernetes + Kustomize + ArgoCD + Vault

kubernetes에 배포하는데 git 저장소에 있는 파일을 수정하면 자동으로 배포가 된다는것이 매력적이었고 대부분이 git에서 돌아가니 개발자도 접근하기도 쉬웠던 것 같습니다.

기회가 된다면 실제 서비스에 적용해봐야겠습니다.

References:

profile
도움이 되고픈 개발자

0개의 댓글