Argo CD と Argo Workflows で SSO + RBAC

blog.hatappi.me

上記の記事で紹介したように最近プライベートKubernetesの構成を変更したことで複数のドメインを設定できるようになった(金銭面)ので、今まで Port Forward でアクセスしていた Argo Workflows を ALB にぶら下げて https 経由でアクセスできるようになりました。

そこで https 化してアクセスできるようにするついでに SSO の設定をすることにしました。
また Argo Workflows だけでなく Argo CD も導入したのでその背景も書きました。

今までの Argo Workflows の用途

用途としては大きく二つありました。

  1. バッチとかを動かす
    • 運用しているサービスの1つに Rails のサービスがあるのですが、任意の Rake タスクをクラスタ上で実行するための便利ワークフローを作ってたりします
  2. デプロイ
    • シンプルなものだと新しいバージョンのコンテナを既存のコンテナと差し替える
    • ちょっと複雑なやつだと例えば Rails なアプリケーションなら最初に bundle exec rails db:migrate してその後に新しいバージョンのコンテナを既存のコンテナと差し替える

デプロイ部分をもう少し補足します。
コンテナを差し替える部分に関しては上記で書いたように Argo Workflows で行います。
差し替えるための Docker Image の作成と ECR への push は Github Actions で行います。
Image が push された後は Argo Workflows は CLI を提供しているので、それを Github Actions の Job 内から実行します。
argoproj.github.io

ここまで書いたことを図で書いてみます。

f:id:hatappi1225:20210103172829j:plain

Argo CD をなぜ導入したのか

次に Argo Workflows を使いながらなぜ Argo CD を使用することになったのかを書きます。
今までの Argo CD の自分の理解では、指定されたマニフェストの状態が更新(例えばGithubの特定のリポジトリのパスにcommit)されたら、そのクラスタがその状態になるように Argo CD が管理してくれるというものでした。

さきほどデプロイの説明の中で Rails なアプリケーションはDBのマイグレーションを実行してその後に新しいバージョンをデプロイしていたので、この用途の場合DBのマイグレーションを実行するのが難しいのではと思い使用するのを断念して Argo Workflows に定義していました。

しかし最近ふとしたタイミングで下記の記事を見て Sync PhaseとSync Wave の存在を知りました。

tech.recruit-mp.co.jp

記事の中では Sync PhaseとSync Wave は下記のように記載されています。
公式ドキュメントにはこちらです。

Argo CDにはSync PhaseとSync Waveという2つの概念があり、Sync PhaseにはPreSync,Sync,PostSyncの3つのPhaseがあり、Sync Waveで各Sync Phaseの間のSync5)の順序を制御できます。

まさに僕がやりたかった DB のマイグレーションして成功した後に新しいバージョンのコンテナに差し替えるが実現できそうです。

これが Argo CD をいれるモチベーションになりました。

導入や設定はそこまで大変ではなくて 公式ドキュメント読んで、何を設定する必要があるかを検討つけて、インストールは Helm chart を利用して設定は YAML で適用するだけでした。
Argo プロダクトは YAML ですべて設定できるようになっているので、便利ですね!!

これで Argo CD で差分を検知したらそれをデプロイできるようになったので、Gtihub Actions で image を push 後に行っていた Argo Workflows でのデプロイを manifest を管理しているリポジトリに commit する処理に変更しました。

image のタグ変更に関しては kustomize を使用しているので kustomize edit set image xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxxxx/app:new-tag のように実行すれコマンド一発で変更できて後はそれをコミットするだけなのでシンプルです。

ここまで変わったことを図でまとめてみます。

f:id:hatappi1225:20210103175152j:plain

Argo Workflows と Argo CD の SSO

最後は Argo Workflows と Argo CD の SSO 化を行っていきます。
今回は Github アカウントで SSO していきます。

また SSO ついでに RBAC での権限設定をしていきます。
権限は特定の Github Organization の特定のチームのメンバーの時のみ権限を付与するというものを設定します。

Argo CD の SSO と RBAC

まずは SSO の設定をしていきます。
SSO は Argo CD の公式のドキュメントが分かりやすいです。
さらに導入例も Github なのでスムーズに設定できると思います。

argoproj.github.io

Helm の values file は下記のように設定します。

server:
  config:
    ~~~
    dex.config: |
      connectors:
        - type: github
          id: github
          name: GitHub
          config:
            clientID: $dex.github.clientId
            clientSecret: $dex.github.clientSecret
            orgs:
            - name: example-org
              teams:
              - argo

次は RBAC の設定です。
こちらも公式ドキュメントに設定方法が書いてあるので参考にしながら設定していきます。

argoproj.github.io

今回は example-org という Github Organization の argo だったら role:admin を付与します。
この role は Argo CD が予め用意している Build-in role です。

これを設定した Helm の values は下記のようになります。
また今回はデフォルトで用意されている admin アカウントは必要なくなるので、 admin.enabled: "false" して未ログインのユーザーは必要ないので、 users.anonymous.enabled: "false" を設定しました。

server:
  config:
    admin.enabled: "false"
    users.anonymous.enabled: "false"
  ~~~
  rbacConfig:
    scopes: '[groups]'
    policy.default: ''
    policy.csv: |
      g, example-org:argo, role:admin

これで一通りの作業は完了です。
ほぼドキュメント通り設定して完了です。

Argo Workflows の SSO と RBAC

最後は Argo Workflows の SSO と RBAC です。
こっちは少し面倒です。

まずは SSO 化から

Argo CD, Argo Workflows は SSO 化する際に Dex という Go 製の OpenID Connect Provider を使用します。
Argo CD に関してはドキュメントに書かれているように Dex をバンドルして提供しています。
Helm Chart でもバンドルされた Dex を立ち上げるオプションが存在しています。
https://github.com/argoproj/argo-helm/tree/master/charts/argo-cd#dex

しかし現時点では Argo Workflows の Helm Chart には用意されていません。
https://github.com/argoproj/argo-helm/tree/master/charts/argo
そのためおそらく自分で Dex コンテナを立ち上げる必要があります。(今回は試してないので確かではありません。)

Argo Workflows のドキュメントには Argo CD の Dex server を使用する方法が書かれているので今回はこちらを使用します。
argoproj.github.io

まずは Argo Workflows を SSO 化するための設定を Argo CD に行っていきます。
Helm の values.yaml は下記のようになりました。

server:
  config:
    ~~~
    dex.config: |
      connectors:
        ~~~
      staticClients:
        - idEnv: ARGO_WORKFLOWS_SSO_CLIENT_ID
          name: Argo Workflow
          redirectURIs:
            - https://argo-workflows.example.com/oauth2/callback
          secretEnv: ARGO_WORKFLOWS_SSO_CLIENT_SECRET

dex:
  image:
    tag: v2.26.0
  env:
    - name: ARGO_WORKFLOWS_SSO_CLIENT_SECRET
      valueFrom:
        secretKeyRef:
          name: argo-workflows-secrets
          key: gh_client_secret
    - name: ARGO_WORKFLOWS_SSO_CLIENT_ID
      valueFrom:
        secretKeyRef:
          name: argo-workflows-secrets
          key: gh_client_id

基本はドキュメントにしたがって Helm Chart の values を書き換えていくのですが 2点だけ気を付けるポイントがあります。

1つ目が Dex のバージョンです。
ドキュメントにあるように Dex は v0.23.0 以上を使う必要があります。
しかし現在の Helm Chart のデフォルトの設定では v2.22.0 なので v0.23.0 以上を指定する必要があります。
私が設定した時の最新が v2.26.0 だったのでそれを指定しています。

2つ目が Github の ClientIDの指定です。
ドキュメントでは Argo CD 側の設定例は下記のようになっています。

     dex:
       image:
         tag: v2.23.0
       env:
         - name: ARGO_WORKFLOWS_SSO_CLIENT_SECRET
           valueFrom:
             secretKeyRef:
               name: argo-workflows-sso
               key: client-secret
     server:
       config:
         dex.config: |
           staticClients:
           - id: argo-workflows-sso
             name: Argo Workflow
             redirectURIs:
               - https://argo-workflows.mydomain.com/oauth2/callback
             secretEnv: ARGO_WORKFLOWS_SSO_CLIENT_SECRET

client_secret は secret 経由で設定していますが、 client_id は設定していません。
client_id は staticClients[0].id に設定するのですが、実はこの id も secret と同じように idEnv というフィールドにすることで環境変数から client_id を設定してくれます。

これで Argo CD 側は終わりで Argo Workflows 側の設定をします。

server:
  extraArgs:
    - --auth-mode=sso
  sso:
    issuer: https://argo-cd.example.com/api/dex
    clientId:
      name: argo-workflows-secrets
      key: gh_client_id
    clientSecret:
      name: argo-workflows-secrets
      key: gh_client_secret
    redirectUrl: https://argo-workflows.example.com/oauth2/callback
    scopes:
      - groups
    orgs:
    - name: example-org
      teams:
      - argo
    rbac:
      enabled: true

これで SSO 化は完了です。

最後は RBAC の設定をします。
Argo Workflows での SSO の RBAC は最近のバージョンで導入された機能です。
Argo CD とは違って ServiceAccount に紐づけて設定していくようです。

blog.argoproj.io

ドキュメントを参考にしつつ下記のようなアカウントを作成します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: example-org-sso-user
  annotations:
    workflows.argoproj.io/rbac-rule: "'example-org:argo' in groups"
    workflows.argoproj.io/rbac-rule-precedence: "1"

またこれだと Argo Workflows のアカウントに何もアクセスできないサービスアカウントなので、今回は Helm Chart でインストールした時にできた ClusterRole を Bind します。
ちなみに Helm Chart で作成される ClusterRole はこちらです。
https://github.com/argoproj/argo-helm/blob/182ef88c67c1ac58d0a922b7101a23e2f91ab2f5/charts/argo/templates/server-cluster-roles.yaml

Binding は下記のような YAML を定義します。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: example-org-sso-user-argo-workflows-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: argo-workflows-server
subjects:
- kind: ServiceAccount
  name: example-org-sso-user
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: example-org-sso-user-argo-workflows-server-cluster-template
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: argo-workflows-server-cluster-template
subjects:
- kind: ServiceAccount
  name: example-org-sso-user

これを apply すればログインした時に適切な ServiceAccount が紐づけられるのですが、現状の Helm Chart で作成された ClusterRole を使用する場合はひとつだけ注意があります。
Argo Workflows はログインが成功した後に ServiceAccount を紐づけるために対象候補の ServiceAccount を取り出すのですが、現状は権限が少し足りません。

解決するための PR は出ているので、待つか自分で ClusterRole を作るなどして対応します。
github.com

これで Argo Workflows も SSO + RBAC できました。

最後に

今回はなぜ Argo CD を導入して Argo CD, Argo Workflows にどうやって SSO + RBAC を導入するかを書きました。
やっぱりいつでも気軽にブラウザから今の状態が見られるのは良いですね。