Homelab: client certificates
In previous log I have set up a server certificate, which is a way to secure (make it "impossible", well, difficult in fact, to read exchanged data, and authenticate the server).
While it's interesting, it's actually pointless since my services are accessible without authentications (preventing data being intercepted, while being freely accessible any time is a vain effort).
That's one of the reason of the existence of client certificates: restrict access to authenticated/authorized clients.
Let's start with the beginning, we have to create a certificate authority (I have chosen one per service):
##!/usr/bin/env bash
if [;
then
fi
SERVICE=
CA_DIR=client/
/caREQ_DIR=client/requests
|
CRL_DIR=
/crl
TARGET_DIR=/etc/nixos/certificates/clients/
TARGET_LOGIN=black@192.168.0.4
With the associated configuration file:
let openssl =
https://raw.githubusercontent.com/blackheaven/dhall-openssl/master/package.dhall
in \(caDir : Text) ->
\(service : Text) ->
openssl.mkCaConfig
openssl.CaConfig::{
, distinguishedName = openssl.DistinguishedName::{
, commonName = "${service} client Root Certificate Authority"
}
, allowedHosts = [ "barracuda.local" ]
, caDir
, crlDir = Some "\$base_dir/crl"
, crl = Some "\$base_dir/crl.pem"
, crlNumber = Some "\$base_dir/number"
, defaultCrlDays = Some 30
}
The main difference with servers' CA are the crl*
fields which stands for Certificate Revocation List,
more on this later.
Then, we have to create and sign client certificates:
#!/usr/bin/env bash
if [;
then
fi
SERVICE=
USER=
CRT_DIR=client/
/CA_DIR=client/
/caREQ_DIR=client/requests
|
# Create a new certificate
# Sign it with our CA
# Export client key
and the configuration file:
let openssl =
https://raw.githubusercontent.com/jvanbruegge/dhall-openssl/master/package.dhall
in \(service : Text) ->
\(user : Text) ->
openssl.mkConfig
openssl.Config::{
, distinguishedName = openssl.DistinguishedName::{
, commonName = "${user} client certificate for barracuda.${service}"
}
}
Let's talk about CRL's, unlike for servers, clients' certificates are sprayed into the wild, so they are more likely to be compromised.
We could, like for the servers, recreate the CA, but doing so would invalidate all accesses to all clients (to their certificates to be precise). Instead, we can emit a revocation request which will the will be registered on the CRL, then, each time a request come, the given client certificate will be checked against the CRL.
Let's revoke this:
#!/usr/bin/env bash
if [;
then
fi
SERVICE=
USER=
CRT_DIR=client/
/CRT_FILE=
/client.pemCA_DIR=client/
/caCRL_DIR=
/crlNEW_CRL=
/revoked.crl
TARGET_DIR=/etc/nixos/certificates/clients/
TARGET_LOGIN=black@192.168.0.4
# scp "$CA_DIR/ca.crt" $TARGET_LOGIN:~
# scp "$CRL_DIR/crl.pem" $TARGET_LOGIN:~
# ssh $TARGET_LOGIN sudo chown root:root ca.crt crl.pem
# ssh $TARGET_LOGIN sudo mv ca.crt crl.pem $TARGET_DIR
Finally we have to update Barracuda (nginx), configuration:
"withings.barracuda.local" = {
enableACME = false;
serverAliases = [ ];
forceSSL = true;
sslCertificate = "/etc/nixos/certificates/servers/withings/server.crt";
sslCertificateKey = "/etc/nixos/certificates/servers/withings/server.key";
extraConfig = ''
ssl_client_certificate /etc/nixos/certificates/clients/transmission/ca.crt;
ssl_crl /etc/nixos/certificates/clients/transmission/crl.pem;
ssl_verify_client on;
'';
locations."/" = {
proxyPass = "http://127.0.0.1:5555/";
};
};
By now, you should get a HTTP 400 status code on each query you submit.
To finalise the setup, you have to import the client.p12
in your browser and indicate it to your tools (such as restic).