Authenticating Icinga 2 API Users with TLS Client Certificates

by | Nov 16, 2022

When interacting with the Icinga 2 API, the client is commonly authenticated using a password provided via HTTP basic auth. Icinga 2 also supports a second authentication mechanism: TLS client certificates. This is a feature of TLS that also allows the client to send a certificate, just like the server does, allowing the server to authenticate the client as well.

Using certificates needs a bit more preparation compared to a password as you need to generate a private key and a matching certificate first. You can start by generating a private key and a certificate signing request (CSR) with the icinga2 pki new-cert command:

icinga2 pki new-cert \
    --cn my-api-client \
    --key my-api-client.key.pem \
    --csr my-api-client.csr.pem

This writes the key and CSR to the files my-api-client.key.pem and my-api-client.csr.pem respectively. Note that you can also use other methods to generate these files. It is only important that the CSR contains a meaningful common name (CN). This allows you to also generate the private key on a hardware security token for example.

Next, the CSR has to be signed by the Icinga CA. This can be achieved by copying the CSR file to the Icinga master and running the following command:

icinga2 pki sign-csr \
    --csr my-api-client.csr.pem \
    --cert my-api-client.cert.pem

This generates a certificate, however, so far, Icinga 2 does not know what to do with this certificate. To fix this, a new ApiUser object has to be created that connects the certificate and its common name with some permissions.

object ApiUser "my-api-client" {
  client_cn = "my-api-client"
  permissions = [ "*" ]
}

After reloading the Icinga 2 configuration, the certificate is now ready to use. The following example uses curl, but any HTTPS client that supports client certificates will do.

curl \
    --cacert /var/lib/icinga2/certs/ca.crt \
    --cert my-api-client.cert.pem \
    --key my-api-client.key.pem 
    --header 'Accept: application/json' \
    'https://icinga-master.example.org:5665/v1/?pretty=1'
{
    "results": [
        {
            "info": "More information about API requests is available in the documentation at https://icinga.com/docs/icinga2/latest/",
            "permissions": [
                "*"
            ],
            "user": "my-api-client",
            "version": "r2.13.6-1"
        }
    ]
}

Keep in mind that this is the same CA that is also used to authenticate Icinga 2 cluster connections. So you should avoid using the name of Icinga 2 endpoints as the common name for an API user: this would allow the API user to authenticate as the endpoint and vice versa. However, you can also use this to your advantage: if you for some reason want to perform requests against the Icinga 2 API on another endpoint, you can reuse the already existing certificate and create an ApiUser object for it. Additionally, you have to remember that certificates have an expiry date, so they have to be renewed regularly.

You May Also Like…

Code Reviews – How do they work?

Code Reviews – How do they work?

We at Icinga / NETWAYS (yes, that’s the order) held an internal event recently. It’s name was Knowledge Days and I got...

Subscribe to our Newsletter

A monthly digest of the latest Icinga news, releases, articles and community topics.