背景

仕事ではArgoCDでGitOpsを行っており、Argo Workflowsでバッチ処理を実行するエンジンとして利用しています。

運用初期は利用者が多くなかったため、Argo CDのSSOはGitHub Team (グループ管理)とArgo CDに付随されているDexを使用していました。 また、認可設定はシンプルに保ち、Basic Built-in Rolesを利用して、クラスタ管理者にrole:admin、利用者にrole:readonly権限を付与していました。一方、Argo WorkflowsではSSOを設定せず、デフォルトのAuth Modeであるserverを使っていたため、認証が通れば誰でもバッチのログを閲覧できる状態でした。

しかし、プラットフォームの成長に伴い、機密性の高いログが増える見込みとなり、現在の運用は対応が難しくなってきました。

そこで、先日最小権限の原則(Principle of Least Privilege、必要最小限の権限のみを付与する運用方針)に従い、Argo CDとArgo Workflowsの権限設定を見直しました。 本記事では、公式ドキュメントに記載されていない落とし穴や、実践してみて明らかになったArgo CDとArgo Workflows権限のポイントについて解説します。 Argo CDやWorkflows権限設定の権限設定を進める際の参考になれば幸いです。

Argo CD

先述の通り、今回の構成ではGitHub Teamでグループを管理し、OpenID Connect ProviderとしてDexを利用しています。この構成における認証・認可のフローは、GitHub Teams → Dex → Argo CD Applicationとなります。

Argo CDでは、グループごとにnamespaceのアクセス権限を設定することで、必要最小限の権限のみを付与できます。 ただし、Argo CDのドキュメントRBAC Configurationの記載によると、namespaceごとに設定する場合、事前にApplication in Any Namespacesを有効化する必要があります。

デフォルトでは、Argo CDのApplicationはargocd namespaceに作成されるため、Applicationリソースを各namespaceに分割して配置する必要があります。この設定は比較的簡単な一方で、ApplicationSetのtemplateにおいてnamespaceがサポートされていないため、この方法を採用するのは現実的ではありませんでした。すでにApplicationSetによって複数のnamespaceにアプリケーションをデプロイしているため、ApplicationSetの廃止は容易ではありません。

その解決策として、namespaceごとにAppProjectを作成し、論理的なグループ化を行いました。AppProjectは、Argo CDにおいてアプリケーションをグループ化し、リソースやアクセス制限を設定するためのリソースです。以下は、その例です。

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: samples
  namespace: argocd
spec:
  destinations:
    - namespace: samples
      server: "https://kubernetes.default.svc"
  sourceRepos:
    - "https://github.com/org/repo.git"

このAppProjectに対応する権限は、Dex設定用のConfigMapに定義します。

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
data:
  policy.csv: |
    g, {YOUR_ORG}/{YOUR_TEAM}, role:user-namespace-samples
    p, role:user-namespace-samples, applications, get, samples/*, allow

    p, role:authenticated, projects, get, default, allow    
  policy.default: role:authenticated

この設定により、AppProjectに付与した権限が間接的にnamespaceの権限として機能し、ApplicationSetのtemplateではnamespaceがサポートされていない問題を回避できました。 全namespaceに対してこの設定を適用することで、namespaceのアクセス権限を分離し、それぞれに最小限の権限を argocd-rbac-cm に設定できるようになります。

Argo Workflows

続いて、Argo WorkflowsのSSO設定について紹介します。 Argo Workflowsの認証認可のフローはGitHub Teams → Dex → ServiceAccount → Workflow/CronWorkflow/WorkflowTemplateになります。

最小限の権限を付与するため、まずはAuth ModeをServerからSSOに変更しておく必要があります。 設定は基本的にドキュメントに従えば問題ありません。ただし、SSO RBAC Namespace Delegationは、ドキュメントでは「オプション」とされていますが、実際には必須と考えるべきです。

理由としては、1人のユーザが複数のグループ (GitHub Teams) を所属する場合、この設定がないままダッシュボードにログインすると、所属しているGitHub Teamsと紐づいている任意のService Accountの権限が付与され、ユーザが本来アクセスするつもりのworkflowにアクセスできない状況が発生します。この挙動を回避するために、SSO RBAC Namespace Delegationの有効化は必須です。 詳細はこちらのissueにご参照ください。

Argo Workflowsの設定

以下は、最終的にArgo Workflowsの設定(Helmのvalues.yaml)です。

server:
  authModes:
    - sso
  sso:
    enabled: true
    issuer: https://argocd.example.com/api/dex
    sessionExpiry: 240h
    clientId:
      name: argo-workflows-sso
      key: client-id
    clientSecret:
      name: argo-workflows-sso
      key: client-secret
    redirectUrl: https://workflows.example.com/oauth2/callback
    scopes:
      - groups
    rbac:
      enabled: true
  extraEnv:
    - name: SSO_DELEGATE_RBAC_TO_NAMESPACE
      value: "true"

ポイント

  • issuer: Dexのエンドポイント
  • redirectUrl: workflowsのredirect先で、path部分デフォルトで問題ので、domain部分だけを置き換えればいい
  • SSO_DELEGATE_RBAC_TO_NAMESPACE: RBACをnamespaceに委譲するためにtrueを指定する

Argo CD側の設定

Argo CD側では、Dexのコンテナにworkflowsのclient secretを追加し、staticClientsを行う必要があります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: argocd-dex-server
spec:
  template:
    metadata:
    spec:
      containers:
        - name: dex
          env:
            - name: ARGO_WORKFLOWS_SSO_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: argo-workflows-sso
                  key: client-secret
---

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
data:
  admin.enabled: "false"
  dex.config: |
    connectors:
      - type: github
        id: github
        name: GitHub
        config:
          clientID: hogehoge
          clientSecret: $argocd-dex:github-client-secret
          orgs:
          - name: your-org
            teams:
            - your-tema
    staticClients:
      - id: argo-workflows-sso
        name: Argo Workflow
        redirectURIs:
          - https://workflows.example.com/oauth2/callback
        secretEnv: ARGO_WORKFLOWS_SSO_CLIENT_SECRET    
  url: https://argocd.example.com

ポイント

  • redirectURIs: workflowsのredirect先で、Workflows側と一致させる必要がある
  • redirectURIsbowser accessibleのリンクでなければならないため、Argo CDとWorkflowsは同じクラスタにある場合でも、クラスタ内通信は難しい

Service Accountの設定

SSOを有効化した後、次のステップとしてService Accountを設定します。特定のnamespaceにあるworkflowなどのArgo Workflows関連のリソースにアクセスするのに、2つのService Accountが必要です。

  1. デフォルトのService Account: ログイン時に使用する
  2. namespace側のService Account: 特定のnamespace内リソースのアクセスを管理する

以下はデフォルトのService Accountの設定例です。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default-user
  namespace: argo-workflows
  annotations:
    workflows.argoproj.io/rbac-rule: "true"
    workflows.argoproj.io/rbac-rule-precedence: "0"

---
apiVersion: v1
kind: Secret
metadata:
  name: default-user.service-account-token
  namespace: argo-workflows
  annotations:
    kubernetes.io/service-account.name: default-user
type: kubernetes.io/service-account-token

ポイント

  • namespace: argo-workflowsに設定する
  • RBACルールの優先順位: デフォルトのため、workflows.argoproj.io/rbac-rule-precedence0に設定する

以下は、namespace側のService Accountの設定例です。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: argo-workflows-user
  namespace: samples
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - cronworkflows
    verbs:
      - get
      - list
      - watch
      - patch

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

---
apiVersion: v1
kind: Secret
metadata:
  name: argo-workflows-user.service-account-token
  namespace: samples
  annotations:
    kubernetes.io/service-account.name: argo-workflows-user
type: kubernetes.io/service-account-token

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argo-workflows-user
  namespace: samples
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: argo-workflows-user
subjects:
  - kind: ServiceAccount
    name: argo-workflows-user
    namespace: samples

ポイント

  • Role, RoleBinding, ServiceAccountとServiceAccountのtokenをセットで設定する
  • workflows.argoproj.io/rbac-ruleはdex側のGitHubの情報に基づいて設定する。例:'your-org:your-team' in groups
  • RBACルールの優先順位: workflows.argoproj.io/rbac-rule-precedence1 に設定する

これらの設定により、ログイン時にデフォルトのService Accountの権限が付与されます。各namespaceのService Account argo-workflows-userにRoleをbindingすることで、WorkflowやCronWorkflowなどアクセスできるリソース範囲を制限できます。

まとめ

本記事では、Argo CDとArgo Workflowsにおける認証・認可の具体的な構築手法を解説しました。

  1. Argo CD: AppProjectとRBACポリシーを組み合わせることで、ApplicationSetの制約を回避しつつ、namespaceごとに柔軟な権限管理を実現
  2. Argo Workflows: SSOを有効化し、RBAC Namespace Delegationを設定することで、Argo CDと同じくGitHub Teamsベースのリソース管理を強化
  3. Argo Workflows: デフォルトのService AccountとnamespaceごとのService Accountを設定し、最小限の権限でworkflowリソースを管理可能に
  4. DexやGitHub Teamを利用しない場合はArgo CD単体の設定を変更するだけで実現可能

皆さんのArgo CDおよびArgo Workflowsの運用に少しでも役立てば幸いです。さらに良い方法や工夫があれば、ぜひ共有してください!