Keystone - Identity service

Fernet Tokens

Fernet tokens require the use of keys that must be synchronised between Keystone servers. Kolla Ansible deploys two containers to handle this - keystone_fernet runs cron jobs to rotate keys via rsync when necessary. keystone_ssh is an SSH server that provides the transport for rsync. In a multi-host control plane, these rotations are performed by the hosts in a round-robin manner.

The following variables may be used to configure the token expiry and key rotation.

fernet_token_expiry

Keystone fernet token expiry in seconds. Default is 86400, which is 1 day.

fernet_token_allow_expired_window

Keystone window to allow expired fernet tokens. Default is 172800, which is 2 days.

fernet_key_rotation_interval

Keystone fernet key rotation interval in seconds. Default is sum of token expiry and allow expired window, which is 3 days.

The default rotation interval is set up to ensure that the minimum number of keys may be active at any time. This is one primary key, one secondary key and a buffer key - three in total. If the rotation interval is set lower than the sum of the token expiry and token allow expired window, more active keys will be configured in Keystone as necessary.

Further infomation on Fernet tokens is available in the Keystone documentation.

Federated identity

Keystone allows users to be authenticated via identity federation. This means integrating OpenStack Keystone with an identity provider. The use of identity federation allows users to access OpenStack services without the necessity of an account in the OpenStack environment per se. The authentication is then off-loaded to the identity provider of the federation.

To enable identity federation, you will need to execute a set of configurations in multiple OpenStack systems. Therefore, it is easier to use Kolla Ansible to execute this process for operators.

For upstream documentations, please see Configuring Keystone for Federation

Supported protocols

OpenStack supports both OpenID Connect and SAML protocols for federated identity, but for now, kolla Ansible supports only OpenID Connect. Therefore, if you desire to use SAML in your environment, you will need to set it up manually or extend Kolla Ansible to also support it.

Setting up OpenID Connect via Kolla Ansible

First, you will need to register the OpenStack (Keystone) in your Identity provider as a Service Provider.

After registering Keystone, you will need to add the Identity Provider configurations in your kolla-ansible globals configuration as the example below:

keystone_identity_providers:
  - name: "myidp1"
    openstack_domain: "my-domain"
    protocol: "openid"
    identifier: "https://accounts.google.com"
    public_name: "Authenticate via myidp1"
    attribute_mapping: "mappingId1"
    metadata_folder: "path/to/metadata/folder"
    certificate_file: "path/to/certificate/file.pem"

keystone_identity_mappings:
  - name: "mappingId1"
    file: "/full/qualified/path/to/mapping/json/file/to/mappingId1"

In some cases it’s necessary to add JWKS (JSON Web Key Set) uri. It is required for auth-openidc endpoint - which is used by OpenStack command line client. Example config shown below:

keystone_federation_oidc_jwks_uri: "https://<AUTH PROVIDER>/<ID>/discovery/v2.0/keys"

Some identity providers need additional mod_auth_openidc config. Example for Keycloak shown below:

keystone_federation_oidc_additional_options:
  OIDCTokenBindingPolicy: disabled

Identity providers configurations

name

The internal name of the Identity provider in OpenStack.

openstack_domain

The OpenStack domain that the Identity Provider belongs.

protocol

The federated protocol used by the IdP; e.g. openid or saml. We support only OpenID connect right now.

identifier

The Identity provider URL; e.g. https://accounts.google.com .

public_name

The Identity provider public name that will be shown for users in the Horizon login page.

attribute_mapping

The attribute mapping to be used for the Identity Provider. This mapping is expected to already exist in OpenStack or be configured in the keystone_identity_mappings property.

metadata_folder

Path to the folder containing all of the identity provider metadata as JSON files.

The metadata folder must have all your Identity Providers configurations, the name of the files will be the name (with path) of the Issuer configuration. Such as:

- <IDP metadata directory>
  - keycloak.example.org%2Fauth%2Frealms%2Fidp.client
  |
  - keycloak.example.org%2Fauth%2Frealms%2Fidp.conf
  |
  - keycloak.example.org%2Fauth%2Frealms%2Fidp.provider

Note

The name of the file must be URL-encoded if needed. For example, if you have an Issuer with / in the URL, then you need to escape it to %2F by applying a URL escape in the file name.

The content of these files must be a JSON

client:

The .client file handles the Service Provider credentials in the Issuer.

During the first step, when you registered the OpenStack as a Service Provider in the Identity Provider, you submitted a cliend_id and generated a client_secret, so these are the values you must use in this JSON file.

{
  "client_id":"<openid_client_id>",
  "client_secret":"<openid_client_secret>"
}

conf:

This file will be a JSON that overrides some of the OpenID Connect options. The options that can be overridden are listed in the OpenID Connect Apache2 plugin documentation. .. OpenID Connect Apache2 plugin documentation: https://github.com/zmartzone/mod_auth_openidc/wiki/Multiple-Providers#opclient-configuration

If you do not want to override the config values, you can leave this file as an empty JSON file such as {}.

provider:

This file will contain all specifications about the IdentityProvider. To simplify, you can just use the JSON returned in the .well-known Identity provider’s endpoint:

{
  "issuer": "https://accounts.google.com",
  "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
  "token_endpoint": "https://oauth2.googleapis.com/token",
  "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
  "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "response_types_supported": [
   "code",
   "token",
   "id_token",
   "code token",
   "code id_token",
   "token id_token",
   "code token id_token",
   "none"
  ],
  "subject_types_supported": [
   "public"
  ],
  "id_token_signing_alg_values_supported": [
   "RS256"
  ],
  "scopes_supported": [
   "openid",
   "email",
   "profile"
  ],
  "token_endpoint_auth_methods_supported": [
   "client_secret_post",
   "client_secret_basic"
  ],
  "claims_supported": [
   "aud",
   "email",
   "email_verified",
   "exp",
   "family_name",
   "given_name",
   "iat",
   "iss",
   "locale",
   "name",
   "picture",
   "sub"
  ],
  "code_challenge_methods_supported": [
   "plain",
   "S256"
  ]
}

certificate_file

Optional path to the Identity Provider certificate file. If included, the file must be named as ‘certificate-key-id.pem’. E.g.:

- fb8ca5b7d8d9a5c6c6788071e866c6c40f3fc1f9.pem

You can find the key-id in the Identity provider .well-known/openid-configuration jwks_uri like in https://www.googleapis.com/oauth2/v3/certs :

{
  "keys": [
    {
      "e": "AQAB",
      "use": "sig",
      "n": "zK8PHf_6V3G5rU-viUOL1HvAYn7q--dxMoU...",
      "kty": "RSA",
      "kid": "fb8ca5b7d8d9a5c6c6788071e866c6c40f3fc1f9",
      "alg": "RS256"
    }
  ]
}

Note

The public key is different from the certificate, the file in this configuration must be the Identity provider’s certificate and not the Identity provider’s public key.