ArgoCD: Multi-tenancy strategy

Geoffrey
14 min readAug 7, 2023

Introduction

When you decide to adopt ArgoCD in your organization, you usually start by letting all users do what they want until you go into production and notice that someone, by deleting their application, has deleted a namespace or CRDs :D
Ok, I’m being a bit dramatic but this use case is possible. That’s why you need to have multi-tenant strategy with access control.
I’m going to show you how you can implement such a strategy by taking advantage of ArgoCD’s native features.

As a bonus, I’ll offer you a Chart + ApplicationSet for implementing it in a large organization using an enterprise Agile framework (example SAfe).

ArgoCD multi-tenancy: the basics

AppProject

ArgoCD AppProject is your first resource for implementing multitenancy.
First, you need to ask yourself the following questions

You need first to ask you the following questions

  • Who ? Who can deploy
  • What ? What can be deployed ?
  • Where ? Where can my code be deployed ?(namespace, cluster)
  • From Where ? From which repository can the code be deployed, and also from which namespace (we’ll look at this feature later).

The AppProject Spec looks like this:

spec:
# Where ?
destinations:
- namespace: '*'
server: '*'
# From Where ?
sourceRepos:
- '*'
# What ?
clusterResourceWhitelist:
- group: '*'
kind: '*'
# Who
roles:
- name: admins
# ...

AppProject supports globs. As you can see from the example above, this AppProject lets you deploy everything anywhere and everywhere. This is the default project and, except for experimentation, should never be used!!!!
Even for administrators, I strongly recommend creating an AppProject with dedicated permissions.
Let’s look at a concrete example with a teamone:

  • Who ? The team one (Azure Active Directory ID is 00000000–0000–0000–0000–000000000000) will be readonly on this project
  • What ? Only namespace resources (no cluster resources)
  • Where ? A good practice that I recommend is to use the team name as namespace prefix. So here any namespace starting by teamone
  • From Where ? Team one is hosting repositories in https://github.com/organization/department/team-one/
# Source: argocd-team-configuration/templates/AppProject.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: teamone
spec:
description: Teamone components
sourceRepos:
- https://github.com/organization/department/team-one/*
destinations:
- namespace: teamone*
server: https://kubernetes.default.svc
namespaceResourceWhitelist:
- group: '*'
kind: '*'
roles:
- name: readonly
description: Teamone readonly role
policies:
- p, proj:teamone:readonly, applications, get, teamone/*, allow
groups:
- 00000000-0000-0000-0000-000000000000

ArgoCD RBACs

ArgoCD RBACs allows you to define roles with permissions. You can then attach group of users to theses roles.

RBACs can be set globally and per-project.

For global RBACs I recommend you to define only Platform admin role and default policy.

rbac:
policy.default: "role:cluster-reader"
policy.csv: |
g, ffffffff-ffff-ffff-ffff-ffffffffffff, role:readonly
# Allows all users to get clusters
p, role:cluster-reader, clusters, get, *, allow

In the above example our admins (Azure ID: ffffffff-ffff-ffff-ffff-ffffffffffff) will have the default readonly role. All other users will be able to list / get the clusters.

Projects RBACs allows you to define granular roles. For example you could imagine having:

  • User administrators, who can perform all actions on the applications belonging to your project.
  • Limited edition users who will be able to perform all actions on the applications belonging to your project, with the exception of creating, updating and deleting applications.
  • Read-only users, who can only obtain application content and read logs.

You can as well enforce Application globs to restrict on which Application a role can perform actions

Here are some examples:

# Readonly can get any application belonging to teamone project
p, proj:teamone:readonly, applications, get, teamone/*, allow

# RedSquad can perform any action on Application
# resources whose name starts with redsquad
# and which belong to the teamone project
p, proj:teamone:redsquad, applications, action/*, teamone/redsquad*, allow

Application in any namespace

Remember:

From Where ? From which repository code can be deployed and also from which namespace (we will see this feature later)

ArgoCD allows you to deploy Application (since 2.5) in different namespaces (other than the control plane namespace).
This allows admin to restrict AppProject usage to certain namespaces.

spec:
sourceNamespaces:
- team-one-cd

In the above example, only Application deployed in team-one-cd will be able to use this AppProject

Here is an explicative schema:

Implementation

Prerequisites

As prerequisite you need to enable Application in any namespace.

We will use argocd-* as namespace prefix. You need as well to define global rbacs.

If you are using helm you can do it like this:

configs:

# Configure oidc authentication
oidc.config: |
name: Azure
issuer: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0
clientID: 00000000-0000-0000-0000-000000000000
clientSecret: $argo-azure-secrets:AZURE_AD_SECRET
requestedIDTokenClaims:
groups:
essential: true
requestedScopes:
- openid
- profile
- email

# Configure Application and ApplicationSet in any namespace
params:
application.namespaces: argocd-*

# Global rbac
# Admin is readonly
# Default user is cluster reader (adjust if needed)
rbac:
policy.default: "role:cluster-reader"
policy.csv: |
g, ffffffff-ffff-ffff-ffff-ffffffffffff, role:readonly
# Allows all users to get clusters
p, role:cluster-reader, clusters, get, *, allow

AppProject per team

Let’s imagine we’re in an organization with an agile framework (like Safe) with entities (i.e. trains) divided into scrum teams (or squads).
We have the following roles:

  • A system team that will be the AppProject administrator
  • 3 agile teams (reqsquad, bluesquad, greensquad) who will be read-only on the whole project, but will have editing permissions on their respective applications.
  • A coordination team, with the system architect, product manager and production release manager (or RTE in Safe), who will be read-only on the entire project so that they can control the application.
  • A front-line incident management team, which will be read-only throughout the project.

Each project will use repositories in this format:

https://github.com/organization/${trainName}/*

Each squad will have Applications prefixed by the squad name:

redsquad-data
redsquad-customerone
...

The Application / ApplicationSet will be deployed in argocd-train-one namespace.

Let’s now create the AppProject

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: train-one
spec:
description: Train-One components
# From where ?
sourceRepos:
- https://github.com/organization/train-one/*
# Where ?
# Train one will be able to deploy to both argocd-train-one
# And any namespace prefixed by train-one
destinations:
- namespace: argocd-train-one
server: https://kubernetes.default.svc
- namespace: train-one*
server: https://kubernetes.default.svc
# What ?
# Only namespace resources are allowed
namespaceResourceWhitelist:
- group: '*'
kind: '*'
# From where ?
# train-one will be usable only from Application and ApplicationSet
# deployed in namespace argocd-train-one
sourceNamespaces:
- argocd-train-one

We need then to apply project RBACs:

  • For admins we want them to be able to create/delete/get/override/sync/update & perform any actions on Application deployed as part of project train-one. To make it simple we can take inspiration from the admin built-in policy
    - name: admins
description: train-one Admin role
policies:
- p, proj:train-one:admins, applications, create, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, delete, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, override, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, sync, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, update, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, action/*, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, create, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, update, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, delete, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, exec, create, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, projects, get, train-one, allow
- p, proj:train-one:admins, repositories, get, train-one/*, allow
- p, proj:train-one:admins, repositories, create, train-one/*, allow
- p, proj:train-one:admins, repositories, update, train-one/*, allow
- p, proj:train-one:admins, repositories, delete, train-one/*, allow
groups:
- 00000000-0000-0000-0000-000000000000

Please note that we force usage of namespace argocd-train-one when using train-one/argocd-train-one/*

  • For readonly we want users to be able to get applications, repositories and logs in applications:
    - name: frontline-readonly
description: train-one Readonly role for frontline
policies:
- p, proj:train-one:frontline-readonly, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:frontline-readonly, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:frontline-readonly, repositories, get, train-one/*, allow
groups:
- 22222222-2222-2222-2222-222222222222
  • For edit we want to be able to get/sync and perform any actions on Application that are prefixed by the squad name (example: red)
    - name: redsquad-edit
description: train-one Readonly role for redsquad
policies:
- p, proj:train-one:redsquad-edit, applications, get, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, applications, sync, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, applications, actions/*, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, logs, get, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, exec, create, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, repositories, get, train-one/*, allow
groups:
- 33333333-3333-3333-3333-333333333333

Make this configurable

Now we have in mind what we want to put in place let’s think about a chart.

apiVersion: v2
name: argocd-team-configuration
description: A chart to deploy team configuration

type: application

version: 0.1.0

The values:


id: project-id

# Defines the source Repos from which an applications can be deployed. It can use globs
sourceRepos: []
# - repo1
# - repo2

# Defines the list of Admins. It is a list of Azure AD security group UUIDs
# the key is an arbitrary name
admins: null
# admin-id-1: uuid1
# admin-id-2: uuid2

# Defines the additional namespaces on which a team can deploy. It can use globs
additionnalNamespaces: []
# - namespace1
# - namespace2

# Defines the list of readonly users with the associated Azure AD security group UUID and application glob (ie: customerone-* for all applications prefixed by customerone in team project)
# the key is an arbitrary name
readonly: null
# readonly-id-1:
# glob: application-glob*
# azureAdId: uuid
# readonly-id-2:
# glob: application-glob*
# azureAdId: uuid

# (Default null) Defines the list of edit users with the associated Azure AD security group UUID and application glob (ie: customerone-* for all applications prefixed by customerone in team project)
# the key is an arbitrary name
edit: null
# readonly-id-1:
# glob: application-glob*
# azureAdId: uuid
# readonly-id-2:
# glob: application-glob*
# azureAdId: uuid

The AppProject template:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: {{ .Values.id }}
spec:
description: {{ .Values.id | title }} components
sourceRepos:
{{ .Values.sourceRepos | toYaml | indent 4 }}
destinations:
- namespace: {{ printf "argocd-%s" .Values.id }}
server: https://kubernetes.default.svc
- namespace: {{ printf "%s*" .Values.id }}
server: https://kubernetes.default.svc
{{- if .Values.additionnalNamespaces }}
{{- range $additionnalNamespace := $.Values.additionnalNamespaces }}
- namespace: {{ $additionnalNamespace }}
server: https://kubernetes.default.svc
{{- end }}
{{- end }}
namespaceResourceWhitelist:
- group: '*'
kind: '*'
sourceNamespaces:
- {{ printf "argocd-%s" .Values.id }}
roles:
- name: admins
description: {{ printf "%s Admin role" .Values.id }}
policies:
- {{ printf "p, proj:%s:admins, applications, create, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applications, delete, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applications, get, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applications, override, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applications, sync, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applications, update, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applications, action/*, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applicationsets, get, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applicationsets, create, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applicationsets, update, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, applicationsets, delete, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, logs, get, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, exec, create, %s/argocd-%s/*, allow" .Values.id .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, projects, get, %s, allow" .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, repositories, get, %s/*, allow" .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, repositories, create, %s/*, allow" .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, repositories, update, %s/*, allow" .Values.id .Values.id }}
- {{ printf "p, proj:%s:admins, repositories, delete, %s/*, allow" .Values.id .Values.id }}
groups:
{{ $.Values.admins | values | toYaml | indent 8 }}
{{- if $.Values.readonly }}
{{- range $readonlyName, $readonlyConfig := $.Values.readonly }}
- name: {{ printf "%s-readonly" $readonlyName }}
description: {{ printf "%s Readonly role for %s" $.Values.id $readonlyName }}
policies:
- {{ printf "p, proj:%s:%s-readonly, applications, get, %s/argocd-%s/%s, allow" $.Values.id $readonlyName $.Values.id $.Values.id $readonlyConfig.glob }}
- {{ printf "p, proj:%s:%s-readonly, logs, get, %s/argocd-%s/%s, allow" $.Values.id $readonlyName $.Values.id $.Values.id $readonlyConfig.glob }}
- {{ printf "p, proj:%s:%s-readonly, repositories, get, %s/*, allow" $.Values.id $readonlyName $.Values.id }}
groups:
- {{ $readonlyConfig.azureAdId }}
{{- end }}
{{- end }}
{{- if $.Values.edit }}
{{- range $editName, $editConfig := $.Values.edit }}
- name: {{ printf "%s-edit" $editName }}
description: {{ printf "%s Edit role for %s" $.Values.id $editName }}
policies:
- {{ printf "p, proj:%s:%s-edit, applications, get, %s/argocd-%s/%s, allow" $.Values.id $editName $.Values.id $.Values.id $editConfig.glob }}
- {{ printf "p, proj:%s:%s-edit, applications, sync, %s/argocd-%s/%s, allow" $.Values.id $editName $.Values.id $.Values.id $editConfig.glob }}
- {{ printf "p, proj:%s:%s-edit, applications, actions/*, %s/argocd-%s/%s, allow" $.Values.id $editName $.Values.id $.Values.id $editConfig.glob }}
- {{ printf "p, proj:%s:%s-edit, logs, get, %s/argocd-%s/%s, allow" $.Values.id $editName $.Values.id $.Values.id $editConfig.glob }}
- {{ printf "p, proj:%s:%s-edit, exec, create, %s/argocd-%s/%s, allow" $.Values.id $editName $.Values.id $.Values.id $editConfig.glob }}
- {{ printf "p, proj:%s:%s-edit, repositories, get, %s/*, allow" $.Values.id $editName $.Values.id }}
groups:
- {{ $editConfig.azureAdId }}
{{- end }}
{{- end }}

An example of config with above example:

id: train-one

sourceRepos:
- https://github.com/organization/train-one/*

admins:
system-team: 00000000-0000-0000-0000-000000000000

readonly:
coordination:
glob: '*'
azureAdId: 11111111-1111-1111-1111-111111111111
frontline:
glob: '*'
azureAdId: 22222222-2222-2222-2222-222222222222
redsquad:
glob: '*'
azureAdId: 33333333-3333-3333-3333-333333333333
bluesquad:
glob: '*'
azureAdId: 44444444-4444-4444-4444-444444444444
greensquad:
glob: '*'
azureAdId: 55555555-5555-5555-5555-555555555555

edit:
redsquad:
glob: 'red-*'
azureAdId: 33333333-3333-3333-3333-333333333333
bluesquad:
glob: 'blue-*'
azureAdId: 44444444-4444-4444-4444-444444444444
greensquad:
glob: 'green-*'
azureAdId: 55555555-5555-5555-5555-555555555555

Another example with a simple scrum team

id: scrum-one

sourceRepos:
- https://github.com/organization/department/team-one/*

admins:
system-team: 00000000-0000-0000-0000-000000000000

An ApplicationSet to deploy it

If you want to put in place a self service so that teams can manage their own permission. You can create a git repository hosting project configurations where team can submit pull requests for their values that will be approved and merged by the platform team.

You can then create an ApplicationSet which will automate the deployment.

Example:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: team-configurations
namespace: argocd
labels:
owner: platform-team
spec:
goTemplate: true
generators:
- git:
repoURL: https://github.com/speedfl/argocd-reallife-samples.git
revision: HEAD
files:
- path: 'organization-multitenancy/configs/*.yaml'
template:
metadata:
name: '{{ index (splitList "." .path.filenameNormalized) 0 }}-team-configuration'
labels:
owner: platform-team
spec:
project: platform
sources:
- repoURL: https://github.com/speedfl/argocd-reallife-samples.git
targetRevision: HEAD
ref: values
- repoURL: https://github.com/speedfl/argocd-reallife-samples.git
targetRevision: HEAD
path: organization-multitenancy/chart
helm:
valueFiles:
- $values/{{ .path.path }}/{{.path.filename}}
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true

The result:

And the content:

---
# Source: argocd-team-configuration/templates/AppProject.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: train-one
spec:
description: Train-One components
sourceRepos:
- https://github.com/organization/train-one/*
destinations:
- namespace: argocd-train-one
server: https://kubernetes.default.svc
- namespace: train-one*
server: https://kubernetes.default.svc
namespaceResourceWhitelist:
- group: '*'
kind: '*'
sourceNamespaces:
- argocd-train-one
roles:
- name: admins
description: train-one Admin role
policies:
- p, proj:train-one:admins, applications, create, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, delete, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, override, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, sync, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, update, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applications, action/*, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, create, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, update, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, applicationsets, delete, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, exec, create, train-one/argocd-train-one/*, allow
- p, proj:train-one:admins, projects, get, train-one, allow
- p, proj:train-one:admins, repositories, get, train-one/*, allow
- p, proj:train-one:admins, repositories, create, train-one/*, allow
- p, proj:train-one:admins, repositories, update, train-one/*, allow
- p, proj:train-one:admins, repositories, delete, train-one/*, allow
groups:
- 00000000-0000-0000-0000-000000000000
- name: bluesquad-readonly
description: train-one Readonly role for bluesquad
policies:
- p, proj:train-one:bluesquad-readonly, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:bluesquad-readonly, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:bluesquad-readonly, repositories, get, train-one/*, allow
groups:
- 44444444-4444-4444-4444-444444444444
- name: coordination-readonly
description: train-one Readonly role for coordination
policies:
- p, proj:train-one:coordination-readonly, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:coordination-readonly, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:coordination-readonly, repositories, get, train-one/*, allow
groups:
- 11111111-1111-1111-1111-111111111111
- name: frontline-readonly
description: train-one Readonly role for frontline
policies:
- p, proj:train-one:frontline-readonly, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:frontline-readonly, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:frontline-readonly, repositories, get, train-one/*, allow
groups:
- 22222222-2222-2222-2222-222222222222
- name: greensquad-readonly
description: train-one Readonly role for greensquad
policies:
- p, proj:train-one:greensquad-readonly, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:greensquad-readonly, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:greensquad-readonly, repositories, get, train-one/*, allow
groups:
- 55555555-5555-5555-5555-555555555555
- name: redsquad-readonly
description: train-one Readonly role for redsquad
policies:
- p, proj:train-one:redsquad-readonly, applications, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:redsquad-readonly, logs, get, train-one/argocd-train-one/*, allow
- p, proj:train-one:redsquad-readonly, repositories, get, train-one/*, allow
groups:
- 33333333-3333-3333-3333-333333333333
- name: bluesquad-edit
description: train-one Edit role for bluesquad
policies:
- p, proj:train-one:bluesquad-edit, applications, get, train-one/argocd-train-one/blue-*, allow
- p, proj:train-one:bluesquad-edit, applications, sync, train-one/argocd-train-one/blue-*, allow
- p, proj:train-one:bluesquad-edit, applications, actions/*, train-one/argocd-train-one/blue-*, allow
- p, proj:train-one:bluesquad-edit, logs, get, train-one/argocd-train-one/blue-*, allow
- p, proj:train-one:bluesquad-edit, exec, create, train-one/argocd-train-one/blue-*, allow
- p, proj:train-one:bluesquad-edit, repositories, get, train-one/*, allow
groups:
- 44444444-4444-4444-4444-444444444444
- name: greensquad-edit
description: train-one Edit role for greensquad
policies:
- p, proj:train-one:greensquad-edit, applications, get, train-one/argocd-train-one/green-*, allow
- p, proj:train-one:greensquad-edit, applications, sync, train-one/argocd-train-one/green-*, allow
- p, proj:train-one:greensquad-edit, applications, actions/*, train-one/argocd-train-one/green-*, allow
- p, proj:train-one:greensquad-edit, logs, get, train-one/argocd-train-one/green-*, allow
- p, proj:train-one:greensquad-edit, exec, create, train-one/argocd-train-one/green-*, allow
- p, proj:train-one:greensquad-edit, repositories, get, train-one/*, allow
groups:
- 55555555-5555-5555-5555-555555555555
- name: redsquad-edit
description: train-one Edit role for redsquad
policies:
- p, proj:train-one:redsquad-edit, applications, get, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, applications, sync, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, applications, actions/*, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, logs, get, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, exec, create, train-one/argocd-train-one/red-*, allow
- p, proj:train-one:redsquad-edit, repositories, get, train-one/*, allow
groups:
- 33333333-3333-3333-3333-333333333333

The full example is here: https://github.com/speedfl/argocd-reallife-samples/tree/main/organization-multitenancy

Disclaimer

Please note that this is only a sample implementation. You must use these features according to your organization’s needs and restrictions (ie: Per env / per cluster / single argocd).

To implement multi-tenancy you mus as well to use:

  • Kubernetes RBAC
  • Workload / Storage / Network isolation
  • Quotas
  • Policies engine

--

--

Geoffrey

French guy 🥖 with a passion for cloud-native technologies, photography and wine