ArgoCD Vault Plugin (AVP) + Helm 導入手順 (kind + ローカル環境)


## はじめに

会社でHelmのArgoCDにVault Pluginを導入することになったため、手順をメモするためにこの記事を書きました。

ArgoCD Vault Plugin (AVP) を使うと、KubernetesのSecretリソースを直接Gitリポジトリに保存することなく、Vaultに格納された秘匿情報を安全にArgoCDで利用できます。これにより、機密情報をセキュアに管理しながらGitOpsを実現できます。

この記事では、ローカル環境（kind）でKubernetesクラスタを構築し、ArgoCDとVaultをHelmでデプロイして、AVPを設定する手順を紹介します。

**読者対象**

*   ArgoCD, Vault, Helmの基本的な使い方を理解している方
*   Kubernetes環境で秘匿情報の管理に課題を感じている方
*   GitOpsに興味があり、セキュアな環境構築を試してみたい方

**この記事でやること**

*   kindによるローカルKubernetesクラスタの作成
*   Helmを使ったArgoCDとVaultのデプロイ
*   ArgoCD Vault Plugin (AVP) の設定と動作確認

**この記事でやらないこと**

*   本番環境への適用
*   ArgoCD, Vault, AVPの詳細な設定（今回は基本的な設定のみ）


> **Note**
> *   将来的にバージョンアップで手順が変わる可能性があるため、ご注意ください。

## 前提条件

*   ローカル環境に以下がインストール済みであること
    *   kind
    *   kubectl
    *   helm
    *   vault cli
*   基本的なKubernetes, ArgoCD, Vault, Helmの知識があること
*   Docker Desktopなどのコンテナ実行環境が整っていること

## 環境構築

### 1. kindによるKubernetesクラスタの作成

```bash
kind create cluster --name argocd-vault-test
```

### 2. Namespaceの作成
```bash
kubectl create namespace argocd
kubectl create namespace vault
```

### 3. ArgoCDのインストール (Helm)

```bash
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd -n argocd -f values.yaml
```

`values.yaml` (ArgoCD Vault Pluginの設定を含む):

```yaml
repoServer:
  envFrom:
   - secretRef:
       name: argocd-vault-plugin-credentials
  initContainers:
  - name: download-tools
    image: alpine:3
    command: [sh, -c]
    # Don't forget to update this to whatever the stable release version is
    # Note the lack of the `v` prefix unlike the git tag
    env:
      - name: AVP_VERSION
        value: "1.18.1"
    args:
      - >-
        wget -O argocd-vault-plugin
        https://github.com/argoproj-labs/argocd-vault-plugin/releases/download/v${AVP_VERSION}/argocd-vault-plugin_${AVP_VERSION}_linux_amd64 &&
        chmod +x argocd-vault-plugin &&
        mv argocd-vault-plugin /custom-tools/
    volumeMounts:
      - mountPath: /custom-tools
        name: custom-tools

  volumes:
    - name: custom-tools
      emptyDir: {}

  volumeMounts:
    - name: custom-tools
      mountPath: /usr/local/bin/argocd-vault-plugin
      subPath: argocd-vault-plugin
  ## end argo vault plugin CMP

configs:
  cm:
    create: true
    # argo vault plugin
    configManagementPlugins: |
      - name: argocd-vault-plugin
        generate:
          command: ["argocd-vault-plugin"]
          args: ["generate", "./"]
      - name: argocd-vault-plugin-helm
        generate:
          command: ["sh", "-c"]
          args: ['helm template "$ARGOCD_APP_NAME" -n "$ARGOCD_APP_NAMESPACE" . | argocd-vault-plugin generate -']
      - name: argocd-vault-plugin-helm-with-args
        generate:
          command: ["sh", -c"]
          args: ['helm template "$ARGOCD_APP_NAME" -n "$ARGOCD_APP_NAMESPACE" ${helm_args} . | argocd-vault-plugin generate -']
      # This lets you pass a values file as a string as described here:
      # https://argocd-vault-plugin.readthedocs.io/en/stable/usage/#with-helm
      - name: argocd-vault-plugin-helm-with-values
        generate:
          command: ["bash", "-c"]
          args: ['helm template "$ARGOCD_APP_NAME" -n "$ARGOCD_APP_NAMESPACE" -f <(echo "$ARGOCD_ENV_HELM_VALUES") . | argocd-vault-plugin generate -']
      - name: argocd-vault-plugin-kustomize
        generate:
          command: ["sh", "-c"]
          args: ["kustomize build . | argocd-vault-plugin generate -"]
    # end argo vault plugin
```

*   `repoServer.initContainers`: ArgoCD Vault Pluginをダウンロードして `/custom-tools` に配置します。
*   `repoServer.volumes` と `repoServer.volumeMounts`:  `/custom-tools` を `/usr/local/bin/argocd-vault-plugin` にマウントして、ArgoCDからプラグインを実行できるようにします。
*   `configs.cm.configManagementPlugins`: ArgoCD Vault PluginをArgoCDのプラグインとして登録します。
    *   `argocd-vault-plugin`:  標準的な使い方
    *   `argocd-vault-plugin-helm`: Helmと連携する場合
    *   `argocd-vault-plugin-helm-with-args`: 任意のHelm引数を渡せる(セキュリティに注意)
    *    `argocd-vault-plugin-helm-with-values`: valuesを文字列で渡す
    *   `argocd-vault-plugin-kustomize`: Kustomizeと連携する場合
*   `helm template "$ARGOCD_APP_NAME" -n "$ARGOCD_APP_NAMESPACE" . | argocd-vault-plugin generate -`
    *   Helmでテンプレートをレンダリングし、その結果を標準出力に出力します。
    *   argocd-vault-plugin は標準入力を受け取り、generateコマンドを実行します。
    *   最後のハイフン(-)は標準入力を意味しています。

### 4. Vaultのインストール (Helm)

```bash
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm install vault hashicorp/vault -n vault -f vault-values.yaml
```
`vault-values.yaml` (例): 開発モードで起動し、UIを有効にする

```yaml
global:
  enabled: true
  tlsDisable: true

server:
  dev:
    enabled: true
    devRootToken: "myroot" # 開発用のrootトークン。本番環境では使用しないこと！

ui:
  enabled: true
```

Vaultの初期設定:

```bash
# ポートフォワード
kubectl port-forward -n vault svc/vault 8200:8200 &

# Vault UIにアクセス (http://localhost:8200)
# Method: Token
# Token: myroot (vault-values.yamlで設定したrootトークン)
```

> **Warning:**
>
> *   `vault-values.yaml` の `devRootToken` は、あくまで**開発用の設定**です。本番環境では、Vaultのドキュメントに従って、適切に初期化とunsealを行ってください。
> *   今回は、`tlsDisable: true` で起動していますが、セキュアな環境を構築したい場合は、TLSを有効にしてください。

### 5.  Vault側の設定

1.  **AppRole認証の有効化**

    ```bash
    vault auth enable approle
    ```

2.  **ポリシーの作成**

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

3.  **Roleの作成**

    ```bash
    vault write auth/approle/role/my-app \
        secret_id_ttl=10m \
        token_ttl=20m \
        token_max_ttl=30m \
        policies=my-app-policy
    ```

4.  **Role IDとSecret IDの取得**

    ```bash
    # Role ID
    vault read auth/approle/role/my-app/role-id

    # Secret ID
    vault write -f auth/approle/role/my-app/secret-id
    ```
    取得した`role_id`と`secret_id`の値をメモすること

### 6. ArgoCD側の設定

1.  **`argocd-vault-plugin-credentials` Secretの作成**
    次のコマンドで`argocd-vault-plugin-credentials.yaml`を作成します。

    ```yaml
    kind: Secret
    apiVersion: v1
    metadata:
      name: argocd-vault-plugin-credentials
    type: Opaque
    stringData:
      AVP_TYPE: "vault"
      VAULT_ADDR: "http://vault.vault.svc.cluster.local:8200" # Vaultのアドレス
      AVP_AUTH_TYPE: "approle"
      AVP_ROLE_ID: "<取得したRole ID>"
      AVP_SECRET_ID: "<取得したSecret ID>"
    ```

    *   `VAULT_ADDR`: Vaultのサービスアドレス。
    *   `AVP_ROLE_ID` と `AVP_SECRET_ID`: Vaultで取得した値を設定する。
    *    サポートされている認証タイプ
        *   approle
        *   token
        *   github
        *   kubernetes
        *   userpass

    ```bash
    kubectl apply -f argocd-vault-plugin-credentials.yaml -n argocd
    ```

## 動作確認

### サンプルアプリケーションのデプロイ

1.  **Helmチャートの作成**

    ```bash
    mkdir my-app
    cd my-app
    helm create my-app
    ```
    `my-app/templates/configmap.yaml`を作成

    ```yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-app-config
    data:
      my-secret: <path:secret/data/my-app/config#my-secret>
    ```
     `my-app/values.yaml`を作成
    ```yaml
        # Default values for my-app.
        # This is a YAML-formatted file.
        # Declare variables to be passed into your templates.

        replicaCount: 1

        image:
          repository: nginx
          pullPolicy: IfNotPresent
          # Overrides the image tag whose default is the chart appVersion.
          tag: ""
    ```

2.  **ArgoCDアプリケーションの作成**

    `my-app-argocd.yaml`を作成:

    ```yaml
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: my-app
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: '<GitリポジトリのURL>' # 自分のリポジトリに置き換える
        path: my-app
        targetRevision: HEAD
        helm:
          valueFiles:
            - values.yaml
      destination:
        server: 'https://kubernetes.default.svc'
        namespace: default
      syncPolicy:
        automated: {}
    ```
    *   `repoURL`:  Helmチャートを配置したGitリポジトリのURLを指定する。
    *   `path`: リポジトリ内のHelmチャートのパスを指定する。

    ```bash
    kubectl apply -f my-app-argocd.yaml -n argocd
    ```

3.  **ArgoCDでの同期と確認**
    ArgoCDのUIで`my-app`アプリケーションを同期します。
    ConfigMapの`my-secret`の値がVaultから取得した`s3cr3t`になっていれば成功です。
    ```bash
    kubectl get configmap my-app-config -o yaml
    ```

## トラブルシューティング

*   **ArgoCD Vault PluginがVaultに接続できない:**
    *   `argocd-vault-plugin-credentials` Secretの内容が正しいか確認する。
    *   Vaultのサービスアドレスが正しいか確認する。
    *   Vaultの認証情報（Role ID, Secret ID）が正しいか確認する。
    *   Vaultのポリシー設定が適切か確認する。
*   **ArgoCDでアプリケーションが同期されない:**
    *   ArgoCDアプリケーションの設定（`repoURL`, `path`, `targetRevision`）が正しいか確認する。
    *   GitリポジトリにHelmチャートが正しく配置されているか確認する。
*   **ConfigMapに値が注入されない:**
    *   Helmチャート内のプレースホルダーの記述が正しいか確認する (`<path:secret/data/my-app/config#my-secret>`)。

## まとめ

この記事では、ローカル環境でArgoCD Vault Plugin (AVP) を使って、Vaultと連携したセキュアなGitOps環境を構築する手順を紹介しました。AVPを使うことで、機密情報を安全に管理し、ArgoCDによるアプリケーションのデプロイを自動化できます。
ArgoCD Vault PluginはGitOps環境において非常に役に立つツールです。

## 参考資料

*   ArgoCD Vault Pluginインストール参考
       [https://www.cloudadmins.org/argo-vault-plugin-avp/](https://www.cloudadmins.org/argo-vault-plugin-avp/)
       [https://argocd-vault-plugin.readthedocs.io/en/stable/installation/](https://argocd-vault-plugin.readthedocs.io/en/stable/installation/)
*   Vaultドキュメント
       [https://developer.hashicorp.com/vault/docs/auth/approle](https://developer.hashicorp.com/vault/docs/auth/approle)
*   Vaultコマンド記事
       [https://qiita.com/saitamanokusa/items/24888fdcabaa7b153be5#approle](https://qiita.com/saitamanokusa/items/24888fdcabaa7b153be5#approle)
*    [Helm] values.yamlを動的に生成して外部コマンドに渡す
       [https://stlog.net/posts/2021/11/helm-dynamic-values-with-pipe/](https://stlog.net/posts/2021/11/helm-dynamic-values-with-pipe/)