Skip to content

Instantly share code, notes, and snippets.

@arax
Last active October 23, 2023 17:31
Show Gist options
  • Save arax/1632db374fc203d726a9895854e26176 to your computer and use it in GitHub Desktop.
Save arax/1632db374fc203d726a9895854e26176 to your computer and use it in GitHub Desktop.
OpenStack with OpenID Connect and OAuth 2.0

OpenStack with OpenID Connect and OAuth 2.0

Motivation

  • Need to delegate user management, authentication, and (partially) authorization.
  • Different sources of "identity information", depending on user community. Only OpenID Connect (OAuth 2.0) in common.
  • Different levels of integration, depending on community. In some cases "part of a larger infrastructure", in some cases "ordinary stand-alone resource provider".

OpenID Connect

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.

OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and session management, when it makes sense for them.

OpenID Connect

For details, see OpenID Connect.

Authentication/Authorization Flow

GUI API

Dashboard Configuration

# Enables keystone web single-sign-on if set to True.
WEBSSO_ENABLED = True

# Determines which authentication choice to show as default.
WEBSSO_INITIAL_CHOICE = "login.cesnet.cz_openid"

# The list of authentication mechanisms which include keystone
# federation protocols and identity provider/federation protocol
# mapping keys (WEBSSO_IDP_MAPPING). Current supported protocol
# IDs are 'saml2' and 'openid' which represent SAML 2.0, OpenID
# Connect respectively.
# Do not remove the mandatory credentials mechanism.
# Note: The last two tuples are sample mapping keys to a identity provider
# and federation protocol combination (WEBSSO_IDP_MAPPING).
WEBSSO_CHOICES = (
    ("credentials", _("Keystone Credentials")),
    ("login.cesnet.cz_openid", _("EINFRA AAI")),
    ("aai.egi.eu_openid", _("EGI AAI")),
    ("login.elixir-czech.org_openid", _("ELIXIR AAI")),
    ("oidc.ics.muni.cz_openid", _("MUNI AAI")),
)

# A dictionary of specific identity provider and federation protocol
# combinations. From the selected authentication mechanism, the value
# will be looked up as keys in the dictionary. If a match is found,
# it will redirect the user to a identity provider and federation protocol
# specific WebSSO endpoint in keystone, otherwise it will use the value
# as the protocol_id when redirecting to the WebSSO by protocol endpoint.
# NOTE: The value is expected to be a tuple formatted as: (<idp_id>, <protocol_id>).
WEBSSO_IDP_MAPPING = {
    "login.cesnet.cz_openid": ("login.cesnet.cz", "openid"),
    "aai.egi.eu_openid": ("aai.egi.eu", "openid"),
    "login.elixir-czech.org_openid": ("login.elixir-czech.org", "openid"),
    "oidc.ics.muni.cz_openid": ("oidc.ics.muni.cz", "openid")
}

Apache2 Configuration for Keystone

  #############################################
  ## GUI
  #############################################

  OIDCMetadataDir /etc/httpd/oidc-metadata
  OIDCRedirectURI http://localhost:5000/oidc-callback
  OIDCCryptoPassphrase password
  OIDCClaimPrefix "OIDC-"
  OIDCClaimDelimiter ";"

  <Location "/oidc-callback">
    AuthType openid-connect
    Require valid-user
  </Location>

  <Location "/v3/auth/OS-FEDERATION/identity_providers/login.cesnet.cz/protocols/openid/websso">
    AuthType openid-connect

    OIDCDiscoverURL http://localhost:5000/oidc-callback?iss=https%3A%2F%2Flogin.cesnet.cz%2Foidc%2F
    Require claim iss:https://login.cesnet.cz/oidc/
  </Location>

  <Location "/v3/auth/OS-FEDERATION/identity_providers/login.elixir-czech.org/protocols/openid/websso">
    AuthType openid-connect
    
    OIDCDiscoverURL http://localhost:5000/oidc-callback?iss=https%3A%2F%2Flogin.elixir-czech.org%2Foidc%2F
    Require claim iss:https://login.elixir-czech.org/oidc/
  </Location>

  <Location "/v3/auth/OS-FEDERATION/identity_providers/aai.egi.eu/protocols/openid/websso">
    AuthType openid-connect
    
    OIDCDiscoverURL http://localhost:5000/oidc-callback?iss=https%3A%2F%2Faai-dev.egi.eu%2Foidc%2F
    Require claim iss:https://aai-dev.egi.eu/oidc/
  </Location>

  <Location "/v3/auth/OS-FEDERATION/identity_providers/oidc.ics.muni.cz/protocols/openid/websso">
    AuthType openid-connect
    
    OIDCDiscoverURL http://localhost:5000/oidc-callback?iss=https%3A%2F%2Foidc.ics.muni.cz%2Foidc%2F
    Require claim iss:https://oidc.ics.muni.cz/oidc/
  </Location>

  #############################################
  ## API
  #############################################

  # Use local ESACO introspection proxy to handle multiple Resource Server endpoints
  # with different providers -> different introspection endpoints
  OIDCOAuthIntrospectionEndpoint https://localhost:8156/introspect
  ### NEVER DO THIS IN PRODUCTION !!! ###
  OIDCOAuthSSLValidateServer Off
  OIDCOAuthClientID esaco-proxy
  OIDCOAuthClientSecret esaco-proxy-pass1+

  <Location "/v3/OS-FEDERATION/identity_providers/login.cesnet.cz/protocols/openid/auth">
    AuthType oauth20
    Require claim iss:https://login.cesnet.cz/oidc/
  </Location>

  <Location "/v3/OS-FEDERATION/identity_providers/login.elixir-czech.org/protocols/openid/auth">
    AuthType oauth20
    Require claim iss:https://login.elixir-czech.org/oidc/
  </Location>

  <Location "/v3/OS-FEDERATION/identity_providers/aai.egi.eu/protocols/openid/auth">
    AuthType oauth20
    Require claim iss:https://aai-dev.egi.eu/oidc/
  </Location>

  <Location "/v3/OS-FEDERATION/identity_providers/oidc.ics.muni.cz/protocols/openid/auth">
    AuthType oauth20
    Require claim iss:https://oidc.ics.muni.cz/oidc/
  </Location>

Keystone Configuration

[auth]
methods = password,token,mapped,application_credential,openid

[federation]
trusted_dashboard = https://dashboard-url/auth/websso/

[openid]
remote_id_attribute = HTTP_OIDC_ISS

ESACO Configuration

See ESACO Docs.

Keystone Mapping

Keystone

Domains

  • Separate domain for each identity provider.
  • Users, groups, projects strictly scoped to domain.
  • Role names global.

Personal Project

  • If you have the right claim ("catch-all membership" from the figure above), you are eligible for an auto-provisioned personal project.
  • Roles on the project are assigned directly to user.
  • Only default quota applies here since the project is auto-provisioned, unless manually adjusted later on.

Group Project

  • If you have the corresponding group membership claim, you are eligible to belong to a local group.
  • Local group is created manually.
  • Project(s) are created manually, with desired quotas.
  • Roles are manually assigned to group, not to individual users.

Examples

Personal project:

[
    {
        "local": [
            {
                "user": {
                    "name": "{0}",
                    "email": "{1}"
                }
            }
        ],
        "remote": [
            {
                "type": "HTTP_OIDC_SUB"
            },
            {
                "type": "HTTP_OIDC_EMAIL"
            }
        ]
    },
    {
        "local": [
            {
                "projects": [
                    {
                        "name": "{0}",
                        "roles": [
                            {
                                "name": "_member_"
                            }
                        ]
                    }
                ]
            }
        ],
        "remote": [
            {
                "type": "HTTP_OIDC_SUB"
            },
            {
                "type": "HTTP_OIDC_GROUPNAMES",
                "any_one_of": [
                    "meta:metacloud"
                ]
            }
        ]
    }
]

Mapping to group:

[
    {
        "local": [
            {
                "user": {
                    "name": "{0}",
                    "email": "{1}"
                }
            }
        ],
        "remote": [
            {
                "type": "HTTP_OIDC_SUB"
            },
            {
                "type": "HTTP_OIDC_EMAIL"
            }
        ]
    },
    {
        "local": [
            {
                "group": {
                    "name": "fedcloud.egi.eu",
                    "domain": {
                        "name": "egi.eu"
                    }
                }
            }
        ],
        "remote": [
            {
                "type": "OIDC-edu_person_entitlements",
                "any_one_of": [
                    "urn:mace:egi.eu:group:fedcloud.egi.eu:role=vm_operator#aai.egi.eu"
                ]
            }
        ]
    }
]

Caveats

  • Complex server-side set up.
  • Annoying CLI/API access with a bunch of different token types.
  • No de-provisioning/clean-up of user accounts and resources.
  • A bunch of configuration issues and bugs throughout the stack.
  • AFAIK, no support for domain quotas.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment