docs/operator-manual/user-management/index.md
Once installed Argo CD has one built-in admin user that has full access to the system. It is recommended to use admin user only
for initial configuration and then switch to local users or configure SSO integration.
The local users/accounts feature serves two main use-cases:
[!NOTE] When you create local users, each of those users will need additional RBAC rules set up, otherwise they will fall back to the default policy specified by
policy.defaultfield of theargocd-rbac-cmConfigMap.
The maximum length of a local account's username is 32.
New users should be defined in argocd-cm ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
# add an additional local user with apiKey and login capabilities
# apiKey - allows generating API keys
# login - allows to login using UI
accounts.alice: apiKey, login
# disables user. User is enabled by default
accounts.alice.enabled: "false"
Each user might have two capabilities:
In order to delete a user, you must remove the corresponding entry defined in the argocd-cm ConfigMap:
Example:
kubectl patch -n argocd cm argocd-cm --type='json' -p='[{"op": "remove", "path": "/data/accounts.alice"}]'
It is recommended to also remove the password entry in the argocd-secret Secret:
Example:
kubectl patch -n argocd secrets argocd-secret --type='json' -p='[{"op": "remove", "path": "/data/accounts.alice.password"}]'
As soon as additional users are created it is recommended to disable admin user:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
admin.enabled: "false"
The Argo CD CLI provides set of commands to set user password and generate tokens.
argocd account list
argocd account get --account <username>
# if you are managing users as the admin user, <current-user-password> should be the current admin password.
argocd account update-password \
--account <name> \
--current-password <current-user-password> \
--new-password <new-user-password>
# if flag --account is omitted then Argo CD generates token for current user
argocd account generate-token --account <username>
Argo CD rejects login attempts after too many failed in order to prevent password brute-forcing. The following environments variables are available to control throttling settings:
ARGOCD_SESSION_FAILURE_MAX_FAIL_COUNT: Maximum number of failed logins before Argo CD starts
rejecting login attempts. Default: 5.
ARGOCD_SESSION_FAILURE_WINDOW_SECONDS: Number of seconds for the failure window.
Default: 300 (5 minutes). If this is set to 0, the failure window is
disabled and the login attempts gets rejected after 10 consecutive logon failures,
regardless of the time frame they happened.
ARGOCD_SESSION_MAX_CACHE_SIZE: Maximum number of entries allowed in the
cache. Default: 1000
ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT: Limits max number of concurrent login requests.
If set to 0 then limit is disabled. Default: 50.
There are two ways that SSO can be configured:
Bundled Dex OIDC provider - use this option if your current provider does not support OIDC (e.g. SAML, LDAP) or if you wish to leverage any of Dex's connector features (e.g. the ability to map GitHub organizations and teams to OIDC groups claims). Dex also supports OIDC directly and can fetch user information from the identity provider when the groups cannot be included in the IDToken.
Existing OIDC provider - use this if you already have an OIDC provider which you are using (e.g. Okta, OneLogin, Auth0, Microsoft, Keycloak, Google (G Suite)), where you manage your users, groups, and memberships.
Argo CD embeds and bundles Dex as part of its installation, for the
purpose of delegating authentication to an external identity provider. Multiple types of identity
providers are supported (OIDC, SAML, LDAP, GitHub, etc...). SSO configuration of Argo CD requires
editing the argocd-cm ConfigMap with
Dex connector settings.
This document describes how to configure Argo CD SSO using GitHub (OAuth2) as an example, but the steps should be similar for other identity providers.
In GitHub, register a new application. The callback address should be the /api/dex/callback
endpoint of your Argo CD URL (e.g. https://argocd.example.com/api/dex/callback).
After registering the app, you will receive an OAuth2 client ID and secret. These values will be inputted into the Argo CD configmap.
Edit the argocd-cm configmap:
kubectl edit configmap argocd-cm -n argocd
url key, input the base URL of Argo CD. In this example, it is https://argocd.example.comadditionalUrls key.dex.config key, add the github connector to the connectors sub field. See Dex's
GitHub connector
documentation for explanation of the fields. A minimal config should populate the clientID,
clientSecret generated in Step 1.connectors.config.orgs list, add one or more GitHub organizations. Any member of the org will
then be able to login to Argo CD to perform management tasks.data:
url: https://argocd.example.com
dex.config: |
connectors:
# GitHub example
- type: github
id: github
name: GitHub
config:
clientID: aabbccddeeff00112233
clientSecret: $dex.github.clientSecret # Alternatively $<some_K8S_secret>:dex.github.clientSecret
orgs:
- name: your-github-org
# GitHub enterprise example
- type: github
id: acme-github
name: Acme GitHub
config:
hostName: github.acme.example.com
clientID: abcdefghijklmnopqrst
clientSecret: $dex.acme.clientSecret # Alternatively $<some_K8S_secret>:dex.acme.clientSecret
orgs:
- name: your-github-org
After saving, the changes should take effect automatically.
NOTES:
redirectURI in the connectors.config as shown in the dex documentation.
Argo CD will automatically use the correct redirectURI for any OAuth2 connectors, to match the
correct external callback URL (e.g. https://argocd.example.com/api/dex/callback)Secret keys such as dex.acme.clientSecret will be looked up in argocd-secret. If you want to use another secret, (some_K8S_secret in the example above), it must have the label app.kubernetes.io/part-of: argocd.Dex can be used for OIDC authentication instead of ArgoCD directly. This provides a separate set of
features such as fetching information from the UserInfo endpoint and
federated tokens
argocd-cm ConfigMap add the OIDC connector to the connectors sub field inside dex.config.
See Dex's OIDC connect documentation to see what other
configuration options might be useful. We're going to be using a minimal configuration here..well-known/openid-configuration under this URL which has information about what the provider supports.
e.g. https://accounts.google.com/.well-known/openid-configurationdata:
url: "https://argocd.example.com"
dex.config: |
connectors:
# OIDC
- type: oidc
id: oidc
name: OIDC
config:
issuer: https://example-OIDC-provider.example.com
clientID: aaaabbbbccccddddeee
clientSecret: $dex.oidc.clientSecret
By default Dex only retrieves the profile and email scopes. In order to retrieve more claims you
can add them under the scopes entry in the Dex configuration. To enable group claims through Dex,
insecureEnableGroups also needs to be enabled. Group information is currently only refreshed at authentication
time and support to refresh group information more dynamically can be tracked here: dexidp/dex#1065.
data:
url: "https://argocd.example.com"
dex.config: |
connectors:
# OIDC
- type: oidc
id: oidc
name: OIDC
config:
issuer: https://example-OIDC-provider.example.com
clientID: aaaabbbbccccddddeee
clientSecret: $dex.oidc.clientSecret
insecureEnableGroups: true
scopes:
- profile
- email
- groups
[!WARNING] Because group information is only refreshed at authentication time just adding or removing an account from a group will not change a user's membership until they reauthenticate. Depending on your organization's needs this could be a security risk and could be mitigated by changing the authentication token's lifetime.
When an Idp does not or cannot support certain claims in an IDToken they can be retrieved separately using
the UserInfo endpoint. Dex supports this functionality using the getUserInfo endpoint. One of the most
common claims that is not supported in the IDToken is the groups claim and both getUserInfo and insecureEnableGroups
must be set to true.
data:
url: "https://argocd.example.com"
dex.config: |
connectors:
# OIDC
- type: oidc
id: oidc
name: OIDC
config:
issuer: https://example-OIDC-provider.example.com
clientID: aaaabbbbccccddddeee
clientSecret: $dex.oidc.clientSecret
insecureEnableGroups: true
scopes:
- profile
- email
- groups
getUserInfo: true
To configure Argo CD to delegate authentication to your existing OIDC provider, add the OAuth2
configuration to the argocd-cm ConfigMap under the oidc.config key:
data:
url: https://argocd.example.com
oidc.config: |
name: Okta
issuer: https://dev-123456.oktapreview.com
clientID: aaaabbbbccccddddeee
clientSecret: $oidc.okta.clientSecret
# Optional list of allowed aud claims. If omitted or empty, defaults to the clientID value above (and the
# cliClientID, if that is also specified). If you specify a list and want the clientID to be allowed, you must
# explicitly include it in the list.
# Token verification will pass if any of the token's audiences matches any of the audiences in this list.
allowedAudiences:
- aaaabbbbccccddddeee
- qqqqwwwweeeerrrrttt
# Optional. If false, tokens without an audience will always fail validation. If true, tokens without an audience
# will always pass validation.
# Defaults to true for Argo CD < 2.6.0. Defaults to false for Argo CD >= 2.6.0.
skipAudienceCheckWhenTokenHasNoAudience: true
# Optional set of OIDC scopes to request. If omitted, defaults to: ["openid", "profile", "email", "groups"]
requestedScopes: ["openid", "profile", "email", "groups"]
# Optional set of OIDC claims to request on the ID token.
requestedIDTokenClaims: {"groups": {"essential": true}}
# Some OIDC providers require a separate clientID for different callback URLs.
# For example, if configuring Argo CD with self-hosted Dex, you will need a separate client ID
# for the 'localhost' (CLI) client to Dex. This field is optional. If omitted, the CLI will
# use the same clientID as the Argo CD server
cliClientID: vvvvwwwwxxxxyyyyzzzz
# PKCE is an OIDC extension to prevent authorization code interception attacks.
# Make sure the identity provider supports it and that it is activated for Argo CD OIDC client.
# Default is false.
enablePKCEAuthentication: true
[!NOTE] The callback address should be the /auth/callback endpoint of your Argo CD URL (e.g. https://argocd.example.com/auth/callback).
Not all OIDC providers support a special groups scope. E.g. Okta, OneLogin and Microsoft do support a special
groups scope and will return group membership with the default requestedScopes.
Other OIDC providers might be able to return a claim with group membership if explicitly requested to do so.
Individual claims can be requested with requestedIDTokenClaims, see
OpenID Connect Claims Parameter
for details. The Argo CD configuration for claims is as follows:
oidc.config: |
requestedIDTokenClaims:
email:
essential: true
groups:
essential: true
value: org:myorg
acr:
essential: true
values:
- urn:mace:incommon:iap:silver
- urn:mace:incommon:iap:bronze
For a simple case this can be:
oidc.config: |
requestedIDTokenClaims: {"groups": {"essential": true}}
Some OIDC providers don't return the group information for a user in the ID token, even if explicitly requested using the requestedIDTokenClaims setting (Okta for example). They instead provide the groups on the user info endpoint. With the following config, Argo CD queries the user info endpoint during login for groups information of a user:
oidc.config: |
enableUserInfoGroups: true
userInfoPath: /userinfo
userInfoCacheExpiration: "5m"
Note: If you omit the userInfoCacheExpiration setting or if it's greater than the expiration of the ID token, the argocd-server will cache group information as long as the ID token is valid!
Optionally, if your OIDC provider exposes a logout API and you wish to configure a custom logout URL for the purposes of invalidating any active session post logout, you can do so by specifying it as follows:
oidc.config: |
name: example-OIDC-provider
issuer: https://example-OIDC-provider.example.com
clientID: xxxxxxxxx
clientSecret: xxxxxxxxx
requestedScopes: ["openid", "profile", "email", "groups"]
requestedIDTokenClaims: {"groups": {"essential": true}}
logoutURL: https://example-OIDC-provider.example.com/logout?id_token_hint={{token}}
By default, this would take the user to their OIDC provider's login page after logout. If you also wish to redirect the user back to Argo CD after logout, you can specify the logout URL as follows:
...
logoutURL: https://example-OIDC-provider.example.com/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}}
You are not required to specify a logoutRedirectURL as this is automatically generated by ArgoCD as your base ArgoCD url + Rootpath
[!NOTE] The post logout redirect URI may need to be whitelisted against your OIDC provider's client settings for ArgoCD.
Argo CD implements server-side token revocation to enhance security when users log out. This is particularly important for SSO configurations using Dex or other OIDC providers.
When a user logs out (either via the UI or CLI using argocd logout), Argo CD:
Revoked tokens cannot be used for API calls, even if they haven't expired yet. This prevents:
The argocd logout command will gracefully handle scenarios where the server is unreachable:
$ argocd logout my-argocd-server
WARN[0000] Failed to invalidate token on server: connection refused. Proceeding with local logout.
Logged out from 'my-argocd-server'
This allows users to logout locally even if the server is down, though the token will not be revoked server-side until it expires naturally.
1.Use short-lived tokens: Configure reasonable token expiration times in the OIDC provider to limit the window of exposure
2.Enable logout URLs: Configure logoutURL in oidc.config for your OIDC provider to ensure SSO sessions are also terminated
3.Monitor token usage: Use Argo CD's audit logging to track token creation and revocation events
If your OIDC provider is setup with a certificate which is not signed by one of the well known certificate authorities
you can provide a custom certificate which will be used in verifying the OIDC provider's TLS certificate when
communicating with it.
Add a rootCA to your oidc.config which contains the PEM encoded root certificate:
oidc.config: |
...
rootCA: |
-----BEGIN CERTIFICATE-----
... encoded certificate data here ...
-----END CERTIFICATE-----
argocd-secret can be used to store sensitive data which can be referenced by ArgoCD. Values starting with $ in configmaps are interpreted as follows:
$<secret>:a.key.in.k8s.secret, look for a k8s secret with the name <secret> (minus the $), and read its value.argocd-secret.SSO clientSecret can thus be stored as a Kubernetes secret with the following manifests
argocd-secret:
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
namespace: argocd
labels:
app.kubernetes.io/name: argocd-secret
app.kubernetes.io/part-of: argocd
type: Opaque
data:
...
# The secret value must be base64 encoded **once**
# this value corresponds to: `printf "hello-world" | base64`
oidc.auth0.clientSecret: "aGVsbG8td29ybGQ="
...
argocd-cm:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
...
oidc.config: |
name: Auth0
clientID: aabbccddeeff00112233
# Reference key in argocd-secret
clientSecret: $oidc.auth0.clientSecret
...
If you want to store sensitive data in another Kubernetes Secret, instead of argocd-secret. ArgoCD knows to check the keys under data in your Kubernetes Secret for a corresponding key whenever a value in a configmap or secret starts with $, then your Kubernetes Secret name and : (colon).
Syntax: $<k8s_secret_name>:<a_key_in_that_k8s_secret>
[!NOTE] Secret must have label
app.kubernetes.io/part-of: argocd
another-secret:
apiVersion: v1
kind: Secret
metadata:
name: another-secret
namespace: argocd
labels:
app.kubernetes.io/part-of: argocd
type: Opaque
data:
...
# Store client secret like below.
# Ensure the secret is base64 encoded
oidc.auth0.clientSecret: <client-secret-base64-encoded>
...
argocd-cm:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
...
oidc.config: |
name: Auth0
clientID: aabbccddeeff00112233
# Reference key in another-secret (and not argocd-secret)
clientSecret: $another-secret:oidc.auth0.clientSecret # Mind the ':'
...
By default, all connections made by the API server to OIDC providers (either external providers or the bundled Dex instance) must pass certificate validation. These connections occur when getting the OIDC provider's well-known configuration, when getting the OIDC provider's keys, and when exchanging an authorization code or verifying an ID token as part of an OIDC login flow.
Disabling certificate verification might make sense if:
oidcConfig.rootCA and you understand and accept the risks of skipping OIDC provider cert
verification.If either of those two applies, then you can disable OIDC provider certificate verification by setting
oidc.tls.insecure.skip.verify to "true" in the argocd-cm ConfigMap.