Using FreeIPA CA as an ACME Provider for Cert-Manager
I’m using FreeIPA for authentication services in my home lab. It’s extreme overkill for my situation, as I don’t have many users (mainly just me!) but alas I like overkill. :)
I am using FreeIPA’s DNS service to host some DNS subdomains for internal services. The way I have configured these subdomains is through DNS delegations, but since my IPA servers are not accessible from the internet, it breaks both the HTTP-01 and DNS-01 verification challenges from LetsEncypt’s.
Yesterday evening, I was playing around with TrueCommand and have it hosted on one of my IPA internal domains, but as I cannot use LetsEncrypt to issue a certificate for it, I decided to use the CA built into FreeIPA since it supports ACME as well.
As all the machines that will need to use the service are enrolled into IPA already, the CA certificate for IPA is also installed on those nodes, meaning any certificate issues by FreeIPA are automatically trusted.
To get this to work, I had to first enable ACME support from within FreeIPA:
[[email protected] ~]# ipa-acme-manage enable
FreeIPA’s ACME service supports both HTTP-01 and DNS-01 challenges, but I generally prefer DNS-01. For cert-manager to add the _acme-challenge DNS record to FreeIPA, we can use cert-manager’s RFC-2136 provider.
To do this, we must create a new TSIG key on our IPA server:
[[email protected] ~]# tsig-keygen -a hmac-sha512 acme-update >> /etc/named/ipa-ext.conf [[email protected] ~]# systemctl restart named-pkcs11.service
Enable dynamic updates for the IPA DNS subdomain:
[[email protected] ~]# ipa dnszone-mod k8s.intahnet.co.uk --dynamic-update=True --update-policy='grant acme-update wildcard * ANY;'
Next, I had to modify my cert-manager installation slightly to include my own CA certificate bundle, which includes my IPA CA cert. To do this I had to first create the bundle, and then create a Kubernetes ConfigMap for it:
[[email protected] ~]# cat /etc/ipa/ca.crt > ca-certificates.crt [[email protected] ~]# kubectl -n cert-manager create configmap ca-bundle --from-file ca-certificates.crt
Next, I had to modify the cert-manager deployment to make use of the ca-bundle. As I am using the cert-manager helm chart, this was quite easy. I added the following to my cert-manager helm values file:
... volumes: - name: ca-bundle configMap: name: ca-bundle volumeMounts: - name: ca-bundle mountPath: /etc/ssl/certs/ca-certificates.crt subPath: ca-certificates.crt readOnly: false ...
Once this has been deployed, we can need to create a secret in Kubernetes for the TSIG key. Grab the TSIG key we generated earlier from your IPA server (/etc/named/ipa-ext.conf), and create a Kubernetes secret with it:
[[email protected] ~]# kubectl -n cert-manager create secret generic ipa-tsig-secret --from-literal=tsig-secret-key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Next, add a new ClusterIssuer for IPA’s ACME service:
--- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: ipa namespace: cert-manager spec: acme: email: [email protected] server: https://ipa-ca.ipa.intahnet.co.uk/acme/directory privateKeySecretRef: name: ipa-issuer-account-key solvers: - dns01: rfc2136: nameserver: 10.0.0.22 tsigKeyName: acme-update tsigAlgorithm: HMACSHA512 tsigSecretSecretRef: name: ipa-tsig-secret key: tsig-secret-key selector: dnsZones: - "k8s.intahnet.co.uk"
Now you should be set to request certificates!
--- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: truecommand-certificate namespace: default spec: commonName: "truecommand.k8s.intahnet.co.uk" dnsNames: - truecommand.k8s.intahnet.co.uk issuerRef: name: ipa kind: ClusterIssuer privateKey: algorithm: RSA encoding: PKCS1 size: 4096 secretName: truecommand-tls
[[email protected] ~]# kubectl get certificate NAME READY SECRET AGE truecommand-certificate True truecommand-tls 23s [[email protected] ~]# kubectl get secrets NAME TYPE DATA AGE truecommand-certificate-q8qkh kubernetes.io/tls 2 29s
It’s a very similar process to use ExternalDNS with FreeIPA as ExternalDNS also supports RFC2136. I have not set this up yet, but the process is described in this excellent blog post: How to set up Dynamic DNS on FreeIPA for your Kubernetes Cluster.