API for client certificates

Answer these questions to help the Community help you with Security questions.

It is not domain specific

I have created a client certificate from the dashboard and enabled WAF rules for MTLS which all works fine. However, I have a requirement to automate the creation of client certificates or even just to update the hosts for existing certificates.

Does an API endpoint exist for client certificates yet?

I have trawled through the API docs and none of the ssl, custom_hostname, origin_tls_client or access endpoints will return anything for client certificates. This leads me to think i’m either failing to find the documentation for the required endpoint or it doesn’t exist yet.

The main functionality needed would be to list the certificate ID and then edit the hosts for that certificate to allow verified clients to access specific backend hosts.

IIRC from CF client TLS cert API scripting at GitHub - centminmod/cfssl-ca-ssl, you need to use the CF API to create the client TLS cert and take note of that certificate ID at the time of creation. Otherwise, there’s no API endpoint to list that created client TLS cert’s creation ID at a later point in time. In the linked example, I capture the cert ID at initial creation time in variable clientcert_id

i.e. using that variable to delete a created client TLS cert

curl -sX DELETE "https://api.cloudflare.com/client/v4/zones/$cfzoneid/origin_tls_client_auth/$clientcert_id" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" -d "$request_body" | jq | tee /etc/cfssl/clientcerts/centminmod.com-cf-origin-tls-cleint-auth-cert-upload-delete.txt
{
  "success": true,
  "errors": [],
  "messages": [],
  "result": {
    "id": "d5035326-5385-4ec3-b77d-d1a122cf3283",
    "status": "pending_deletion",
    "issuer": "CN=Intermediate CA,OU=Intermediate CA,L=San Francisco,ST=CA,C=US",
    "signature": "ECDSA-SHA256",
    "serial_number": "364027147676626726289571183730041490650282141970",
    "certificate": "-----BEGIN CERTIFICATE-----\nMIICUDxxxxxxagAwIBAgIUP8OKtxl8+vxl38jCZ64JkcoZKRIwCgYIKoZIzj0EAwIw\nZjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMRgwFgYDVQQLEw9JbnRlcm1lZGlhdGUgQ0ExGDAWBgNVBAMTD0ludGVybWVk\naWF0ZSBDQTAeFw0yMjA1MjQxNjUxMDBaFw0zMjA1MjExNjUxMDBaMEgxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIG\nA1UEAxMLY2VudG1pbi5kZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASXHo+L\nWdZLL0E1D7F8LUc24SdO8duZfd4qhabKy/mEcxmUYAiOawcY0poQ+I1x1pCm+Wqz\noa9CWKC2C50i9Zdvo4GfMIGcMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr\nBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQHGhsS/h56zI8U6bf7dvAc\nrb2dTjAfBgNVHSMEGDAWgBQGaefF8v06LjDXH31/ud6bUrnUdzAnBgNVHREEIDAe\nggtjZW50bWluLmRldoIPd3d3LmNlbnRtaW4uZGV2MAoGCCqGSM49BAMCA0gAMEUC\nIQD+CnZSL4S7jdq4Zipde3pxAIk2ofdUvh2YuoaT5BkHlgIgI0vKUWQofPoW6vB+\nVMLu0MAcXDgmkz6iX9wTHNVk7UM=\n-----END CERTIFICATE-----\n",
    "uploaded_on": "2022-05-24T16:57:16.801883Z",
    "expires_on": "2032-05-21T16:51:00Z"
  }
}

then to verify deletion status

curl -sX GET "https://api.cloudflare.com/client/v4/zones/$cfzoneid/origin_tls_client_auth/$clientcert_id" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" -d "$request_body" | jq
{
  "success": true,
  "errors": [],
  "messages": [],
  "result": {
    "id": "d5035326-5385-4ec3-b77d-d1a122cf3283",
    "status": "deleted",
    "issuer": "CN=Intermediate CA,OU=Intermediate CA,L=San Francisco,ST=CA,C=US",
    "signature": "ECDSA-SHA256",
    "serial_number": "364027147676626726289571183730041490650282141970",
    "certificate": "-----BEGIN CERTIFICATE-----\nMIICUDxxxxxxagAwIBAgIUP8OKtxl8+vxl38jCZ64JkcoZKRIwCgYIKoZIzj0EAwIw\nZjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMRgwFgYDVQQLEw9JbnRlcm1lZGlhdGUgQ0ExGDAWBgNVBAMTD0ludGVybWVk\naWF0ZSBDQTAeFw0yMjA1MjQxNjUxMDBaFw0zMjA1MjExNjUxMDBaMEgxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIG\nA1UEAxMLY2VudG1pbi5kZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASXHo+L\nWdZLL0E1D7F8LUc24SdO8duZfd4qhabKy/mEcxmUYAiOawcY0poQ+I1x1pCm+Wqz\noa9CWKC2C50i9Zdvo4GfMIGcMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr\nBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQHGhsS/h56zI8U6bf7dvAc\nrb2dTjAfBgNVHSMEGDAWgBQGaefF8v06LjDXH31/ud6bUrnUdzAnBgNVHREEIDAe\nggtjZW50bWluLmRldoIPd3d3LmNlbnRtaW4uZGV2MAoGCCqGSM49BAMCA0gAMEUC\nIQD+CnZSL4S7jdq4Zipde3pxAIk2ofdUvh2YuoaT5BkHlgIgI0vKUWQofPoW6vB+\nVMLu0MAcXDgmkz6iX9wTHNVk7UM=\n-----END CERTIFICATE-----\n",
    "uploaded_on": "2022-05-24T16:57:16.801883Z",
    "expires_on": "2032-05-21T16:51:00Z"
  }
}

Ah spoke too soon, you might want to try querying this endpoint for listing client TLS certs at https://api.cloudflare.com/client/v4/zones/ZONEID/client_certificates?status=all

Thanks a lot! The client_certificates endpoint is what I needed. It doesn’t seem to feature anywhere in the docs site api.Cloudflare . Is there somewhere else I should be looking?

Sorry, I was a bit quick to mark it as a solution. I am now able to list all certificates and them individually by ID but they don’t contain the hosts parameter in the output. Any links to where I might be able to find the structure for that data?

It’s undocumented. Usually the CF GUI dashboard URLs follow API closely, so if you inspect the web browser developer tools for URL and payloads when you use the dashboard, you can get an idea of the API endpoints.

You should see it in JSON output in the certificate hostname listed in the common_name field.

example

curl -sX GET -H "X-Auth-Key: $CF_API_KEY" -H "X-Auth-Email: $CF_API_EMAIL" \
     -H "Content-Type: application/json" \
     https://api.cloudflare.com/client/v4/zones/ZONEID/client_certificates?status=all | jq -r '.result[] | "\(.id) \(.common_name) \(.status)"'
********-9edc-4a32-9afd-************ sub.domain.com revoked
********-bb00-4d68-887a-************ Cloudflare active

though looks like some common_name just shows Cloudflare instead of domain name. The ones with domain name I provided my own CSR/Private key IIRC. Been a while since I created these so memory is vague.

edit: oh you can extract the actual certificate or CSR file from output and parse the cert too

of course you can probably ask Cloudflare support for a more accurate instructions

1 Like

Ok was curious so looked into this and the endpoints for client certificates from dashboard aren’t same as ones I used at GitHub - centminmod/cfssl-ca-ssl

example endpoints for client certificates to get the client TLS cert details, revoke and restore revoked certs

get cert details

endpoint=https://api.cloudflare.com/client/v4/
zid='your_zoneid'
cert_id='77c9ae51-62e4-45de-****-************'
endpoint_target="zones/$zid/client_certificates/$cert_id"
curl -4sX GET "${endpoint}${endpoint_target}" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" | jq -r

{
  "success": true,
  "errors": [],
  "messages": [],
  "result": {
    "id": "77c9ae51-62e4-45de-****-************",
    "certificate_authority": {
      "id": "c3006d2d-5d9f-49e9-bcec-***********",
      "name": "Cloudflare Managed CA for account accountid"
    },
    "certificate": "-----BEGIN CERTIFICATE-----\nABC-----END CERTIFICATE-----\n",
    "csr": "-----BEGIN CERTIFICATE REQUEST-----\r\nXYZ-----END CERTIFICATE REQUEST-----\r\n",
    "ski": "skinumber",
    "serial_number": "serialnumber",
    "signature": "SHA256WithRSA",
    "common_name": "Cloudflare",
    "country": "US",
    "expires_on": "2023-08-27T01:24:00Z",
    "issued_on": "2022-08-27T01:24:00Z",
    "fingerprint_sha256": "fingerprint",
    "validity_days": 365,
    "status": "active"
  }
}

delete a client TLS cert via DELETE

endpoint=https://api.cloudflare.com/client/v4/
zid='your_zoneid'
cert_id='77c9ae51-62e4-45de-****-************'
endpoint_target="zones/$zid/client_certificates/$cert_id"
curl -4sX DELETE "${endpoint}${endpoint_target}" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" | jq -r

{
  "success": true,
  "errors": [],
  "messages": [],
  "result": {
    "id": "77c9ae51-62e4-45de-****-************",
    "certificate_authority": {
      "id": "c3006d2d-5d9f-49e9-bcec-***********",
      "name": "Cloudflare Managed CA for account accountid"
    },
    "certificate": "-----BEGIN CERTIFICATE-----\nABC-----END CERTIFICATE-----\n",
    "csr": "-----BEGIN CERTIFICATE REQUEST-----\r\nXYZ-----END CERTIFICATE REQUEST-----\r\n",
    "ski": "skinumber",
    "serial_number": "serialnumber",
    "signature": "SHA256WithRSA",
    "common_name": "Cloudflare",
    "country": "US",
    "expires_on": "2023-08-27T01:24:00Z",
    "issued_on": "2022-08-27T01:24:00Z",
    "fingerprint_sha256": "fingerprint",
    "validity_days": 365,
    "status": "pending_revocation"
  }
}

restore a revoked client TLS cert via PATCH

endpoint=https://api.cloudflare.com/client/v4/
zid='your_zoneid'
cert_id='77c9ae51-62e4-45de-****-************'
endpoint_target="zones/$zid/client_certificates/$cert_id"
curl -4sX PATCH "${endpoint}${endpoint_target}" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" -d '{"reactivate":true}' | jq -r

{
  "success": true,
  "errors": [],
  "messages": [],
  "result": {
    "id": "77c9ae51-62e4-45de-****-************",
    "certificate_authority": {
      "id": "c3006d2d-5d9f-49e9-bcec-***********",
      "name": "Cloudflare Managed CA for account accountid"
    },
    "certificate": "-----BEGIN CERTIFICATE-----\nABC-----END CERTIFICATE-----\n",
    "csr": "-----BEGIN CERTIFICATE REQUEST-----\r\nXYZ-----END CERTIFICATE REQUEST-----\r\n",
    "ski": "skinumber",
    "serial_number": "serialnumber",
    "signature": "SHA256WithRSA",
    "common_name": "Cloudflare",
    "country": "US",
    "expires_on": "2023-08-27T01:24:00Z",
    "issued_on": "2022-08-27T01:24:00Z",
    "fingerprint_sha256": "fingerprint",
    "validity_days": 365,
    "status": "pending_reactivation"
  }
}

If you create client TLS cert using Cloudflare provided private key and CSR, there is no hostname listed on the SSL certificate or CSR file. So it’s domain zone wide applicable and you’d use Firewall mTLS rules to control the hostname access I’d imagine.

parse certificate and CSR from cert

endpoint=https://api.cloudflare.com/client/v4/
zid='your_zoneid'
cert_id='77c9ae51-62e4-45de-****-************'
endpoint_target="zones/$zid/client_certificates/$cert_id"

parse certificate

openssl x509 -in <(curl -4sX GET "${endpoint}${endpoint_target}" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" | jq -r '.result.certificate') -text -noout

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            74:b5:5e:2e:e5:42:19:0a:6b:57:d8:a7:82:5d:42:19:49:**:**:**
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=California, L=San Francisco, O=Cloudflare, Inc., OU=www.cloudflare.com, CN=Managed CA accountid
        Validity
            Not Before: Aug 27 01:24:00 2022 GMT
            Not After : Aug 27 01:24:00 2023 GMT
        Subject: C=US, CN=Cloudflare
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub: 
                    04:c5:a0:d4:3b:06:39:6d:41:8a:bb:f7:3c:c2:e0:
                    f7:78:1b:85:51:be:ca:6e:83:7b:a1:7a:12:0e:22:
                    27:94:89:6c:9b:7e:e9:55:d7:c0:a2:b8:5c:c5:3e:
                    c2:8a:84:c8:05:7d:03:38:c4:11:90:59:80:76:53:
                    06:ad:**:**:**
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier: 
                AA:29:FB:3C:71:00:39:DB:F2:EF:79:6B:23:40:7F:82:E7:**:**:**
            X509v3 Authority Key Identifier: 
                keyid:1E:C8:41:05:58:CF:14:7C:BD:3F:65:3B:3F:DA:78:3D:EB:D7:FE:BB

            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://crl.cloudflare.com/c3006d2d-5d9f-49e9-bcec-517a2552ad42.crl

    Signature Algorithm: sha256WithRSAEncryption
         7a:8d:02:67:25:09:66:b4:65:f7:fc:ee:20:85:aa:85:9a:fb:
         f1:d8:8b:58:bd:b7:81:ad:82:b0:7c:70:87:ba:27:65:57:76:
         f5:6c:2c:97:40:47:9b:31:d3:e7:1c:6c:3b:b6:90:d2:82:81:
         ca:ad:18:ff:66:83:fa:49:23:86:5b:83:6c:f9:d1:d8:db:44:
         bb:d5:33:ad:fe:2c:77:df:51:40:f9:b2:af:e4:1c:24:44:c6:
         83:9b:c0:65:63:96:6f:89:a1:d6:c0:c3:6a:78:e4:f9:63:b1:
         e2:d1:65:50:13:0e:28:18:34:d4:3e:b9:9f:5d:8e:9d:db:89:
         01:85:42:af:97:63:98:d8:92:a8:eb:58:0f:db:1d:29:21:98:
         ca:9d:19:97:af:4a:65:9e:37:0a:a4:0c:93:b2:a4:2c:8d:b3:
         16:40:50:62:f5:17:7b:a6:31:6b:b6:ac:51:38:d3:a5:31:6e:
         b2:3b:76:06:a1:c8:4b:65:90:b3:76:0f:6e:31:68:c8:bf:a5:
         73:da:5b:a2:df:3f:c4:33:8d:81:2b:2b:ad:b4:fe:c7:1b:03:
         a8:2e:cf:19:f3:0c:13:b0:8c:0c:39:cc:e4:47:7c:1d:30:67:
         4f:cd:a3:c5:31:c0:c7:ab:62:07:2f:0b:9c:b0:4e:8d:50:43:
         19:**:**:**

parse CSR

openssl req -text -noout -verify -in <(curl -4sX GET "${endpoint}${endpoint_target}" -H "X-Auth-Email: $cfemail" -H "X-Auth-Key: $cftoken" -H "Content-Type: application/json" | jq -r '.result.csr')
verify OK
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=US, CN=Cloudflare
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub: 
                    04:c5:a0:d4:3b:06:39:6d:41:8a:bb:f7:3c:c2:e0:
                    f7:78:1b:85:51:be:ca:6e:83:7b:a1:7a:12:0e:22:
                    27:94:89:6c:9b:7e:e9:55:d7:c0:a2:b8:5c:c5:3e:
                    c2:8a:84:c8:05:7d:03:38:c4:11:90:59:80:76:53:
                    06:ad:**:**:**
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        Attributes:
            a0:00
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:21:00:a5:42:0f:62:d7:d8:ac:54:bd:a4:db:e2:2c:
         6e:0d:9a:3b:98:17:34:ec:3d:46:1f:14:79:fe:1b:a6:3c:35:
         fa:02:20:23:e4:29:e8:37:d5:15:53:fd:fb:e0:cf:2d:5f:fe:
         92:21:ce:a6:f6:8e:b3:b7:a6:1e:14:ef:24:75:3e:59:89
1 Like

LOL did all the previous post work only to find my 5 month old gist for this at Cloudflare Client TLS certificate generation for mTLS Authentication via undocumented Cloudflare API Commands · GitHub for creating client TLS with your own CSR and private key and specific hostname LOL

seems while CF API docs don’t mention API for this, the CF developer docs do see Configure your mobile app or IoT device · Cloudflare SSL/TLS docs

2 Likes

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.