Skip to content

Client Certificate Authorization (v4.10.3 and higher)

dr-provision 4.10.3 and higher has the ability to authenticate with Client Certificates. The server will request a certificate from the client, and if one is presented will attempt to use it for authentication and authorization if the following conditions are met:

  • The HTTP request does not have an Authorization header.
  • The certificate is signed by the same authority as the server certificate.
  • (v4.11 and higher): The certificate has one of the client trust roots in its chain of trust.

NOTE: The browser may pop-up an window to select a certificate. If you are not using client certificates, clicking cancel or ignore will continue to normal operations. This is particularly noticeable with Microsoft products, Skype and Teams. They inject certificates that the browser attempts to use when it is not within those certificate's scope. If an certificate is selected, the browser must be told to forget that choice by using the security configuration pieces of your browser.

Client Trust Roots (v4.11 and higher)

dr-provision v4.11 and higher add support for managing a set of certificates that can be used to determine whether a client certificate should be used for authentication and authorization purposes.

You can set the client trust roots with the following command:

    drpcli system certs client set certList.pem

and retrieve the current set of client trust roots with:

    drpcli system certs client get certList.pem

In both cases, certList.pem should contain certificates from all of the certificate authorities that are trusted to issue client certificates on behalf of dr-provision.

RackN OID Extensions

RackN has reserved the OID space rooted at 1.3.6.1.4.1.59257 to include extra RackN specific data in certificates used for client authentication. Unless otherwise specified, all of our OIDs refer to values that are ASN1::UTF8String encoded.

1.3.6.1.4.1.59257.1.1 - CertClaimsOid

This OID specifies a JSON-encoded claims list that can be used to grant the holder of the client certificate additional authority beyond what they would have by default. Example:

1.3.6.1.4.1.59257.1.1=ASN1:UTF8String:[ { "scope": "machines", "action": "*", "specific": "*" } ]

1.3.6.1.4.1.59257.1.2 - CertRolesOid

This OID specifies a comma-separated list of Role names that the holder of the client certificate has in addition to what they have by default. Example:

1.3.6.1.4.1.59257.1.2=ASN1:UTF8String:operator

1.3.6.1.4.1.59257.1.3 - CertPrincipalOid (v4.11 and higher)

This OID specifies the user or service that the holder of the certificate should be authenticated as. If this OID is present in a certificate, then Subject.CommonName is not used for authentication purposes. Examples:

  • 1.3.6.1.4.1.59257.1.3=ASN1:UTF8String:user:rocketskates indicates that the certificate authenticates its holder as the rocketskates user. The user must exist, and any additional claims and roles are added to the set that the user has by default.
  • 1.3.6.1.4.1.59257.1.3=ASN1:UTF8String:service:external-service indicates that the certificate authenticates its holder as a service named external-service. The certificate must also have either a CertClaimsOid or CertPrincipalOid extension to specify what actions the holder is permitted to take.

How dr-provision Uses Client Certificates

dr-provision only uses client cert authentication if the following conditions are met:

  • There is no Authorization header in the HTTP request. If there is, then it will be used for authentication and authorization, and any information in the certificate will be ignored.
  • If any RackN OIDs are present, they must be well-formed. If they are not, then the certificate will be ignored.
  • (v4.11 and higher) The client certificate has a certificate from the client trust roots in its chain of trust. If it does, then the client certificate will be used for authentication.
  • The client certificate has the CA that signed the server certificate in its chain of trust. If it is, then the certificate will be used for authentication.

Once dr-provision determines it can use a certificate for authentication, we determine what actions it is authorized to perform and who those actions are being performed for.

CertPrincipalOid is present (v4.11 and higher)

If the CertPrincipalOid extension is present in the presented certificate, it indicates who the certificate is authenticating as. This can be one of two types:

  • Authenticating as a user, as indicated by a user: prefix in the value embedded in the certificate. In this case, the user must still exist, and any additional roles and claims present in the certificate will be added to the ones the user already has.
  • Authenticating as a service, as indicated by a service: prefix in the value embedded in the certificate. In this case, the certificate must also contain at least one of the CertClaimsOid or CertRolesOid extensions to specify what actions the bearer of the certificate is allowed to take.

CertPrincipalOid is not present

If the certificate does not contain a CertPrincipalOid extension, dr-provision will fall back to authenticating based on the Subject.CommonName field of the certificate.

  • If a User is found, authentication succeeds. The holder of the certificate will have whatever rights that User has plus any that are embedded in the certificate.
  • If a User is not found and the certificate has either the CertClaimsOid or CertRolesOid extensions, then the CommonName field will be used as the principal for normal operations and auditing.

OpenSSL Examples

This is an example of an OpenSSL extensions file that could be used to generate a client certificate.

basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
1.3.6.1.4.1.59257.1.2=ASN1:UTF8String:readonly
1.3.6.1.4.1.59257.1.1=ASN1:UTF8String:[ { "scope": "machines", "action": "*", "specific": "*" } ]

The following commands for Linux OpenSSL could be used to sign/create a client key. This assumes that your openssl configuration has access to your CA Key and CA Certificate. This will create a certificate for client-1.

mkdir -p client_certs
CL=client-1
cat >client_certs/${CL}_ext.cnf <<EOF
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
1.3.6.1.4.1.59257.1.2=ASN1:UTF8String:readonly
1.3.6.1.4.1.59257.1.1=ASN1:UTF8String:[ { "scope": "machines", "action": "*", "specific": "*" } ]
EOF
openssl req -nodes -newkey rsa:4096 -keyout client_certs/${CL}.key.pem -out client_certs/${CL}.csr -subj "/C=US/ST=TX/L=Austin/O=RackN/OU=Engineering/CN=${CL}/emailAddress=support@rackn.com"
openssl ca -extfile client_certs/${CL}_ext.cnf -days 1650 -notext -batch -in client_certs/${CL}.csr -out client_certs/${CL}.cert.pem

To generate a Certificate without Authorizations, remove the two lines with 1.3.6.1.3 from the extensions file.

Mutual TLS Setup

The following script can be used to setup MTLS. It will create a CA certificate (self-signed). It will then create client and server certificates that can be used. Everything will be stored under the mtls directory.

It requires Linux and has been tested with default OpenSSL configuration on Ubuntu 20.04.

#!/usr/bin/env bash

set -e
set -x

IP1=$1
DNS1=$2

# Start with config file from bottom
mkdir mtls
cd mtls
mkdir demoCA server_certs client_certs demoCA/private demoCA/newcerts
echo 01 > demoCA/serial
touch demoCA/index.txt

# Build CA
openssl req -nodes -newkey rsa:4096 -keyout demoCA/private/cakey.pem -new -x509 -out demoCA/cacert.pem -subj "/C=US/ST=TX/L=Austin/O=RackN/OU=Engineering/CN=ca-server/emailAddress=support@rackn.com"
openssl x509 -in demoCA/cacert.pem -out demoCA/cacert.pem -outform PEM

# Create empty extent
cat >client_certs/client-1_ext.cnf <<EOF
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
EOF

cp client_certs/client-1_ext.cnf client_certs/client-2_ext.cnf
cat >>client_certs/client-2_ext.cnf <<EOF
1.3.6.1.4.1.59257.1.2=ASN1:UTF8String:readonly
EOF

cp client_certs/client-1_ext.cnf client_certs/client-3_ext.cnf
cat >>client_certs/client-3_ext.cnf <<-EOF
1.3.6.1.4.1.59257.1.1=ASN1:UTF8String:[ { "scope": "machines", "action": "*", "specific": "*" } ]
EOF

cp client_certs/client-1_ext.cnf client_certs/client-4_ext.cnf
cat >>client_certs/client-4_ext.cnf <<-EOF
1.3.6.1.4.1.59257.1.1=ASN1:UTF8String:[ { "scope": "machines", "action": "*", "specific": "*" } ]
1.3.6.1.4.1.59257.1.2=ASN1:UTF8String:readonly
EOF

cp client_certs/client-1_ext.cnf client_certs/client-5_ext.cnf

for CL in client-1 client-2 client-3 client-4 client-5 ; do
  openssl req -nodes -newkey rsa:4096 -keyout client_certs/${CL}.key.pem -out client_certs/${CL}.csr -subj "/C=US/ST=TX/L=Austin/O=RackN/OU=Engineering/CN=${CL}/emailAddress=support@rackn.com"
  openssl ca -extfile client_certs/${CL}_ext.cnf -days 1650 -notext -batch -in client_certs/${CL}.csr -out client_certs/${CL}.cert.pem
done


# Make Server certs

# Only config piece is DNS name and IP address
cat >server_certs/server_ext.cnf <<EOF
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = ${IP1}
IP.2 = 127.0.0.1
DNS.1 = ${DNS1}
DNS.2 = localhost
EOF

openssl req -nodes -newkey rsa:4096 -keyout server_certs/server.key.pem -out server_certs/server.csr -subj "/C=US/ST=TX/L=Austin/O=RackN/OU=Engineering/CN=server/emailAddress=support@rackn.com"
openssl ca -extfile server_certs/server_ext.cnf -days 1650 -notext -batch -in server_certs/server.csr -out server_certs/server.cert.pem

To Use, save the script as setup-mtls.sh. The script requires the IP address of the system and the name of the system. The server certificate will be generated with server as the CN, but additional names and IPs are added.

The script can be run as:

chmod +x setup-mtls.sh
./setup-mtls.sh 1.2.3.4 myhost.company.com

The following files are used for the RackN client and server.

  • mtls/demoCA/cacert.pem - the CA Certificate for validation. This is used by dr-provision and drpcli to validate certificates.
  • mtls/server_certs/server.key.pem - The Server's key file
  • mtls/server_certs/server.cert.pem - The Server's cert file
  • mtls/client_certs/client-##.key.pem - The Client's key file
  • mtls/client_certs/client-##.cert.pem - The Client's cert file

There are 5 certs generated for clients.

  • client-1 - CN = client1 and NO extensions
  • client-2 - CN = client2 and a Roles extension of read-only (requires ux-views plugin)
  • client-3 - CN = client3 and a Claims extension of access to machines.
  • client-4 - CN = client4 and both the above extensions
  • client-5 - CN = client5 and NO extensions

To use client-1 and client-5, you will need to create a User in the system for access.

To use the server certificate and key use the commands above to load the certificates. The server will use the system default location for CA certificates. Additionally, the server can be started with the SSL_CERT_FILE environment variable to point at the specific CA certificate or the SSL_CERT_DIR environment variable to point to a complete directory of certificates. These will override the system level locations.

For client certificate usage, drpcli has additional flags, drpclirc, and environment variable support to specify the client certificate file and key file.

The client by default does NOT verify the certificate of the server. This can be turned on by adding an additional flag. The client will attempt to use the system enabled certificates, but an additional flag is added to allow for the specification of the CA certificate.