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 6 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,50 @@
---
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 POST it to `/ca_certificates`:

{% navtabs %}
{% navtab Kong Admin API %}
```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"
}
```
{% endnavtab %}

{% navtab Konnect %}

Go through the Gateway Manager:
1. In {{site.konnect_short_name}}, click {% konnect_icon runtimes %} **Gateway Manager**.
2. Select the control plane you want to add the CA certificate to.
3. Click **Certificates**.
4. Select the **CA Certificates** tab.
5. Click **+ Add CA Certificate**
6. Copy and paste your certificate information and click **Save**.

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

To add a certificate via curl, you need:
* {{site.konnect_short_name}} ID
* A generated access cookie
lena-larionova marked this conversation as resolved.
Show resolved Hide resolved

```bash
curl -X POST https:konnect.konghq.com/api/control_planes/[Konnect-ID]/ca_certificates -F [email protected] --cookie '[generated access cookie]'
```
{% 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,76 @@
---
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). More information: 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 Kong Gateway with certs and plugin

Check failure on line 25 in app/_hub/kong-inc/header-cert-auth/how-to/_aws-alb-integration.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [kong.kongterms] Use '{{site.base_gateway}}' instead of 'Kong Gateway'. Raw Output: {"message": "[kong.kongterms] Use '{{site.base_gateway}}' instead of 'Kong Gateway'.", "location": {"path": "app/_hub/kong-inc/header-cert-auth/how-to/_aws-alb-integration.md", "range": {"start": {"line": 25, "column": 14}}}, "severity": "ERROR"}

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`.
61 changes: 61 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,61 @@
---
nav_title: Overview
---

The Header Cert Authentication plugin authenticates API calls using client certificates received in HTTP headers,
rather than through traditional TLS termination.
This is necessary in scenarios where TLS traffic is not terminated at {{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.

## How it works

This plugin addresses the inability of the Kong API 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 Kong API Gateway, but rather at an external CDN or load balancer, and the client certificate is preserved in an HTTP header for further validation.

Existing options, such as the mtls-auth plugin, are not sufficient as they are designed for traditional TLS termination and do not support receiving client certificates in HTTP headers. Additionally, these plugins do not provide the necessary flexibility and configurability to accommodate the varying requirements of different customers and use cases.

The 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 consumer did not present a valid certificate (this includes requests not
sent to the HTTPS port), then the response is `HTTP 401 No required TLS certificate was sent`.
The exception is if the `config.anonymous` option is configured on the plugin, in which
case the 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.

### FAQ

**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 authentication or key-auth authentication 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
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading