diff --git a/docs/reference/settings/security-settings.asciidoc b/docs/reference/settings/security-settings.asciidoc index 58ec623282c72..bcde849402086 100644 --- a/docs/reference/settings/security-settings.asciidoc +++ b/docs/reference/settings/security-settings.asciidoc @@ -858,10 +858,13 @@ Defaults to `100000`. `delegation.enabled`:: Generally, in order for the clients to be authenticated by the PKI realm they must connect directly to {es}. That is, they must not pass through proxies -which terminate the TLS connection. In order to allow for a *trusted* and +which terminate the TLS connection. In order to allow for a *trusted* and *smart* proxy, such as Kibana, to sit before {es} and terminate TLS connections, but still allow clients to be authenticated on {es} by this realm, -you need to toggle this to `true`. Defaults to `false`. +you need to toggle this to `true`. Defaults to `false`. If delegation is +enabled, then either `truststore.path` or `certificate_authorities` setting +must be defined. For more details, see <>. [[ref-saml-settings]] [float] diff --git a/x-pack/docs/build.gradle b/x-pack/docs/build.gradle index fe07450bbc10e..df4a318e1ffd2 100644 --- a/x-pack/docs/build.gradle +++ b/x-pack/docs/build.gradle @@ -34,6 +34,7 @@ project.copyRestSpec.from(xpackResources) { testClusters.integTest { extraConfigFile 'op-jwks.json', xpackProject('test:idp-fixture').file("oidc/op-jwks.json") + extraConfigFile 'testClient.crt', xpackProject('plugin:security').file("src/test/resources/org/elasticsearch/xpack/security/action/pki_delegation/testClient.crt") setting 'xpack.security.enabled', 'true' setting 'xpack.security.authc.api_key.enabled', 'true' setting 'xpack.security.authc.token.enabled', 'true' @@ -53,6 +54,9 @@ testClusters.integTest { 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' + setting 'xpack.security.authc.realms.pki.pki1.order', '3' + setting 'xpack.security.authc.realms.pki.pki1.certificate_authorities', '[ "testClient.crt" ]' + setting 'xpack.security.authc.realms.pki.pki1.delegation.enabled', 'true' user username: 'test_admin' } diff --git a/x-pack/docs/en/rest-api/security.asciidoc b/x-pack/docs/en/rest-api/security.asciidoc index 059dbc1e74716..d385ef29c4672 100644 --- a/x-pack/docs/en/rest-api/security.asciidoc +++ b/x-pack/docs/en/rest-api/security.asciidoc @@ -6,6 +6,7 @@ You can use the following APIs to perform security activities. * <> * <> +* <> * <> * <> * <> @@ -98,6 +99,7 @@ include::security/put-app-privileges.asciidoc[] include::security/create-role-mappings.asciidoc[] include::security/create-roles.asciidoc[] include::security/create-users.asciidoc[] +include::security/delegate-pki-authentication.asciidoc[] include::security/delete-app-privileges.asciidoc[] include::security/delete-role-mappings.asciidoc[] include::security/delete-roles.asciidoc[] diff --git a/x-pack/docs/en/rest-api/security/delegate-pki-authentication.asciidoc b/x-pack/docs/en/rest-api/security/delegate-pki-authentication.asciidoc new file mode 100644 index 0000000000000..92d82f1c273e9 --- /dev/null +++ b/x-pack/docs/en/rest-api/security/delegate-pki-authentication.asciidoc @@ -0,0 +1,96 @@ +[role="xpack"] +[[security-api-delegate-pki-authentication]] +=== Delegate PKI authentication API +++++ +Delegate PKI authentication +++++ + +Implements the exchange of an {@code X509Certificate} chain into an {es} access +token. + +[[security-api-delegate-pki-authentication-request]] +==== {api-request-title} + +`POST /_security/delegate_pki` + +[[security-api-delegate-pki-authentication-prereqs]] +==== {api-prereq-title} + +* To call this API, the (proxy) user must have the `delegate_pki` or the `all` +cluster privilege. The `kibana_system` built-in role already grants this +privilege. See {stack-ov}/security-privileges.html[Security privileges]. + +[[security-api-delegate-pki-authentication-desc]] +==== {api-description-title} + +This API implements the exchange of an _X509Certificate_ chain for an {es} +access token. The certificate chain is validated, according to RFC 5280, by +sequentially considering the trust configuration of every installed PKI realm +that has `delegation.enabled` set to `true` (default is `false`). A +successfully trusted client certificate is also subject to the validation of +the subject distinguished name according to that respective's realm +`username_pattern`. + +This API is called by *smart* and *trusted* proxies, such as {kib}, which +terminate the user's TLS session but still want to authenticate the user +by using a PKI realm--as if the user connected directly to {es}. For more +details, see <>. + +IMPORTANT: The association between the subject public key in the target +certificate and the corresponding private key is *not* validated. This is part +of the TLS authentication process and it is delegated to the proxy that calls +this API. The proxy is *trusted* to have performed the TLS authentication and +this API translates that authentication into an {es} access token. + +[[security-api-delegate-pki-authentication-request-body]] +==== {api-request-body-title} + +`x509_certificate_chain`:: +(Required, list of strings) The _X509Certificate_ chain, which is represented as +an ordered string array. Each string in the array is a base64-encoded +(Section 4 of RFC4648 - not base64url-encoded) of the certificate's DER encoding. ++ +The first element is the target certificate contains the subject distinguished +name that is requesting access. This may be followed by additional certificates; +each subsequent certificate is used to certify the previous one. + + +[[security-api-delegate-pki-authentication-response-body]] +==== {api-response-body-title} + +`access_token`:: +(string) An access token associated to the subject distinguished name of the +client's certificate. + +`expires_in`:: +(time units) The amount of time (in seconds) that the token expires in. + +`type`:: +(string) The type of token. + +[[security-api-delegate-pki-authentication-example]] +==== {api-examples-title} + +The following is an example request: + +[source, js] +------------------------------------------------------------ +POST /_security/delegate_pki +{ + "x509_certificate_chain": ["MIIDbTCCAlWgAwIBAgIJAIxTS7Qdho9jMA0GCSqGSIb3DQEBCwUAMFMxKzApBgNVBAMTIkVsYXN0aWNzZWFyY2ggVGVzdCBJbnRlcm1lZGlhdGUgQ0ExFjAUBgNVBAsTDUVsYXN0aWNzZWFyY2gxDDAKBgNVBAoTA29yZzAeFw0xOTA3MTkxMzMzNDFaFw0yMzA3MTgxMzMzNDFaMEoxIjAgBgNVBAMTGUVsYXN0aWNzZWFyY2ggVGVzdCBDbGllbnQxFjAUBgNVBAsTDUVsYXN0aWNzZWFyY2gxDDAKBgNVBAoTA29yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANHgMX2aX8t0nj4sGLNuKISmmXIYCj9RwRqS7L03l9Nng7kOKnhHu/nXDt7zMRJyHj+q6FAt5khlavYSVCQyrDybRuA5z31gOdqXerrjs2OXS5HSHNvoDAnHFsaYX/5geMewVTtc/vqpd7Ph/QtaKfmG2FK0JNQo0k24tcgCIcyMtBh6BA70yGBM0OT8GdOgd/d/mA7mRhaxIUMNYQzRYRsp4hMnnWoOTkR5Q8KSO3MKw9dPSpPe8EnwtJE10S3s5aXmgytru/xQqrFycPBNj4KbKVmqMP0G60CzXik5pr2LNvOFz3Qb6sYJtqeZF+JKgGWdaTC89m63+TEnUHqk0lcCAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQU/+aAD6Q4mFq1vpHorC25/OY5zjcwHwYDVR0jBBgwFoAU8siFCiMiYZZm/95qFC75AG/LRE0wDQYJKoZIhvcNAQELBQADggEBAIRpCgDLpvXcgDHUk10uhxev21mlIbU+VP46ANnCuj0UELhTrdTuWvO1PAI4z+WbDUxryQfOOXO9R6D0dE5yR56L/J7d+KayW34zU7yRDZM7+rXpocdQ1Ex8mjP9HJ/Bf56YZTBQJpXeDrKow4FvtkI3bcIMkqmbG16LHQXeG3RS4ds4S4wCnE2nA6vIn9y+4R999q6y1VSBORrYULcDWxS54plHLEdiMr1vVallg82AGobS9GMcTL2U4Nx5IYZG7sbTk3LrDxVpVg/S2wLofEdOEwqCeHug/iOihNLJBabEW6z4TDLJAVW5KCY1DfhkYlBfHn7vxKkfKoCUK/yLWWI="] <1> +} +------------------------------------------------------------ +// CONSOLE +<1> A one element certificate chain. + +Which returns the following response: + +[source,js] +-------------------------------------------------- +{ + "access_token" : "dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvbmx5IHRlc3QgZGF0YS4gZG8gbm90IHRyeSB0byByZWFkIHRva2VuIQ==", + "type" : "Bearer", + "expires_in" : 1200 +} +-------------------------------------------------- +// TESTRESPONSE[s/dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvbmx5IHRlc3QgZGF0YS4gZG8gbm90IHRyeSB0byByZWFkIHRva2VuIQ==/$body.access_token/] diff --git a/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc b/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc index 58144d0b23c1a..a3fc1a6c0b0a1 100644 --- a/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc +++ b/x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc @@ -2,26 +2,39 @@ [[configuring-pki-realm]] === Configuring a PKI realm -You can configure {es} to use Public Key Infrastructure (PKI) certificates -to authenticate users. This requires clients to present X.509 certificates. +You can configure {es} to use Public Key Infrastructure (PKI) certificates to +authenticate users. This requires clients connecting directly to {es} to +present X.509 certificates. The certificates must first be accepted for +authentication on the SSL/TLS layer on {es}. Only then they are optionally +further validated by a PKI realm. -NOTE: You cannot use PKI certificates to authenticate users in {kib}. +Users may also use PKI certificates to authenticate to {kib}, however this +requires some <>. On +{es}, this configuration enables {kib} to act as a proxy for SSL/TLS +authentication and to submit the client certificates to {es} for further +validation by a PKI realm. + +For more general information, see {stack-ov}/pki-realm.html[PKI user authentication]. + +[float] +[role="xpack"] +[[pki-realm-for-direct-clients]] +==== PKI authentication for clients connecting directly to {es} To use PKI in {es}, you configure a PKI realm, enable client authentication on -the desired network layers (transport or http), and map the Distinguished Names -(DNs) from the user certificates to roles in the -<> or role-mapping file. +the desired network layers (transport or http), and map the Distinguished Name +(DN) from the Subject field in the user certificate to roles by using the +<> or the role-mapping file. You can also use a combination of PKI and username/password authentication. For example, you can enable SSL/TLS on the transport layer and define a PKI realm to require transport clients to authenticate with X.509 certificates, while still -authenticating HTTP traffic using username and password credentials. You can -also set `xpack.security.transport.ssl.client_authentication` to `optional` to +authenticating HTTP traffic using username and password credentials. You can +also set `xpack.security.transport.ssl.client_authentication` to `optional` to allow clients without certificates to authenticate with other credentials. -IMPORTANT: You must enable SSL/TLS and enable client authentication to use PKI. - -For more information, see {stack-ov}/pki-realm.html[PKI User Authentication]. +IMPORTANT: You must enable SSL/TLS with client authentication to use PKI when +clients connect directly to {es}. . Add a realm configuration for a `pki` realm to `elasticsearch.yml` under the `xpack.security.authc.realms.pki` namespace. @@ -43,17 +56,19 @@ xpack: order: 1 ------------------------------------------------------------ -With this configuration, any certificate trusted by the SSL/TLS layer is accepted -for authentication. The username is the common name (CN) extracted from the DN -of the certificate. +With this configuration, any certificate trusted by the {es} SSL/TLS layer is +accepted for authentication. The username is the common name (CN) extracted +from the DN in the Subject field of the end-entity certificate. This +configuration does not permit PKI authentication to {kib}. IMPORTANT: When you configure realms in `elasticsearch.yml`, only the realms you specify are used for authentication. If you also want to use the `native` or `file` realms, you must include them in the realm chain. -If you want to use something other than the CN of the DN as the username, you -can specify a regex to extract the desired username. For example, the regex in -the following configuration extracts the email address from the DN: +If you want to use something other than the CN of the Subject DN as the +username, you can specify a regex to extract the desired username. The regex is +applied on the Subject DN. For example, the regex in the following +configuration extracts the email address from the Subject DN: [source, yaml] ------------------------------------------------------------ @@ -65,23 +80,29 @@ xpack: pki1: username_pattern: "EMAILADDRESS=(.*?)(?:,|$)" ------------------------------------------------------------ + +NOTE: If the regex is too restrictive and does not match the Subject DN of the +client's certificate, then the realm does not authenticate the certificate. + -- -. Restart {es}. +. Restart {es} because realm configuration is not reloaded automatically. If +you're following through with the next steps, you might wish to hold the +restart for last. -. <>. +. <>. . Enable client authentication on the desired network layers (transport or http). + -- -The PKI realm relies on the TLS settings of the node's network interface. The -realm can be configured to be more restrictive than the underlying network -connection - that is, it is possible to configure the node such that some -connections are accepted by the network interface but then fail to be -authenticated by the PKI realm. However, the reverse is not possible. The PKI -realm cannot authenticate a connection that has been refused by the network -interface. +When clients connect directly to {es} and are not proxy-authenticated, the PKI +realm relies on the TLS settings of the node's network interface. The realm can +be configured to be more restrictive than the underlying network connection. +That is, it is possible to configure the node such that some connections +are accepted by the network interface but then fail to be authenticated by the +PKI realm. However, the reverse is not possible. The PKI realm cannot +authenticate a connection that has been refused by the network interface. In particular this means: @@ -96,14 +117,15 @@ In particular this means: used by the client. The relevant network interface (transport or http) must be configured to trust -any certificate that is to be used within the PKI realm. However, it possible to +any certificate that is to be used within the PKI realm. However, it is possible to configure the PKI realm to trust only a _subset_ of the certificates accepted by the network interface. This is useful when the SSL/TLS layer trusts clients with certificates that are signed by a different CA than the one that signs your users' certificates. -To configure the PKI realm with its own truststore, specify the `truststore.path` -option. For example: +To configure the PKI realm with its own truststore, specify the +`truststore.path` option. The path must be located within the Elasticsearch +configuration directory (ES_PATH_CONF). For example: [source, yaml] ------------------------------------------------------------ @@ -114,22 +136,33 @@ xpack: pki: pki1: truststore: - path: "/path/to/pki_truststore.jks" - password: "x-pack-test-password" + path: "pki1_truststore.jks" +------------------------------------------------------------ + +If the truststore is password protected, the password should be configured by +adding the appropriate `secure_password` setting to the {es} keystore. For +example, the following command adds the password for the example realm above: + +[source, shell] +------------------------------------------------------------ +bin/elasticsearch-keystore add \ +xpack.security.authc.realms.pki.pki1.truststore.secure_password ------------------------------------------------------------ The `certificate_authorities` option can be used as an alternative to the -`truststore.path` setting. +`truststore.path` setting, when the certificate files are PEM formatted +. The setting accepts a list. The two options are exclusive, they cannot be both used +simultaneously. -- . Map roles for PKI users. + -- -You map roles for PKI users through the -<> or by using a file stored on -each node. When a user authenticates against a PKI realm, the privileges for -that user are the union of all privileges defined by the roles to which the -user is mapped. +You map roles for PKI users through the <> or by using a file stored on each node. Both configuration +options are merged together. When a user authenticates against a PKI realm, the +privileges for that user are the union of all privileges defined by the roles +to which the user is mapped. You identify a user by the distinguished name in their certificate. For example, the following mapping configuration maps `John Doe` to the @@ -150,7 +183,11 @@ PUT /_security/role_mapping/users // CONSOLE <1> The distinguished name (DN) of a PKI user. -Or, alternatively, configured in a role-mapping file: +Or, alternatively, configured inside a role-mapping file. The file's path +defaults to `ES_PATH_CONF/role_mapping.yml`. You can specify a different path (which must be within +ES_PATH_CONF) by using the `files.role_mapping` realm setting (e.g. +`xpack.security.authc.realms.pki.pki1.files.role_mapping`): + [source, yaml] ------------------------------------------------------------ user: <1> @@ -163,7 +200,7 @@ The distinguished name for a PKI user follows X.500 naming conventions which place the most specific fields (like `cn` or `uid`) at the beginning of the name, and the most general fields (like `o` or `dc`) at the end of the name. Some tools, such as _openssl_, may print out the subject name in a different - format. +format. One way that you can determine the correct DN for a certificate is to use the <> (use the relevant PKI @@ -179,3 +216,76 @@ NOTE: The PKI realm supports alternative to role mapping. -- + +[float] +[role="xpack"] +[[pki-realm-for-proxied-clients]] +==== PKI authentication for clients connecting to {kib} + +By default, the PKI realm relies on the node's network interface to perform the +SSL/TLS handshake and extract the client certificate. This behaviour requires +that that clients connect directly to {es} so that their SSL connection is +terminated by the {es} node. If SSL/TLS authenticatication is to be performed +by {kib}, the PKI realm must be configured to permit delegation. + +Specifically, when clients presenting X.509 certificates connect to {kib}, +{kib} performs the SSL/TLS authentication. {kib} then forwards the client's +certificate chain, by calling an {es} API, to have them further validated by +the PKI realms that have been configured for delegation. + +To permit authentication delegation for a specific {es} PKI realm, start by +configuring the realm for the usual case, as detailed in the +<> +section. Note that you must explicitly configure a `truststore` (or, +equivalently `certificate_authorities`) even though it is the same trust +configuration that you have configured on the network layer. Afterwards, +simply toggle the `delegation.enabled` realm setting to `true`. This realm is +now allowed to validate delegated PKI authentication (after restarting {es}). + +NOTE: PKI authentication delegation requires that the +`xpack.security.authc.token.enabled` setting be `true` and that SSL/TLS be +configured (without SSL/TLS client authentication). + +NOTE: {kib} also needs to be configured to allow PKI certificate authentication. + +A PKI realm with `delegation.enabled` still works unchanged for clients +connecting directly to {es}. Directly authenticated users, and users that are PKI +authenticated by delegation to {kib} both follow the same +{stack-ov}/mapping-roles.html[role mapping rules] or +{stack-ov}/realm-chains.html#authorization_realms[authorization realms +configurations]. + +However, if you use the <>, +you can distinguish between users that are authenticated by delegation and +users that are authenticated directly. The former have the +extra fields `pki_delegated_by_user` and `pki_delegated_by_realm` in the user's +metadata. In the common setup, where authentication is delegated to {kib}, the +values of these fields are `kibana` and `reserved`, respectively. For example, +the following role mapping rule will assign the `role_for_pki1_direct` role to +all users that have been authenticated directly by the `pki1` realm, by +connecting to {es} instead of going through {kib}: + +[source,js] +-------------------------------------------------- +PUT /_security/role_mapping/direct_pki_only +{ + "roles" : [ "role_for_pki1_direct" ], + "rules" : { + "all": [ + { + "field": {"realm.name": "pki1"} + }, + { + "field": { + "metadata.pki_delegated_by_user": null <1> + } + } + ] + }, + "enabled": true +} +-------------------------------------------------- +// CONSOLE +<1> only when this metadata field is set (it is *not* `null`) the user has been +authenticated in the delegation scenario. + diff --git a/x-pack/docs/en/security/authorization/mapping-roles.asciidoc b/x-pack/docs/en/security/authorization/mapping-roles.asciidoc index a99e385bd8c25..c4950d18f55c4 100644 --- a/x-pack/docs/en/security/authorization/mapping-roles.asciidoc +++ b/x-pack/docs/en/security/authorization/mapping-roles.asciidoc @@ -28,6 +28,11 @@ you are able to map users to both API-managed roles and file-managed roles NOTE: The PKI, LDAP, Kerberos and SAML realms support using <> as an alternative to role mapping. +NOTE: When {ref}/anonymous-access.html[anonymous access] is enabled the roles +of the anonymous user are mapped to all the other users as well. + +NOTE: Users with no roles assigned will be unauthorized for any action. + [[mapping-roles-api]] ==== Using the role mapping API diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthDelegationIntegTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthDelegationIntegTests.java index 28beeed8cbcfa..fd84e71b91e0a 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthDelegationIntegTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthDelegationIntegTests.java @@ -26,7 +26,9 @@ import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecuritySettingsSourceField; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.security.action.realm.ClearRealmCacheRequestBuilder; import org.elasticsearch.xpack.core.security.authc.support.Hasher; +import org.junit.Before; import org.elasticsearch.test.SecuritySettingsSource; import java.io.InputStream; @@ -120,6 +122,11 @@ protected boolean addMockHttpTransport() { return false; // enable http } + @Before + void clearRealmCache() { + new ClearRealmCacheRequestBuilder(client()).get(); + } + public void testDelegateThenAuthenticate() throws Exception { final X509Certificate clientCertificate = readCertForPkiDelegation("testClient.crt"); final X509Certificate intermediateCA = readCertForPkiDelegation("testIntermediateCA.crt");