Two corrections on top of the naming pass, both found by checking the live cluster rather than the source. The rename had silently changed the user-facing annotation key from argocd.argoproj.io/sync-wave to cd.argoproj.io/sync-wave — 63 live Applications carry the old key, so deploying that would have ignored every sync-wave and broken fleet deploy ordering. The key is now cd.hanzo.ai/*, and universe 575650286 moves the ApplicationSet template that stamps it, so the controller regenerates all 63 consistently. The API group in code said argoproj.io/v1alpha1 in 157 places while the cluster has served apps.hanzo.ai/v1alpha1 since 2026-07-23 (the CRDs are applications.apps.hanzo.ai). Code now matches what is actually served. The legacy applications.argoproj.io/app-name label had ZERO live users, so it went with the rest. foo.argoproj.io test fixtures became foo.example.com — arbitrary test domains should not carry a vendor name. go build ./... exit 0. Co-authored-by: Hanzo Dev <[email protected]>
10 KiB
Okta
Note
Are you using this? Please contribute!
If you're using this IdP please consider contributing to this document.
A working Single Sign-On configuration using Okta via at least two methods was achieved using:
SAML (with Dex)
Note
Okta app group assignment
The Okta app's Group Attribute Statements regex will be used later to map Okta groups to Hanzo CD RBAC roles.
- Create a new SAML application in Okta UI.
- Click
View setup instructionsafter creating the application in Okta. - Copy the Hanzo CD URL to the
cd-cmin the data.url
data:
url: https://cd.example.com
- Download the CA certificate to use in the
cd-cmconfiguration.- If you are using this in the caData field, you will need to pass the entire certificate (including
-----BEGIN CERTIFICATE-----and-----END CERTIFICATE-----stanzas) through base64 encoding, for example,base64 my_cert.pem. - If you are using the ca field and storing the CA certificate separately as a secret, you will need to mount the secret to the
dexcontainer in thecd-dex-serverDeployment. 
- If you are using this in the caData field, you will need to pass the entire certificate (including
- Edit the
cd-cmand configure thedata.dex.configsection:
dex.config: |
logger:
level: debug
format: json
connectors:
- type: saml
id: okta
name: Okta
config:
ssoURL: https://yourorganization.oktapreview.com/app/yourorganizationsandbox_appnamesaml_2/rghdr9s6hg98s9dse/sso/saml
# You need `caData` _OR_ `ca`, but not both.
caData: |
<CA cert passed through base64 encoding>
# You need `caData` _OR_ `ca`, but not both.
# Path to mount the secret to the dex container
ca: /path/to/ca.pem
redirectURI: https://ui.cd.yourorganization.net/api/dex/callback
usernameAttr: email
emailAttr: email
groupsAttr: group
Private deployment
It is possible to setup Okta SSO with a private Hanzo CD installation, where the Okta callback URL is the only publicly exposed endpoint.
The settings are largely the same with a few changes in the Okta app configuration and the data.dex.config section of the cd-cm ConfigMap.
Using this deployment model, the user connects to the private Hanzo CD UI and the Okta authentication flow seamlessly redirects back to the private UI URL.
Often this public endpoint is exposed through an Ingress object.
- Update the URLs in the Okta app's General settings
- Update the
data.dex.configsection of thecd-cmConfigMap with the external endpoint reference.
dex.config: |
logger:
level: debug
connectors:
- type: saml
id: okta
name: Okta
config:
ssoURL: https://yourorganization.oktapreview.com/app/yourorganizationsandbox_appnamesaml_2/rghdr9s6hg98s9dse/sso/saml
# You need `caData` _OR_ `ca`, but not both.
caData: |
<CA cert passed through base64 encoding>
# You need `caData` _OR_ `ca`, but not both.
# Path to mount the secret to the dex container
ca: /path/to/ca.pem
redirectURI: https://external.path.to.cd.io/api/dex/callback
usernameAttr: email
emailAttr: email
groupsAttr: group
Connect Okta Groups to Hanzo CD Roles
Hanzo CD is aware of user memberships of Okta groups that match the Group Attribute Statements regex.
The example above uses the cd-* regex, so Hanzo CD would be aware of a group named cd-admins.
Modify the cd-rbac-cm ConfigMap to connect the cd-admins Okta group to the builtin Hanzo CD admin role.
apiVersion: v1
kind: ConfigMap
metadata:
name: cd-rbac-cm
data:
policy.csv: |
g, cd-admins, role:admin
scopes: '[email,groups]'
OIDC (without Dex)
Warning
Okta groups for RBAC
If you want
groupsscope returned from Okta, you will need to enable API Access Management with Okta. This addon is free, and automatically enabled, on Okta developer edition. However, it's an optional add-on for production environments, with an additional associated cost.You may alternately add a "groups" scope and claim to the default authorization server, and then filter the claim in the Okta application configuration. It's not clear if this requires the Authorization Server add-on.
If this is not an option for you, use the SAML (with Dex) option above instead.
Note
These instructions and screenshots are of Okta version 2023.05.2 E. You can find the current version in the Okta website footer.
First, create the OIDC integration:
- On the
Okta Adminpage, navigate to the Okta Applications atApplications > Applications. - Choose
Create App Integration, and chooseOIDC, and thenWeb Applicationin the resulting dialogues.
- Update the following:
App Integration nameandLogo- set these to suit your needs; they'll be displayed in the Okta catalogue.Sign-in redirect URLs: Addhttps://cd.example.com/auth/callback; replacingcd.example.comwith your Hanzo CD web interface URL.Sign-out redirect URIs: Addhttps://cd.example.com; substituting the correct domain name as above.- Either assign groups, or choose to skip this step for now.
- Leave the rest of the options as-is, and save the integration.

- Copy the
Client IDand theClient Secretfrom the newly created app; you will need these later.
Next, create a custom Authorization server:
- On the
Okta Adminpage, navigate to the Okta API Management atSecurity > API. - Click
Add Authorization Server, and assign it a name and a description. TheAudienceshould match your Hanzo CD URL -https://cd.example.com - Click
Scopes > Add Scope: - Click
Claims > Add Claim: - Click on
Access Policies>Add Policy.This policy will restrict how this authorization server is used. - Add a rule to the policy:
- Add a name;
defaultis a reasonable name for this rule. - Fine-tune the settings to suit your organization's security posture. Some ideas:
- Add a name;
- Finally, click
Back to Authorization Servers, and copy theIssuer URI. You will need this later.
CLI login
In order to login with the CLI cd login https://cd.example.com --sso, Okta requires a separate dedicated App Integration:
- Create a new
Create App Integration, and chooseOIDC, and thenSingle-Page Application. - Update the following:
App Integration nameandLogo- set these to suit your needs; they'll be displayed in the Okta catalogue.Sign-in redirect URLs: Addhttp://localhost:8085/auth/callback.Sign-out redirect URIs: Addhttp://localhost:8085.- Either assign groups, or choose to skip this step for now.
- Leave the rest of the options as-is, and save the integration.
- Copy the
Client IDfrom the newly created app;cliClientID: <Client ID>will be used in yourcd-cmConfigMap.
- Edit your Authorization Server
Access Policies:
If you haven't yet created Okta groups, and assigned them to the application integration, you should do that now:
- Go to
Directory > Groups - For each group you wish to add:
- Click
Add Group, and choose a meaningful name. It should match the regex or pattern you added to your customgroupclaim. - Click on the group (refresh the page if the new group didn't show up in the list).
- Assign Okta users to the group.
- Click on
Applicationsand assign the OIDC application integration you created to this group. - Repeat as needed.
- Click
Finally, configure Hanzo CD itself. Edit the cd-cm configmap:
url: https://cd.example.com
oidc.config: |
name: Okta
# this is the authorization server URI
issuer: https://example.okta.com/oauth2/aus9abcdefgABCDEFGd7
clientID: 0oa9abcdefgh123AB5d7
cliClientID: gfedcba0987654321GEFDCBA # Optional if using the CLI for SSO
clientSecret: ABCDEFG1234567890abcdefg
requestedScopes: ["openid", "profile", "email", "groups"]
requestedIDTokenClaims: {"groups": {"essential": true}}
You may want to store the clientSecret in a Kubernetes secret; see how to deal with SSO secrets for more details.








