いろいろなAWSアカウントのArgo CDを統合した話(1) - kubell Creator's Note では統合することになった背景を簡単に記載しました。
(2),(3)では、統合の際に対応に時間がかかったところを記載していきたいと思います。
(2)では主にAWSのクロスアカウントに関して記載し、(3)ではApplicationSetへの対応に関して記載したいと思います。
Argo CDでAWSのクロスアカウント越しにKubernetesのリソースを操作する
Argo CDではクラスタの登録をCluster Credential(Cluster Secretと言ったりもするっぽい。実態はKubernetes Secret)を作成することで行います。 大まかな内容は下記に記載されていますが、ServiceAccountを作成したTokenでの認証の方法しか記載されておらず、弊社では可能な限りIRSAを利用して認証したいのですが、これだけではよくわかりませんでした。
いろいろと調べて下記のissueやブログに非常に詳細に記載されており、これを参考にすることで、Argo CDのApplication ControllerとServerで利用しているIRSAのRoleで別EKSクラスタのaws-authに記載されているRoleにAssume Roleすることで、Argo CDからin-clusterではないEKSクラスタの操作を行えるようになりました。 github.com Deploy ArgoCD on AWS — Modulo 2
これで、Role経由でEKSクラスタ内のリソースの操作は可能となりました。
Argo CD PluginでAWSのクロスアカウント越しにParameter Storeの値を取得する
helmfileと外部参照機能
Chatworkでは、helmfileを多用しており、ほぼすべてのKubernetes上のアプリケーションをhelmfileを利用して展開しています。
helmfileには外部に保存されている値を参照する機能があり、Chatworkではこれを利用して、AWS Systems Manager Parameter Storeに外部SaaSのトークンなどのクレデンシャルなデータをおいて、helmfileとしてはその参照先を記載するのみにすることで、GitHub上でhelmfileを管理しても問題ないようにしています。
AWS Secrets Managerにもhelmfileは(正確にはvalsは)対応しているのですが、Parameter Storeのほうが扱いがシンプルであり、基本的には無料ということもあり、利用しています。
しかしParameter Storeには、クロスアカウントのポリシーを設定する機能はなく、別アカウントからParameter Storeの値を参照するためには、Assume Roleしかありません。
Argo CD統合の際に、AWS Secrets Managerへの移行(全箇所の書き換え)も検討しましたが、Parameter Storeの参照箇所が多く、機械的な書き換えも相当な労力になりそうだったので、Parameter Storeを継続して利用できる方法を検討し、採用しました。
Argo CDのSidecar pluginによるmanifestの展開
ところで、Argo CDでは、manifestを生成したり差分を確認するためにplugin機能があります。
helmfileはArgo CDのデフォルトでは対応していないので、自前でpluginを用意する必要があり、Chatworkでは専用のイメージを作成して利用しています。
この機能もなかなかわかりにくいのですが、もともと2.6ぐらいで、既存のplugin方式(ConfigMap Plugin)が消される予定だったので、ChatworkではSidecar pluginに対応しています。
Sidecar pluginはmanifestを展開するコマンドを自由に書くことが可能で、下記はdockerfileのレポジトリに記載している内容ですが、generate
がmanifestを生成するコマンドになります。
apiVersion: v1 kind: ConfigMap metadata: name: helmfile-plugin namespace: argocd data: plugin.yaml: | apiVersion: argoproj.io/v1alpha1 kind: ConfigManagementPlugin metadata: name: helmfile-plugin spec: version: v1.0 generate: args: - helmfile -q template --include-crds --skip-tests command: - /bin/sh - -c discover: find: command: - sh - -c - find . -name helmfile.yaml
helmfile-pluginのgenerateで各AWSアカウントのEKSクラスタのParameter Storeの値を取得する
ということで、helmfileでmanifestを展開しつつ、各AWSアカウントのAWS Systems Manager Parameter Storeから値を取得するためには、helmfile実行時に各AWSアカウントのRoleにAssume Roleする必要があります。
valsの機能としてAssume Roleできると、一番わかりやすいのですが、2023/07/05時点ではまだリリースされておらず*1、2023/07/05時点のhelmfileの最新では利用できません。
ということで、いろいろと試しましたが、最終的にはgenerate.args
でaws cliを利用してAssume Roleして、そのTokenを利用する方式を採用しました。
具体的には下記のコマンドです。実際にはワンライナーで記載しています。あとenvを吐き出しているのはデバッグ用です。
unset AWS_SESSION_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; read AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN<<< $(aws sts assume-role --role-arn $ARGOCD_ENV_REPO_SERVER_IAM_ROLE_ARN --role-session-name argocd-reposerver --output json | jq -r '.Credentials | [.AccessKeyId ,.SecretAccessKey ,.SessionToken] | join(" ")' ); export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN; env > /tmp/env; helmfile -q --environment $ARGOCD_ENV_HELMFILE_ENV template --include-crds --skip-tests
$ARGOCD_ENV_REPO_SERVER_IAM_ROLE_ARN
と$ARGOCD_ENV_HELMFILE_ENV
は、Argo CDのApplicationのpluginのところに記載しているenvです。
pluginのenvに記載した場合、使うときには$ARGOCD_ENV_
というプレフィックスがつくのでお気をつけください。2.4からこの仕様になって、2.3 -> 2.4でハマりました。
REPO_SERVER_IAM_ROLE_ARN
に、Parameter StoreのあるAWSアカウントで利用したいRole(つまりhelmfile実行時にAssume RoleするRole)を記載し、HELMFILE_ENV
にhelmfileで利用するenvironemnt(Chatworkの場合はクラスタ名)を記載しています。
下記が実際の画面のキャプチャです。どのようにroleをhelmfile pluginに渡すのかはいろいろと悩みましたが、下記の観点から最終的にこのようになりました。
- ApplicationSetを経由して、Applicationが作成され、ApplicationはCluster Generatorを利用して、EKSクラスタごとに作成される
- Cluster GeneratorはCluster Credentialsに付与したlabelごとにvaluesを設定でき、EKSクラスタごとに使用するRoleを判断しやすい
- Cluster Generator - ApplicationSet Controller
- どのEKSクラスタがどのAWSアカウントなのか判断できる
- リリースする人(開発者)が、誤ってenvのRoleを消したとしても、そのタイミングではリリースはできないが、Paramete Storeの値ができないためにエラーになるだけで、変な値が入ることはない
ということで、Argo CDからAWSのクロスアカウント越しにリソースを操作したり、manifestを生成する方法に関して記載しました。 (3)では今回の統合に伴って導入したApplicationSetに関して記載したいと思います。
*1:masterには入っている https://github.com/helmfile/vals/pull/151