Skip to content
Unified Defense StackUnified Defense Stack

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 pre-configures two Keycloak groups:

GroupPurpose
/UDS Core/AdminPlatform administrators with 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. For Authservice protection, also add enableAuthserviceSelector as described in Protect applications with Authservice.

    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/auth/callback"
    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 passes the group requirement to the Keycloak SSO client. UDS Core uses that client configuration to enforce group membership during authentication.

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. For these browser-based SSO flows, access should be denied during Keycloak authentication before the user reaches the application.

Verify the Keycloak client configuration for both integrations:

  1. In the Keycloak admin UI, open the client identified by clientId.
  2. Confirm that its uds.core.groups attribute contains the expected anyOf group paths.
  3. Test the login flow with an authorized and unauthorized user.

For Authservice-protected applications, you can additionally check the generated policy:

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

This policy confirms JWT and Authservice enforcement, but the uds.core.groups client attribute controls group membership. Native SSO does not create an Authservice chain.

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: UDS Core checks the user’s server-side Keycloak group membership during authentication. Confirm that:

  • The group exists at the exact path listed in groups.anyOf.
  • The user belongs to that group in Keycloak.
  • The user logs out and back in after a group membership change so Keycloak evaluates the updated membership.

The groups token claim does not control groups.anyOf enforcement, but application code can use it for fine-grained authorization after the platform grants access. To include the claim in tokens, see Register and customize SSO clients for the group membership mapper. To inspect token claims, use the Keycloak Account console at sso.<domain> or a tool like jwt.io.

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.