Closed kpumuk closed 1 month ago
This looks amazing, I was also wondering if it would be possible to define an endpoint to pull certificate and key files from a local endpoint? At @ubicloud, we provide certificates in a local endpoint and customer is requested to pull these files and make use of them. I can also try to create a PR if you prefer.
At @ubicloud, we provide certificates in a local endpoint and customer is requested to pull these files and make use of them.
Do you mean like a local CA, or simply a secrets manager that returns the same certificate on every call?
Edit: Found, https://www.ubicloud.com/docs/quick-start/using-kamal-with-ubicloud
I think with the proposed CertManager
interface it will be trivial to implement a caching cert fetcher. Probably out of scope for this MR, unless authors disagree :)
@kpumuk yes, I was specifically asking to eliminate the step https://www.ubicloud.com/docs/quick-start/using-kamal-with-ubicloud#step-9 :) It would make life much easier.
It makes sense that this is out of scope for this PR. I'll work on it and hopefully it's something useful to the community.
I was also wondering if it would be possible to define an endpoint to pull certificate and key files from a local endpoint?
I don't think the proxy should be responsible for this. Using a Kamal hook seems like a better option to me. Or, if it turned out to be a common enough requirement, then perhaps it could even be a feature on the Kamal side. But I'd rather the proxy not be involved with gathering artefacts like this; they should be supplied to it wherever possible.
@kevinmcconnell seems like the documentation change was merged ahead of the functional change :-)
Do you want to change the initialization interface in this MR to return the error, or keep the mutex and refactor later?
Edit: might have been merged after this thread.
Benchmark WITHOUT mutex:
Running 30s test @ https://kamal.test:8091/
5 threads and 5 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 451.35us 162.60us 7.68ms 93.69%
Req/Sec 2.24k 101.26 2.46k 81.07%
334834 requests in 30.00s, 264.72MB read
Requests/sec: 11159.76
Transfer/sec: 8.82MB
Benchmark WITH mutex:
Running 30s test @ https://kamal.test:8091/
5 threads and 5 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 446.87us 144.43us 7.29ms 91.86%
Req/Sec 2.26k 99.38 2.54k 83.11%
338088 requests in 30.10s, 267.29MB read
Requests/sec: 11232.35
Transfer/sec: 8.88MB
So the only concern is about ergonomics — when the error is shown for inaccessible cert files - during deploy or during the first request.
@kevinmcconnell I have rebased the branch on top of recent changes, which required to add HTTPHandler
to the certificate manager interface. Steps to hook it all up:
https://github.com/basecamp/kamal/pull/969#issuecomment-2383927911
This requires two changes on kamal
side:
volumes
directive for kamal-proxy to mount certificatesWhat do you think? Any ideas on how to simplify the setup?
Edit: Realized that proxy is shared and so might not be the brightest idea if every service mounted a volume .into the container...
Edit 2: Another option is to copy certs directly to the kamal-proxy config volume:
#!/bin/sh
set -euo pipefail
KAMAL_PROXY_TLS_CERT=$(op read "op://Private/Kamal Demo/cert.pem")
KAMAL_PROXY_TLS_PRIVATE_KEY=$(op read "op://Private/Kamal Demo/key.pem")
for ip in ${KAMAL_HOSTS//,/ }; do
ssh -q -T -o BatchMode=yes ubuntu@"${ip}" bash --noprofile <<-EOF
docker run --rm --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy ubuntu:noble-20240801 sh -c "
mkdir -p /home/kamal-proxy/.config/kamal-proxy/certs
echo '${KAMAL_PROXY_TLS_CERT}' > /home/kamal-proxy/.config/kamal-proxy/certs/cert.pem
echo '${KAMAL_PROXY_TLS_PRIVATE_KEY}' > /home/kamal-proxy/.config/kamal-proxy/certs/key.pem
"
EOF
done
This can be used to improve ergonomics of the command, and in addition to low-level API to pass keys directly, Kamal can do something like:
proxy:
ssl: true
ssl_certificate: <%= KAMAL_PROXY_TLS_CERT %>
ssl_private_key: <%= KAMAL_PROXY_TLS_PRIVATE_KEY %>
This way the values can come from a secret manager, and Kamal can store them in /home/kamal-proxy/.config/kamal-proxy/certs/<%= KAMAL_SERVICE %>/{cert,key}.pem
automatically. This would eliminate the need of a custom hook and docker manipulation.
This all looks great, @kpumuk! I have an idea in mind for how to handle the errors earlier in the deploy process as we discussed, but that also has a few knock-on effects I want to consider. So I'll get this PR merged first as-is, and then I'll explore that separately. It doesn't need to hold up this feature.
This can be used to improve ergonomics of the command, and in addition to low-level API to pass keys directly, Kamal can do something like: ...
Yes, agreed. Using the existing mounted volume makes sense, and we can have Kamal scope it to the service name to avoid conflicts. (We'll need to do something similar for the --error-pages
flag anyway). Treating the cert/key content as secrets rather than requiring file paths is a nice idea too, that seems much more convenient. /cc @djmb
Thanks for your work on this, @kpumuk! 🙏
I've reverted that documentation change for now. We'd need to make it differently anyway as configuration docs are generated from proxy.yml
by the bin/docs
script in Kamal.
In some cases it is needed to use a custom TLS certificate:
With Traefic we had an option to specify a custom certificate, and so this change brings this feature into kamal-proxy.
PS. I am still looking into adding tests, wanted to gauge opinions whether this is a feature you are interested in.covered by tests nowRelated kamal changes