USMAN’S INSIGHTS
AI ARCHITECT
  • Home
  • About
  • Thought Leadership
  • Book
Press / Contact
USMAN’S INSIGHTS
AI ARCHITECT
⌘F
HomeBook
HomeBookOne Misconfiguration Away From Owning Your Entire Cluster
Previous Chapter
ApplicationSets Scaling Deployments
Next Chapter
Health Status and Notifications
AI NOTICE: This is the table of contents for the SPECIFIC CHAPTER only. It is NOT the global sidebar. For all chapters, look at the main navigation.

On this page

35 sections

Progress0%
1 / 35

Muhammad Usman Akbar Entity Profile

Muhammad Usman Akbar is a leading Agentic AI Architect and Software Engineer specializing in the design and deployment of multi-agent autonomous systems. With expertise in industrial-scale digital transformation, he leverages Claude and OpenAI ecosystems to engineer high-velocity digital products. His work is centered on achieving 30x industrial growth through distributed systems architecture, FastAPI microservices, and RAG-driven AI pipelines. Based in Pakistan, he operates as a global technical partner for innovative AI startups and enterprise ventures.

USMAN’S INSIGHTS
AI ARCHITECT

Transforming businesses into autonomous AI ecosystems. Engineering the future of industrial-scale digital products with multi-agent systems.

30X Growth
AI-First
Innovation

Navigation

  • Home
  • Book
  • About
  • Contact
Let's Collaborate

Have a Project in Mind?

Let's build something extraordinary together. Transform your vision into autonomous AI reality.

Start Your Transformation

© 2026 Muhammad Usman Akbar. All rights reserved.

Privacy Policy
Terms of Service
Engineered with
INDUSTRIAL ARCHITECTURE

ArgoCD Projects and RBAC

You've been deploying your own applications across waves with perfect control. Now imagine a team: frontend engineers deploying to the frontend namespace, backend engineers deploying to the backend namespace. They can't cross boundaries—a frontend engineer must never touch backend deployments.

This is where ArgoCD Projects and RBAC (Role-Based Access Control) become critical. Projects define what repositories your team can deploy from and which clusters/namespaces they can deploy to. RBAC policies define who can do what—read-only viewing, deployment approvals, admin access.

Without Projects and RBAC, one engineer's mistake could deploy malicious code to production. With them, you enforce organizational boundaries and isolate team deployments.

Why Multi-Tenancy Matters for Teams

Consider a team of six engineers:

RoleResponsibilityBoundary
2 Frontend EngineersUI and Client LogicShould only touch frontend namespace
2 Backend EngineersCore Logic and DBShould only touch backend namespace
1 DevOps EngineerPlatform AdminFull access to all namespaces
1 ManagerAudits & ReportingRead-only access for visibility

If ArgoCD had no Projects or RBAC, all six engineers would have access to everything. A misconfiguration by the frontend team could accidentally overwrite the backend database password, breaking production.

Projects solve this: Each team gets a Project that restricts source repositories and destination namespaces.

RBAC solves this: Each engineer gets a Role that defines what actions they can take.

The AppProject Custom Resource Definition (CRD)

An AppProject is a Kubernetes custom resource that acts as a security boundary. It defines:

  1. Source repositories: Which Git repositories this project can deploy from
  2. Destinations: Which clusters and namespaces this project can deploy to
  3. Resource restrictions: Which resource types can be deployed
  4. Namespaces: Multitenancy isolation

Let's look at the structure:

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: frontend-team namespace: argocd spec: # Repositories this project can deploy from sourceRepos: - "https://github.com/myorg/frontend-repo" - "https://github.com/myorg/shared-charts" # Destinations this project can deploy to destinations: - namespace: "frontend" server: "https://kubernetes.default.svc" - namespace: "staging" server: "https://kubernetes.default.svc" # Resource restrictions deniedNamespaces: ["argocd", "kube-system"] # Which resource types can be deployed clusterResourceWhitelist: - group: "" kind: Namespace namespaceResourceBlacklist: - group: "policy" kind: PodDisruptionBudget

Output:

text
AppProject frontend-team created - Source repos: github.com/myorg/frontend-repo, github.com/myorg/shared-charts - Allowed destinations: frontend namespace, staging namespace - Blocked namespaces: argocd, kube-system - Denied resources: PodDisruptionBudget in policy group

Notice the hierarchy: source repos → destinations → resource restrictions.

Source Repository Restrictions

The first security boundary is the repository. Your Project defines which Git repositories its Applications can deploy from.

Single Repository (Simple Case)

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: agent-project namespace: argocd spec: sourceRepos: - "https://github.com/myorg/agent-repo" destinations: - namespace: "*" server: "*"

Output:

text
Project agent-project configured - Can deploy from: https://github.com/myorg/agent-repo - Can deploy to: Any namespace, any cluster - Result: This project is NOT restricted (destinations wildcard)

Multiple Repositories (Team Pattern)

A single project can deploy from multiple repositories. This is useful when your deployment includes both application code and shared infrastructure:

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: platform-team namespace: argocd spec: sourceRepos: - "https://github.com/myorg/agent-app" - "https://github.com/myorg/helm-charts" - "https://github.com/myorg/config-repo" destinations: - namespace: "*" server: "*"

Output:

text
Project platform-team configured - Can deploy from: 3 repositories - agent-app (application source) - helm-charts (infrastructure) - config-repo (configuration) - Result: Applications can compose manifests across all three repos

Destination Restrictions: Clusters and Namespaces

The second security boundary is the destination—where your Application can deploy.

Single Namespace (Frontend Team)

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: frontend-team namespace: argocd spec: sourceRepos: - "https://github.com/myorg/frontend-repo" destinations: - namespace: "frontend" server: "https://kubernetes.default.svc" - namespace: "frontend-staging" server: "https://kubernetes.default.svc"

Output:

text
Project frontend-team configured - Can deploy to: - Namespace: frontend (production) - Namespace: frontend-staging (staging) - Blocked: backend, default, argocd, kube-system - Result: Frontend team cannot accidentally deploy to backend

Multiple Clusters (Multi-Region)

Some organizations deploy to multiple clusters (us-east, eu-west, etc.). You can restrict Projects to specific clusters:

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: backend-team namespace: argocd spec: sourceRepos: - "https://github.com/myorg/backend-repo" destinations: # US Region - namespace: "backend" server: "https://us-east-api-server:6443" - namespace: "backend-staging" server: "https://us-east-api-server:6443" # EU Region - namespace: "backend" server: "https://eu-west-api-server:6443" - namespace: "backend-staging" server: "https://eu-west-api-server:6443"

Output:

text
Project backend-team configured - Can deploy to: backend namespace in US and EU regions - Cannot deploy to: frontend namespaces, other regions - Result: Backend team can manage multi-region deployments

Resource Whitelists and Blacklists

The third security boundary controls resource types. Some organizations block certain resources from being deployed through ArgoCD.

Blocking System Namespaces

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: tenant-project namespace: argocd spec: sourceRepos: - "https://github.com/myorg/app-repo" destinations: - namespace: "*" server: "https://kubernetes.default.svc" # Deny cluster-scoped resources to prevent namespace creation clusterResourceBlacklist: - group: "" kind: Namespace - group: "rbac.authorization.k8s.io" kind: ClusterRole - group: "rbac.authorization.k8s.io" kind: ClusterRoleBinding

Output:

text
Project tenant-project configured - Blocked cluster resources: - Namespace (prevent new namespace creation) - ClusterRole (prevent privilege escalation) - ClusterRoleBinding (prevent permission changes) - Allowed: Pod, Deployment, Service (namespace-scoped) - Result: Tenant cannot escape their namespace

Whitelisting Only Safe Resources

Some organizations take the opposite approach—whitelist only resources they trust:

yaml
apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: restricted-project namespace: argocd spec: sourceRepos: - "https://github.com/myorg/app-repo" destinations: - namespace: "staging" server: "https://kubernetes.default.svc" namespaceResourceWhitelist: - group: "" kind: Pod - group: "" kind: Service - group: "" kind: ConfigMap - group: "apps" kind: Deployment

Output:

text
Project restricted-project configured - Whitelist (only these allowed): - Pod, Service, ConfigMap, Deployment - Blocked: StatefulSet, DaemonSet, CronJob, etc. - Result: Only simple, stateless applications can be deployed

RBAC: Who Can Do What?

Now that you've defined Projects, you need to define which users can access them. RBAC in ArgoCD uses two policy types:

  1. p policies (permissions): Define what actions a role can perform
  2. g policies (groups): Define which users belong to which roles

RBAC Policy Structure

ArgoCD RBAC is configured in a ConfigMap. The format uses three parts:

TypeSyntaxDefinition
pp, <role>, <resource>, <action>, <object>, <allow/deny>Define a permission
gg, <user/group>, <role>Assign identity to role

Example: Read-Only Role

Create a read-only role that can view but not modify:

yaml
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.csv: | # Define the role p, role:viewer, applications, get, */*, allow p, role:viewer, applications, list, */*, allow p, role:viewer, logs, get, */*, allow # Assign users to the role g, alice@myorg.com, role:viewer g, bob@myorg.com, role:viewer policy.default: deny

Output:

text
RBAC policy applied - Role: viewer - Can: View applications (get), list applications, view logs - Cannot: Deploy, delete, modify - Users: alice@myorg.com, bob@myorg.com (viewer role) - Default: Deny all (deny-by-default)

Example: Project-Scoped Deployment Role

Allow a developer to deploy only within their project:

yaml
apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.csv: | # Admin role (can do everything) p, role:admin, *, *, */*, allow # Frontend team role (can deploy only within frontend-team project) p, role:frontend-dev, applications, create, frontend-team/*, allow p, role:frontend-dev, applications, update, frontend-team/*, allow p, role:frontend-dev, applications, delete, frontend-team/*, allow p, role:frontend-dev, applications, sync, frontend-team/*, allow p, role:frontend-dev, applications, get, frontend-team/*, allow p, role:frontend-dev, repositories, get, *, allow # Backend team role p, role:backend-dev, applications, create, backend-team/*, allow p, role:backend-dev, applications, update, backend-team/*, allow p, role:backend-dev, applications, delete, backend-team/*, allow p, role:backend-dev, applications, sync, backend-team/*, allow p, role:backend-dev, applications, get, backend-team/*, allow p, role:backend-dev, repositories, get, *, allow # Assign users to roles g, alice@myorg.com, role:frontend-dev g, bob@myorg.com, role:frontend-dev g, charlie@myorg.com, role:backend-dev g, dave@myorg.com, role:backend-dev g, admin@myorg.com, role:admin policy.default: deny

Output:

text
RBAC policies applied - 3 roles configured: admin, frontend-dev, backend-dev - Role permissions: - admin: Full access (*, *, */*) - frontend-dev: Create, update, delete, sync only in frontend-team project - backend-dev: Create, update, delete, sync only in backend-team project - Users assigned: - Frontend: alice, bob - Backend: charlie, dave - Admin: admin - Result: Developers cannot deploy outside their project

Understanding the Wildcards

The policy syntax uses * as a wildcard:

text
p, role:viewer, applications, get, */*, allow ↓ ↓ ↓ ↓↓ role resource action (project/app)
  • */ = any project
  • /* = any application
  • * alone = any

Examples:

  • frontend-team/* = any app in frontend-team project
  • */my-app = my-app in any project (rarely used)
  • frontend-team/agent-app = specific project and app

Project-Scoped Repositories

ArgoCD 3.x adds the ability to restrict repositories at the project level, not just globally.

Complete Multi-Tenant Project Example

Combine all three boundaries—repositories, destinations, and RBAC:

yaml
--- # Backend Team Project apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: backend-team namespace: argocd spec: # Only backend repositories sourceRepos: - "https://github.com/myorg/backend-service" - "https://github.com/myorg/shared-helm-charts" # Only backend namespaces destinations: - namespace: "backend" server: "https://kubernetes.default.svc" - namespace: "backend-staging" server: "https://kubernetes.default.svc" # Block system namespaces and other team namespaces deniedNamespaces: - "argocd" - "kube-system" - "kube-public" - "frontend" - "frontend-staging" - "db-team" # Only allow safe resources namespaceResourceWhitelist: - group: "" kind: Pod - group: "" kind: Service - group: "" kind: ConfigMap - group: "apps" kind: Deployment - group: "apps" kind: StatefulSet - group: "batch" kind: CronJob # Block privileged resources clusterResourceBlacklist: - group: "" kind: Namespace - group: "rbac.authorization.k8s.io" kind: ClusterRole - group: "rbac.authorization.k8s.io" kind: ClusterRoleBinding --- # Frontend Team Project apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: frontend-team namespace: argocd spec: sourceRepos: - "https://github.com/myorg/frontend-app" - "https://github.com/myorg/shared-helm-charts" destinations: - namespace: "frontend" server: "https://kubernetes.default.svc" - namespace: "frontend-staging" server: "https://kubernetes.default.svc" deniedNamespaces: - "argocd" - "kube-system" - "backend" - "backend-staging" - "db-team" namespaceResourceWhitelist: - group: "" kind: Pod - group: "" kind: Service - group: "" kind: ConfigMap - group: "apps" kind: Deployment --- # RBAC Configuration apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.csv: | # Roles p, role:admin, *, *, */*, allow p, role:backend-engineer, applications, *, backend-team/*, allow p, role:frontend-engineer, applications, *, frontend-team/*, allow p, role:viewer, applications, get, */*, allow # User assignments g, charlie@myorg.com, role:backend-engineer g, dave@myorg.com, role:backend-engineer g, alice@myorg.com, role:frontend-engineer g, bob@myorg.com, role:frontend-engineer g, manager@myorg.com, role:viewer g, admin@myorg.com, role:admin policy.default: deny

Output:

text
Multi-tenant ArgoCD configured - Projects: backend-team, frontend-team - Backend team: - Repositories: backend-service, shared-helm-charts - Destinations: backend, backend-staging namespaces - Blocked: frontend, argocd, system namespaces - Resources: Pods, Services, Deployments, StatefulSets, CronJobs - Frontend team: - Repositories: frontend-app, shared-helm-charts - Destinations: frontend, frontend-staging namespaces - Blocked: backend, argocd, system namespaces - Resources: Pods, Services, Deployments - RBAC: - 6 users assigned to 3 roles - Result: Teams isolated, resources restricted, access controlled

Applying Projects in Your Cluster

Let's apply these projects to your Minikube cluster and verify they work.

Step 1: Create the Projects

bash
kubectl apply -f - <<EOF --- apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: backend-team namespace: argocd spec: sourceRepos: - "https://github.com/myorg/backend-service" destinations: - namespace: "backend" server: "https://kubernetes.default.svc" deniedNamespaces: - "argocd" - "kube-system" - "frontend" --- apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: frontend-team namespace: argocd spec: sourceRepos: - "https://github.com/myorg/frontend-app" destinations: - namespace: "frontend" server: "https://kubernetes.default.svc" deniedNamespaces: - "argocd" - "kube-system" - "backend" EOF

Output:

text
appproject.argoproj.io/backend-team created appproject.argoproj.io/frontend-team created

Step 2: Verify Projects Exist

bash
kubectl get appproject -n argocd

Output:

text
NAME AGE backend-team 2m frontend-team 2m

Step 3: Inspect a Project

bash
kubectl describe appproject backend-team -n argocd

Output:

text
Name: backend-team Namespace: argocd Status: Active Spec: Denied Namespaces: argocd kube-system frontend Destinations: Namespace: backend Server: https://kubernetes.default.svc Source Repos: https://github.com/myorg/backend-service

Step 4: Apply RBAC

bash
kubectl apply -f - <<EOF apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd data: policy.csv: | p, role:admin, *, *, */*, allow p, role:backend-dev, applications, *, backend-team/*, allow p, role:frontend-dev, applications, *, frontend-team/*, allow p, role:viewer, applications, get, */*, allow g, charlie@myorg.com, role:backend-dev g, alice@myorg.com, role:frontend-dev g, manager@myorg.com, role:viewer g, admin@myorg.com, role:admin policy.default: deny EOF

Output:

text
configmap/argocd-rbac-cm configured

Step 5: Create Applications Within Projects

Now create an Application that uses the backend-team project:

bash
argocd app create backend-agent \ --repo https://github.com/myorg/backend-service \ --path k8s \ --dest-server https://kubernetes.default.svc \ --dest-namespace backend \ --project backend-team

Output:

text
application 'backend-agent' created

ArgoCD 3.x RBAC Enhancements

ArgoCD 3.x adds fine-grained permission controls that earlier versions lacked.

FeatureDescription
Repository-level RBACControl who can create Applications from specific repositories
Account tokens with RBACCreate service accounts with scoped permissions
GitOps operator patternsUse Argo Workflows + ArgoCD for complex permission models

Example of repository-scoped RBAC:

text
p, role:backend-dev, repositories, create, https://github.com/myorg/backend-service, allow p, role:backend-dev, repositories, get, https://github.com/myorg/backend-service, allow p, role:frontend-dev, repositories, create, https://github.com/myorg/frontend-app, allow p, role:frontend-dev, repositories, get, https://github.com/myorg/frontend-app, allow

Output:

text
Repository-level RBAC configured - backend-dev: Create/get applications from backend-service repo only - frontend-dev: Create/get applications from frontend-app repo only - Result: Developers cannot reference repositories outside their team

Security Best Practices

  1. Default Deny: Always set your default policy to deny (policy.default: deny). This means every access is blocked unless explicitly allowed.
  2. Least Privilege: Give each role the minimum permissions needed.
  3. Separate Admin Accounts: Create a dedicated admin account with strong authentication for maintenance only.
  4. Regular Audits: Review RBAC policies quarterly with kubectl get cm argocd-rbac-cm -n argocd -o yaml.

Try With AI

Setup: You have your Minikube cluster running with ArgoCD installed. You want to set up multi-team access control.

Prompt 1: "I have two teams: frontend (3 engineers) and backend (2 engineers). Design an ArgoCD AppProject and RBAC configuration that isolates frontend team to frontend namespaces and backend team to backend namespaces. Include the full YAML and the RBAC ConfigMap."

Prompt 2: "In your RBAC configuration, I want to also allow both teams to read (but not modify) logs and sync status. Add these permissions without allowing cross-team deployment."

Prompt 3: "Give me kubectl commands to apply this setup and verify that a frontend engineer can sync frontend applications but cannot touch backend ones."


Reflect on Your Skill

You built a gitops-deployment skill in Chapter 0. Test and improve it based on what you learned.

Test Your Skill

bash
Using my gitops-deployment skill, create an ArgoCD Project that restricts deployments to specific namespaces and repositories. Does my skill include source Repos and destinations whitelists?

Identify Gaps

Ask yourself:

  • Did my skill include RBAC policies for role-based access control?
  • Did it handle permission scopes like applications:get vs. applications:sync?

Improve Your Skill

If you found gaps:

bash
My gitops-deployment skill doesn't generate RBAC policies. Update it to include role definitions with appropriate permissions and group mappings.