Add support to OpenID Connect Authentication flow

Registered by Pedro Henrique Pereira Martins

Adds support for the OpenID Connect authentication flow in Keystone and enables both ID and access token authentication
flows. The ID token configuration is designed to allow users to authenticate via Horizon using an identity federation; whereas the
Access token is used to allow users to authenticate in the OpenStack CLI using a federated user.

Blueprint information

Status:
Complete
Approver:
None
Priority:
Medium
Drafter:
Pedro Henrique Pereira Martins
Direction:
Approved
Assignee:
None
Definition:
Approved
Series goal:
Accepted for wallaby
Implementation:
Implemented
Milestone target:
milestone icon 12.0.0
Started by
Mark Goddard
Completed by
Mark Goddard

Related branches

Sprints

Whiteboard

Problem description
============
If we want to configure OpenStack to work with identity federation, more specifically, with the OpenID Connect protocol, we need to do a lot of configurations in many files of the Keystone and Horizon systems. It is unpleasant for an administrator to apply and maintain these configurations scattered among many files and CLI systems.
Furthermore, all the configurations need to be reviewed at any time an Identity Provider joins or leaves the federation. For example, imagine that you are an administrator and you want to use one or more Identity Providers to people accessing your OpenStack environment, you will have a long road ahead.

You will need to:

 - In Horizon local_settings:
   - Set WEBSSO_ENABLED;
   - Set WEBSSO_CHOICES;
   - Set WEBSSO_IDP_MAPPING;
 - In Keystone.conf:
   - Define which dashboards are allowed to use the identity federated plugin;
 - In wsgi-keystone.conf:
   - Configure the protected endpoints that will handle the authentication flow;
   - Set the protocol used for each endpoint;
   - Set the path to the Identity Providers metadata/cert directories that you will create;
   - In some directory in the Keystone host:
 - Create a metadata directory containing files named (URL escaped) like:
   - Idp1.domain%2Fissuer.provider (will contain the issuer metadata as a JSON);
   - Idp1.domain%2Fissuer.conf (will contain some confs to override if desired, but if not, its file will be an empty JSON);
   - Idp1.domain%2Fissuer.client (will contain the client ID and client secret as a JSON);
   - Idp2.domain%2Fissuer.provider (will contain the issuer metadata as a JSON);
   - Idp2.domain%2Fissuer.conf (will contain some confs to override if desired, but if not, its file will be an empty JSON);
   - Idp2.domain%2Fissuer.client (will contain the client ID and client secret as a JSON);
 - If you desire to allow the access token authentication flow (used by OpenStack CLI):
   - In some directory in the Keystone host:
     - Save the Idp1's x509 certificate;
     - Save the Idp2's x509 certificate;

And some other configurations not listed here. After the configurations are properly set, then you will need to run a set of commands in the OpenStack CLI to register the IdPs in the Keystone and link them with their respective attributes mappings. Then, you will be able to authenticate federated users in your OpenStack environment.

This whole process is loosely coupled and can be quite troublesome to manage in production in a multi IdP environment. Therefore, we need to find a better and easier method to connect OpenStack as a service provider (SP) in a federated environment.

Proposal
=====
Imagine the same scenario, but all you will need to do is to create the Identity Provider attribute mapping and present some metadata of the IdPs to Kolla-ansible and leave it (Kolla-ansible) to do all the hard work. The new configurations in your Kolla-ansible globals.yml will be something like :

identity_providers:
  - {
      name: "myidp1",
      protocol: "openid",
      identifier: "idp1",
      public_name: "Authenticate via myidp1",
      client_id: "myidp1.client.id",
      client_secret: "myidp1-secret",
      attribute_mapping: "mappingId1",
      organization_domain_name: "xyz.com",
      certificate_url: "url/to/the/idp1/certificate",
      key_id: "the-idp-public-key-id-or-a-url-to-load-the-key-id",
      certificate_transformer: "python-command-to-do-some-transformation-in-the-certificate",
      key_transformer: "python-command-to-do-some-transformation-in-the-key-id"
    }
  - {
      name: "myidp2",
      protocol: "openid",
      identifier: "idp2",
      public_name: "Authenticate via myidp2",
      client_id: "myidp2.client.id",
      client_secret: "myidp2-secret",
      attribute_mapping: "mappingId2",
      organization_domain_name: "xyz.com",
      certificate_url: "url/to/the/idp2/certificate",
      key_id: "the-idp-public-key-id-or-a-url-to-load-the-key-id",
      certificate_transformer: "python-command-to-do-some-transformation-in-the-certificate",
      key_transformer: "python-command-to-do-some-transformation-in-the-key-id"
    }

identity_providers_attribute_mappings:
  - {name: "mappingId1", file: "/full/qualified/path/to/mapping/json/file/to/mappingId1"}
  - {name: "mappingId2", file: "/full/qualified/path/to/mapping/json/file/to/mappingId2"}

By adopting this approach we can have a smoother and easier way to add OpenStack in a federated environment. No dispersed configurations; no multiple commands to be executed; easy to add and remove Identity Providers; compatible with Horizon and OpenStack CLI. However, for the moment, this implementation will support only OpenID Connect. Therefore, to also support SAML, some adjustments will be needed in the future.

Gerrit topic: https://review.opendev.org/#/q/topic:bp/add-openid-support

Addressed by: https://review.opendev.org/695432
    Add suport to OpenID Connect Authentication flow

Gerrit topic: https://review.opendev.org/#/q/topic:openid-federation

(?)

Work Items

This blueprint contains Public information 
Everyone can see this information.