Skip to content

External Secrets Operatorの導入 Azure編

本章では、Qmonus Value Streamの応用として、Official Cloud Native AdapterであるExternal Secrets Operator AdapterとAKS Cluster Secret Store Adapterを使用して、AzureのKey Vault(キーコンテナ)の秘密情報をAKSのSecretリソースへ自動連携する手順を解説します。

External Secrets Operatorは、秘密情報を管理するプロバイダ(GCP Secret Manager, Azure Key Vault, AWS Secrets Managerなど)と連携し、Kubernetes環境のSecretリソースと同期できます。 External Secrets Operatorが提供する主なCustom Resourceとして、Cluster Secret StoreリソースとExternal Secretリソースが存在します。Cluster Secret Storeはクラスタ単位でデプロイされ、外部プロバイダへ認証し、External SecretはCluster Secret Storeを指定して外部プロバイダの秘密情報を取得し、Secretリソースを生成します。

公式イメージ: External Secrets Operatorの導入 Azure編

Qmonus Value Streamを使用したExternal Secrets Operator導入の公式の手順として、Official Cloud Native Adapterを使用してCluster Secret StoreをAKSへデプロイし、Azure Key VaultがAKSのSecretリソースへ同期できる環境を提供します。
以下のプライベートリポジトリが作成されていることを前提とします。

  • 持ち込みのGitリポジトリ
    • GitHub、GitLabなどのインターネットからアクセス可能なGitリポジトリをご用意ください。
    • 本チュートリアルではGitHubを使って説明しますが、適宜ご利用されているサービスに読み替えてください。
    • GitHubリポジトリへの認証は Personal Access Token (GitLabの場合は Personal access tokens)を使用することを前提とします。

以降のステップでは主に下記の作業を通じて、External SecretリソースにAzure Key Vaultの秘密情報が連携されていることを確認します。

  • External Secrets Operator AdapterとAKS Cluster Secret Store AdapterをQmonus Values Streamでデプロイする
  • Azure Key Vault内のキーコンテナへ機密情報を登録し、サンプルExternal SecretリソースをApplyして自動作成されるSecretリソースに秘密情報が連携されていることを確認する

0-1. 準備:External Secrets OperatorのCustom Resource Definition の適用

External Secrets OperatorのCustom Resource Definitionから、v0.5.0以上の任意のバージョンを指定してAKSにApplyしてください。

bash
# v0.5.0以上の任意のバージョンをcloneする
git clone -b ${v0.5.0_or_more} https://github.com/external-secrets/external-secrets.git

# kubectl の現在のコンテキストを確認する
kubectl config current-context
(External Secrets Operatorをデプロイするクラスタ名)

# Custom Resource DefinitionをApplyする
kubectl apply -f external-secrets/deploy/crds/bundle.yaml

0-2. 準備:Workload Identityの構成

Azure Workload Identityを使用することで、Key Vaultへのアクセス権限を持つMicrosoft Entra External ID アプリケーションの権限をAKSのService Accountへ付与することが可能になります。これにより、ワークロードがAzureリソースにアクセス出来るようになります。

コマンド例を以下に記しますので、それらを参考にAzure Workload Identityを設定してください。ただし、詳細はAzureのドキュメントを参照してください。

  1. 事前準備として下記のツールのインストールを行ってください。また、インストールしてある場合でも最新版へアップデートを行ってください。

    ToolGuide
    Azure CLI (azcli)install
    aks-previewinstall
    Entra ID Workload CLI (azwi)install
  2. AKSクラスタのEnableOIDCIssuerPreview 機能 の有効化とOIDC issuer URLを取得します。

    • azコマンドを用いてEnableOIDCIssuerPreview機能を有効化する
      bash
      # azコマンド例
      
      # 初めてazコマンドを実施する場合は下記コマンドを実施ください
      # tenant_idはonmicrosoft.comで終わるAzureドメイン名です
      az login --tenant ${tenant_id}
      
      # EnableOIDCIssuerPreview 機能を登録する
      az feature register --name EnableOIDCIssuerPreview --namespace Microsoft.ContainerService
      
       # StateがRegisteredになることをaz feature listコマンドを利用して確認します(登録までに時間がかかる場合があります)
      az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/EnableOIDCIssuerPreview')].{Name:name,State:properties.state}"
      
      # StateがRegisteredとなったらMicrosoft.ContainerService リソースプロバイダの登録を更新します
      az provider register --namespace Microsoft.ContainerService
    • OIDC issuer URLを取得する 下記コマンドを実行しOIDC issuer URLを取得します。${k8sClusterName}はAKSクラスタ名、${myResourceGroup}はAKSクラスタが所属するリソースグループに読み替えてください
      bash
      # azコマンド例
      # AKSクラスタへ OIDC issuer を有効化
      az aks update -n ${k8sClusterName} -g ${myResourceGroup} --enable-oidc-issuer
      
      # OIDC issuer URLを表示
      az aks show -n ${k8sClusterName} -g ${myResourceGroup} --query "oidcIssuerProfile.issuerUrl" -otsv
      出力されたhttpsから始まるURLは今後の手順で使用するため控えておいてください。
  3. Microsoft Entra External ID のアプリケーション(以下、AADアプリケーション)を作成し、Azure Key Vaultへの権限を付与します。

    • Azureポータルからキーコンテナーの画面へアクセスし、キーコンテナーを作成します。 詳細はAzure Key Vaultのクイックスタートより、ご確認ください。
    • AADアプリケーションを作成します。${applicationName}は、登録するアプリケーションの名前です。
      bash
      azwi serviceaccount create phase app --aad-application-name ${applicationName}
      上記コマンドを実行すると下記のように出力されます
      bash
      INFO[0000] No subscription provided, using selected subscription from Azure CLI: REDACTED
      INFO[0005] [aad-application] created an AAD application  clientID=REDACTED name=${applicationName} objectID=REDACTED
      WARN[0005] --service-principal-name not specified, falling back to AAD application name
      INFO[0005] [aad-application] created service principal   clientID=REDACTED name=${applicationName} objectID=REDACTED
    • 作成したAADアプリケーションへKey Vaultへのアクセス権限を付与します。${azureKeyContainerName}は作成したキーコンテナ名となります。
      bash
      # AADアプリケーションのクライアントIDを取得します
      export applicationCliendId="$(az ad sp list --display-name ${applicationName} --query '[0].appId' -otsv)"
      
      # AADアプリケーションへKey Vaultへのアクセス権限を付与します
      az keyvault set-policy --name ${azureKeyContainerName} --secret-permissions get --spn ${applicationCliendId}
  4. Kubernetes Service Account(以下、KSA)を作成し、Entra ID Workload Identityを使用してAzure Key Vaultへのアクセス権限を付与します。

    • Namespaceを作成し、そのNamespace配下へKSAを作成します。 ${ksaName}はKSA名、${ksaNamespace}はKSAが属するnamespaceとしてください。 default値を使用する場合は、それぞれ"azure-key-vault", "qmonus-system"として指定してください。
      bash
      # Namespaceを作成する
      kubectl create ns ${ksaNamespace}
      
      # KSAを作成する
      azwi serviceaccount create phase sa --aad-application-name ${applicationName} --service-account-namespace ${ksaNamespace} --service-account-name ${ksaName}
    • 作成したKSAとKey Vaultへの権限を持つAADアプリケーション間で認証する 下記コマンドを実行することで認証します。ここで${oidcIssuerUrl}は手順0-2の2.で取得したOIDC issuer URLを記載してください。
      bash
      azwi serviceaccount create phase federated-identity --aad-application-name ${applicationName} --service-account-name ${ksaName} --service-account-namespace ${ksaNamespace} --service-account-issuer-url ${oidcIssuerUrl}

    ここで使用したパラメータのうちadapterで使用するパラメータの詳細は以下の通りです。特に変更する必要がなければ、default値のあるものはdefault値を使用することを推奨します。また、このパラメータは手順5で再度使用します。

    Parameter NameDefaultDescription
    azureKeyContainerName-Azure キーコンテナ名
    ksaNameazure-key-vaultKSA名
    ksaNamespaceqmonus-systemKSAが存在するnamespace

1. Kubeconfigの作成 (CLI)

Qmonus Value Streamは、Kubeconfigと呼ばれる認証ファイルを利用してKubernetesへアプリケーションをデプロイします。 ここでは、クラスタ・スコープのKubeconfigを生成します。

以下の手順にしたがって、Kubernetesクラスタにアクセスし、External Secrets Operator AdapterとAKS Cluster Secret Store Adapter によって定義されるリソースをデプロイするためのNamespaceを作成し、Kubeconfigを生成してください。Namespaceは、default値を使用するのであればqmonus-systemとなります。 ここで、${cluster_name}はKubernetesクラスタ名、${cluster_name}はAzure Resource Group名を指定します。

bash
# 利用するKubernetesへ接続
az aks get-credentials --admin --name ${cluster_name} --resource-group ${resource_group}

# External Secrets Operator AdapterとGKE Cluster Secret Store Adapter デプロイ用のKubeconfigを生成
# Namespaceがクラスタに存在しない場合は新たに作成されます。
# Namespaceは、default値を使用するのであれば"qmonus-system"
qvsctl plugin gen-kubeconfig -p -o cluster.kubeconfig.yaml [-n ${esoNamespace}]

WARNING

クラスタ・スコープのKubeconfigは権限が非常に強力なため、お取り扱いには注意してください。

なお、azコマンドをはじめて実行する場合は、以下の手順によりazコマンドを初期化してください。ここで、${tenant_id}はonmicrosoft.comで終わるAzureドメイン名です。

bash
az login --tenant ${tenant_id}

2. Applicationの登録 (GUI)

今回利用するサンプルアプリケーションを登録します。

  1. 左メニューより、Applicationを選択します。
  2. 画面右上の NEW APPLICATION ボタンを押下します。
  3. 各フォームに以下の値を入力し、画面右下の NEXT ボタンを押下します。
    • Display Name: External Secrets Operator
    • Description: (任意の文章または空白)
    • QVS Config Repository: + Create New Repositoryを選択し、手順2-aに従いRepositoryを作成
    • QVS Config File Path: eso-clustersecretstore/.valuestream/qvs.yaml

以下は、必要な値を入力した状態のApplicationの登録画面になります。

Applicationの登録

2-a. Repositoryの登録

今回用意したプライベートリポジトリをQmonus Value Streamに登録します。

以下のパラメータの値を変更し、画面右下のCREATEボタンを押下します。

  • Repository Kind: github
  • Git Clone Protocol: https
  • Repository Visibility: private
  • Git Clone URL: (チュートリアルで利用するリポジトリのURLを入力、例:https://github.com/sample-org/sample-repo-name.git)
  • Description: (任意の文章または空白)
  • Git Token:(プライベートリポジトリへの認証に利用するTokenを入力)

3. Deploymentの登録 (GUI)

手順1で生成した、クラスタ・スコープのkubeconfigを使用してDeploymentを作成します。

各フォームに以下の値を入力し、画面右下の CREATE ボタンを押下します。

  • Display Name: staging
  • Name: (Environment選択時に自動入力)
  • Environment: + Create New Environmentを選択し、手順3-aに従いEnvironmentを作成
    • 注) Application単位で、同一Environmentを選択できません
  • Credentials
    • kubeconfig: 手順1で生成した、cluster.kubeconfig.yamlの内容

以下は、必要な値を入力した状態のDeploymentの登録画面になります。

Deploymentの登録

3-a. Environmentの登録

デプロイ先となる環境を登録します。検証環境、商用環境といった、プロジェクト/プロダクトに応じて任意の環境を定義してください。 また、Qmonus Value Streamが推奨する環境の考え方については、環境定義を参考にしてください。

各フォームに以下の値を入力し、画面右下のCREATEボタンを押下します。

  • Display Name: (staging など、任意の環境名)
  • Description: (任意の文章または空白)
  • Provisioning Target:
    • Kind:kubernetes
    • DisplayName: Provisioning Targetを一意に指定できるNameやID
    • Alias:(空白)
    • 同じタイプのProvisioning Targetを複数登録する際は、2つ目以降については Aliasのフォームに そのProvisioning Targetを特定できるエイリアス名を付与してください。

4. Official Cloud Native Adapterのダウンロード (CLI)

プライベートリポジトリでOfficial Cloud Native AdapterのCI/CD AdapterとInfrastructure Adapterをqvsctlコマンドでダウンロードします。

bash
# プライベートリポジトリをcloneする
git clone https://gihub.com/${your_organization}/${your_repository}

# プライベートリポジトリに移動
cd ${your_repository}

# 本チュートリアル用のブランチを作成する
git checkout -b qvs_eso_clustersecretstore

# KubeconfigをGitリポジトリの管理から除外する
echo 'cluster.kubeconfig.yaml' >> .gitignore

# 本チュートリアル用のディレクトリを作成する
mkdir -p eso-clustersecretstore/.valuestream
cd eso-clustersecretstore/.valuestream

# qvsctl auth コマンドを使用して認証する(出力されたurlへアクセスしてください)
qvsctl auth

# Official Cloud Native Adapter でダウンロードできるパッケージの確認
qvsctl adapter list

NAME                         LATEST  RELEASED DATE
qmonus.net/adapter/official  vx.x.x  YYYY-MM-DD hh:mm:ss

# Official Cloud Native Adapterをダウンロードする
qvsctl adapter get qmonus.net/adapter/official

5. QVS Configの作成 (CLI)

ダウンロードしたOfficial Cloud Native Adapterから、Tekton Pipeline/Task を構成するCI/CD Adapterと、Kubernetesリソースを提供するInfrastructure Adapter(External Secrets Operator AdapterとAKS Cluster Secret Store Adapter)を指定するQVS Configを作成します。

bash
# QVS Configを作成する
vim qvs.yaml
yaml
params:
  - name: version
    type: string
  - name: esoNamespace
    type: string
  - name: appName
    type: string
  - name: azureKeyContainerName
    type: string
  - name: ksaName
    type: string
  - name: ksaNamespace
    type: string
    

modules:
  - name: qmonus.net/adapter/official
    local: 
      path: .

designPatterns:
  - pattern: qmonus.net/adapter/official/kubernetes/secrets/eso
    params:
      version:   $(params.version)
      k8sNamespace: $(params.esoNamespace)

  - pattern: qmonus.net/adapter/official/kubernetes/secrets/aks/clustersecretstore
    params:
      appName: $(params.appName)
      azureKeyContainerName:  $(params.azureKeyContainerName)
      ksaName: $(params.ksaName)
      ksaNamespace: $(params.ksaNamespace)

  - pattern: qmonus.net/adapter/official/pipeline/deploy:simple

6. Pipeline Manifestの生成および登録 (CLI)

手順5で作成したQVS Configを用いてPipeline Manifestを生成し、Qmonus Value Streamへ登録します。 projectName はQmonus Value StreamのProject Nameです。Project Nameは、qvsctl project list で取得したPROJECT NAMEを指定してください。

bash
# コンパイルする
qvsctl pipeline compile -m . -c qvs.yaml -o pipelines --prefix external-secrets-operator

# Project Nameを取得する
qvsctl project list

# Pipeline Manifestを登録する
qvsctl pipeline apply -p ${projectName} -f pipelines/manifests.yml

7. AssemblyLineの登録(CLI)

作成したPipelineを実行するためのAssemblyLineを作成し、Qmonus Value Streamへ登録します。

bash
# AssemblyLineを作成する
vim pipelines/eso-clustersecretstore-deploy-assemblyline.yaml
yaml
apiVersion: vs.axis-dev.io/v1
kind: AssemblyLine
metadata:
  name: eso-clustersecretstore-deploy
spec:
  params:
    - name: gitRevision
      description: ""
  results: []
  artifacts: []
  stages:
    - name: eso-deploy
      spec:
        deployment:
          app: external-secrets-operator
          name: staging
        params:
          - name: gitRevision
            value: $(inputs.gitRevision)
          - name: providerType
            value: kubernetes-helm
          - name: deployStateName
            value: externalsecretsoperator
        pipeline: external-secrets-operator-deploy
    - name: clustersecretstore-deploy
      spec:
        deployment:
          app: external-secrets-operator
          name: staging
        params:
          - name: gitRevision
            value: $(inputs.gitRevision)
          - name: deployStateName
            value: clustersecretstore
        pipeline: external-secrets-operator-deploy
      runAfter:
        - eso-deploy

info

ここでは、deployStateNameの値をPipeline毎に分けることで、Qmonus Value Streamでのリソース管理の単位を分割しています。基本的にはPipelineのデフォルトの値で定まっているため、今回は例外として、基本的には修正しないことを推奨します。

作成したAssemblyLineを登録します。

bash
# AssemblyLineを登録する
qvsctl pipeline apply -p ${projectName} -f pipelines/eso-clustersecretstore-deploy-assemblyline.yaml

リモートリポジトリに変更を反映します。

bash
git add --all
git commit -m "Qmonus Value Stream Official Introduction for External Secrets Operator"
git push origin qvs_eso_clustersecretstore

8. Deployment Configの登録 (GUI)

CLIで登録したAssemblyLineをGUIから確認し、AssemblyLine詳細画面より、不足しているパラメータを設定します。

  1. 左メニューより、AssemblyLineを選択します。
  2. 画面中央に表示される eso-clustersecretstore-deploy を選択します。
  3. AssemblyLinePipeline Stageseso-deploy パネルを選択します。
  4. AssemblyLine Stage 画面右に表示される Edit Deployment Config リンクを選択します。
  5. YAMLモードのEditorが表示されますので、Infrastructure Adapterに必要なパラメータをYAML形式で入力します。
yaml
version:                ${version}
esoNamespace:           ${esoNamespace}
azureKeyContainerName:  ${azureKeyContainerName}
ksaName:                ${ksaName}
appName:                ${appName}
ksaNamespace:           ${ksaNamespace}

ここで、パラメータは以下の通りです。 External Secrets Operator Adapter:

  • ${version}: 手順0-1で指定したExternal Secrets OperatorのCRDのバージョン (0.5.0 など"v"を除いた状態で指定してください)
  • ${esoNamespace}: 手順1で作成した${esoNamespace}

AKS Cluster Secret Store Adapter:

  • ${azureKeyContainerName}: 手順0-2で作成したキーコンテナ名
  • ${ksaName}: 手順0-2で指定したKSA
  • ${ksaNamespace}: 手順0-2で作成した${ksaNamespace}
  • ${appName}: Cluster Secret Storeのリソース名を指定。今回はazure-key-vaultとDeployment Configに記載してください
  1. Saveボタンを押下し、Input Parameters 一覧全てが緑で表示されていることを確認します。

9. AssemblyLineの実行 (GUI)

登録したAssemblyLineを実行し、External Secrets OperatorとCluster Secret StoreをKubernetesにデプロイします。 以下のInput Parameterを入力し、eso-clustersecretstore-deploy AssemblylineのRUN ボタンを押下してCI/CDを開始します。

  • gitRevision: qvs_eso_clustersecretstore

10. デプロイされたアプリケーションの確認(CLI)

Kubernetesにアクセスして、デプロイに成功したExternal Secrets Operator と Cluster Secret Storeを確認します。 ここで、${esoNamespace}${appName}はそれぞれ手順8で指定したExternal Secrets Operatorが使用するnamespaceとCluster Secret Storeのリソース名です。

bash
# kubectl の現在のコンテキストを確認する
kubectl config current-context
(External Secrets Operatorをデプロイしたクラスタ名)

## External Secrets Opeartorのデプロイによって作成されたDeploymentリソースを確認する
kubectl get deployment -n ${esoNamespace}

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
external-secrets-operator                   1/1     1            1           
external-secrets-operator-cert-controller   1/1     1            1           
external-secrets-operator-webhook           1/1     1            1           

# clustersecretstoreがデプロイされていることを確認する
kubectl get clustersecretstore

NAME                 AGE
${appName}           

# clustersecretstoreのステータスを確認する
kubectl describe clustersecretstore ${appName}

[...]
Events:
  Type     Reason                 Age                 From                  Message
  ----     ------                 ----                ----                  -------
  Normal   Valid                                      cluster-secret-store  store validated

11. External Secret の動作確認(CLI)

External Secretをデプロイし、キーコンテナの秘密情報がKubernetes Secretリソースへ連携できていることを確認します。

以下の値の通り、動作確認用のキーコンテナのシークレットを作成します。

  • シークレットの名前: qvs-secret-manager
  • シークレットの値: Hello, Qmonus Value Stream! Azureポータル、もしくは下記のコマンドでシークレットを作成して下さい。
bash
az keyvault secret set --vault-name ${azureKeyContainerName} --name "qvs-secret-manager" --value "Hello, Qmonus Value Stream!"

上記コマンドを実行した際、下記のようにjsonの形で出力されます。 ここでの出力結果からid列の末尾${keyVersion}と記載している部分にバージョンが記載されます。この値はSecretを取得する際に扱うため記録してください。 AzureポータルからSecretを作成した場合は、作成したSecretをクリックし"現在のバージョン"と記載されている文字列を記録してください。

json
{
  "attributes": {
    "created": "YYYY-MM-DDTHH:MM:SS+00:00",
    "enabled": true,
    "expires": null,
    "notBefore": null,
    "recoveryLevel": "Recoverable+Purgeable",
    "updated": "YYYY-MM-DDTHH:MM:SS+00:00"
  },
  "contentType": null,
  "id": "https://${azureKeyContainerName}.vault.azure.net/secrets/qvs-secret-manager/${keyVersion}",
  "kid": null,
  "managed": null,
  "name": "qvs-secret-manager",
  "tags": {
    "file-encoding": "utf-8"
  },
  "value": "Hello, Qmonus Value Stream!"
}

External Secretリソースをデプロイします。以下のサンプルManifestを使用してください。

bash
vim qvs-sample-externalsecret.yaml

なお${keyVersion}はバージョンを登録したさいのバージョンの値を記載してください。 また、Versionについては省略も可能です。省略した場合は最新のバージョンが取得できます。

yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: example
spec:
  refreshInterval: "0"
  secretStoreRef:
    name: ${appName}
    kind: ClusterSecretStore
  target:
    name: qvs-kubernetes-secret
    creationPolicy: Owner
  data:
  - secretKey: greeting
    remoteRef:
      key: qvs-secret-manager
      version: "${keyVersion}"
bash
# External SecretをDefault namespaceにApplyする
kubectl apply -f qvs-sample-externalsecret.yaml

# External SecretのStatusを確認する
kubectl get externalsecret.external-secrets.io/example

NAME      STORE                REFRESH INTERVAL   STATUS
example   ${appName}           0                  SecretSynced

# Secretに値が連携できているかを確認する
kubectl get secrets qvs-kubernetes-secret -o json | jq -r .data.greeting | base64 --decode
Hello, Qmonus Value Stream!