Skip to content

Enforce group-based access controls

You’ll restrict access to a UDS application so that only users in specific Keycloak groups can authenticate. Users who are not in the required group will be denied — even if they have a valid Keycloak account.

  • UDS Core deployed
  • Application deployed as a UDS Package with SSO and Authservice configured (see Protect non-OIDC apps with SSO)
  • Relevant Keycloak groups exist — either the built-in platform groups or custom groups you have created

UDS Core pre-configures two Keycloak groups:

GroupPurpose
/UDS Core/AdminPlatform administrators — full access to Grafana, Keycloak admin console, Alertmanager
/UDS Core/AuditorRead-only access to Grafana, log browsing

Application teams can define their own group paths. Group paths follow Keycloak’s hierarchy notation:

  • /ParentGroup/ChildGroup — nested groups use / as separator
  • If a group name itself contains a /, escape it with ~ (e.g., a group named a/b becomes a~/b)
  1. Identify the group path

    In the Keycloak admin UI (uds realm), go to Groups and locate the group you want to require. Note the full hierarchical path including any parent groups.

    For the built-in platform groups, the paths are:

    • /UDS Core/Admin
    • /UDS Core/Auditor
  2. Add groups.anyOf to your Package CR

    In your application’s Package CR, add a groups.anyOf list under the relevant SSO client. Users must be a member of at least one of the listed groups to be granted access.

    package.yaml
    apiVersion: uds.dev/v1alpha1
    kind: Package
    metadata:
    name: httpbin
    namespace: httpbin
    spec:
    sso:
    - name: Demo SSO
    clientId: uds-core-httpbin
    redirectUris:
    - "https://protected.uds.dev/login"
    enableAuthserviceSelector:
    app: httpbin
    groups:
    anyOf:
    - "/UDS Core/Admin"

    To allow multiple groups (users in any one of the listed groups are granted access):

    groups:
    anyOf:
    - "/UDS Core/Admin"
    - "/MyApp/Operators"
  3. Apply the Package CR

    Terminal window
    uds zarf tools kubectl apply -f package.yaml

    The UDS Operator reconciles the Package CR and updates the Authservice authorization policy to enforce group membership.

Confirm group-based access is enforced:

Test with an authorized user:

  1. Log in with a user who is a member of the required group
  2. Access should be granted to the application

Test with an unauthorized user:

  1. Log in with a user who is NOT a member of the required group
  2. Access should be denied with a 403 Forbidden response

Check the Authservice chain configuration:

Terminal window
uds zarf tools kubectl get authorizationpolicy -n <app-namespace>

Symptoms: Even users who should have access receive a 403.

Solution: Verify the group path in groups.anyOf is exactly correct:

  1. Log in to the Keycloak admin UI (uds realm)
  2. Go to Groups and navigate to the intended group
  3. Copy the full path including parent groups and leading /
  4. Compare it character-for-character with the value in your Package CR — paths are case-sensitive

Problem: Group membership does not match what’s in Keycloak

Section titled “Problem: Group membership does not match what’s in Keycloak”

Symptoms: A user is in the group in Keycloak but is still denied access.

Solution: Confirm the user’s group membership is included in the token. This can fail if:

  • The user’s group claim is not included in the SSO client’s default scopes — in the Keycloak admin UI, go to Clients → your client → Client Scopes and confirm the groups scope is assigned
  • The token was issued before the user was added to the group (the user needs to log out and log back in)

To inspect the token claims, use the Keycloak Account console at sso.<domain> to view recent tokens, or use a tool like jwt.io to decode a token.

Symptoms: Group path is not matching even though the group exists.

Solution: If the group name itself contains a / character (not a hierarchy separator), escape it with ~. For example, a group named a/b nested under ParentGroup would be written as /ParentGroup/a~/b.

These guides and concepts may be useful to explore next: