4. Argo CD Projects 深度解析:Project 角色、权限模型、Source/Destination 限制、Sync Windows

Argo CD Project 是多租户隔离的核心资源边界。每个 Project 定义了一组逻辑上的应用集合,并强制约束这些应用可以使用的 Git 仓库(Source)、目标集群与命名空间(Destination)、同步行为(Sync Windows)以及 RBAC 权限。理解 Project 的深度机制,是构建安全多租户架构的前提。

4.1 Project 角色与权限模型

Argo CD 的 RBAC 模型以 Project 为粒度,通过 argocd-rbac-cm ConfigMap 定义角色绑定。每个 Project 可以拥有独立的角色集合,控制用户或组对 Project 内应用的 CRUD 操作。

角色 权限范围 典型操作
role:admin Project 内所有资源 创建/更新/删除应用、管理 Project 设置、触发同步
role:maintainer Project 内应用 更新应用参数、触发同步、查看状态
role:viewer Project 内应用 只读查看应用状态、同步历史、事件
自定义角色 按需定义 通过 RBAC 策略精确匹配操作与资源
关键实践: 为每个租户创建独立的 Project,并绑定 role:admin 给租户管理员,role:viewer 给审计人员。避免使用全局 role:admin 跨 Project 操作。

RBAC 策略示例(argocd-rbac-cm):

data:
  policy.csv: |
    p, role:tenant-admin, projects, get, my-project, allow
    p, role:tenant-admin, applications, *, my-project/*, allow
    p, role:tenant-viewer, projects, get, my-project, allow
    p, role:tenant-viewer, applications, get, my-project/*, allow
    g, alice, role:tenant-admin
    g, bob, role:tenant-viewer

4.2 Source 限制:控制代码来源

Source 限制定义了 Project 内的应用允许从哪些 Git 仓库或 Helm Chart 仓库拉取配置。这是防止恶意代码注入的第一道防线。

  • 允许的仓库列表: 通过 sourceRepos 字段指定,支持精确 URL 或通配符。
  • 拒绝默认: 如果 sourceRepos 为空,则 Project 内所有应用都无法创建,必须显式添加。
  • 路径限制: 可以进一步限制仓库内的子路径,例如只允许 https://git.example.com/team-a/*。
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-a-project
spec:
  sourceRepos:
  - 'https://git.example.com/team-a/*'
  - 'https://charts.example.com/team-a'
  # 拒绝所有其他仓库
安全警告: 避免使用 '*' 通配符开放所有仓库。如果必须使用,请结合 sourceNamespaces 或 admission webhook 做二次校验。

4.3 Destination 限制:控制部署目标

Destination 限制定义了应用可以部署到哪些 Kubernetes 集群和命名空间。这是多租户隔离的第二个关键维度。

字段 说明 示例
destinations 允许的目标集群与命名空间列表 server: https://kubernetes.default.svc
namespace: team-a-*
namespaceResourceWhitelist 允许在目标命名空间内创建的 Kubernetes 资源类型 Group: ''; Kind: 'Deployment'
namespaceResourceBlacklist 禁止在目标命名空间内创建的 Kubernetes 资源类型 Group: 'rbac.authorization.k8s.io'; Kind: 'ClusterRole'
spec:
  destinations:
  - namespace: 'team-a-*'
    server: 'https://kubernetes.default.svc'
  - namespace: 'team-a-*'
    server: 'https://cluster-2.example.com'
  namespaceResourceBlacklist:
  - group: 'rbac.authorization.k8s.io'
    kind: 'ClusterRole'
  - group: 'rbac.authorization.k8s.io'
    kind: 'ClusterRoleBinding'
最佳实践: 使用命名空间前缀(如 team-a-*)隔离租户,并利用 namespaceResourceBlacklist 禁止租户创建集群范围的资源(ClusterRole、ClusterRoleBinding、PersistentVolume 等)。

4.4 Sync Windows:控制同步时间窗口

Sync Windows 允许管理员定义 Project 内应用可以执行同步操作的时间段。这用于防止在业务高峰期或维护窗口外发生意外变更。

  • 窗口类型: allow(允许同步)或 deny(拒绝同步)。
  • 调度格式: 使用 cron 表达式或简单的时间范围(如 * * * * 1-5 表示工作日)。
  • 应用范围: 可以针对整个 Project 或特定应用(通过 applications 列表)。
  • 手动同步覆盖: 默认情况下,手动触发的同步也会受窗口限制,但可以通过 manualSync: true 允许管理员绕过。
spec:
  syncWindows:
  - kind: deny
    schedule: '* * * * 1-5'
    duration: 8h
    applications:
    - 'production-*'
    manualSync: false
  - kind: allow
    schedule: '* * * * 6,0'
    duration: 24h
    applications:
    - '*'
典型场景: 生产环境 Project 配置 deny 窗口在工作日 9:00-17:00 禁止自动同步,仅允许紧急手动同步(需审批)。开发环境 Project 不设窗口,允许随时同步。

4.5 综合架构:Project 资源边界

以下 SVG 图展示了单个 Project 如何通过 Source、Destination、Sync Windows 和 RBAC 构建完整的资源边界。

Argo CD Project 资源边界架构 AppProject team-a-project Source 限制 允许的 Git 仓库 允许的 Helm 仓库 路径白名单 Destination 限制 目标集群列表 命名空间白名单 资源类型黑名单 Sync Windows 允许/拒绝窗口 Cron 调度 应用范围 RBAC 权限 角色绑定 操作策略 资源范围 资源边界总结 Source + Destination + Sync Windows + RBAC 共同构成不可绕过的隔离边界

4.6 多 Project 隔离策略对比

策略 隔离粒度 管理复杂度 推荐场景
单 Project 多命名空间 命名空间级别 低 开发环境、信任度高的团队
每租户独立 Project Project 级别 中 多租户生产环境、合规要求
每应用独立 Project 应用级别 高 高安全环境、独立审计需求
推荐: 对于大多数多租户场景,采用“每租户独立 Project”策略,结合命名空间前缀隔离和资源黑名单,在安全性与运维成本之间取得平衡。

4.7 常见配置陷阱与修复

  • 陷阱: sourceRepos 使用 '*' 导致任意仓库可部署。
    修复: 明确列出允许的仓库 URL,并使用路径通配符限制子路径。
  • 陷阱: destinations 未限制命名空间,导致跨租户命名空间部署。
    修复: 使用命名空间前缀白名单,如 namespace: 'tenant-a-*'。
  • 陷阱: Sync Windows 未设置 manualSync: false,导致管理员可绕过窗口。
    修复: 对生产环境 Project 设置 manualSync: false,强制所有同步受窗口约束。
  • 陷阱: RBAC 策略中 projects, get 未限制 Project 名称,导致用户可查看所有 Project。
    修复: 在策略中明确指定 Project 名称,如 p, role:tenant-admin, projects, get, my-project, allow。
审计建议: 定期使用 argocd proj list 和 argocd proj get <project> 检查每个 Project 的 Source/Destination 限制是否仍然符合安全基线。任何宽泛规则(如 '*' 通配符)都应触发告警。