Managing access to all of your internal systems can be a real pain in the neck. Many companies are turning to services such as Okta, OneLogin, JumpCloud, et. al to bring user management under control. When it comes to on-premise solutions, there are a few well-respected offerings – one of them being the open-source, RedHat-sponsored application KeyCloak.

In this article, we will configure Hashicorp Vault and KeyCloak so that users can log into Vault using their KeyCloak credentials.
Prerequisites
- A running Hashicorp Vault installation with root token or admin-level token
- A running KeyCloak installation with admin access
- Terraform Open Source
- Editor of your choosing
Create a Vault Admin group in KeyCloak
We will create a group within Keycloak called “vault-admin”. Later on, we will associate this group with a role within Vault that allows users to perform some administrative tasks.

Add a group
We will create the vault-admin group with KeyCloak.
- From the Keycloak Administrative Interface, click on Manage >> Groups
- Click the New button
- Enter “vault-admin”
- Click on Save
Add User to vault-admin group
We will add your user to the vault-admin group.
- From the KeyCloak Administrative Interface, click on Manage >> Users
- Highlight the “vault-admin” group under the Available Groups
- Click Join
Create Vault Client within KeyCloak
In order for Vault use KeyCloak as an identity provider (IdP), we must create a unique OpenID Connect (OIDC) client. This will create a set of application credentials that will allow Vault to participate in OAuth and read user token information.
Add a client for Vault

To to create a new client:
- Within the KeyCloak Admin console, click on Configure >> Clients
- Click the Create button
- Fill out the form accordingly:
- Client ID: Your choice. “vault-demo” is used throughout this example.
- Client Protocol: openid-connect
- Click the Save button
This will provide an initial client configuration. There will be more settings to configure at this point.
Configure the Vault client
After creating the client in the step above, you should now be redirected to the client’s Settings tab.
Fill out the form accordingly:
- Access Type: confidential
- Root URL: https://[[YOUR_VAULT_ADDR]]
- Base URL: https://[[YOUR_VAULT_ADDR]]
- Web Origins: https://[[YOUR_VAULT_ADDR]]
- Valid Redirect URIs:
- http://localhost:8250/oidc/callback
- https://[[YOUR_VAULT_ADDR]]/ui/vault/auth/oidc/oidc/callback
- Click the Save button at the bottom of the page
Map Groups to User token claim
In this implementation, we want members of the “vault-admin” KeyCloak group to be assigned a corresponding Vault role. In order to achieve this, we need to include group membership into the tokens issued by the KeyCloak client. In KeyCloak we need to setup a “Mapper”, a little automated snippet that knows how to include groups in the user token scope.

- Within the client configuration page, click the Mappers tab
- Click the Create button
- Fill out the form accordingly:
- Name: groups
- Mapper Type: Group Membership
- Token Claim Name: groups
- Full group path: OFF
- Click the Save button.
This will create a claim (field on the user token) called “groups” and will map a user’s KeyCloak groups to this list automatically.
Validate the User token scope
Now that we configured the group membership mapper, let’s verify that this is properly configured.

- Within the KeyCloak console, go to Configure >> Clients >> Your client (vault-demo)
- Click on the Client Scopes tab
- Click on the Evaluate sub-tab
- Change the User selector to your user
- Click the Evaluate button
- Click the Generated ID Token tab at the bottom of the page
We are now presented with a JSON representation of the User ID Token for your user.
{
"exp": 1234845375,
"iat": 1234845315,
"auth_time": 0,
"jti": "abc123-5958-4a69-4fda-c93025bd258d",
"iss": "https://keycloak.fqdn.com/auth/realms/master",
"aud": "vault-demo",
"sub": "e0118be4-7bee-4ef7-a6b3-deadbeefcafe",
"typ": "ID",
"azp": "vault-demo",
"session_state": "0167d412-efc5-4d79-9622-2b24bd96368d",
"acr": "1",
"sid": "deadbeef-efc5-4d79-9622-2b24bd96368d",
"email_verified": true,
"name": "Kevin Wojkovich",
"groups": [
"another-group",
"vault-admin"
],
"preferred_username": "kwojkovich",
"given_name": "Kevin",
"family_name": "Wojkovich",
"email": "kevin@fqdn.com"
}
Verify that there is a field called “groups” with a list containing “vault-admin”.
Copy Client ID and Client Secret
Now that we have configured the client we will need to take note of the client ID
and client secret
for the Vault client. In KeyCloak, the client ID is the name of the client we created in the first step. The client secret is shown under the Credentials tab for the client.

Configure the Vault OIDC Auth Engine
This section focuses on setting up the Terraform Infrastructure as Code (IaC) that is responsible for configuring Hashicorp Vault. Leveraging infrastructure as code gives us a reproducible and auditable configuration.
You may choose to download the Terraform code files directly if you wish.
Setup the Terraform Project
We will create a directory with several Terraform (.tf) files that will contain the code necessary to configure Vault to allow authentication from KeyCloak using the OpenID Connect (OIDC) protocol.
Create a new directory called terraform_vault
/. This directory will be used to store our Terraform code.
Connect to Vault with a provider
Terraform uses something called a “provider” to drive the APIs necessary to manage resources declared in Terraform code. We will use the hashicorp/vault provider to interact with our Vault instance.
Create a new file called providers.tf
. Withinproviders.tf
, copy and paste the following content:
terraform {
required_providers {
vault = {
source = "hashicorp/vault"
version = "2.24.0"
}
}
}
provider "vault" {
}
The code within providers.tf
uses a pattern called Partial Configuration meaning that in order for Terraform to successfully apply, you will need to supply additional information.
This provides several benefits:
- Allows us to re-use our Terraform code to manage multiple Vault instances.
- Prevents hard-coding sensitive information into your Terraform code.
In our case, we need to provide credentials that supply the vault address and vault token. This provider knows to use VAULT_ADDR
and VAULT_TOKEN
if they are set as environment variables. We will set these during our Terraform Plan and Terraform Apply steps.
Declare variables
When authoring code, we want to try to write DRY code allowing us to reuse our Terraform code in other projects. We separate out variables into a separate file allowing us to reuse the code within our project.
Create a new file called variables.tf
and paste the following content:
variable "client_secret" {
description = "Required: OIDC Client secret for Hashicorp Vault"
type = string
}
variable "client_id" {
description = "Required: OIDC Client ID for Hashicorp Vault"
}
variable "discovery_url" {
description = "OIDC Discovery endpoint"
type = string
default = "https://keycloak.fqdn.com/auth/realms/master"
}
variable "authorized_redirects" {
description = "List of authorized redirects for Okta OIDC"
type = list(string)
default = ["http://localhost:8250/oidc/callback", "https://[[YOUR_VAULT_ADDR]]/ui/vault/auth/oidc/oidc/callback"]
}
The variables will be provided to Terraform during the Plan and Apply stages, however please update the BOLD default values to suit your deployment parameters. You will need to supply the discovery_url
default value as well as the user-accessible endpoint for your Vault instance under authorized_redirects
.
Generally-speaking the discovery_url
should be the path to your KeyCloak realm. More detailed documentation is available in KeyCloaks documentation if you need more advanced guidance.
Speaking of authorized_redirects
, the localhost value should not be changed, it will be used to complete the OpenID Connect authentication flow when using the Vault CLI from your workstation.
Create a Vault Admin policy
Vault leverages access control list (ACL) policies to give access to identity entities (users, groups, roles, etc). We will manage our Vault policies in-line with Terraform.
Create a new file called policies.tf
and paste the following content:
resource "vault_policy" "vault_admin" {
name = "vault-admin"
policy = <<EOT
# Read system health check
path "sys/health"
{
capabilities = ["read", "sudo"]
}
# Create and manage ACL policies broadly across Vault
# List existing policies
path "sys/policies/acl"
{
capabilities = ["list"]
}
# Create and manage ACL policies
path "sys/policies/acl/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Enable and manage authentication methods broadly across Vault
# Manage auth methods broadly across Vault
path "auth/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Create, update, and delete auth methods
path "sys/auth/*"
{
capabilities = ["create", "update", "delete", "sudo"]
}
# List auth methods
path "sys/auth"
{
capabilities = ["read"]
}
# Enable and manage the key/value secrets engine at `secret/` path
# List, create, update, and delete key/value secrets
path "secret/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage secrets engines
path "sys/mounts/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List existing secrets engines.
path "sys/mounts"
{
capabilities = ["read"]
}
path "kv/*"
{
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOT
}
This Terraform code creates a Vault ACL policy that gives admin-level permissions to an entity. In this example, we will assign the policy to a role that is tied to the “vault-admin” KeyCloak group.
Configure the auth backend
Vault has a plugin-based integrations system. In order to integrate with KeyCloak, we need to configure an auth backend that supports OpenID Connect (OIDC).
Create a new file called auth_backend.tf
and paste the following content:
resource "vault_jwt_auth_backend" "keycloak" {
description = "Keycloak"
path = "oidc"
type = "oidc"
oidc_discovery_url = var.discovery_url
oidc_client_id = var.client_id
oidc_client_secret = var.client_secret
default_role = "default"
tune {
default_lease_ttl = "1h"
max_lease_ttl = "8h"
allowed_response_headers = []
audit_non_hmac_request_keys = []
audit_non_hmac_response_keys = []
listing_visibility = "unauth"
passthrough_request_headers = []
token_type = "default-service"
}
}
resource "vault_jwt_auth_backend_role" "default" {
backend = vault_jwt_auth_backend.keycloak.path
role_name = "default"
token_policies = ["default"]
user_claim = "sub"
groups_claim = "groups"
role_type = "oidc"
allowed_redirect_uris = var.authorized_redirects
}
resource "vault_identity_group" "vault_admin" {
name = "vault-admin"
type = "external"
policies = [vault_policy.vault_admin.name]
}
resource "vault_identity_group_alias" "vault_admin" {
name = "vault-admin"
mount_accessor = vault_jwt_auth_backend.keycloak.accessor
canonical_id = vault_identity_group.vault_admin.id
}
There are a few key pieces contained in this code. We create several resources within Vault that are vital for this integration:
Auth Backend
An Auth Backend is a component with Vault that is responsible for performing authentication and assigning identity to an entity (user, group, role, etc). In this article we are using the OpenID Connect method. There are other supported methods, however OIDC is well-supported by multiple vendors including KeyCloak. We provide additional configuration:
- default_ttl: the amount of time a user token is valid
- max_ttl: the maximum amount of time a token can live after being periodically refreshed
Additionally we have to specify the token type. It is appropriate to issue a service token. There are other token types that are well beyond the scope of this exercise. More information can be found in the Hashicorp Vault documentation if you are interested.
Backend Role
The Backend Role is what ties everything together. In our example we create a role called “default” that is associated with our OIDC backend.
Without any additional information, successful login with KeyCloak will yield a Vault token with the “default” policy. The default policy is a generic policy with no permissions, so unprivileged users will be presented with no sensitive information or functionality within Vault.
We direct the backend to inspect the user token and map the “sub” claim as the Vault user and the “groups” claim as the field that Vault will read group membership from.
Additionally Vault must provide authorized redirect URIs in KeyCloak auth requests, so we provide the information from our variables.tf file.
External Group
Vault requires an entry for KeyCloak groups that we want to leverage for Vault authorization. This is done by creating an External Group entry. In this example, we have a “vault-admin” group within KeyCloak. We specify that members of this group should be assigned the vault-admin Vault ACL policy.
Group Alias
We’ve configured Vault to know that an external group called “vault-admin” will assume a policy called “vault-admin”, but we haven’t told Vault the source of that group. We create a Group Alias to bind the External Group to the KeyCloak auth backend.
Run Terraform
Now that we have all of the necessary configuration captured in our Terraform code, we are ready to start running Terraform to configure Vault.
The first step will be configuring our Terminal environment with the proper information and secrets. The following code snippet sets environment variables required to complete the Partial Configuration for the Terraform Vault Provider and to pass Terraform Variables into our code through environment variables.
export VAULT_ADDR=https://vault.fqdn.com
export VAULT_TOKEN="root_token"
export TF_VAR_client_secret="client secret from step 3.5 - Copy Client ID and Client Secret"
export TF_VAR_client_id="client id from step 3.5 - Copy Client ID and Client Secret"
Now that we have our environment setup, it’s time to verify our connection and preview our changes.
$ terraform plan
...
Plan: 5 to add, 0 to change, 0 to destroy.
Terraform should output its intended actions. It should create 5 resources. If this looks acceptable and no errors were presented, you can proceed to Apply these changes.
terraform apply
Log into Vault with SSO
If you navigate to your Vault’s UI, you should now see the OIDC method configured for use.

Click Sign in with OIDC provider and you should will be presented with a KeyCloak login. Use your KeyCloak user’s credentials to log in.

Upon successful login, you will be presented with access to the secret/
key-value secret store, Access, and Policies. Additionally clicking on the User menu in the top-right corner will reveal your token’s subscription ID, prefixed with OIDC-
indicating your token is associated with the OIDC Auth Backend (eg: KeyCloak).

Congratulations, you’ve integrated Hashicorp Vault with KeyCloak single-sign on using Terraform!
This is an example configuration that is relatively portable and tunable to your organization’s needs. We use the best-in-class DevOps tooling to configure highly-sophisticated tools to simply your day-to-day operations.
These integrations are the type of things that we specialize in over at SpicyOmelet. If you would like to see what else is possible, reach out through phone, text, or email. We’d love to help you on your DevOps journey.