Cheatsheet: get SSL certificates from Let’s Encrypt for a private VMware ESXi host, using an RFC2136-compatible name server

Most of the available options for integrating Let’s Encrypt (or other ACME providers) with VMware ESXi require the host to be accessible from the public Internet. It goes without saying that exposing ESXi’s port 80 to the public is a Bad Idea. DNS validation works well for private hosts, but none of the solutions I’ve run across for ESXi support it. Here’s how I got it working.

(Quick note: this was implemented on a host running ESXi 7.0 Update 3. Things might need to be tweaked for older or newer versions.)

First, set up a TSIG key on your public DNS server and configure the zone in which the host resides to allow TXT updates for _acme-challenge.hostname.example.tld. This page describes setting this up with the Technitium DNS server, which is what I use, but there should be something equivalent for your server.

Next, bring up a new Alpine Linux VM on your ESXi host. Requirements are minimal; I think I set mine to 2 GB RAM, 16 GB of disk (actual space used is well under 1 GB, so you can go lower here), secure boot disabled, and autostart enabled. Once it’s up and running, SSH in with whatever normal user you configured and do the following additional setup:

doas sed -i "s/ persist / nopass /" /etc/doas.d/20-wheel.conf
doas apk add open-vm-tools certbot certbot-dns-rfc2136 cronie
cat <<EOF >renew.sh && chmod +x renew.sh
#!/usr/bin/env ash
cd /home/`whoami`
. /etc/profile

EMAIL=yourname@example.tld
ESXI_HOST=esxi.invalid.tld

# get (or update) the certificate
doas certbot certonly -n -t -m $EMAIL --agree-tos \
  --dns-rfc2136 --dns-rfc2136-credentials /home/`whoami`/rfc2136.ini --dns-rfc2136-propagation-seconds 60 \
  --cert-name $ESXI_HOST --key-type rsa \
  -d $ESXI_HOST

# copy and rename it to what ESXi expects
doas cp /etc/letsencrypt/live/$ESXI_HOST/privkey.pem /tmp/rui.key
doas cp /etc/letsencrypt/live/$ESXI_HOST/fullchain.pem /tmp/rui.crt
doas chown `whoami` /tmp/rui.*

# upload it and restart the web interface
scp /tmp/rui.* root@$ESXI_HOST:/etc/vmware/ssl/
rm /tmp/rui.*
ssh root@$ESXI_HOST services.sh restart
EOF

Edit renew.sh to set EMAIL and ESXI_HOST to appropriate values, then generate an SSH keypair:

ssh-keygen && cat .ssh/id_ed25519.pub

Hit Enter all the way through to accept the defaults for ssh-keygen, and make note of the public key that’s printed at the end. We’ll need it later.

rfc2136.ini also needs to be created. Fill it in with this template (note the dot at the end of the dns_rfc2136_name line…leave it in!):

dns_rfc2136_server = <IP addr of your public DNS>
dns_rfc2136_port = 53
dns_rfc2136_name = <TSIG key name>.
dns_rfc2136_secret = <TSIG secret>
dns_rfc2136_algorithm = <TSIG key algorithm (probably HMAC-SHA256)>

Next, enable SSH access on your ESXi host (how you do this varies between ESXi versions). We need this to enable the VM to push updated certificates to ESXi and restart the web interface.

SSH into the root account on your ESXi host. The first time around, you’ll need your password. Once you’re in, append the public key generated above to /etc/ssh/keys-root/authorized_keys. Log out and log back in; you shouldn’t be asked for your password. If you got back in without your password, you can disable password logins for root:

sed -i "s/^PermitRootLogin .*/PermitRootLogin prohibit-password/" /etc/ssh/sshd_config && /etc/init.d/SSH restart

With all of this in place, you should be able to get a key and deploy it. Log back in to the Certbot VM and kick it off:

./renew.sh

If all goes well, the certifcate should be obtained from Let’s Encrypt and installed on your ESXi box. Try logging into it with the full hostname you provided; it should now show up as a secure connection.

The last step is to set up periodic renewal. Weekly ought to be enough:

echo "0 0 * * 0 /home/`whoami`/renew.sh" | crontab -

Leave a Reply

Only people in my network can comment.