Skip to content

Commit

Permalink
Update instructions for haproxy based reverse proxies w/ step-ca (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewmzhang authored Apr 28, 2024
1 parent 7e07d83 commit 23c7e8b
Showing 1 changed file with 22 additions and 49 deletions.
71 changes: 22 additions & 49 deletions _posts/2023-05-25-reverse-proxies-with-custom-acme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,66 +21,39 @@ Docker-swag is a complete solution. It'll renew the certificates once a day and

# HAProxy + ACME.sh - [haproxy](https://github.com/haproxy/haproxy)
## Issues
**EDIT: This section was updated on 2024-04-17. The previous instructions were out of date**

HAProxy suffers several issues.
1. It cannot provision its own SSL certs, ie it cannot do the ACME dance
2. It hogs port 80 and 443, in order for 3rd party acme to work correctly the acme program needs 80 and 443.
3. It demands that the SSL privkey be in the same file as the cert bundle
4. It cannot tell if the SSL cert has changed on disk, thus users need to send commands to get HAProxy to refresh the certs

To fix part 1, we use `acme.sh`.
```
# Runs the acme.sh program on port 8888.
"/home/pi/.acme.sh"/acme.sh --cron --home "/home/pi/.acme.sh" --force --httpport 8888
```
To fix part 2, we need to tell HAProxy to redirect AMCE dance over http to redirect to `acme.sh`
Fortunately, `acme.sh` has some helpers that make this procedure relatively painless
```bash
# Register an account thumbprint. This will produce a thumbprint. Copy that value
./acme.sh --register-account --server https://step-ca.internal/acme/acme/directory -m myemail@example.com

# Edit the following into /etc/haproxy/haproxy.cfg
global
[...]
stats socket /var/run/haproxy/admin.sock level admin mode 660 # This command lets ./acme.sh communicate to HAProxy to reload SSL certs
setenv ACCOUNT_THUMBPRINT 'THE VALUE COPIED FROM THE PREVIOUS COMMAND'

```
"/home/pi/.acme.sh"/acme.sh --cron --home "/home/pi/.acme.sh" --force --httpport 8888
```
```
frontend public
bind :::80 v4v6
bind :::443 v4v6 ssl crt /etc/haproxy/certs/ strict-sni # This allows haproxy to boot without certs, which you wont have initially
# The directive below means when the certificate authority navigates to my.domain.internal/.well-known/acme-challenge/ HAProxy will reply with the account thumbprint
http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}\n" if { path_beg '/.well-known/acme-challenge/' }

# Redirects AMCE challenges towards our other ACME program
acl letsencrypt-acl path_beg /.well-known/acme-challenge/
use_backend letsencrypt-backend if letsencrypt-acl
# Set the SSL certificate
bind :::443 v4v6 ssl crt /home/pi/.acme.sh/octoprint.aws.pem
option forwardfor except 127.0.0.1
http-request redirect scheme https code 301 unless { ssl_fc }
use_backend webcam if { path_beg /webcam/ }
use_backend webcam_hls if { path_beg /hls/ }
use_backend webcam_hls if { path_beg /jpeg/ }
default_backend octoprint
# Sets the amce backend to the 8888 port
backend letsencrypt-backend
server letsencrypt 127.0.0.1:8888
# Do the ACME dance, ACME will write some config files under ~/.acme.sh/mydomain.internal_ecc. Note the deploy-hook and --days 1
./acme.sh --stateless --issue -d my.domain.internal --server https://step-ca.internal/acme/acme/directory --ca-bundle ~/my_root_ca.crt --deploy --deploy-hook haproxy --days 1
# Remember to update cron
./acme.sh --install-cronjob
```
To fix part 3, concatenate the key and the crt together after running `acme.sh`
```bash
# This is the code that runs for my Octoprint rpi.
cat /home/pi/.acme.sh/octoprint.aws.key /home/pi/.acme.sh/octoprint.aws.crt > /home/pi/.acme.sh/octoprint.aws.pem
```

To fix part 4, we need to send some commands to HAProxy to set a new SSL cert.

```
#!/bin/bash
echo “========================== SET SSL CERT ==========================“
echo "$(cat /home/pi/.acme.sh/octoprint.aws.pem)"
echo -e "set ssl cert /home/pi/.acme.sh/octoprint.aws.pem <<\n$(cat /home/pi/.acme.sh/octoprint.aws.pem)\n" | socat tcp-connect:localhost:9999 -
Remember to check the .acme.sh config files, namely the `Le_RenewalDays` value. It defaults to 60 days, but step-ca certs default expires in 1 day, so you'll need to mess with this value
echo “========================== SHOW SSL CERT - before ==========================“
echo "show ssl cert */home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 -
echo “========================== COMMIT SSL CERT ==========================“
echo "commit ssl cert /home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 -
echo “========================== SHOW SSL CERT - after ==========================“
echo "show ssl cert /home/pi/.acme.sh/octoprint.aws.pem" | socat tcp-connect:localhost:9999 -
```
### Resources
1. https://www.haproxy.com/blog/haproxy-and-let-s-encrypt

0 comments on commit 23c7e8b

Please sign in to comment.