Skip to content

Identity and Access Management (IAM) Deployment Guide⚓︎

Currently, APISIX Ingress Controller is the only supported ingress controller for the IAM Building Block. The deployment guide will be updated to support other ingress controllers in the future.

The EOEPCA Identity and Access Management (IAM) Building Block provides secure authentication and authorisation for all platform services. It enables you to manage users, roles, policies, and integrate with external identity providers.

Key Features:

  • Central user management via Keycloak
  • Fine-grained policy decisions using OPA & OPAL
  • Integration with external IdPs (e.g., GitHub)
  • Enforcement of policies at the APISIX ingress layer

Prerequisites⚓︎

Component Requirement Documentation Link
Kubernetes Cluster (tested on v1.32) Installation Guide
Helm Version 3.5 or newer Installation Guide
kubectl Configured for cluster access Installation Guide
Ingress Controller Properly installed Installation Guide
TLS Certificates Managed via cert-manager or manually TLS Certificate Management Guide

Clone the Deployment Guide Repository:

git clone https://github.com/EOEPCA/deployment-guide
cd deployment-guide/scripts/iam

Check Prerequisites:

bash check-prerequisites.sh

If any checks fail, address them before proceeding.


Overview of Deployment Steps⚓︎

  1. Configure the IAM Environment: Provide ingress host, storage classes, etc.
  2. Deploy Keycloak: Set up the central identity provider.
  3. Create the eoepca Realm and Basic Users: Keep master for admin tasks only.
  4. (Optional) Integrate External IdPs: Add GitHub or other providers.
  5. Deploy OPA & OPAL: For advanced policy decisions.
  6. Set up Policies & Permissions: Restrict access to services as needed.
  7. Test & Validate: Confirm that IAM is working as intended.

For production, use proper TLS, stable storage, and consider external identity providers. For development, simpler self-signed certs and test credentials may suffice.


Step-by-Step Deployment⚓︎

1. Configure the IAM Deployment⚓︎

bash configure-iam.sh

Configuration Parameters

During the script execution, you will be prompted to provide:

  • INGRESS_HOST: Base domain for ingress hosts.
    • Example: example.com
  • PERSISTENT_STORAGECLASS: Kubernetes storage class for persistent volumes.
    • Example: standard
  • CLUSTER_ISSUER: Issuer for TLS certificates
    • Example: letsencrypt-http01-apisix

The script will also generate secure passwords for:

  • KEYCLOAK_ADMIN_PASSWORD: Password for the Keycloak admin account.
  • KEYCLOAK_POSTGRES_PASSWORD: Password for the Keycloak PostgreSQL database.
  • OPA_CLIENT_SECRET: Secret for the opa (Open Policy Agent) client in Keycloak

These credentials will be stored in a state file at ~/.eoepca/state.

2. Apply Secrets⚓︎

bash apply-secrets.sh

This creates Kubernetes secrets from the credentials generated earlier.

3. Deploy IAM Building Block⚓︎

helm repo add eoepca-dev https://eoepca.github.io/helm-charts-dev
helm repo update eoepca-dev
helm upgrade -i iam eoepca-dev/iam-bb \
  --version 2.0.0-rc2 \
  --namespace iam \
  --values generated-values.yaml \
  --create-namespace

Then apply the APISIX TLS resource:

kubectl apply -f apisix-tls.yaml

4. Create the eoepca Realm⚓︎

Get admin token

source ~/.eoepca/state
ACCESS_TOKEN=$( \
  curl -X POST "${HTTP_SCHEME}://auth.${INGRESS_HOST}/realms/master/protocol/openid-connect/token" \
    --silent --show-error \
    -d "username=${KEYCLOAK_ADMIN_USER=}" \
    --data-urlencode "password=${KEYCLOAK_ADMIN_PASSWORD}" \
    -d "grant_type=password" \
    -d "client_id=admin-cli" \
    | jq -r '.access_token' \
)
echo "Access Token: ${ACCESS_TOKEN:0:20}..."

Create realm

source ~/.eoepca/state
curl -X POST "${HTTP_SCHEME}://auth.${INGRESS_HOST}/admin/realms" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d @- <<EOF
{
  "realm": "${REALM}",
  "enabled": true,
  "displayName": "EOEPCA"
}
EOF

5. Establish Keycloak Management via Crossplane⚓︎

Using the Crossplane Keycloak provider, we create a Keycloak client that allows Crossplane to manage Keycloak resources declaratively via CRDs. This is established via the following steps:

  • Create a dedicated Keycloak client iam-management for Crossplane, with the necessary Realm Management roles (manage-users, manage-clients, manage-authorization, create-client)
  • Create the namespace iam-management for Crossplane Keycloak resources
  • Establish Crossplane Keycloak provider configuration to connect to Keycloak using the iam-management client - serving resources in the iam-management namespace

This provides the framework through which to manage the eoepca realm and its clients, by creation of Crossplane Keycloak resources in the iam-management namespace that will be satisfied by the Crossplane Keycloak provider.

5.1. Keycloak Client for Crossplane Provider⚓︎

Create a Keycloak client for the Crossplane Keycloak provider to allow it to interface with Keycloak. We create the client iam-management, which is used to perform administrative actions against the Keycloak API.

Use the create-client.sh script in the /scripts/utils/ directory. This script prompts you for basic details and automatically creates a Keycloak client in your chosen realm.

bash ../utils/create-client.sh

When prompted:

In many cases the default values (indicated '-') are acceptable.

Prompt Description iam-management
Keycloak Admin Username and Password Enter the credentials of your Keycloak admin user -
Ingress Host Platform base domain - e.g. ${INGRESS_HOST} -
Keycloak Host e.g. auth.${INGRESS_HOST} -
Realm Typically eoepca -
Confidential Client? Specify true to create a CONFIDENTIAL client true
Client ID Identifier for the client in Keycloak iam-management
Client Name Display name for the client - for example… IAM Management
Client Description Descriptive text for the client - for example… Management of Keycloak resource via Crossplane
Client secret Enter the Client Secret that was generated during the configuration script (check ~/.eoepca/state) ref. env IAM_MANAGEMENT_CLIENT_SECRET
Subdomain Redirect URL - Main service endpoint hostname as a prefix to INGRESS_HOST iam-management
Additional Subdomains Redirect URL - Additional Subdomain (prefix to INGRESS_HOST)
Comma-separated, or leave empty (e.g. service-api,service-swagger)
<blank>
Additional Hosts Redirect URL - Additional full hostnames (i.e. outside of INGRESS_HOST)
Comma-separated, or leave empty (e.g. service.some.platform)
<blank>

After it completes, you should see a JSON snippet confirming the newly created client.

The iam-management client requires specific realm-management roles to perform administrative actions against Keycloak.

Run the crossplane-client-roles.sh script in the /scripts/utils/ directory, providing the iam-management client ID as an argument:

bash ../utils/crossplane-client-roles.sh iam-management

The client is updated with the required roles.

5.2. Create Crossplane Keycloak Provider Configuration⚓︎

Now the Keycloak client is created, we can set up the Crossplane Keycloak provider configuration to connect to Keycloak using this client.

source ~/.eoepca/state
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: iam-management
---
apiVersion: v1
kind: Secret
metadata:
  name: iam-management-client
  namespace: iam-management
stringData:
  credentials: |
    {
      "client_id": "$IAM_MANAGEMENT_CLIENT_ID",
      "client_secret": "$IAM_MANAGEMENT_CLIENT_SECRET",
      "url": "http://iam-keycloak.iam",
      "base_path": "",
      "realm": "$REALM"
    }
---
apiVersion: keycloak.m.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
  name: provider-keycloak
  namespace: iam-management
spec:
  credentialsSecretRef:
    name: iam-management-client
    key: credentials
EOF

5.3. Create realm-management Client⚓︎

Register a Crossplane-managed representation of the built-in the realm-management Client.

Note that this client already exists in Keycloak by default - but we need a k8s Custom Resource in order to reference the client by name in other CRDs supported by the Keycloak Provider.

source ~/.eoepca/state
cat <<EOF | kubectl apply -f -
apiVersion: openidclient.keycloak.m.crossplane.io/v1alpha1
kind: Client
metadata:
  name: realm-management
  namespace: iam-management
spec:
  managementPolicies:
    - Observe
  forProvider:
    realmId: ${REALM}
    clientId: realm-management
  providerConfigRef:
    name: provider-keycloak
    kind: ProviderConfig
EOF

6. Create Test Users⚓︎

Test users (admin and normal user) are created with the usernames and password that were specified during IAM configuration. These users will be used for testing purposes throughout the deployment of other Building Blocks (BBs). You can configure the usernames and password as per your requirements. Defaults:

  • Admin User: eoepcaadmin
  • Normal User: eoepcauser
  • Password: eoepcapassword (both)

The users are created declaratively using the CRD defined by the Crossplane Keycloak provider. A Secret is used to inject the password securely.

Secret

source ~/.eoepca/state
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: test-user-password
  namespace: iam-management
stringData:
  password: ${KEYCLOAK_TEST_PASSWORD}
EOF
Users

source ~/.eoepca/state
for username in ${KEYCLOAK_TEST_ADMIN} ${KEYCLOAK_TEST_USER}; do
cat <<EOF | kubectl apply -f -
apiVersion: user.keycloak.m.crossplane.io/v1alpha1
kind: User
metadata:
  name: ${username}
  namespace: iam-management
spec:
  forProvider:
    realmId: eoepca
    username: ${username}
    email: ${username}@eoepca.org
    emailVerified: true
    firstName: ${username}
    lastName: Testuser
    initialPassword:
      - temporary: false
        valueSecretRef:
          name: test-user-password
          key: password
  providerConfigRef:
    name: provider-keycloak
    kind: ProviderConfig
EOF
done

7. Create the Keycloak Client for OPA⚓︎

A Keycloak client is required for the ingress protection of the OPA service. The client can be created using the Crossplane Keycloak provider via the Client CRD.

source ~/.eoepca/state
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: ${OPA_CLIENT_ID}-keycloak-client
  namespace: iam-management
stringData:
  client_secret: ${OPA_CLIENT_SECRET}
---
apiVersion: openidclient.keycloak.m.crossplane.io/v1alpha1
kind: Client
metadata:
  name: ${OPA_CLIENT_ID}
  namespace: iam-management
spec:
  forProvider:
    realmId: ${REALM}
    clientId: ${OPA_CLIENT_ID}
    name: Open Policy Agent
    description: Open Policy Agent OIDC
    enabled: true
    accessType: CONFIDENTIAL
    rootUrl: ${HTTP_SCHEME}://opa.${INGRESS_HOST}
    baseUrl: ${HTTP_SCHEME}://opa.${INGRESS_HOST}
    adminUrl: ${HTTP_SCHEME}://opa.${INGRESS_HOST}
    serviceAccountsEnabled: true
    directAccessGrantsEnabled: true
    standardFlowEnabled: true
    oauth2DeviceAuthorizationGrantEnabled: true
    useRefreshTokens: true
    authorization:
      - allowRemoteResourceManagement: false
        decisionStrategy: UNANIMOUS
        keepDefaults: true
        policyEnforcementMode: ENFORCING
    validRedirectUris:
      - "/*"
    webOrigins:
      - "/*"
    clientSecretSecretRef:
      name: ${OPA_CLIENT_ID}-keycloak-client
      key: client_secret
  providerConfigRef:
    name: provider-keycloak
    kind: ProviderConfig
EOF

6. Testing & Validation⚓︎

bash validation.sh

Check all pods:

kubectl get pods -n iam

Ensure all components (Keycloak, OPA, etc.) are running and accessible.

9. Test Suite Execution⚓︎

Run the IAM tests from the system test suite.

We only run the smoke tests here, since the full IAM tests rely upon the (example) protection of the Processing BB (OGC API Processes engine).

../../test-suite.sh -m smoketest test/iam

The test results are summarised to the file test-report.xml.

If the Processing BB (example) protection has been applied, then the full IAM test suite can be run:

../../test-suite.sh test/iam

Further Configuration & Usage⚓︎

For detailed steps on:

  • Creating and managing Keycloak clients
  • Integrating external IdPs
  • Applying advanced resource protection (groups, roles, OPA policies)
  • Using the device flow to obtain tokens in a script or notebook

Refer to the Client Administration and Advanced Configuration.

After deployment, the IAM exposes several endpoints for authentication, authorization, and administration. Replace ${INGRESS_HOST} with your actual ingress host domain in the URLs below.

Keycloak⚓︎

Keycloak Home Page:

  • URL: ${HTTP_SCHEME}://auth.${INGRESS_HOST}/

OpenID Connect Discovery Endpoint:

  • URL: ${HTTP_SCHEME}://auth.${INGRESS_HOST}/realms/${REALM}/.well-known/openid-configuration

OAuth 2.0 Authorization Endpoint:

  • URL: ${HTTP_SCHEME}://auth.${INGRESS_HOST}/realms/${REALM}/protocol/openid-connect/auth

OAuth 2.0 Token Endpoint:

  • URL: ${HTTP_SCHEME}://auth.${INGRESS_HOST}/realms/${REALM}/protocol/openid-connect/token

Administration Console:

  • URL: ${HTTP_SCHEME}://auth.${INGRESS_HOST}/admin/

Accessing the Administration Console:

  1. Retrieve Admin Credentials

    The admin credentials are stored in the state file. Retrieve them using:

    source ~/.eoepca/state
    echo "Username: $KEYCLOAK_ADMIN_USER"
    echo "Password: $KEYCLOAK_ADMIN_PASSWORD"
    
  2. Login to the Console

    Navigate to the Administration Console URL and log in with the retrieved credentials.

Open Policy Agent (OPA)⚓︎

OPA Endpoint:

  • URL: ${HTTP_SCHEME}://opa.${INGRESS_HOST}/

You can test policy evaluations by sending requests to OPA’s REST API.

Authenticate as test user eoepcauser

source ~/.eoepca/state
# Authenticate as test user `eoepcauser`
ACCESS_TOKEN=$( \
  curl --silent --show-error \
    -X POST \
    -d "username=${KEYCLOAK_TEST_USER}" \
    --data-urlencode "password=${KEYCLOAK_TEST_PASSWORD}" \
    -d "grant_type=password" \
    -d "client_id=${OPA_CLIENT_ID}" \
    -d "client_secret=${OPA_CLIENT_SECRET}" \
    "${HTTP_SCHEME}://auth.${INGRESS_HOST}/realms/${REALM}/protocol/openid-connect/token" | jq -r '.access_token' \
)
echo "Access Token: ${ACCESS_TOKEN:0:20}..."

Simple allow all test query…

curl -X GET "${HTTP_SCHEME}://opa.${INGRESS_HOST}/v1/data/example/allow_all" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json"

User bob is a privileged user…

curl -X POST "${HTTP_SCHEME}://opa.${INGRESS_HOST}/v1/data/example/privileged_user" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"input": {"identity": {"attributes": { "preferred_username": ["bob"]}}}}'

User larry is NOT a privileged user…

curl -X POST "${HTTP_SCHEME}://opa.${INGRESS_HOST}/v1/data/example/privileged_user" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"input": {"identity": {"attributes": { "preferred_username": ["larry"]}}}}'

User larry has a verified email…

curl -X POST "${HTTP_SCHEME}://opa.${INGRESS_HOST}/v1/data/example/email_verified" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"input": {"identity": {"attributes": { "preferred_username": ["larry"], "email_verified": ["true"]}}}}'

Validating Kubernetes Resources⚓︎

Ensure that all Kubernetes resources are running correctly.

kubectl get pods -n iam

Expected Output:

  • All pods should be in the Running state.
  • No pods should be in CrashLoopBackOff or Error states.

Cleanup⚓︎

To remove IAM components:

helm -n iam uninstall iam
kubectl delete ns iam

If you created custom clients or realms, remove them using the scripts in scripts/ or the instructions in the appendices.


Further Reading⚓︎