When configuring vault with keycloak IPD so that keycloak authenticates vault users through oidc, we have a problem with a verification that vault makes on the issuer
field.
We have a specific setup with keycloak:
- Vault reaches keycloak through a private network (backend url)
- end users reach keycloak from a public network (frontend url)
With this setup, keycloak considers the issuer as a frontend element: in the .well-known/openid-configuration
discovery URL, the issuer is https://<frontend-keycloak-hostname>/auth/realms/myrealm
Upon initializing the oidc configuration (when building the auth backend), vault makes a verification about the issuer that makes the process fail : it seems that vault is trying to guess what the issuer should be by concatenating
- the hostname vault is using to reach keycloak :
https://<backend-keycloak-hostname>
- with the path configured in the oidc_discovery_url
/auth/realms/myrealm
We can see in vault logs:
2024-01-16T11:57:12.474+0100 [ERROR] auth.oidc.auth_oidc_xxxx: error checking oidc discovery URL: error="error creating provider with given values: NewProvider:
unable to create provider: oidc: issuer did not match the issuer returned by provider,
expected \"https://<backend-keycloak-hostname>/auth/realms/myrealm\"
got \"https://<frontend-keycloak-hostname>/auth/realms/myrealm\""
The assumption that the issuer must have the same hostname as the oidc discovery address is incorrect when the idp can be reached from different URLS.
The error appears even when bound_issuer
is configured in the auth backends. Vault could simply compare the value of bound_issuer
with the issuer given by the discovery URL in that case rather than assuming what the issuer hostname should be.
Setup:
- vault (terraform)
resource "vault_jwt_auth_backend" "keycloak" {
description = "Keycloak"
path = "oidc"
type = "oidc"
oidc_discovery_url = "https://<backend-keycloak-hostname>/auth/realms/myrealm"
bound_issuer = "https://<frontend-keycloak-hostname>/auth/realms/myrealm"
oidc_client_id = var.keycloak_client_id
oidc_client_secret = var.keycloak_client_secret
default_role = "default-keycloak"
tune {
default_lease_ttl = "2h"
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_keycloak" {
backend = vault_jwt_auth_backend.keycloak.path
role_name = "default-keycloak"
token_policies = ["default"]
user_claim = "xxx"
groups_claim = "groups"
role_type = "oidc"
allowed_redirect_uris = var.oidc_authorized_redirects
verbose_oidc_logging = true
}
- keycloak:
KC_HOSTNAME_STRICT=false
: backend urls are built based on the requestKC_HOSTNAME_URL=https://<frontend-keycloak-hostname>/auth
: The front-end url is forced in keycloak with so that users are not redirected to the backend URL
With this setup, accessing to https://<backend-keycloak-hostname>/auth/realm/myrealm/.well-known/openid-configuration
displays the issuer as https://<frontend-keycloak-hostname>/auth/realm/myrealm
.
Issue can be circumvented by making vault access keycloak through the public URL https://<frontend-keycloak-hostname>
but it’s not what we want to do from a network point of view.
Another solution would be to not use the discovery URL from vault but if possible I would like to use it for vault to get the other pieces of information, except the issuer.
Tested with:
- keycloak 23.0.4
- hashicorp vault 1.15.4+ent
I’ve already initiated the discussion on keycloak side. So far i’ve been told that it seems more a vault issue than keycloak issue.
Related discussions / issues on keycloak side: