Skip to content

Mutual TLS

Mutual TLS (mTLS) authentication ensures that traffic is both secure and trusted in both directions between a client and server. It allows requests that do not log in with an identity provider (like IoT devices) to demonstrate that they can reach a given resource. Client certificate authentication is also a second layer of security for team members who both log in with an identity provider (IdP) and present a valid client certificate.

With a root certificate authority (CA) in place, Access only allows requests from devices with a corresponding client certificate. When a request reaches the application, Access responds with a request for the client to present a certificate. If the device fails to present the certificate, the request is not allowed to proceed. If the client does have a certificate, Access completes a key exchange to verify.

mTLS handshake diagram

Add mTLS authentication to your Access configuration

To enforce mTLS authentication from Zero Trust:

  1. Go to Access > Service auth > Mutual TLS.

  2. Select Add mTLS Certificate.

  3. Give the Root CA any name.

  4. Paste the content of the ca.pem file into the Certificate content field.

    • The CA certificate can be from a publicly trusted CA or self-signed.
    • In the certificate Basic Constraints, the attribute CA must be set to TRUE.
    • The certificate must use one of the signature algorithms listed below:

    Allowed signature algorithms

    x509.SHA1WithRSA

    x509.SHA256WithRSA

    x509.SHA384WithRSA

    x509.SHA512WithRSA

    x509.ECDSAWithSHA1

    x509.ECDSAWithSHA256

    x509.ECDSAWithSHA384

    x509.ECDSAWithSHA512

  5. In Associated hostnames, enter the fully-qualified domain names (FQDN) that will use this certificate.

    These FQDNs will be the hostnames used for the resources being protected in the Access policy. You must associate the Root CA with the FQDN that the application being protected uses.

  6. Select Save.

    If your zone is using an intermediate certificate in addition to the root certificate, upload the entire chain.

  7. Next, go to Access > Applications.

  8. Find the application you would like to enforce mTLS on and select Edit. The application must be included in the Associated hostnames list from Step 5.

  9. Create a new (or amend an existing) Access policy.

    If this is for a client who does not need to log in through an IdP, set the policy Action to Service Auth.

  10. Add an mTLS authentication rule using the following selectors:

    SelectorDescription
    Common NameOnly client certificates with a specific common name will be allowed to proceed.
    Valid CertificateAny client certificate that can authenticate with the Root CA will be allowed to proceed.
  11. Save the policy.

Test mTLS using cURL

To test the application protected by an mTLS policy:

  1. First, attempt to curl the site without a client certificate. This curl command example is for the site example.com that has an Access policy set for https://auth.example.com:

    Terminal window
    curl -sv https://auth.example.com

    Without a client certificate in the request, a 403 forbidden response displays and the site cannot be accessed.

  2. Now, add your client certificate information to the request:

    Terminal window
    curl -sv https://auth.example.com --cert example.pem --key key.pem

When the authentication process completes successfully, a CF_Authorization Set-Cookie header returns in the response.

Test mTLS using Cloudflare PKI

You can use Cloudflare's open source tools for private key infrastructure (PKI) to test the mTLS feature in Cloudflare Access. This guide details the process to generate a Root Client Authority (CA), add it to the Cloudflare dashboard, and issue client certificates that can authenticate against the root CA and reach a protected resource.

1. Install dependencies

The process requires two packages from Cloudflare's PKI toolkit:

  • cf-ssl
  • cfssljson

You can install these packages from the Cloudflare SSL GitHub repository. You will need a working installation of Go, version 1.12 or later. Alternatively, you can download the packages directly. Use the instructions under Installation to install the toolkit, and ensure that you install all of the utility programs in the toolkit.

2. Generate the Root CA

  1. Create a new directory to store the Root CA.

  2. Within that directory, create two new files:

    • CSR. Create a file named ca-csr.json and add the following JSON blob, then save the file.

      {
      "CN": "Access Testing CA",
      "key": {
      "algo": "rsa",
      "size": 4096
      },
      "names": [
      {
      "C": "US",
      "L": "Austin",
      "O": "Access Testing",
      "OU": "TX",
      "ST": "Texas"
      }
      ]
      }
    • config. Create a file named ca-config.json and add the following JSON blob, then save the file.

      {
      "signing": {
      "default": {
      "expiry": "8760h"
      },
      "profiles": {
      "server": {
      "usages": ["signing", "key encipherment", "server auth"],
      "expiry": "8760h"
      },
      "client": {
      "usages": ["signing", "key encipherment", "client auth"],
      "expiry": "8760h"
      }
      }
      }
      }
  3. Now, run the following command to generate the Root CA with those files.

    Terminal window
    cfssl gencert -initca ca-csr.json | cfssljson -bare ca
  4. Within the directory, check its content to confirm the output was successful.

    Terminal window
    ls

    The output should now return the following content:

    Terminal window
    ca-config.json ca-csr.json ca-key.pem ca.csr ca.pem

3. Generate a client certificate

Returning to the terminal, generate a client certificate that will authenticate against the Root CA uploaded.

  1. Create a file named client-csr.json and add the following JSON blob:

    {
    "CN": "James Royal",
    "hosts": [""],
    "key": {
    "algo": "rsa",
    "size": 4096
    },
    "names": [
    {
    "C": "US",
    "L": "Austin",
    "O": "Access",
    "OU": "Access Admins",
    "ST": "Texas"
    }
    ]
    }
  2. Now, use the following command to generate a client certificate with the Cloudflare PKI toolkit:

    Terminal window
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client-csr.json | cfssljson -bare client
  3. You can now test the client certificate with the following cURL command.

    Terminal window
    curl -v --cert client.pem --key client-key.pem https://iot.widgetcorp.tech

Test in the browser

The instructions here cover usage with a computer running macOS.

  1. In the same working directory, run the following command to add the client certificate into the macOS Keychain.
Terminal window
open client.pem
security import client-key.pem -k ~/Library/Keychains/login.keychain-db
  1. Select the certificate in the Keychain list to set the certificate to trusted. Confirm that the certificate is listed in My Certificates.

Create a CRL

You can use the Cloudflare PKI toolkit to generate a certificate revocation list (CRL), as well. This list will contain client certificates that are revoked.

  1. Get the serial number from the client certificate generated earlier. Add that serial number, or any others you intend to revoke, in hex format in a text file. This example uses a file named serials.txt.

  2. Create the CRL with the following command.

    Terminal window
    cfssl gencrl serials.txt ../mtls-test/ca.pem ../mtls-test/ca-key.pem | base64 -D > ca.crl

You will need to add the CRL to your server or enforce the revocation in a Cloudflare Worker. An example Worker Script can be found on the Cloudflare GitHub repository.

Forward a client certificate

In addition to enforcing mTLS authentication for your host, you can also forward a client certificate to your origin server as an HTTP header. This setup is often helpful for server logging.

To avoid adding the certificate to every single request, the certificate is only forwarded on the first request of an mTLS connection.

Cloudflare API

The most common approach to forwarding a certificate is to use the Cloudflare API to update an mTLS certificate's hostname settings.

Request
curl --request PUT \
https://api.cloudflare.com/client/v4/zones/{zone_id}/access/certificates/settings \
--header "X-Auth-Email: <EMAIL>" \
--header "X-Auth-Key: <API_KEY>" \
--header "Content-Type: application/json" \
--data '{
"settings": [
{
"hostname": "<HOSTNAME>",
"china_network": false,
"client_certificate_forwarding": true
}
]
}'

Once client_certificate_forwarding is set to true, the first request of an mTLS connection will now include the following headers:

  • Cf-Client-Cert-Der-Base64
  • Cf-Client-Cert-Sha256

Managed Transforms

You can also modify HTTP response headers using Managed Transforms to pass along TLS client auth headers.

Cloudflare Workers

Additionally, Workers can provide details around the client certificate.

const tlsHeaders = {
'X-CERT-ISSUER-DN': request.cf.tlsClientAuth.certIssuerDN,
'X-CERT-SUBJECT-DN': request.cf.tlsClientAuth.certSubjectDN,
'X-CERT-ISSUER-DN-L': request.cf.tlsClientAuth.certIssuerDNLegacy,
'X-CERT-SUBJECT-DN-L': request.cf.tlsClientAuth.certSubjectDNLegacy,
'X-CERT-SERIAL': request.cf.tlsClientAuth.certSerial,
'X-CERT-FINGER': request.cf.tlsClientAuth.certFingerprintSHA1,
'X-CERT-VERIFY': request.cf.tlsClientAuth.certVerify,
'X-CERT-NOTBE': request.cf.tlsClientAuth.certNotBefore,
'X-CERT-NOTAF': request.cf.tlsClientAuth.certNotAfter
};

Known limitations

mTLS does not currently work for:

Set up alerts for mutual TLS certificates

You can configure alerts to receive notifications before your mutual TLS certificates expire.

Access mTLS Certificate Expiration Alert

Who is it for?

Access customers that use client certificates for mutual TLS authentication. This notification will be sent 30 and 14 days before the expiration of the certificate.

Other options / filters

None.

Included with

Purchase of Access and/or Cloudflare for SaaS.

What should you do if you receive one?

Upload a renewed certificate.

Refer to Cloudflare Notifications for more information on how to set up an alert.