« Keystone with OpenID Connect » : différence entre les versions
Aucun résumé des modifications |
mAucun résumé des modifications |
||
(24 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
Configure an external [https://www.keycloak.org/ Keycloak] to provide authentication for [https://docs.openstack.org/keystone/latest/ Keystone] | Configure an external [https://www.keycloak.org/ Keycloak] to provide authentication for [https://docs.openstack.org/keystone/latest/ Keystone] | ||
<br /> | <br /> | ||
The objective is to identify | The objective is to identify users and allow them to find their projects in Openstack. | ||
== Keycloak client and user configuration == | |||
This guide assumes you already have a working Keycloak server with a realm named '''cloud.ld'''. | |||
This guide assumes you already have a working Keycloak server. | |||
<br /> | <br /> | ||
What is covered here is how to : | What is covered here is how to : | ||
* create a client in Keycloak for Keystone | * create a client in Keycloak for Keystone | ||
* configure this client | * configure this client | ||
* creation of groups (one Keycloak group per Openstack project) | |||
* create a user | |||
=== Client creation and settings === | === Client creation and settings === | ||
Ligne 16 : | Ligne 17 : | ||
* Got to your Keycloak admin console and configure a new client (click ''Create'') | * Got to your Keycloak admin console and configure a new client (click ''Create'') | ||
[[Fichier: | [[Fichier:keycloak11.png|1024px|thumb|center|Keycloak admin console]] | ||
* Let's assume your client is named ''Keystone'' | * Let's assume your client is named ''Keystone'' | ||
** Leave ''Root URL'' | ** Leave ''Root URL'' & ''Home URL'' empty | ||
** The ''FQDN'' for ''Valid Redirect URIs'' should match the value of ''kolla_external_fqdn''. If your ''kolla_internal_fqdn'' is ''par1.cloud.ld'', then your ''Valid Redirect URIs'' should be ''https://par1.cloud.ld:5000/redirect_uri''. You can also add the URI of your [https://docs.openstack.org/horizon/latest/ Horizon dashboard] | |||
** | ** ''Client authentication'' and ''Authorization'' must be off | ||
** ''Standard Flow Enabled'', ''Implicit Flow Enabled'' and ''Direct Access Grants Enabled'' must be on. ''OAuth 2.0 Device Authorization Grant'' is optional | |||
** In ''advanced settings'', choose ''S256'' for ''Proof Key for Code Exchange Code Challenge Method'' (required for PKCE) | |||
[[Fichier: | [[Fichier:keycloak12.png|1024px|thumb|center|Keycloak client access settings]] | ||
[[Fichier:keycloak13.png|1024px|thumb|center|Keycloak client capability config]] | |||
[[Fichier:keycloak14.png|1024px|thumb|center|Keycloak client advanced settings]] | |||
=== Client mappers === | === Client mappers === | ||
Add the following mappers to the new client : | Add the following mappers to the new client : | ||
* ''groups'' via ''Add | * ''groups'' via ''Add mapper'' -> ''By configuration'' button and select ''Group Membership''. (cf below for configuration details) | ||
* ''email'' via ''Add | * ''email'' via ''Add mapper'' -> ''From predifined mappers'' button and select ''email'' | ||
* ''username'' via ''Add | * ''username'' via ''Add mapper'' -> ''From predifined mappers'' button and select ''username'' | ||
[[Fichier:keycloak15.png|1024px|thumb|center|Keycloak client mappers]] | |||
[[Fichier:keycloak16.png|1024px|thumb|center|Keycloak client, Group Membership]] | |||
=== Creation of groups === | |||
One Keycloak group is created per Openstack project (''Manage'' -> ''Groups''). | |||
=== Creation of user === | |||
Create one user, fill its ''username'', ''email'' and affect one (or more) group(s) to this user (''Manage'' -> ''Users''). | |||
== Kolla-ansible configuration and deployment == | |||
=== Configuration === | |||
* Follow instructions found at https://docs.openstack.org/kolla-ansible/latest/contributor/setup-identity-provider.html#configuring-kolla-ansible-to-use-the-identity-provider (''client_secret'' can be a random string as ''Client authentication'' and ''Authorization'' are off for the Keycloak client) | |||
* Replace ''new_realm'' with the actual keycloak realm ('''cloud.ld''' in this guide) | |||
* As a result, here is a ''globals.yml'' example settings for ''keystone_identity_providers'' : | |||
<syntaxhighlight lang="yaml"> | |||
keystone_identity_providers: | |||
- name: "cloud.ld" | |||
openstack_domain: "cloud.ld" | |||
protocol: "openid" | |||
identifier: "https://sso.paris.ld/auth/realms/cloud.ld" | |||
public_name: "Authenticate via cloud.ld" | |||
attribute_mapping: "attribute_mapping_keycloak_cloud_ld" | |||
metadata_folder: "/etc/keycloak/meta-idp" | |||
certificate_file: "/etc/keycloak/certs/LdJnukYBN53JwEI8A-ITtmkW-544_RZe-jvQ0q0NCUGk.pem" | |||
keystone_identity_mappings: | |||
- name: "attribute_mapping_keycloak_cloud_ld" | |||
file: "/etc/keycloak/attr_map/attribute_mapping.json" | |||
keystone_federation_oidc_jwks_uri: "https://sso.paris.ld/auth/realms/cloud.ld/protocol/openid-connect/certs" | |||
</syntaxhighlight> | |||
* Use the following attribute mapping file (''attribute_mapping.json'') : | |||
<syntaxhighlight lang="json"> | |||
[ | |||
{ | |||
"local": [ | |||
{ | |||
"user": { | |||
"name": "{0}", | |||
"email": "{1}", | |||
"domain": { | |||
"name": "cloud.ld" | |||
} | |||
} | |||
}, | |||
{ | |||
"groups": "{2}", | |||
"domain": { | |||
"name": "cloud.ld" | |||
} | |||
} | |||
], | |||
"remote": [ | |||
{ | |||
"type": "OIDC-preferred_username" | |||
}, | |||
{ | |||
"type": "OIDC-email" | |||
}, | |||
{ | |||
"type": "OIDC-groups" | |||
} | |||
] | |||
} | |||
] | |||
</syntaxhighlight> | |||
=== Redeploy Keystone === | |||
With ''kolla-ansible'' configured, this is done with : | |||
<syntaxhighlight lang="bash"> | |||
$ kolla-ansible deploy -i multinode --tags keystone | |||
</syntaxhighlight> | |||
=== Patch keystone containers === | |||
This is the ugliest part... From Kolla Keystone containers (quay.io/openstack.kolla/keystone:2023.2-rocky-9), using openstack-cli with OpenID connect does not work and results in HTTP 502 errors ... | |||
<br /> | |||
Apache in these containers is crashing (segfault) as soon as you run an openstack-cli command with OpenID connect. | |||
<br /> | |||
The solution is to upgrade ''mod_auth_openidc'' in these containers to a more recent version (e.g. ''2.4.15''). | |||
<br /> | |||
You can grab the RPM from https://github.com/OpenIDC/mod_auth_openidc/releases ; be careful, ''hiredis'' is a required dependency (you can grab it from https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/h/hiredis-1.0.2-1.el9.x86_64.rpm) | |||
<br /> | |||
So ... For each ''keystone'' container : | |||
<syntaxhighlight lang="bash"> | |||
docker cp mod_auth_openidc-2.4.15.1-1.el9.x86_64.rpm keystone:/tmp | |||
docker cp hiredis-1.0.2-1.el9.x86_64.rpm keystone:/tmp | |||
docker exec -it -u root keystone yum -y localinstall /tmp/hiredis-1.0.2-1.el9.x86_64.rpm | |||
docker exec -it -u root keystone yum -y upgrade /tmp/mod_auth_openidc-2.4.15.1-1.el9.x86_64.rpm | |||
docker exec -it -u root keystone rm -f /tmp/*.rpm | |||
docker restart keystone | |||
</syntaxhighlight> | |||
== Openstack group and project configuration == | |||
As explained above, Keycloak users are mapped to specific groups and these groups correspond to projects in Openstack. | |||
=== Group creation === | |||
Let's create a group named ''teria'' : | |||
<syntaxhighlight lang="bash"> | |||
$ openstack group create --domain cloud.ld teria | |||
</syntaxhighlight> | |||
=== Project creation and project affectation === | |||
A project named ''teria'' is created with the group ''teria'' as member. | |||
<syntaxhighlight lang="bash"> | |||
$ openstack project create --description 'Teria' --domain cloud.ld teria | |||
$ openstack role add --group teria --project teria member | |||
</syntaxhighlight> | |||
== Test ! == | |||
=== AUTH_TYPE ''v3oidcpassword'' === | |||
''v3oidcpassword'' requires entering the user's Keycloak password | |||
<syntaxhighlight lang="bash"> | |||
export OS_AUTH_URL=https://auth.cloud.ld:13000/v3 | |||
export OS_PROJECT_NAME="teria" | |||
export OS_PROJECT_DOMAIN_NAME="cloud.ld" | |||
export OS_USERNAME="chris" | |||
export OS_PASSWORD=<Keycloak_user_chris_password> | |||
export OS_INTERFACE=public | |||
export OS_IDENTITY_API_VERSION=3 | |||
export OS_CACERT=/etc/pki/tls/certs/ca-bundle.crt | |||
export OS_AUTH_TYPE=v3oidcpassword | |||
export OS_CLIENT_ID=keystone | |||
export OS_CLIENT_SECRET=<some_random_string_can_be_null> | |||
export OS_IDENTITY_PROVIDER=cloud.ld | |||
export OS_PROTOCOL=openid | |||
export OS_ACCESS_TOKEN_ENDPOINT=https://sso.paris.ld/auth/realms/cloud.ld/protocol/openid-connect/token | |||
$ openstack user show chris | |||
+---------------------+------------------------------------------------------------------------------------------+ | |||
| Field | Value | | |||
+---------------------+------------------------------------------------------------------------------------------+ | |||
| domain_id | 09badf2ac3cf4486bac93e02fc3d73d7 | | |||
| email | chris@cloud.ld | | |||
| enabled | True | | |||
| federated | [{'idp_id': 'cloud.ld', 'protocols': [{'protocol_id': 'openid', 'unique_id': 'chris'}]}] | | |||
| id | 1029524718feb03078319e57ebfa4e7051787f8dd3ec3cce215e5c44cdab09bb | | |||
| name | chris | | |||
| options | {} | | |||
| password_expires_at | None | | |||
+---------------------+------------------------------------------------------------------------------------------+ | |||
</syntaxhighlight> | |||
=== AUTH_TYPE ''v3oidcdeviceauthz'' === | |||
With this method, a URL is offered to the user. When the URL is opened in a web browser, the user identifies themselves via Keycloak then a Keystone token (with a validity of 24 hours) is given in the shell | |||
<syntaxhighlight lang="bash"> | |||
$ cat > testrc << 'EOF' | |||
#!/usr/bin/env bash | |||
_output=$(mktemp) | |||
export OS_AUTH_URL=https://auth.cloud.ld:13000 | |||
export OS_IDENTITY_API_VERSION=3 | |||
export OS_CACERT=/etc/pki/tls/certs/ca-bundle.crt | |||
export OS_PROJECT_NAME="teria" | |||
export OS_PROJECT_DOMAIN_NAME="cloud.ld" | |||
export OS_AUTH_TYPE="v3token" | |||
unset OS_TOKEN | |||
$(which python3) -u $(which openstack) token issue -f value -c id \ | |||
--os-auth-type v3oidcdeviceauthz \ | |||
--os-identity-provider cloud.ld \ | |||
--os-protocol openid \ | |||
--os-discovery-endpoint https://sso.paris.ld/realms/cloud.ld/.well-known/openid-configuration \ | |||
--os-client-id keystone \ | |||
--os-code-challenge-method 'S256' | tee -a $_output | |||
if [ -s $_output ]; then | |||
export OS_TOKEN=$(tail -1 $_output) | |||
fi | |||
rm -f $_output | |||
EOF | |||
$ source testrc | |||
To authenticate please go to: https://sso.paris.ld/realms/cloud.ld/device?user_code=UWSY-YHZL | |||
<TOKEN> | |||
[[ | $ openstack user show chris | ||
+---------------------+------------------------------------------------------------------------------------------+ | |||
| Field | Value | | |||
+---------------------+------------------------------------------------------------------------------------------+ | |||
| domain_id | 09badf2ac3cf4486bac93e02fc3d73d7 | | |||
| email | chris@cloud.ld | | |||
| enabled | True | | |||
| federated | [{'idp_id': 'cloud.ld', 'protocols': [{'protocol_id': 'openid', 'unique_id': 'chris'}]}] | | |||
| id | 1029524718feb03078319e57ebfa4e7051787f8dd3ec3cce215e5c44cdab09bb | | |||
| name | chris | | |||
| options | {} | | |||
| password_expires_at | None | | |||
+---------------------+------------------------------------------------------------------------------------------+ | |||
</syntaxhighlight> |
Dernière version du 16 octobre 2024 à 15:17
Configure an external Keycloak to provide authentication for Keystone
The objective is to identify users and allow them to find their projects in Openstack.
Keycloak client and user configuration
This guide assumes you already have a working Keycloak server with a realm named cloud.ld.
What is covered here is how to :
- create a client in Keycloak for Keystone
- configure this client
- creation of groups (one Keycloak group per Openstack project)
- create a user
Client creation and settings
- Got to your Keycloak admin console and configure a new client (click Create)
- Let's assume your client is named Keystone
- Leave Root URL & Home URL empty
- The FQDN for Valid Redirect URIs should match the value of kolla_external_fqdn. If your kolla_internal_fqdn is par1.cloud.ld, then your Valid Redirect URIs should be https://par1.cloud.ld:5000/redirect_uri. You can also add the URI of your Horizon dashboard
- Client authentication and Authorization must be off
- Standard Flow Enabled, Implicit Flow Enabled and Direct Access Grants Enabled must be on. OAuth 2.0 Device Authorization Grant is optional
- In advanced settings, choose S256 for Proof Key for Code Exchange Code Challenge Method (required for PKCE)
Client mappers
Add the following mappers to the new client :
- groups via Add mapper -> By configuration button and select Group Membership. (cf below for configuration details)
- email via Add mapper -> From predifined mappers button and select email
- username via Add mapper -> From predifined mappers button and select username
Creation of groups
One Keycloak group is created per Openstack project (Manage -> Groups).
Creation of user
Create one user, fill its username, email and affect one (or more) group(s) to this user (Manage -> Users).
Kolla-ansible configuration and deployment
Configuration
- Follow instructions found at https://docs.openstack.org/kolla-ansible/latest/contributor/setup-identity-provider.html#configuring-kolla-ansible-to-use-the-identity-provider (client_secret can be a random string as Client authentication and Authorization are off for the Keycloak client)
- Replace new_realm with the actual keycloak realm (cloud.ld in this guide)
- As a result, here is a globals.yml example settings for keystone_identity_providers :
keystone_identity_providers:
- name: "cloud.ld"
openstack_domain: "cloud.ld"
protocol: "openid"
identifier: "https://sso.paris.ld/auth/realms/cloud.ld"
public_name: "Authenticate via cloud.ld"
attribute_mapping: "attribute_mapping_keycloak_cloud_ld"
metadata_folder: "/etc/keycloak/meta-idp"
certificate_file: "/etc/keycloak/certs/LdJnukYBN53JwEI8A-ITtmkW-544_RZe-jvQ0q0NCUGk.pem"
keystone_identity_mappings:
- name: "attribute_mapping_keycloak_cloud_ld"
file: "/etc/keycloak/attr_map/attribute_mapping.json"
keystone_federation_oidc_jwks_uri: "https://sso.paris.ld/auth/realms/cloud.ld/protocol/openid-connect/certs"
- Use the following attribute mapping file (attribute_mapping.json) :
[
{
"local": [
{
"user": {
"name": "{0}",
"email": "{1}",
"domain": {
"name": "cloud.ld"
}
}
},
{
"groups": "{2}",
"domain": {
"name": "cloud.ld"
}
}
],
"remote": [
{
"type": "OIDC-preferred_username"
},
{
"type": "OIDC-email"
},
{
"type": "OIDC-groups"
}
]
}
]
Redeploy Keystone
With kolla-ansible configured, this is done with :
$ kolla-ansible deploy -i multinode --tags keystone
Patch keystone containers
This is the ugliest part... From Kolla Keystone containers (quay.io/openstack.kolla/keystone:2023.2-rocky-9), using openstack-cli with OpenID connect does not work and results in HTTP 502 errors ...
Apache in these containers is crashing (segfault) as soon as you run an openstack-cli command with OpenID connect.
The solution is to upgrade mod_auth_openidc in these containers to a more recent version (e.g. 2.4.15).
You can grab the RPM from https://github.com/OpenIDC/mod_auth_openidc/releases ; be careful, hiredis is a required dependency (you can grab it from https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/h/hiredis-1.0.2-1.el9.x86_64.rpm)
So ... For each keystone container :
docker cp mod_auth_openidc-2.4.15.1-1.el9.x86_64.rpm keystone:/tmp
docker cp hiredis-1.0.2-1.el9.x86_64.rpm keystone:/tmp
docker exec -it -u root keystone yum -y localinstall /tmp/hiredis-1.0.2-1.el9.x86_64.rpm
docker exec -it -u root keystone yum -y upgrade /tmp/mod_auth_openidc-2.4.15.1-1.el9.x86_64.rpm
docker exec -it -u root keystone rm -f /tmp/*.rpm
docker restart keystone
Openstack group and project configuration
As explained above, Keycloak users are mapped to specific groups and these groups correspond to projects in Openstack.
Group creation
Let's create a group named teria :
$ openstack group create --domain cloud.ld teria
Project creation and project affectation
A project named teria is created with the group teria as member.
$ openstack project create --description 'Teria' --domain cloud.ld teria
$ openstack role add --group teria --project teria member
Test !
AUTH_TYPE v3oidcpassword
v3oidcpassword requires entering the user's Keycloak password
export OS_AUTH_URL=https://auth.cloud.ld:13000/v3
export OS_PROJECT_NAME="teria"
export OS_PROJECT_DOMAIN_NAME="cloud.ld"
export OS_USERNAME="chris"
export OS_PASSWORD=<Keycloak_user_chris_password>
export OS_INTERFACE=public
export OS_IDENTITY_API_VERSION=3
export OS_CACERT=/etc/pki/tls/certs/ca-bundle.crt
export OS_AUTH_TYPE=v3oidcpassword
export OS_CLIENT_ID=keystone
export OS_CLIENT_SECRET=<some_random_string_can_be_null>
export OS_IDENTITY_PROVIDER=cloud.ld
export OS_PROTOCOL=openid
export OS_ACCESS_TOKEN_ENDPOINT=https://sso.paris.ld/auth/realms/cloud.ld/protocol/openid-connect/token
$ openstack user show chris
+---------------------+------------------------------------------------------------------------------------------+
| Field | Value |
+---------------------+------------------------------------------------------------------------------------------+
| domain_id | 09badf2ac3cf4486bac93e02fc3d73d7 |
| email | chris@cloud.ld |
| enabled | True |
| federated | [{'idp_id': 'cloud.ld', 'protocols': [{'protocol_id': 'openid', 'unique_id': 'chris'}]}] |
| id | 1029524718feb03078319e57ebfa4e7051787f8dd3ec3cce215e5c44cdab09bb |
| name | chris |
| options | {} |
| password_expires_at | None |
+---------------------+------------------------------------------------------------------------------------------+
AUTH_TYPE v3oidcdeviceauthz
With this method, a URL is offered to the user. When the URL is opened in a web browser, the user identifies themselves via Keycloak then a Keystone token (with a validity of 24 hours) is given in the shell
$ cat > testrc << 'EOF'
#!/usr/bin/env bash
_output=$(mktemp)
export OS_AUTH_URL=https://auth.cloud.ld:13000
export OS_IDENTITY_API_VERSION=3
export OS_CACERT=/etc/pki/tls/certs/ca-bundle.crt
export OS_PROJECT_NAME="teria"
export OS_PROJECT_DOMAIN_NAME="cloud.ld"
export OS_AUTH_TYPE="v3token"
unset OS_TOKEN
$(which python3) -u $(which openstack) token issue -f value -c id \
--os-auth-type v3oidcdeviceauthz \
--os-identity-provider cloud.ld \
--os-protocol openid \
--os-discovery-endpoint https://sso.paris.ld/realms/cloud.ld/.well-known/openid-configuration \
--os-client-id keystone \
--os-code-challenge-method 'S256' | tee -a $_output
if [ -s $_output ]; then
export OS_TOKEN=$(tail -1 $_output)
fi
rm -f $_output
EOF
$ source testrc
To authenticate please go to: https://sso.paris.ld/realms/cloud.ld/device?user_code=UWSY-YHZL
<TOKEN>
$ openstack user show chris
+---------------------+------------------------------------------------------------------------------------------+
| Field | Value |
+---------------------+------------------------------------------------------------------------------------------+
| domain_id | 09badf2ac3cf4486bac93e02fc3d73d7 |
| email | chris@cloud.ld |
| enabled | True |
| federated | [{'idp_id': 'cloud.ld', 'protocols': [{'protocol_id': 'openid', 'unique_id': 'chris'}]}] |
| id | 1029524718feb03078319e57ebfa4e7051787f8dd3ec3cce215e5c44cdab09bb |
| name | chris |
| options | {} |
| password_expires_at | None |
+---------------------+------------------------------------------------------------------------------------------+