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:
Check Prerequisites:
If any checks fail, address them before proceeding.
Overview of Deployment Steps⚓︎
- Configure the IAM Environment: Provide ingress host, storage classes, etc.
- Deploy Keycloak: Set up the central identity provider.
- Create the
eoepcaRealm and Basic Users: Keepmasterfor admin tasks only. - (Optional) Integrate External IdPs: Add GitHub or other providers.
- Deploy OPA & OPAL: For advanced policy decisions.
- Set up Policies & Permissions: Restrict access to services as needed.
- 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⚓︎
Configuration Parameters
During the script execution, you will be prompted to provide:
INGRESS_HOST: Base domain for ingress hosts.- Example:
example.com
- Example:
PERSISTENT_STORAGECLASS: Kubernetes storage class for persistent volumes.- Example:
standard
- Example:
CLUSTER_ISSUER: Issuer for TLS certificates- Example:
letsencrypt-http01-apisix
- Example:
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 theopa(Open Policy Agent) client in Keycloak
These credentials will be stored in a state file at ~/.eoepca/state.
2. Apply Secrets⚓︎
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:
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-managementfor Crossplane, with the necessary Realm Management roles (manage-users,manage-clients,manage-authorization,create-client) - Create the namespace
iam-managementfor Crossplane Keycloak resources - Establish Crossplane Keycloak provider configuration to connect to Keycloak using the
iam-managementclient - serving resources in theiam-managementnamespace
This provides the framework through which to manage the
eoepcarealm and its clients, by creation of Crossplane Keycloak resources in theiam-managementnamespace 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.
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:
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
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⚓︎
Check all pods:
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).
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:
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:
-
Retrieve Admin Credentials
The admin credentials are stored in the state file. Retrieve them using:
-
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.
Expected Output:
- All pods should be in the
Runningstate. - No pods should be in
CrashLoopBackOfforErrorstates.
Cleanup⚓︎
To remove IAM components:
If you created custom clients or realms, remove them using the scripts in scripts/ or the instructions in the appendices.