[Backport 7.x] OpenID Connect realm guide (#42836)

This commit adds a configuration guide for the newly introduced
OpenID Connect realm. The guide is similar to the style of the
SAML Guide and shares certain parts where applicable (role mapping)
It also contains a short section on how the realm can be used for
authenticating users without Kibana.

Co-Authored-By: Lisa Cawley <lcawley@elastic.co>

Backport of #41423 and #42555
This commit is contained in:
Ioannis Kakavas 2019-06-04 14:08:41 +03:00 committed by GitHub
parent 928f49992f
commit 440ec4d9f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 714 additions and 16 deletions

View File

@ -31,6 +31,7 @@ project.copyRestSpec.from(xpackResources) {
}
testClusters.integTest {
extraConfigFile 'op-jwks.json', xpackProject('test:idp-fixture').file("oidc/op-jwks.json")
setting 'xpack.security.enabled', 'true'
setting 'xpack.security.authc.api_key.enabled', 'true'
setting 'xpack.security.authc.token.enabled', 'true'
@ -38,6 +39,18 @@ testClusters.integTest {
setting 'xpack.monitoring.exporters._local.type', 'local'
setting 'xpack.monitoring.exporters._local.enabled', 'false'
setting 'xpack.license.self_generated.type', 'trial'
setting 'xpack.security.authc.realms.file.file.order', '0'
setting 'xpack.security.authc.realms.native.native.order', '1'
setting 'xpack.security.authc.realms.oidc.oidc1.order', '2'
setting 'xpack.security.authc.realms.oidc.oidc1.op.issuer', 'http://127.0.0.1:8080'
setting 'xpack.security.authc.realms.oidc.oidc1.op.authorization_endpoint', "http://127.0.0.1:8080/c2id-login"
setting 'xpack.security.authc.realms.oidc.oidc1.op.token_endpoint', "http://127.0.0.1:8080/c2id/token"
setting 'xpack.security.authc.realms.oidc.oidc1.op.jwkset_path', 'op-jwks.json'
setting 'xpack.security.authc.realms.oidc.oidc1.rp.redirect_uri', 'https://my.fantastic.rp/cb'
setting 'xpack.security.authc.realms.oidc.oidc1.rp.client_id', 'elasticsearch-rp'
keystore 'xpack.security.authc.realms.oidc.oidc1.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2'
setting 'xpack.security.authc.realms.oidc.oidc1.rp.response_type', 'id_token'
setting 'xpack.security.authc.realms.oidc.oidc1.claims.principal', 'sub'
user username: 'test_admin'
}

View File

@ -76,6 +76,8 @@ native realm:
* <<security-api-enable-user,Enable users>>
* <<security-api-get-user,Get users>>
[float]
[[security-openid-apis]]
=== OpenID Connect
You can use the following APIs to authenticate users against an OpenID Connect
@ -110,7 +112,7 @@ include::security/get-users.asciidoc[]
include::security/has-privileges.asciidoc[]
include::security/invalidate-api-keys.asciidoc[]
include::security/invalidate-tokens.asciidoc[]
include::security/ssl.asciidoc[]
include::security/oidc-prepare-authentication-api.asciidoc[]
include::security/oidc-authenticate-api.asciidoc[]
include::security/oidc-logout-api.asciidoc[]
include::security/ssl.asciidoc[]

View File

@ -46,11 +46,11 @@ The following example output provides information about the "rdeniro" user:
"metadata": { },
"enabled": true,
"authentication_realm": {
"name" : "default_file",
"name" : "file",
"type" : "file"
},
"lookup_realm": {
"name" : "default_file",
"name" : "file",
"type" : "file"
}
}

View File

@ -51,7 +51,7 @@ POST /_security/oidc/authenticate
}
--------------------------------------------------
// CONSOLE
// TEST[skip:These are properly tested in the OpenIDConnectIT suite]
// TEST[catch:unauthorized]
The following example output contains the access token that was generated in response, the amount of time (in
seconds) that the token expires in, the type, and the refresh token:

View File

@ -39,7 +39,7 @@ POST /_security/oidc/logout
}
--------------------------------------------------
// CONSOLE
// TEST[skip:These are properly tested in the OpenIDConnectIT suite]
// TEST[catch:unauthorized]
The following example output of the response contains the URI pointing to the End Session Endpoint of the
OpenID Connect Provider with all the parameters of the Logout Request, as HTTP GET parameters

View File

@ -57,20 +57,19 @@ POST /_security/oidc/prepare
}
--------------------------------------------------
// CONSOLE
// TEST[skip:These are properly tested in the OpenIDConnectIT suite]
The following example output of the response contains the URI pointing to the Authorization Endpoint of the
OpenID Connect Provider with all the parameters of the Authentication Request, as HTTP GET parameters
[source,js]
--------------------------------------------------
{
"redirect" : "https://op-provider.org/login?scope=openid&response_type=code&redirect_uri=http%3A%2F%2Foidc-kibana.elastic.co%3A5603%2Fkmi%2Fapi%2Fsecurity%2Fv1%2Foidc&state=4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I&nonce=WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM&client_id=0o43gasov3TxMWJOt839",
"redirect" : "http://127.0.0.1:8080/c2id-login?scope=openid&response_type=id_token&redirect_uri=https%3A%2F%2Fmy.fantastic.rp%2Fcb&state=4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I&nonce=WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM&client_id=elasticsearch-rp",
"state" : "4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I",
"nonce" : "WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM"
}
--------------------------------------------------
// NOTCONSOLE
// TESTRESPONSE[s/4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I/\$\{body.state\}/]
// TESTRESPONSE[s/WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM/\$\{body.nonce\}/]
The following example generates an authentication request for the OpenID Connect Realm `oidc1`, where the
values for the state and the nonce have been generated by the client
@ -85,7 +84,6 @@ POST /_security/oidc/prepare
}
--------------------------------------------------
// CONSOLE
// TEST[skip:These are properly tested in the OpenIDConnectIT suite]
The following example output of the response contains the URI pointing to the Authorization Endpoint of the
OpenID Connect Provider with all the parameters of the Authentication Request, as HTTP GET parameters
@ -93,12 +91,12 @@ OpenID Connect Provider with all the parameters of the Authentication Request, a
[source,js]
--------------------------------------------------
{
"redirect" : "https://op-provider.org/login?scope=openid&response_type=code&redirect_uri=http%3A%2F%2Foidc-kibana.elastic.co%3A5603%2Fkmi%2Fapi%2Fsecurity%2Fv1%2Foidc&state=lGYK0EcSLjqH6pkT5EVZjC6eIW5YCGgywj2sxROO&nonce=zOBXLJGUooRrbLbQk5YCcyC8AXw3iloynvluYhZ5&client_id=0o43gasov3TxMWJOt839",
"redirect" : "http://127.0.0.1:8080/c2id-login?scope=openid&response_type=id_token&redirect_uri=https%3A%2F%2Fmy.fantastic.rp%2Fcb&state=lGYK0EcSLjqH6pkT5EVZjC6eIW5YCGgywj2sxROO&nonce=zOBXLJGUooRrbLbQk5YCcyC8AXw3iloynvluYhZ5&client_id=elasticsearch-rp",
"state" : "lGYK0EcSLjqH6pkT5EVZjC6eIW5YCGgywj2sxROO",
"nonce" : "zOBXLJGUooRrbLbQk5YCcyC8AXw3iloynvluYhZ5"
}
--------------------------------------------------
// NOTCONSOLE
// TESTRESPONSE
The following example generates an authentication request for a 3rd party initiated single sign on, specifying the
issuer that should be used for matching the appropriate OpenID Connect Authentication realm
@ -107,12 +105,11 @@ issuer that should be used for matching the appropriate OpenID Connect Authentic
--------------------------------------------------
POST /_security/oidc/prepare
{
"issuer" : "https://op-issuer.org:8800",
"iss" : "http://127.0.0.1:8080",
"login_hint": "this_is_an_opaque_string"
}
--------------------------------------------------
// CONSOLE
// TEST[skip:These are properly tested in the OpenIDConnectIT suite]
The following example output of the response contains the URI pointing to the Authorization Endpoint of the
OpenID Connect Provider with all the parameters of the Authentication Request, as HTTP GET parameters
@ -120,9 +117,10 @@ OpenID Connect Provider with all the parameters of the Authentication Request, a
[source,js]
--------------------------------------------------
{
"redirect" : "https://op-provider.org/login?scope=openid&response_type=code&redirect_uri=http%3A%2F%2Foidc-kibana.elastic.co%3A5603%2Fkmi%2Fapi%2Fsecurity%2Fv1%2Foidc&state=lGYK0EcSLjqH6pkT5EVZjC6eIW5YCGgywj2sxROO&nonce=zOBXLJGUooRrbLbQk5YCcyC8AXw3iloynvluYhZ5&client_id=0o43gasov3TxMWJOt839&login_hint=this_is_an_opaque_string",
"redirect" : "http://127.0.0.1:8080/c2id-login?login_hint=this_is_an_opaque_string&scope=openid&response_type=id_token&redirect_uri=https%3A%2F%2Fmy.fantastic.rp%2Fcb&state=4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I&nonce=WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM&client_id=elasticsearch-rp",
"state" : "4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I",
"nonce" : "WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM"
}
--------------------------------------------------
// NOTCONSOLE
// TESTRESPONSE[s/4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I/\$\{body.state\}/]
// TESTRESPONSE[s/WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM/\$\{body.nonce\}/]

View File

@ -0,0 +1,685 @@
[role="xpack"]
[[oidc-guide]]
== Configuring single sign-on to the {stack} using OpenID Connect
The Elastic Stack supports single sign-on (SSO) using OpenID Connect via {kib} using
{es} as the backend service that holds most of the functionality. {kib} and {es}
together represent an OpenID Connect Relying Party (RP) that supports the Authorization
Code Flow as this is defined in the OpenID Connect specification.
This guide assumes that you have an OpenID Connect Provider where the
Elastic Stack Relying Party will be registered.
NOTE: The OpenID Connect realm support in {kib} is designed with the expectation that it
will be the primary authentication method for the users of that {kib} instance. The
<<oidc-kibana>> section describes what this entails and how you can set it up to support
other realms if necessary.
[[oidc-guide-op]]
=== The OpenID Connect Provider
The OpenID Connect Provider (OP) is the entity in OpenID Connect that is responsible for
authenticating the user and for granting the necessary tokens with the authentication and
user information to be consumed by the Relying Parties.
In order for the Elastic Stack to be able use your OpenID Connect Provider for authentication,
a trust relationship needs to be established between the OP and the RP. In the OpenID Connect
Provider, this means registering the RP as a client. OpenID Connect defines a dynamic client
registration protocol but this is usually geared towards real-time client registration and
not the trust establishment process for cross security domain single sign on. All OPs will
also allow for the manual registration of an RP as a client, via a user interface or (less often)
via the consumption of a metadata document.
The process for registering the Elastic Stack RP will be different from OP to OP and following
the provider's relevant documentation is prudent. The information for the
RP that you commonly need to provide for registration are the following:
- `Relying Party Name`: An arbitrary identifier for the relying party. Neither the specification
nor the Elastic Stack implementation impose any constraints on this value.
- `Redirect URI`: This is the URI where the OP will redirect the user's browser after authentication. The
appropriate value for this will depend on your setup and whether or not {kib} sits behind a proxy or
load balancer. It will typically be +$\{kibana-url}/api/security/v1/oidc+ where _$\{kibana-url}_
is the base URL for your {kib} instance. You might also see this called `Callback URI`.
At the end of the registration process, the OP will assign a Client Identifier and a Client Secret for the RP ({stack}) to use.
Note these two values as they will be used in the {es} configuration.
[[oidc-guide-authentication]]
=== Configure {es} for OpenID Connect authentication
The following is a summary of the configuration steps required in order to enable authentication
using OpenID Connect in {es}:
. <<oidc-enable-http,Enable SSL/TLS for HTTP>>
. <<oidc-enable-token,Enable the Token Service>>
. <<oidc-create-realm,Create one or more OpenID Connect realms>>
. <<oidc-role-mapping,Configure role mappings>>
[[oidc-enable-http]]
==== Enable TLS for HTTP
If your {es} cluster is operating in production mode, then you must
configure the HTTP interface to use SSL/TLS before you can enable OpenID Connect
authentication.
For more information, see
{ref}/configuring-tls.html#tls-http[Encrypting HTTP Client Communications].
[[oidc-enable-token]]
==== Enable the token service
The {es} OpenID Connect implementation makes use of the {es} Token Service. This service
is automatically enabled if you configure TLS on the HTTP interface, and can be
explicitly configured by including the following in your `elasticsearch.yml` file:
[source, yaml]
------------------------------------------------------------
xpack.security.authc.token.enabled: true
------------------------------------------------------------
[[oidc-create-realm]]
==== Create an OpenID Connect realm
OpenID Connect based authentication is enabled by configuring the appropriate realm within
the authentication chain for {es}.
This realm has a few mandatory settings, and a number of optional settings.
The available settings are described in detail in the
{ref}/security-settings.html#ref-oidc-settings[Security settings in {es}]. This
guide will explore the most common settings.
Create an OpenID Connect (the realm type is `oidc`) realm in your `elasticsearch.yml` file
similar to what is shown below:
NOTE: The values used below are meant to be an example and are not intended to apply to
every use case. The details below the configuration snippet provide insights and suggestions
to help you pick the proper values, depending on your OP configuration.
[source, yaml]
-------------------------------------------------------------------------------------
xpack.security.authc.realms.oidc.oidc1:
order: 2
rp.client_id: "the_client_id"
rp.response_type: code
rp.redirect_uri: "https://kibana.example.org:5601/api/security/v1/oidc"
op.issuer: "https://op.example.org"
op.authorization_endpoint: "https://op.example.org/oauth2/v1/authorize"
op.token_endpoint: "https://op.example.org/oauth2/v1/token"
op.jwkset_path: oidc/jwkset.json
op.userinfo_endpoint: "https://op.example.org/oauth2/v1/userinfo"
op.endsession_endpoint: "https://op.example.org/oauth2/v1/logout"
rp.post_logout_redirect_uri: "https://kibana.example.org:5601/logged_out"
claims.principal: sub
claims.groups: "http://example.info/claims/groups"
-------------------------------------------------------------------------------------
The configuration values used in the example above are:
xpack.security.authc.realms.oidc.oidc1::
This defines a new `oidc` authentication realm named "oidc1".
See <<realms>> for more explanation of realms.
order::
You should define a unique order on each realm in your authentication chain.
It is recommended that the OpenID Connect realm be at the bottom of your authentication
chain (that is, that it has the _highest_ order).
rp.client_id::
This, usually opaque, arbitrary string, is the Client Identifier that was assigned to the Elastic Stack RP by the OP upon
registration.
rp.response_type::
This is an identifier that controls which OpenID Connect authentication flow this RP supports and also
which flow this RP requests the OP should follow. Supported values are
- `code`, which means that the RP wants to use the Authorization Code flow. If your OP supports the
Authorization Code flow, you should select this instead of the Implicit Flow.
- `id_token token` which means that the RP wants to use the Implicit flow and we also request an oAuth2
access token from the OP, that we can potentially use for follow up requests ( UserInfo ). This
should be selected if the OP offers a UserInfo endpoint in its configuration, or if you know that
the claims you will need to use for role mapping are not available in the ID Token.
- `id_token` which means that the RP wants to use the Implicit flow, but is not interested in getting
an oAuth2 token too. Select this if you are certain that all necessary claims will be contained in
the ID Token or if the OP doesn't offer a User Info endpoint.
rp.redirect_uri::
The redirect URI where the OP will redirect the browser after authentication. This needs to be
_exactly_ the same as the one <<oidc-guide-op, configured with the OP upon registration>> and will
typically be +$\{kibana-url}/api/security/v1/oidc+ where _$\{kibana-url}_ is the base URL for your {kib} instance
op.issuer::
A verifiable Identifier for your OpenID Connect Provider. An Issuer Identifier is usually a case sensitive URL.
The value for this setting should be provided by your OpenID Connect Provider.
op.authorization_endpoint::
The URL for the Authorization Endpoint in the OP. This is where the user's browser
will be redirected to start the authentication process. The value for this setting should be provided by your
OpenID Connect Provider.
op.token_endpoint::
The URL for the Token Endpoint in the OpenID Connect Provider. This is the endpoint where
{es} will send a request to exchange the code for an ID Token, in the case where the Authorization Code
flow is used. The value for this setting should be provided by your OpenID Connect Provider.
op.jwkset_path::
The path to a file or a URL containing a JSON Web Key Set with the key material that the OpenID Connect
Provider uses for signing tokens and claims responses. If a path is set, it is resolved relative to the {es}
config directory.
{es} will automatically monitor this file for changes and will reload the configuration whenever
it is updated. Your OpenID Connect Provider should provide you with this file or a URL where it is available.
op.userinfo_endpoint::
(Optional) The URL for the UserInfo Endpoint in the OpenID Connect Provider. This is the endpoint of the OP that
can be queried to get further user information, if required. The value for this setting should be provided by your
OpenID Connect Provider.
op.endsession_endpoint::
(Optional) The URL to the End Session Endpoint in the OpenID Connect Provider. This is the endpoint where the user's
browser will be redirected after local logout, if the realm is configured for RP initiated Single Logout and
the OP supports it. The value for this setting should be provided by your OpenID Connect Provider.
rp.post_logout_redirect_uri::
(Optional) The Redirect URL where the OpenID Connect Provider should redirect the user after a
successful Single Logout (assuming `op.endsession_endpoint` above is also set). This should be set to a value that
will not trigger a new OpenID Connect Authentication, such as +$\{kibana-url}/logged_out+ where _$\{kibana-url}_ is
the base URL for your {kib} instance.
claims.principal:: See <<oidc-claims-mapping>>.
claims.groups:: See <<oidc-claims-mapping>>.
A final piece of configuration of the OpenID Connect realm is to set the `Client Secret` that was assigned
to the RP during registration in the OP. This is a secure setting and as such is not defined in the realm
configuration in `elasticsearch.yml` but added to the {ref}/secure-settings.html[elasticsearch keystore].
For instance
[source,sh]
----
bin/elasticsearch-keystore add xpack.security.authc.realms.oidc.oidc1.rp.client_secret
----
NOTE: According to the OpenID Connect specification, the OP should also make their configuration
available at a well known URL, which is the concatenation of their `Issuer` value with the
`.well-known/openid-configuration` string. For example: `https://op.org.com/.well-known/openid-configuration`
That document should contain all the necessary information to configure the OpenID Connect realm in {es}.
[[oidc-claims-mapping]]
==== Claims mapping
===== Claims and scopes
When authenticating to {kib} using OpenID Connect, the OP will provide information about the user
in the form of OpenID Connect Claims, that can be included either in the ID Token, or be retrieved from the
UserInfo endpoint of the OP. The claim is defined as a piece of information asserted by the OP
for the authenticated user. Simply put, a claim is a name/value pair that contains information about
the user. Related to claims, we also have the notion of OpenID Connect Scopes. Scopes are identifiers
that are used to request access to specific lists of claims. The standard defines a set of scope
identifiers that can be requested. The only mandatory one is `openid`, while commonly used ones are
`profile` and `email`. The `profile` scope requests access to the `name`,`family_name`,`given_name`,`middle_name`,`nickname`,
`preferred_username`,`profile`,`picture`,`website`,`gender`,`birthdate`,`zoneinfo`,`locale`, and `updated_at` claims.
The `email` scope requests access to the `email` and `email_verified` claims. The process is that
the RP requests specific scopes during the authentication request. If the OP Privacy Policy
allows it and the authenticating user consents to it, the related claims are returned to the
RP (either in the ID Token or as a UserInfo response).
The list of the supported claims will vary depending on the OP you are using, but you can expect
the https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims[Standard Claims] to be
largely supported.
[[oidc-claim-to-property]]
===== Mapping claims to user properties
The goal of claims mapping is to configure {es} in such a way as to be able to map the values of
specified returned claims to one of the <<oidc-user-properties, user properties>> that are supported
by {es}. These user properties are then utilized to identify the user in the {kib} UI or the audit
logs, and can also be used to create <<oidc-role-mapping, role mapping>> rules.
The recommended steps for configuring OpenID Claims mapping are as follows:
. Consult your OP configuration to see what claims it might support. Note that
the list provided in the OP's metadata or in the configuration page of the OP
is a list of potentially supported claims. However, for privacy reasons it might
not be a complete one, or not all supported claims will be available for all
authenticated users.
. Read through the list of <<oidc-user-properties, user properties>> that {es}
supports, and decide which of them are useful to you, and can be provided by
your OP in the form of claims. At a _minimum_, the `principal` user property
is required.
. Configure your OP to "release" those claims to your {stack} Relying
party. This process greatly varies by provider. You can use a static
configuration while others will support that the RP requests the scopes that
correspond to the claims to be "released" on authentication time. See
{ref}/security-settings.html#ref-oidc-settings[`rp.requested_scopes`] for details about how
to configure the scopes to request. To ensure interoperability and minimize
the errors, you should only request scopes that the OP supports, and which you
intend to map to {es} user properties.
. Configure the OpenID Connect realm in {es} to associate the {es} user properties (see
<<oidc-user-properties, the listing>> below), to the name of the claims that your
OP will release. In the example above, we have configured the `principal` and
`groups` user properties as follows:
.. `claims.principal: sub` : This instructs {es} to look for the OpenID Connect claim named `sub`
in the ID Token that the OP issued for the user ( or in the UserInfo response ) and assign the
value of this claim to the `principal` user property. `sub` is a commonly used claim for the
principal property as it is an identifier of the user in the OP and it is also a required
claim of the ID Token, thus offering guarantees that it will be available. It is, however,
only used as an example here, the OP may provide another claim that is a better fit for your needs.
.. `claims.groups: "http://example.info/claims/groups"` : Similarly, this instructs {es} to look
for the claim with the name `http://example.info/claims/groups` (note that this is a URI - an
identifier, treated as a string and not a URL pointing to a location that will be retrieved)
either in the ID Token or in the UserInfo response, and map the value(s) of it to the user
property `groups` in {es}. There is no standard claim in the specification that is used for
expressing roles or group memberships of the authenticated user in the OP, so the name of the
claim that should be mapped here, will vary greatly between providers. Consult your OP
documentation for more details.
[[oidc-user-properties]]
===== {es} user properties
The {es} OpenID Connect realm can be configured to map OpenID Connect claims to the
following properties on the authenticated user:
principal:: _(Required)_
This is the _username_ that will be applied to a user that authenticates
against this realm.
The `principal` appears in places such as the {es} audit logs.
NOTE: If the principal property fails to be mapped from a claim, the authentication fails.
groups:: _(Recommended)_
If you wish to use your OP's concept of groups or roles as the basis for a
user's {es} privileges, you should map them with this property.
The `groups` are passed directly to your <<oidc-role-mapping, role mapping rules>>.
name:: _(Optional)_ The user's full name.
mail:: _(Optional)_ The user's email address.
dn:: _(Optional)_ The user's X.500 _Distinguished Name_.
===== Extracting partial values from OpenID Connect claims
There are some occasions where the value of a claim may contain more information
than you wish to use within {es}. A common example of this is one where the
OP works exclusively with email addresses, but you would like the user's
`principal` to use the _local-name_ part of the email address.
For example if their email address was `james.wong@staff.example.com`, then you
would like their principal to simply be `james.wong`.
This can be achieved using the `claim_patterns` setting in the {es}
realm, as demonstrated in the realm configuration below:
[source, yaml]
-------------------------------------------------------------------------------------
xpack.security.authc.realms.oidc.oidc1:
order: 2
rp.client_id: "the_client_id"
rp.response_type: code
rp.redirect_uri: "https://kibana.example.org:5601/api/security/v1/oidc"
op.authorization_endpoint: "https://op.example.org/oauth2/v1/authorize"
op.token_endpoint: "https://op.example.org/oauth2/v1/token"
op.userinfo_endpoint: "https://op.example.org/oauth2/v1/userinfo"
op.endsession_endpoint: "https://op.example.org/oauth2/v1/logout"
op.issuer: "https://op.example.org"
op.jwkset_path: oidc/jwkset.json
claims.principal: email_verified
claim_patterns.principal: "^([^@]+)@staff\\.example\\.com$"
-------------------------------------------------------------------------------------
In this case, the user's `principal` is mapped from the `email_verified` claim, but a
regular expression is applied to the value before it is assigned to the user.
If the regular expression matches, then the result of the first group is used as the
effective value. If the regular expression does not match then the claim
mapping fails.
In this example, the email address must belong to the `staff.example.com` domain,
and then the local-part (anything before the `@`) is used as the principal.
Any users who try to login using a different email domain will fail because the
regular expression will not match against their email address, and thus their
principal user property - which is mandatory - will not be populated.
IMPORTANT: Small mistakes in these regular expressions can have significant
security consequences. For example, if we accidentally left off the trailing
`$` from the example above, then we would match any email address where the
domain starts with `staff.example.com`, and this would accept an email
address such as `admin@staff.example.com.attacker.net`. It is important that
you make sure your regular expressions are as precise as possible so that
you do not inadvertently open an avenue for user impersonation attacks.
[[third-party-login]]
==== Third party initiated single sign-on
The Open ID Connect realm in {es} supports 3rd party initiated login as described in the
https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin[relevant specification].
This allows the OP itself or another, third party other than the RP, to initiate the authentication
process while requesting the OP to be used for the authentication. Please note that the Elastic
Stack RP should already be configured for this OP, in order for this process to succeed.
[[oidc-logout]]
==== OpenID Connect Logout
The OpenID Connect realm in {es} supports RP-Initiated Logout Functionality as
described in the
https://openid.net/specs/openid-connect-session-1_0.html#RPLogout[relevant part of the specification]
In this process, the OpenID Connect RP (the Elastic Stack in this case) will redirect the user's
browser to predefined URL of the OP after successfully completing a local logout. The OP can then
logout the user also, depending on the configuration, and should finally redirect the user back to the
RP. The `op.endsession_endpoint` in the realm configuration determines the URL in the OP that the browser
will be redirected to. The `rp.post_logout_redirect_uri` setting determines the URL to redirect
the user back to after the OP logs them out.
When configuring `rp.post_logout_redirect_uri`, care should be taken to not point this to a URL that
will trigger re-authentication of the user. For instance, when using OpenID Connect to support
single sign-on to {kib}, this could be set to +$\{kibana-url}/logged_out+, which will show a user-
friendly message to the user.
[[oidc-ssl-config]]
==== OpenID Connect Realm SSL Configuration
OpenID Connect depends on TLS to provide security properties such as encryption in transit and endpoint authentication. The RP
is required to establish back-channel communication with the OP in order to exchange the code for an ID Token during the
Authorization code grant flow and in order to get additional user information from the UserInfo endpoint. Furthermore, if
you configure `op.jwks_path` as a URL, {es} will need to get the OP's signing keys from the file hosted there. As such, it is
important that {es} can validate and trust the server certificate that the OP uses for TLS. Since the system truststore is
used for the client context of outgoing https connections, if your OP is using a certificate from a trusted CA, no additional
configuration is needed.
However, if the issuer of your OP's certificate is not trusted by the JVM on which {es} is running (e.g it uses a organization CA), then you must configure
{es} to trust that CA. Assuming that you have the CA certificate that has signed the certificate that the OP uses for TLS
stored in the /oidc/company-ca.pem` file stored in the configuration directory of {es}, you need to set the following
property in the realm configuration:
[source, yaml]
-------------------------------------------------------------------------------------
xpack.security.authc.realms.oidc.oidc1:
order: 1
...
ssl.certificate_authorities: ["/oidc/company-ca.pem"]
-------------------------------------------------------------------------------------
[[oidc-role-mapping]]
=== Configuring role mappings
When a user authenticates using OpenID Connect, they are identified to the Elastic Stack,
but this does not automatically grant them access to perform any actions or
access any data.
Your OpenID Connect users cannot do anything until they are assigned roles. This can be done
through either the
{ref}/security-api-put-role-mapping.html[add role mapping API], or with
<<authorization_realms, authorization realms>>.
NOTE: You cannot use {stack-ov}/mapping-roles.html#mapping-roles-file[role mapping files]
to grant roles to users authenticating via OpenID Connect.
This is an example of a simple role mapping that grants the `kibana_user` role
to any user who authenticates against the `oidc1` OpenID Connect realm:
[source,js]
--------------------------------------------------
PUT /_security/role_mapping/oidc-kibana
{
"roles": [ "kibana_user" ],
"enabled": true,
"rules": {
"field": { "realm.name": "oidc1" }
}
}
--------------------------------------------------
// CONSOLE
// TEST
The user properties that are mapped via the realm configuration are used to process
role mapping rules, and these rules determine which roles a user is granted.
The user fields that are provided to the role
mapping are derived from the OpenID Connect claims as follows:
- `username`: The `principal` user property
- `dn`: The `dn` user property
- `groups`: The `groups` user property
- `metadata`: See <<oidc-user-metadata>>
For more information, see <<mapping-roles>> and
{ref}/security-api.html#security-role-mapping-apis[role mapping APIs].
If your OP has the ability to provide groups or roles to RPs via tha use of
an OpenID Claim, then you should map this claim to the `claims.groups` setting in
the {es} realm (see <<oidc-claim-to-property>>), and then make use of it in a role mapping
as per the example below.
This mapping grants the {es} `finance_data` role, to any users who authenticate
via the `oidc1` realm with the `finance-team` group membership.
[source,js]
--------------------------------------------------
PUT /_security/role_mapping/oidc-finance
{
"roles": [ "finance_data" ],
"enabled": true,
"rules": { "all": [
{ "field": { "realm.name": "oidc1" } },
{ "field": { "groups": "finance-team" } }
] }
}
--------------------------------------------------
// CONSOLE
// TEST
If your users also exist in a repository that can be directly accessed by {es}
(such as an LDAP directory) then you can use
<<authorization_realms, authorization realms>> instead of role mappings.
In this case, you perform the following steps:
1. In your OpenID Connect realm, assign a claim to act as the lookup userid,
by configuring the `claims.principal` setting.
2. Create a new realm that can lookup users from your local repository (e.g. an
`ldap` realm)
3. In your OpenID Connect realm, set `authorization_realms` to the name of the realm you
created in step 2.
[[oidc-user-metadata]]
=== User metadata
By default users who authenticate via OpenID Connect will have some additional metadata
fields. These fields will include every OpenID Claim that is provided in the authentication response
(regardless of whether it is mapped to an {es} user property). For example,
in the metadata field `oidc(claim_name)`, "claim_name" is the name of the
claim as it was contained in the ID Token or in the User Info response. Note that these will
include all the https://openid.net/specs/openid-connect-core-1_0.html#IDToken[ID Token claims]
that pertain to the authentication event, rather than the user themselves.
This behaviour can be disabled by adding `populate_user_metadata: false` as
a setting in the oidc realm.
[[oidc-kibana]]
=== Configuring {kib}
OpenID Connect authentication in {kib} requires a small number of additional settings
in addition to the standard {kib} security configuration. The
{kibana-ref}/using-kibana-with-security.html[{kib} security documentation]
provides details on the available configuration options that you can apply.
In particular, since your {es} nodes have been configured to use TLS on the HTTP
interface, you must configure {kib} to use a `https` URL to connect to {es}, and
you may need to configure `elasticsearch.ssl.certificateAuthorities` to trust
the certificates that {es} has been configured to use.
OpenID Connect authentication in {kib} is also subject to the
`xpack.security.sessionTimeout` setting that is described in the {kib} security
documentation, and you may wish to adjust this timeout to meet your local needs.
The three additional settings that are required for OpenID Connect support are shown below:
[source, yaml]
------------------------------------------------------------
xpack.security.authProviders: [oidc]
xpack.security.auth.oidc.realm: "oidc1"
server.xsrf.whitelist: [/api/security/v1/oidc]
------------------------------------------------------------
The configuration values used in the example above are:
`xpack.security.authProviders`::
Set this to `[ oidc ]` to instruct {kib} to use OpenID Connect single sign-on as the
authentication method. This instructs Kibana to attempt to initiate an SSO flow
everytime a user attempts to access a URL in Kibana, if the user is not already
authenticated. If you also want to allow users to login with a username and password,
you must enable the `basic` authProvider too. For example:
[source, yaml]
------------------------------------------------------------
xpack.security.authProviders: [oidc, basic]
------------------------------------------------------------
This will allow users that haven't already authenticated with OpenID Connect to
navigate directly to the `/login` page in {kib} in order to use the login form.
`xpack.security.auth.oidc.realm`::
The name of the OpenID Connect realm in {es} that should handle authentication
for this Kibana instance.
`server.xsrf.whitelist`::
{kib} has in-built protection against _Cross Site Request Forgery_ attacks, which
is designed to prevent the {kib} server from processing requests that
originated from outside the {kib} application.
In order to support OpenID Connect messages that originate from your
OP or a third party (see <<third-party-login>>, we need to explicitly _whitelist_ the
OpenID Connect authentication endpoint within {kib}, so that the {kib} server will
not reject these external messages.
=== OpenID Connect without {kib}
The OpenID Connect realm is designed to allow users to authenticate to {kib} and as
such, most of the parts of the guide above make the assumption that {kib} is used.
This section describes how a custom web application could use the relevant OpenID
Connect REST APIs in order to authenticate the users to {es}, with OpenID Connect.
Single sign-on realms such as OpenID Connect and SAML make use of the Token Service in
{es} and in principle exchange a SAML or OpenID Connect Authentication response for
an {es} access token and a refresh token. The access token is used as credentials for subsequent calls to {es}. The
refresh token enables the user to get new {es} access tokens after the current one
expires.
NOTE: The {es} Token Service can be seen as a minimal oAuth2 authorization server
and the access token and refresh token mentioned above are tokens that pertain
_only_ to this authorization server. They are generated and consumed _only_ by {es}
and are in no way related to the tokens ( access token and ID Token ) that the
OpenID Connect Provider issues.
==== Register the RP with an OpenID Connect Provider
The Relying Party ( {es} and the custom web app ) will need to be registered as
client with the OpenID Connect Provider. Note that when registering the
`Redirect URI`, it needs to be a URL in the custom web app.
==== OpenID Connect Realm
An OpenID Connect realm needs to be created and configured accordingly
in {es}. See <<oidc-guide-authentication>>
==== Service Account user for accessing the APIs
The realm is designed with the assumption that there needs to be a privileged entity
acting as an authentication proxy. In this case, the custom web application is the
authentication proxy handling the authentication of end users ( more correctly,
"delegating" the authentication to the OpenID Connect Provider ). The OpenID Connect
APIs require authentication and the necessary authorization level for the authenticated
user. For this reason, a Service Account user needs to be created and assigned a role
that gives them the `manage_oidc` cluster privilege. The use of the `manage_token`
cluster privilege will be necessary after the authentication takes place, so that the
the user can maintain access or be subsequently logged out.
[source,js]
--------------------------------------------------
POST /_security/role/facilitator-role
{
"cluster" : ["manage_oidc", "manage_token"]
}
--------------------------------------------------
// CONSOLE
[source,js]
--------------------------------------------------
POST /_security/user/facilitator
{
"password" : "<somePasswordHere>",
"roles" : [ "facilitator-role"]
}
--------------------------------------------------
// CONSOLE
==== Handling the authentication flow
On a high level, the custom web application would need to perform the following steps in order to
authenticate a user with OpenID Connect:
. Make an HTTP POST request to `_security/oidc/prepare`, authenticating as the `facilitator` user, using the name of the
OpenID Connect realm in the {es} configuration in the request body. See the
{ref}/security-api-oidc-prepare-authentication.html[OIDC Prepare Authentication API] for more details
+
[source,js]
--------------------------------------------------
POST /_security/oidc/prepare
{
"realm" : "oidc1"
}
--------------------------------------------------
// CONSOLE
+
. Handle the response to `/_security/oidc/prepare`. The response from {es} will contain 3 parameters:
`redirect`, `state`, `nonce`. The custom web application would need to store the values for `state`
and `nonce` in the user's session (client side in a cookie or server side if session information is
persisted this way) and redirect the user's browser to the URL that will be contained in the
`redirect` value.
. Handle a subsequent response from the OP. After the user is successfully authenticated with the
OpenID Connect Provider, they will be redirected back to the callback/redirect URI. Upon receiving
this HTTP GET request, the custom web app will need to make an HTTP POST request to
`_security/oidc/authenticate`, again - authenticating as the `facilitator` user - passing the URL
where the user's browser was redirected to, as a parameter, along with the
values for `nonce` and `state` it had saved in the user's session previously.
See {ref}/security-api-oidc-authenticate.html[OIDC Authenticate API] for more details
+
[source,js]
-----------------------------------------------------------------------
POST /_security/oidc/authenticate
{
"redirect_uri" : "https://oidc-kibana.elastic.co:5603/api/security/v1/oidc?code=jtI3Ntt8v3_XvcLzCFGq&state=4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I",
"state" : "4dbrihtIAt3wBTwo6DxK-vdk-sSyDBV8Yf0AjdkdT5I",
"nonce" : "WaBPH0KqPVdG5HHdSxPRjfoZbXMCicm5v1OiAj0DUFM"
}
-----------------------------------------------------------------------
// CONSOLE
// TEST[catch:unauthorized]
+
Elasticsearch will validate this and if all is correct will respond with an access token that can be used
as a `Bearer` token for subsequent requests and a refresh token that can be later used to refresh the given
access token as described in {ref}/security-api-get-token.html[get token API].
. At some point, if necessary, the custom web application can log the user out by using the
{ref}/security-api-oidc-logout.html[OIDC Logout API] passing the access token and refresh token as parameters. For example:
+
[source,js]
--------------------------------------------------
POST /_security/oidc/logout
{
"token" : "dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvbmx5IHRlc3QgZGF0YS4gZG8gbm90IHRyeSB0byByZWFkIHRva2VuIQ==",
"refresh_token": "vLBPvmAB6KvwvJZr27cS"
}
--------------------------------------------------
// CONSOLE
// TEST[catch:unauthorized]
+
If the realm is configured accordingly, this may result in a response with a `redirect` parameter indicating where
the user needs to be redirected in the OP in order to complete the logout process.