APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【AKS】External Secret Operatorを使ったKey Vaultとの連携によりSecret情報を安全に管理する

はじめに

こんにちは。ACS事業部 木戸と申します。

今までAKS環境でのGitOpsを実現する為の検証を実施してきましたが、その中でGitリポジトリやユーザのログイン認証などの連携には様々な認証が必要となります。
Argo CDへのログインの為のSSOにGitHub OAuth認証を利用し、Argo CDがGitリポジトリにアクセスするための認証にGitHub Apps認証を利用しています。
その際、認証に必要な情報(主にSecretなど)を設定する必要がありますが、マニフェストYAMLや設定ファイルにそのまま値を記載することはセキュリティ上問題です。

今回は External Secrets Operator を利用して、Argo CDで必要となる認証用のSecretをAzure Key Vaultに登録し、AKSクラスターのSecretと同期を行う事で安全にSecret情報を連携できるようにしたいと思います。

1. External Secrets Operator (ESO)とは

External Secrets Operator は外部の秘匿情報ストアとKubernetesの Secret を自動同期することでシークレットの管理を一元化することができます。
また機密情報(Secretや接続文字列など)の記述が必要なマニフェストのYAMLやアプリの設定ファイルについてもGitで管理するファイル自体に実値が記載されることを防ぐことができます。

external-secrets.io

2. 事前設定

AKSクラスタの OIDC issuer, Workload Identityの有効化

以下のコマンドを実行して、必要機能を有効化します。

az aks update \
  --resource-group <リソースグループ名> \
   --name <AKS名> \
  --enable-oidc-issuer \
  --enable-workload-identity

Azure Key Vaultの作成、AKSのOIDC Issuer URLとの連携

まずKey Vaultを作成します。

# Key Vaultの作成
az keyvault create --name <Key Vault名> --resource-group <リソースグループ名> --location <リージョン>

AKSとKey VaultをOIDCで連携するために、UserAssignedのMangedIDを作成し、専用のFederated Credentialを設定します。

# UAM IDの作成
az identity create --resource-group <リソースグループ名> --name <マネージドID名>

# AKSのOIDC発行者URLを取得
oidc_issuer_url="$(az aks show -n <AKS名> -g <リソースグループ名> --query "oidcIssuerProfile.issuerUrl" -o tsv)"

# IDにFederatedCredentialを設定
# ※Helmチャートのデフォルト設定では、メインのコントローラーが利用するServiceAccount名が external-secrets となる
# Helmインストール時にServiceAccount名を変更する場合は指定した名称を設定
az identity federated-credential create \
  --name <Federated-Credential名> \
  --identity-name <マネージドID名> \
  --resource-group <リソースグループ名> \
  --issuer $oidc_issuer_url \
  --subject system:serviceaccount:external-secrets:external-secrets 

Key VaultのRBACにマネージドIDの権限を設定します。

# ESO 用 UAMI の Principal ID を取得(Terraform output から確認した値を使用)
eso_uami_principalId=$(az identity show \
  --resource-group "<リソースグループ名>" \
  --name "<マネージドID名>" \
  --query "principalId" -o tsv)

# Key Vault Secrets User: Secret の読み取り専用(最小権限)
az role assignment create \
  --assignee "$eso_uami_principalId" \
  --role "Key Vault Secrets User" \
  --scope "<Key VaultのリソースID>"

Azure Key Vaultへのシークレット登録

今回はAzure Key Vaultに以下の情報を登録します。
登録するユーザには Key Vault Secrets Officer のRBAC権限を付与しています。
- Argo CDとGitリポジトリを連携するのに使用するGitHub Appsの秘密鍵
- Argo CDのログインに使用するGitHub OAuthのClientIDとSecret

# 秘密鍵など改行の含まれる文字列を Azure Portal から登録すると正しい情報として認識されない場合がある為、azコマンドから登録しています。
az keyvault secret set --vault-name "<Key Vault名>" --name "ArgoCD-Repository-GitHubApp-Key" --file "<GitHub Appsの秘密鍵(pem)ファイル>"
az keyvault secret set --vault-name "<Key Vault名>" --name "GitHub-OAuth-ClientID" --value "GitHub OAuthのClientID"
az keyvault secret set --vault-name "<Key Vault名>" --name "GitHub-OAuth-Secret" --value "GitHub OAuthのSecret"

3. External Secrets Operator のインストール

今回は公式が提供しているHelm Chartを利用してExternal Secrets Operator (ESO) をインストールします。
external-secrets.io

HelmによりExternal Secrets Operatorをインストールします。
その際、事前に作成したマネージドIDを指定します。

# リポジトリの追加
helm repo add external-secrets https://charts.external-secrets.io
helm repo update

# マネージドIDのclientIDを取得
uamid=$(az identity show -g "<リソースグループ名>" -n "<マネージドID名>" --query clientId -o tsv)

# ESO のインストール
helm install external-secrets external-secrets/external-secrets \
  --namespace external-secrets \
  --create-namespace \
  --set serviceAccount.annotations.'azure\.workload\.identity/client-id'=$uamid \
  --set serviceAccount.labels.'azure\.workload\.identity/use'="true"

4. External Secretの設定を行う

ESO のClusterSecretStoreとして、Key Vaultの設定を追加します。
以下のYAMLを反映します。

# ExternalSecretsのClusterSecretStoreの設定
kubectl apply -f manifests/cluster_secret_store.yaml

# cluster_secret_store.yamlの内容

apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
  name: azure-keyvault-store
spec:
  provider:
    azurekv:
      authType: WorkloadIdentity
      vaultUrl: "<Key VaultのDNS名(https://~)>"
      tenantId: "<Key Vaultが作成されているテナントID>"
      serviceAccountRef:
        name: external-secrets           # K8S側のESO のサービスアカウント (Helmで作成されサービスアカウント)
        namespace: external-secrets  # K8S側のESO の名前空間

External Secretをデプロイします。
この設定によりArgo CDのargocd-secretの値がKey Vaultのシークレットの内容に同期され、正しいSecret値として反映されます。
Exeternal SecretのSTATUSが SecretSynced、READYが Trueの状態であれば正常にKey Vaultから値が同期されています。

# 各ExternalSecretsの設定
kubectl apply -f manifests/external_secret_argocd.yaml

# ExternalSecretの一覧
kubectl get externalsecret -n argocd

NAME                                    STORETYPE               STORE                         REFRESH INTERVAL   STATUS              READY   LAST SYNC
argocd-dex-github-secret     ClusterSecretStore   azure-keyvault-store   5m                             SecretSynced     True       18m

#  STATUS が SecretSynced になっており正常に連携されている事を確認出来たらargocdのDeploymentを再起動する
kubectl rollout restart deployment -n argocd

# GitHub OAuth App の ClientIDと Secret を argocd-secret にマージ
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: argocd-dex-github-secret
  namespace: argocd
spec:
  refreshInterval: 5m
  secretStoreRef:
    name: azure-keyvault-store
    kind: ClusterSecretStore
  target:
    name: argocd-secret
    creationPolicy: Merge  # 既存の argocd-secret を保持しつつ、以下の値を注入
  data:
    # GitHub OAuth Client ID
    - secretKey: dex.github.clientID
      remoteRef:
        key: GitHub-OAuth-ClientID
    # GitHub OAuth Client Secret
    - secretKey: dex.github.clientSecret
      remoteRef:
        key: GitHub-OAuth-Secret

Argo CDのログイン画面にGitHubログインのアイコンが表示されます。
クリックすると、GitHubの認証画面が表示されます。

認証するとArgo CDのUI画面にアクセスできます。

5. Argo CDで管理するGitリポジトリをマニフェストのYAMLに秘密鍵を埋め込んで登録する

次にArgo CDで管理するGitリポジトリをマニフェストYAMLから登録したいと思います。
通常、このタイミングで手動で認証用のSecretを埋め込む必要がありますが、ESOにより同期が行われているため、以下のようなYAMLを指定することでGitリポジトリに接続することができます。

# ArgoCDのGitリポジトリ情報のExternalSecretを作成
kubectl apply -f repository.yaml

# repository.yamlの情報
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: <External Secret名 (repository名)>
  namespace: argocd
spec:
  refreshInterval: 5m
  secretStoreRef:
    name: azure-keyvault-store
    kind: ClusterSecretStore
  target:
    name: <External Secret名 (repository名)>
    creationPolicy: Owner
    template:
      metadata:
        labels:
          argocd.argoproj.io/secret-type: repository
      data:
        type: git
        url: <GitリポジトリのURL>
        githubAppID: "<GitHub Apps認証のAppID>"
        githubAppInstallationID: "<GitHub Apps認証のInstallationID>"
        githubAppPrivateKey: "{{ .privateKey }}"
  data:
    # remoteRefの値にKey Vaultの秘密鍵のシークレット名を設定する。
    - secretKey: privateKey
      remoteRef:
        key: ArgoCD-Repository-GitHubApp-Key             # Key Vault のシークレット名

Argo CDに、Gitリポジトリが正常に接続されている事を確認できました。

6. まとめ

今回は、External Secrets Operatorを活用してAzure Key VaultとArgo CDを連携させ、Secretの同期によるGitHub認証ログインやGitリポジトリの登録を実装しました。

機密情報を外部ストアで一元管理することは、セキュリティの向上と運用管理の負荷軽減に直結します。
特に、GitOpsでは管理しづらい認証情報において、手動で値を埋め込む手間を排除できる点は大きなメリットです。
人為的な設定ミスの防止や運用プロセスの自動化の効果も得られると思います。

一方で、機密情報が集約される外部ストアへのアクセス権限設計が特に重要となり、実際の運用に際しては適切な権限設計とロールの付与が必要になると感じました。

ACS事業部のご紹介

私達ACS事業部はクラウドネイティブ技術、Azure AI サービス、Platform Engineering、AI駆動開発支援などを通して、攻めのDX成功に向けた開発者体験・開発生産性の向上・内製化のご支援をしております。

www.ap-com.co.jp また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。
※求人名の冒頭に【ACSD】と入っている求人が当事業部の求人となります。 www.ap-com.co.jp