Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Header Cert Auth plugin #7775

Merged
merged 9 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/_hub/kong-inc/header-cert-auth/_changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## Changelog

### {{site.base_gateway}} 3.8.x
* Introduced the Header Cert Authentication plugin.
17 changes: 17 additions & 0 deletions app/_hub/kong-inc/header-cert-auth/_metadata/_index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Header Cert Authentication
gruceo marked this conversation as resolved.
Show resolved Hide resolved
search_aliases:
- header cert auth
- header-cert-auth
- authentication
dbless_compatible:
dbless_explanation:
free: false
enterprise: true
konnect: true
network_config_opts: All
notes: --
categories:
- authentication
publisher: Kong Inc.
desc: Authenticate clients with mTLS certificates passed in headers by a WAF or load balancer

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
nav_title: Add Certificate Authorities
title: Add Certificate Authorities
---

To use this plugin, you must add certificate authority (CA) certificates. These are
stored in a separate `ca_certificates` store rather than the main certificates store because
they do not require private keys. To add one, obtain a PEM-encoded copy of your CA certificate
and pass it to the `/ca_certificates` endpoint in a `POST` request:

{% navtabs %}
{% navtab Kong Admin API %}
```bash
curl -X POST https://localhost:8001/ca_certificates -F [email protected]
```

The response will contain an `id` value that can now be used for the Header Cert Auth plugin configurations or consumer mappings.

{% endnavtab %}

{% navtab Konnect %}

Go through the Gateway Manager:
1. From the {{site.konnect_short_name}} [{% konnect_icon runtimes %} **Gateway Manager**](https://cloud.konghq.com/us/gateway-manager/).
1. Select a control plane and click **Certificates**
1. Select the **CA Certificates** tab and **Add CA Certificate**
1. Copy and paste your certificate information and click **Save**.

You can view the certificate listed in the **Certificates** tab.

To add a certificate via the {{site.konnect_short_name}} API, you need:
* {{site.konnect_short_name}} control plane ID
* [A personal access token](/konnect/api/)

```bash
curl -X POST https://konnect.konghq.com/api/control_planes/{controlPlaneID}/ca_certificates \
-F [email protected] \
--header "Authorization: Bearer TOKEN"
```
{% endnavtab %}
{% endnavtabs %}
The `id` value returned can now be used for the Header Cert Auth plugin configurations or consumer mappings.

{:.important}
> **Important:** To ensure proper certificate validation, it is important to upload all required Certificate Authorities (CAs) and their intermediates into the Kong CA store.
> <br><br>
> Failure to do so may result in incomplete certificate validation, as some WAF and load balancer providers only send the end-leaf certificate in their header, rather than encoding the entire certificate chain sent by the client. This is especially crucial when using the `base64_encoded` format.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
nav_title: AWS ALB Integration
title: AWS ALB Integration
---

AWS has support for mutually authenticating clients that present X509 certificates to Application Load Balancer (ALB).
You can learn more about mTLS with ALB in [AWS's blog post](https://aws.amazon.com/blogs/networking-and-content-delivery/introducing-mtls-for-application-load-balancer/).

To make sure AWS/ALB works with the Header Cert Auth plugin with mTLS enabled, we first need to generate the required certificates.
For development certificates, you can use OpenSSL to generate certificates or tools such as `mkcert`.

## Add HTTPS listener to the ALB
gruceo marked this conversation as resolved.
Show resolved Hide resolved

Configure the ALB by adding an HTTPS listener.

1. In the Listener configuration, configure the following settings:
* Protocol: HTTPS
* Port: 443
* Routing actions: Forward to target groups

2. In the Secure listener settings, configure the certificate from AWS Certificate Manager (ACM).
Make sure to upload your certificates to ACM and use them in the ALB.
* Certificate source: From ACM
* Certificate (from ACM): Select the certificate that you want to use
* Client certificate handling: Select Mutual authentication (mTLS) with Passthrough

## Configure {{site.base_gateway}} with certificate and plugin

Next, configure {{site.base_gateway}}.

1. Add the root CA to the CA certificates:

```bash
curl -sX POST https://localhost:8001/ca_certificates -F [email protected]
{
"tags": null,
"created_at": 1566597621,
"cert": "-----BEGIN CERTIFICATE-----\FullPEMOmittedForBrevity==\n-----END CERTIFICATE-----\n",
"id": "322dce96-d434-4e0d-9038-311b3520f0a3"
}
```

2. Add the Header Cert Auth plugin to the service (or route).

* We need to update the `certificate_header_name` to `X-Amzn-Mtls-Clientcert`.
* The `certificate_header_format` should be `url_encoded` for AWS/ALB.

```bash
curl -X POST http://localhost:8001/services/{serviceName|Id}/plugins \
--header "accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "header-cert-auth",
"config": {
"ca_certificates": [
"0D769DE8-7CC0-4541-989B-F9C23E20054C"
],
"certificate_header_name": "X-Amzn-Mtls-Clientcert",
"certificate_header_format": "url_encoded",
"secure_source": false
}
}
```

## Validate

Use the certificate and key to proxy the traffic:

```bash
curl -k --cert <client_certificate> --key <client_key> https://test-alb-<id>.us-east-2.elb.amazonaws.com/test
```

You should then be able to see the certificate in the response headers:

```bash
"X-Amzn-Mtls-Clientcert": "-----BEGIN%20CERTIFICATE-----%0AMIIDbDCCAdSgAwIBAgIUa...-----END%20CERTIFICATE-----"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
nav_title: Manual Mappings Between Certificate and Consumer Objects
title: Manual Mappings Between Certificate and Consumer Objects
---
Sometimes, you might not want to use automatic consumer lookup, or you have certificates
that contain a field value not directly associated with consumer objects. In those
situations, you may manually assign one or more subject names to the consumer object for
identifying the correct consumer.

{:.note}
> **Note**: Subject names refer to the certificate's Subject Alternative Names (SAN) or
Common Name (CN). CN is only used if the SAN extension does not exist.

{% navtabs %}
{% navtab Kong Admin API %}

Create a mapping:

```bash
curl -X POST http://localhost:8001/consumers/{consumer}/header-cert-auth \
-d '[email protected]'
```

Where `{consumer}` is the `id` or `username` property of the
[consumer](/gateway/latest/admin-api/#consumer-object) entity to associate the
credentials to.

Once created, you'll see a `201` success message:

```json
HTTP/1.1 201 Created

{
"consumer": { "id": "876bf719-8f18-4ce5-cc9f-5b5af6c36007" },
"created_at": 1443371053000,
"subject_name": "[email protected]"
}
```

{% endnavtab %}
{% navtab Declarative (YAML) %}

To create a subject name mapping using declarative configuration, you must generate a UUID for each `header_cert_auth_credentials` mapping. You can use any
UUID generator to do this. Here are some common ones, depending on your OS:
* [Linux](https://man7.org/linux/man-pages/man1/uuidgen.1.html)
* [MacOS](https://www.unix.com/man-page/mojave/1/uuidgen/)
* [Windows](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/new-guid?view=powershell-7)

After you have generated a UUID, add the following to your declarative
configuration file:

```yaml
consumers:
- custom_id: my-consumer
username: {consumer}
header_cert_auth_credentials:
- id: bda09448-3b10-4da7-a83b-2a8ba6021f0c
subject_name: [email protected]
```

{% endnavtab %}
{% endnavtabs %}

#### Parameters for manual mapping

Form Parameter | Default | Description
--- | --- | ---
`id`<br>*required for declarative config* | none | UUID of the consumer-mapping. Required if adding mapping using declarative configuration, otherwise generated automatically by Kong's Admin API.
`subject_name`<br>*required* | none | The Subject Alternative Name (SAN) or Common Name (CN) that should be mapped to `consumer` (in order of lookup).
`ca_certificate`<br>*optional* | none | **If using the Kong Admin API:** UUID of the Certificate Authority (CA). <br><br> **If using declarative configuration:** Full PEM-encoded CA certificate. <br><br>The provided CA UUID or full certificate has to be verifiable by the issuing certificate authority for the mapping to succeed. This is to help distinguish multiple certificates with the same subject name that are issued under different CAs. <br><br>If empty, the subject name matches certificates issued by any CA under the corresponding `config.ca_certificates`.

### Matching behaviors

After a client certificate has been verified as valid, the consumer object is determined in the following order, unless `skip_consumer_lookup` is set to `true`:

1. Manual mappings with `subject_name` matching the certificate's SAN or CN (in that order) and `ca_certificate = <issuing authority of the client certificate>`
2. Manual mappings with `subject_name` matching the certificate's SAN or CN (in that order) and `ca_certificate = NULL`
3. If `config.consumer_by` is not null, consumer with `username` and/or `id` matching the certificate's SAN or CN (in that order)
4. The `config.anonymous` consumer (if set)

{:.note}
> **Note**: Matching stops as soon as the first successful match is found.

{% include_cached /md/plugins-hub/upstream-headers.md %}

When `skip_consumer_lookup` is set to `true`, consumer lookup is skipped and instead of appending aforementioned headers, the plugin appends the following two headers

* `X-Client-Cert-Dn`, distinguished name of the client certificate
* `X-Client-Cert-San`, SAN of the client certificate

Once `skip_consumer_lookup` is applied, any client with a valid certificate can access the Service/API.
To restrict usage to only some of the authenticated users, also add the ACL plugin (not covered here) and create
allowed or denied groups of users using the same
certificate property being set in `authenticated_group_by`.
63 changes: 63 additions & 0 deletions app/_hub/kong-inc/header-cert-auth/overview/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
nav_title: Overview
---

The Header Cert Authentication plugin authenticates API calls by using client certificates provided in HTTP headers,
instead of relying on traditional TLS termination.
This approach is particularly useful in scenarios where TLS traffic is terminated outside of {{site.base_gateway}} such as at an external CDN or load balancer and the client certificate is passed along in an HTTP header for subsequent validation.

## How it works

This plugin addresses the inability of the {{site.base_gateway}} to authenticate API calls using client certificates received in HTTP headers, rather than through traditional TLS termination.
This occurs in scenarios where TLS traffic is not terminated at the {{site.base_gateway}}, but rather at an external CDN or load balancer, and the client certificate is preserved in an HTTP header for further validation.

The Header Cert Authentication plugin is similar to the [mTLS Auth plugin](/hub/kong-inc/mtls-auth).
However, the mTLS plugin is only designed for traditional TLS termination, while the Header Cert Auth plugin also provides support for client certificates in headers.

The Header Cert Auth plugin extracts the client certificate from the HTTP header and validates it against the configured CA list.
If the certificate is valid, the plugin maps the certificate to a consumer based on the common name field.

The plugin validates the certificate provided against the configured CA list based on the
requested route or service:
* If the certificate is not trusted or has expired, the response is
`HTTP 401 TLS certificate failed verification`.
* If a valid certificate is not presented (including when requests are not sent to the HTTPS port),
the response is HTTP 401 No required TLS certificate was sent.
* However, if the config.anonymous option is configured on the plugin,
an anonymous consumer is used, and the request is allowed to proceed.

The plugin can be configured to only accept certificates from trusted IP addresses, as specified by the [`trusted_ips`](/gateway/{{page.release}}/reference/configuration/#trusted_ips) config option. This ensures that Kong can trust the header sent from the source and provides L4 level of security.

{:.important}
> **Important:** Incomplete or improper configuration of the Header Cert Authentication plugin can compromise the security of your API.
<br><br>
> For instance, enabling the option to bypass origin verification can allow malicious actors to inject fake certificates, as Kong will not be able to verify the authenticity of the header. This can downgrade the security level of the plugin, making your API vulnerable to attacks. Ensure you carefully evaluate and configure the plugin according to your specific use case and security requirements.

Additionally, the plugin has a [static priority](/konnect/reference/plugins/) configured so that it runs after all authentication plugins, allowing other auth plugins (e.g. basic-auth) to secure the source first. This ensures that the source is secured by multiple layers of authentication by providing L7 level of security.

### Client certificate request

The `send_ca_dn` option is not supported in this plugin. This is used in mutual TLS authentication, where the server sends the list of trusted CAs to the client, and the client then uses this list to select the appropriate certificate to present. In this case since the plugin does not do TLS handshakes and only parses the client certificate from the header, it is not applicable.

The same applies to SNI functionality. The plugin can verify the certificate without needing to know the specific hostname or domain being accessed. The plugin's authentication logic is decoupled from the TLS handshake and SNI, so it doesn't need to rely on SNI to function correctly (pretty much anything that deals with the actual TLS handshake is not needed for the plugin to work).

## Troubleshooting

When authentication fails, the client does not have access to any details that explain the failure. The security reason for this omission is to prevent malicious reconnaissance. Instead, the details are recorded inside Kong's error logs under the `[header-cert-auth]` filter.

### FAQs

**Q: Will the client need to encrypt the message with a private key and certificate when passing the certificate in the header?**

**A:** No, the client only needs to send the target's certificate encoded in a header. Kong will validate the certificate, but it requires a high level of trust that the WAF/LB is the only entrypoint to the Kong proxy. The Header Cert Auth plugin will provide an option to secure the source, but additional layers of security are always preferable. Network level security (so that Kong only accepts requests from WAF - IP allow/deny mechanisms) and application-level security (Basic Auth or Key Auth plugins to authenticate the source first) are examples of multiple layers of security that can be applied.

## Get started with the Header Cert Authentication plugin

* [Add certificate authorities](/hub/kong-inc/header-cert-auth/how-to/add-cert-authorities/):
To use this plugin, you must add certificate authority (CA) certificates.
Set them up before configuring the plugin.
* [Configuration reference](/hub/kong-inc/header-cert-auth/configuration/)
* [Basic configuration example](/hub/kong-inc/header-cert-auth/how-to/basic-example/)
* [Learn how to use the plugin](/hub/kong-inc/header-cert-auth/how-to/)
* [Create manual mappings between certificate and consumer objects](/hub/kong-inc/header-cert-auth/how-to/manual-mapping-cert-consumers/)
* [AWS ALB integration](/hub/kong-inc/header-cert-auth/how-to/aws-alb-integration/)
3 changes: 3 additions & 0 deletions app/_hub/kong-inc/header-cert-auth/versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
strategy: gateway
releases:
minimum_version: '3.8.x'
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading