Setup a local CA for your homelab

Why ?

I hate seeing red locks on the website I browse.

That’s it.

img

And since I have friends that like to do very smart pranks involving MITM attacks, I want to protect myself (and my passwords, as long as they might be) from them……

Ok I may be the “friend” that does these pranks but I always ask for their consent!

Jokes aside, we will use step-ca as it’s lightweight, easy to deploy and it just works.

Machine

I have deployed my instance on a separate LXC on proxmox:

  • OS: Debian
  • CPU: 1
  • RAM: 2G (Might be overkill, but I have loads of RAM)
  • Storage: 15 GB (Bit too much, but I don’t care)

Its IP address is assigned by DHCP but its lease is static; make sure to assign it an entry in your local DNS server!

Installation

First, download the latest release of step here and install it. This is pretty straightforward, just follow this example (on an amd64 platform):

wget https://dl.smallstep.com/gh-release/cli/docs-ca-install/v0.23.2/step-cli_0.23.2_amd64.deb
sudo dpkg -i step-cli_0.23.2_amd64.deb

Then, do the same thing with the latest version step-ca of (https://github.com/smallstep/certificates/releases/latest). Again, just do:

wget https://dl.smallstep.com/gh-release/certificates/docs-ca-install/v0.23.2/step-ca_0.23.2_amd64.deb
sudo dpkg -i step-ca_0.23.2_amd64.deb

step-ca can be setup as a systemd service, but instead of copy-pasting their instructions like a moron, I’ll just tell you to follow them here. There are a lot of steps so please be sure to read the instructions carefully.

Configuration

As I am sure that you’ve carefully followed the instructions on how to make your CA a daemon, your latest creation should be correctly initialized, so no need to step ca init 😉. Congratulations, you can now generate and distribute TLS certificates to whomever you want! You might want to continue reading this though as we’ll see how to setup the ACME server and that, I can assure you, is really cool.

ACME server ?

Come on, I’m pretty sure that you’ve already heard about it; does Let’s Encrypt ring any bell ? Maybe their certbot script ? Well, it can request certs as an ACME client. If you love reading documentations, go ahead and do so here.

TLDR: deploying an ACME server on your CA will allow you to request certificates for your local services using certbot or Traefik (and we’ll even talk about this later on) for example.

I’m sold, show me the magic

I knew you’d like it! Setting up the server isn’t hard at all, you’ll just need to add an ACME provisionner:

step ca provisioner add acme --type ACME

then restart your server (the following command only works if you’ve made your CA a systemd daemon):

sudo systemctl restart step-ca

You can try to request a certificate from your ACME server with:

step ca certificate <domain name> --provisioner acme

Please note that this last command might not work if you already have a service listening on port 80 as it launches an HTTP server.

Actual usage

Remember that your ACME server must be able to find your servers to give them certificates; you might be good by just requesting certs with IPs but, in case you want to distribute “named certificates” (probably not the right way to call them, but you get me), don’t forget to add a DNS entry to your local DNS server for each (v)host that needs a “named cert”.

Traefik

I have been proxying my services with Traefik for a while now and I don’t regret switching to it one bit; it is easier to expose my containerised service, easier to get new certificates, easier to use in general. I might have had a hard time setting up all the TLS params at the beginning but it was all worth it in the end though. I won’t do a tutorial on how to setup a Traefik reverse proxy, but I’ll show you how to use it like you’d normally use the Let’s Encrypt resolver. To add your ACME server as a certificates resolver, add these commands to your Traefik container (you can add multiple resolvers; I personally have Let’s Encrypt AND my internal CA setup):

# Lets call the resolver myca
# The HTTP entrypoint is called http
# Your caServer's address in myca.lan
- "--certificatesresolvers.myca.acme.httpchallenge=true"
- "--certificatesresolvers.myca.acme.httpchallenge.entrypoint=http"
- "--certificatesresolvers.myca.acme.caServer=https://myca.lan/acme/acme/directory"
- "--certificatesresolvers.myca.acme.email=me@mail.lan"
- "--certificatesresolvers.myca.acme.storage=/myca/acme.json"

You’ll have to:

  • Mount the host certs folder to the container’s certs folder so that the root CA cert can be retrieved by the container
  • Add a volume to the container and mount it to /myca/; it’ll contain the certs, etc.

Once your Traefik container is setup, requesting certs from the CA is quite easy; just add the following label:

# The router here is called myservice
- "traefik.http.routers.myservice.tls.certresolver=myca"

This will make Traefik automatically fetch the certificates from your CA, just like it would with Let’s Encrypt.

Certbot

Using your ACME server with certbot is also pretty easy; you just have to add --server https://myca.lan/acme/acme/directory to the command (e.g certbot certonly -n --standalone -d test.lan --server https://myca.lan/acme/acme/directory).