Post

Configure a local CA for your private homelab

Intro

Have you wanted to run some stuff in your local homelab with TLS but don’t want to have to rely on the public lets encrypt and public DNS? This tutorial/guide is for just that and still works with most ACME clients thanks to a project called Lab-CA

This will mainly target services running in Kubernetes using cert-manager and Traefik to automate the process of obtaining certificates, although, I will touch on some other things I use TLS certs from lab-ca for like Proxmox.

Requirements

  • Local DNS server with local private domain like yourdomain.lan, .home, etc. (my DNS server is windows DNS on 2019 server running active directory) but you don’t need that, this will work on most other DNS servers like pi-hole as long as you can manually add the proper record for lab-ca to be recognized as the authorized cert issuer for the domain
  • Fresh Debian 11/12 vm or one running docker for lab-ca
  • Services you want to run with TLS

Initial Setup

Lab-CA

You will need to get your DNS and Lab-CA up and running first. I won’t go into full details on lab-CA setup since they have good directions on the website/github.

Trust the certs

For the certificates issued by lab-ca to be trusted on your client devices in your homelab environment you need to install the root ca cert into that client’s trusted cert store. There is a way to do this for Linux, Windows, and even Android devices, I don’t know about mac but I would assume there is a way I just don’t have any so I didn’t research that.

To save space in the tutorial I won’t go into details on these processes as there are plenty of articles online how to do it. Personally since I have windows active directory I used a GPO (group policy object) to auto-deploy it on all my windows PC’s. On linux I just made a script to do it in BASH but you can just as easily use ansible too if you are comfortable with that.

k3s/kubernetes

If you don’t have a k3s cluster already running, set that up and deploy cert-manager with the following changes below.

To have cert-manager trust your root CA cert from Lab-CA, create a configmap with the cert contents and apply it:

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
metadata:
  name: ca-pemstore
  namespace: cert-manager
data:
  internal-ca.pem: |
    -----BEGIN CERTIFICATE-----
    <<-- cert data here make sure to include the begin and end cert lines -->
    -----END CERTIFICATE-----
kind: ConfigMap

When deploying the cert-manager helm chart add the following to the values by specifying a values file:

1
2
3
4
5
6
7
8
9
10
11
volumeMounts:
  - name: ca-pemstore
    mountPath: /etc/ssl/certs/internal-ca.pem
    subPath: internal-ca.pem
    readOnly: true
volumes:
  - name: ca-pemstore
    configMap:
      # Provide the name of the ConfigMap containing the files you want
      # to add to the container
      name: ca-pemstore

Issuing Certs for k8s clustered services

Now that cert-manager is up and configured you need a clusterIssuer that cert-manager will use to talk to lab-ca and pull certs using ACME just like let’s encrypt would. Here I refer to traefik as my ingress class. If you have nginx or other custom ingress class you would change that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: lab-ca
spec:
  acme:
    email: [email protected]
    #change this to the DNS name of your lab-ca instance
    server: https://ca.pcgeek.lan/directory
    privateKeySecretRef:
      # Secret resource that will be used to store the account's private key.
      name: lab-ca-issuer-account-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: traefik

After that it’s as easy as defining a certificate for your service like you would for lets encrypt.

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: secure-pcgeek-cert
  namespace: default
spec:
  secretName: secure-pcgeek-tls
  issuerRef:
    name: lab-ca
    kind: ClusterIssuer
  dnsNames:
  - secure.pcgeek.lan

Create an simple NGINX deployment to test with if you want along with an ingress referencing the secretName for the tls cert and the same dns name(s).

Make sure you didn’t forget to add the CNAME entry to your local DNS though to match the service or test NGINX or the certificate will fail to create since it can’t find the http solver which cert-manager will make as a temp to validate the domain

Other services

Proxmox

  • SSH into the server or use the ‘shell’ from the web ui.
  • Make sure your proxmox server has the root CA installed
  • Run the following commmand
1
pvenode acme account register default [email protected]
  • choose option #2 and enter in the URL to your lab-CA https://lab-ca.yourdomain.lan/directory
  • press Y to agree (there wont be any terms text)
  • return to proxmox UI and under the node settings find the certificats option, under ACME pane click add and input the private DNS name for your proxmox server.
  • Click Order certificates now under the ACME pane to request your cert from lab-ca. It will run the process and validate then the web-ui process will restart. (you will likely have to close your browser and re-open for it to recognize it now has a valid cert)

Misc

The great thing about this in kubernetes is you can use traefik to ‘proxy’ any lan service that is insecure or has only http using headless services with certificates and ingress definitions.

Troubleshooting

If your TLS certs are issuing but the client device still says its not trusted, view the cert, make sure it is from your lab-ca instance. If it is then double check you have the root CA cert installed properly for that device. Firefox and chrome might even need an additional step to tell them to use the OS trusted store and not only their own built-in one in recent versions, again articles on that online. I might link a couple here on a future update if I think of it.

This post is licensed under CC BY 4.0 by the author.