An experimental Keycloak deployment for the VEDA project.
config/src
- Configuration YAML files.keycloak/providers
- Custom Service Provider Interfaces.keycloak/themes
- Custom Keycloak themes.
We currently make use of the keycloak-config-cli to apply configuration at time of deployment.
keycloak-config-cli
is a Keycloak utility to ensure the desired configuration state for a realm based on a JSON/YAML file. The format of the JSON/YAML file based on the export realm format.
Configuration is stored within config/src
in YAML files for each Keycloak realm managed.
Important
At each deployment, the keycloak-config-cli will likely overwrite changes made outside of the configuration stored within this repository for a given realm.
Creating a client application within Keycloak is done by editing the config YAML for the realm.
A minimum example of a public client (ie a client that only runs within the frontend, such as single page application):
clients:
- clientId: grafana
name: Grafana
publicClient: true
rootUrl: https://example.com
redirectUris:
- https://example.com/*
webOrigins:
- https://example.com
protocol: openid-connect
fullScopeAllowed: true
For a private client (ie a client that runs within the frontend, such as single page application), a secret will automatically be created and injected into the configuration runtime environemt at time of deployment. This secret will be made avaiable at an environment variable of $SLUG_CLIENT_SECRET
where $SLUG
represents a slugify version of the clientId
value (e.g. a client with an id of stac-api
will have a secret available at STAC_API_CLIENT_SECRET
).
A minimum example of a private client (note publicClient: false
and secret
):
clients:
- clientId: grafana
name: Grafana
publicClient: false
secret: $(env:GRAFANA_CLIENT_SECRET)
rootUrl: https://example.com
redirectUris:
- https://example.com/*
webOrigins:
- https://example.com
protocol: openid-connect
fullScopeAllowed: true
Clients will typically have associated Scopes, Roles, and Groups.
- Scopes can be thought of as individual permissions used by a client.
- Roles are collections of permissions that enable a typical function (e.g. system administration)
- Groups are collections of users that we want to grant with roles.
An exmaple:
clients:
- clientId: grafana
# ... omitted for brevity
fullScopeAllowed: true
defaultClientScopes:
- web-origins
- acr
- profile
- roles
- basic
- email
- grafana:admin
- grafana:editor
- grafana:viewer
roles:
client:
grafana:
- name: Administrator
description: Grafana Administrator
- name: Editor
description: Grafana Editor
- name: Viewer
description: Grafana Viewer
clientScopeMappings:
grafana:
- clientScope: grafana:admin
roles:
- Administrator
- clientScope: grafana:editor
roles:
- Editor
- clientScope: grafana:viewer
roles:
- Viewer
clientScopes:
- name: grafana:admin
description: Admin access to Grafana
protocol: openid-connect
- name: grafana:editor
description: Editor access to Grafana
protocol: openid-connect
- name: grafana:viewer
description: Viewer access to Grafana
protocol: openid-connect
groups:
- name: System Administrators
clientRoles:
grafana:
- Administrator
- name: Developers
clientRoles:
grafana:
- Editor
- name: Data Editors
clientRoles:
grafana:
- Viewer
When a third party service operates as an Identity Provider (IdP, e.g. CILogon or GitHub) for Keycloak, we must register that IdP within the Keycloak configuration. This involves registering the IdP's OAuth client ID and client secret within Keycloak's configuration (along with additional information about the OAuth endpoints used within the login process).
At time of deployment, environment variables starting with IDP_SECRET_ARN_
will be treated as ARNs to Secrets stored within AWS Secrets Manager. These secrets should be JSON objects containing both an id
and secret
key. These values will be injected into the docker instance running the Keycloak Config CLI, making them avaiable under {CLIENTID}_CLIENT_ID
and {CLIENTID}_CLIENT_SECRET
environment variables, allowing for their usage within a Keycloak configuration YAML file.
Example of injecting an IdP OAuth2 Client Secret
For this example, let's imagine we're attempting to insert the Client ID and Client Secret for a Github Identity Provider. To achieve this, we would take the following steps:
-
Submit these values to AWS Secrets Manager:
$ aws secretsmanager \ create-secret \ --name veda-keycloak-github-idp-creds \ --secret-string '{"id": "cl13nt1d", "secret": "cl13ntS3cr3t!"}'
AWS will respond with the ARN of the newly created Secret.
-
Register the secret with the Github environment, named
IDP_SECRET_ARN_$CLIENTID
, where$CLIENTID
is a unique identifier for that IDP (for this example, we'll useGH
). This can be done via the Github CLI if run from within the project repo:# Add variable value for the current repository in an interactive prompt $ gh variable set IDP_SECRET_ARN_GH --env dev
-
Update the Github Actions workflow to inject this variable into the runtime environment when calling
cdk deploy
:- name: Deploy CDK to dev environment run: | cdk deploy --require-approval never --outputs-file outputs.json env: # ... + IDP_SECRET_ARN_GH: ${{ vars.IDP_SECRET_ARN_GH }}
-
The
id
andsecret
will now be available when configuring Keycloak. We can add a secrtion like the following to make use of these variables withconfig/src/master.yaml
:identityProviders: # GitHub with Org Check - alias: github-org-check # NOTE: this alias appears in the redirect_uri for the auth flow, update Github OAuth settings accordingly displayName: GitHub [NASA-IMPACT] providerId: github-org enabled: true updateProfileFirstLoginMode: on trustEmail: false storeToken: false addReadTokenRoleOnCreate: false authenticateByDefault: false linkOnly: false config: clientId: $(env:GH_CLIENT_ID) clientSecret: $(env:GH_CLIENT_SECRET) defaultScope: openid read:org user:email organization: nasa-impact caseSensitiveOriginalUsername: "false" syncMode: FORCE
Beyond configuration, customization of Keycloak (e.g. a custom Identity Providers) may require development of custom Service Provider Interfaces (SPIs).
Tip
See the Service Provider Interfaces section in the Server Developer Guide for more details about how to create custom themes.
Tip
See the theme section in the Server Developer Guide for more details about how to create custom themes.
npm run build
compile typescript to jsnpm run watch
watch for changes and compilenpm run test
perform the jest unit testsnpx cdk deploy
deploy this stack to your default AWS account/regionnpx cdk diff
compare deployed stack with current statenpx cdk synth
emits the synthesized CloudFormation template