Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pki: Embedded ACME server #3198

merged 12 commits into from May 5, 2020

pki: Embedded ACME server #3198

merged 12 commits into from May 5, 2020


Copy link

@mholt mholt commented Mar 27, 2020

This PR implements an embedded ACME server, powered by Smallstep libraries.

See #3021

It's really cool! You can use it simply by giving your own ACME directory endpoint in your other Caddy configs.

🚫 Not ready to merge. Ready to merge after 2.0

Still some cleanup to do, and some more features to come as well!

Below is a config that demonstrates this feature. To use it, simply add to your hosts file so that it points to

When you start Caddy, you should see that it will try to obtain a certificate for from the ACME CA at https://localhost/acme/local/directory.

	"apps": {
		"http": {
			"servers": {
				"dev": {
					"listen": [":443"],
					"routes": [
							"match": [
								{"host": ["localhost"]}
							"handle": [
								{"handler": "acme_server"},
								{"handler": "static_response", "body": "Hello! Not an ACME request."}
		"tls": {
			"certificates": {
				"automate": [
			"automation": {
				"policies": [
						"issuer": {
							"module": "acme",
							"ca": "https://localhost/acme/local/directory"

My logs:

$ go run main.go run --config acme.json
2020/03/27 16:52:57.456 INFO    using provided configuration    {"config_file": "acme.json", "config_adapter": ""}
2020/03/27 16:52:57.503 INFO    admin   admin endpoint started  {"address": "localhost:2019", "enforce_origin": false, "origins": ["localhost:2019"]}
2020/03/27 10:52:57 [INFO][cache:0xc000878910] Started certificate maintenance routine
2020/03/27 16:52:57.504 INFO    http    server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "dev", "https_port": 443}
2020/03/27 16:52:57.504 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "dev"}
2020/03/27 16:52:57.511 INFO    tls     setting internal issuer for automation policy that has only internal subjects but no issuer configured  {"subjects": ["localhost"]}
2020/03/27 10:52:57 [INFO][] Obtain certificate; acquiring lock...
2020/03/27 10:52:57 [INFO][] Obtain: Lock acquired; proceeding...
2020/03/27 16:52:57.545 INFO    tls     cleaned up storage units
2020/03/27 10:52:57 [ERROR] Making new ACME client: get directory at 'https://localhost/acme/local/directory': Get "https://localhost/acme/local/directory": dial tcp [::1]:443: connect: connection refused (attempt 1/2)
2020/03/27 16:52:57.654 INFO    root certificate is already trusted by system   {"path": "storage:pki/authorities/local/root.crt"}
2020/03/27 16:52:57.654 INFO    http    enabling automatic TLS certificate management   {"domains": ["localhost"]}
2020/03/27 10:52:57 [WARNING] Stapling OCSP: no OCSP stapling for [localhost]: no OCSP server specified in certificate
2020/03/27 16:52:57.655 INFO    autosaved config        {"file": "/Users/matt/Library/Application Support/Caddy/autosave.json"}
2020/03/27 16:52:57.655 INFO    serving initial configuration
2020/03/27 10:52:58 {"newNonce":"https://localhost/acme/local/new-nonce","newAccount":"https://localhost/acme/local/new-account","newOrder":"https://localhost/acme/local/new-order","revokeCert":"https://localhost/acme/local/revoke-cert","keyChange":"https://localhost/acme/local/key-change"}
2020/03/27 10:52:58 {"status":"valid","orders":"https://localhost/acme/local/account/nkTzog8cB7UrAnIYlR0Kf13XYSg6NwJS/orders"}
2020/03/27 10:52:58 [INFO][] Waiting on rate limiter...
2020/03/27 10:52:58 [INFO][] Done waiting
2020/03/27 10:52:58 [INFO] [] acme: Obtaining bundled SAN certificate given a CSR
2020/03/27 10:52:58 {"status":"pending","expires":"2020-03-28T16:52:59Z","identifiers":[{"type":"dns","value":""}],"notBefore":"0001-01-01T00:00:00Z","notAfter":"0001-01-01T00:00:00Z","authorizations":["https://localhost/acme/local/authz/KyGbdYrA9xVLmJK6UI3ExW376hsiG1s9"],"finalize":"https://localhost/acme/local/order/7qcFUSq12gynXfIQlMsCFdRXlLmhkyUQ/finalize"}
2020/03/27 10:52:58 {"identifier":{"type":"dns","value":""},"status":"pending","expires":"2020-03-28T16:52:59Z","challenges":[{"type":"http-01","status":"pending","token":"GIqfrUkkVThJa2zA3kglUMrkCBzhTIYh","url":"https://localhost/acme/local/challenge/XNdyhajxbVHFve42rJOvaoK0YxlbtDt8"},{"type":"tls-alpn-01","status":"pending","token":"rp6Lmvugg1dT75qxQlaBSLPFuTtCzIAj","url":"https://localhost/acme/local/challenge/SNoUMHk1eLeb6bk5eUUjQXGfRx3OUCKv"},{"type":"dns-01","status":"pending","token":"gflNMacyMR6bPxbf0kybd74MfdnpywyK","url":"https://localhost/acme/local/challenge/RYSY2RFDZSTr77VB3A4NFGteSQrBqutp"}],"wildcard":false}
2020/03/27 10:52:58 [INFO] [] AuthURL: https://localhost/acme/local/authz/KyGbdYrA9xVLmJK6UI3ExW376hsiG1s9
2020/03/27 10:52:58 [INFO] [] acme: Could not find solver for: tls-alpn-01
2020/03/27 10:52:58 [INFO] [] acme: use http-01 solver
2020/03/27 10:52:58 [INFO] [] acme: Trying to solve HTTP-01
2020/03/27 10:52:58 [INFO][] Served key authentication (HTTP challenge)
2020/03/27 10:52:58 {"type":"http-01","status":"valid","token":"GIqfrUkkVThJa2zA3kglUMrkCBzhTIYh","validated":"2020-03-27T16:52:59Z","url":"https://localhost/acme/local/challenge/XNdyhajxbVHFve42rJOvaoK0YxlbtDt8"}
2020/03/27 10:52:58 [INFO] [] The server validated our request
2020/03/27 10:52:58 [INFO] [] acme: Validations succeeded; requesting certificates
2020/03/27 10:52:58 {"status":"valid","expires":"2020-03-28T16:52:59Z","identifiers":[{"type":"dns","value":""}],"notBefore":"0001-01-01T00:00:00Z","notAfter":"0001-01-01T00:00:00Z","authorizations":["https://localhost/acme/local/authz/KyGbdYrA9xVLmJK6UI3ExW376hsiG1s9"],"finalize":"https://localhost/acme/local/order/7qcFUSq12gynXfIQlMsCFdRXlLmhkyUQ/finalize","certificate":"https://localhost/acme/local/certificate/IGVyxAJ5P0OsGGgC5j4E7GIX3Sp437bJ"}
2020/03/27 10:52:58 [INFO] [] Server responded with a certificate.
2020/03/27 10:52:58 [INFO][] Certificate obtained successfully
2020/03/27 10:52:58 [INFO][] Obtain: Releasing lock

You'll notice that the ACME server is in fact just an HTTP handler module, which is pretty neat.

The above config also uses all default settings, but some things can be customized.

/cc @mmalone @maraino @dopey - at some point, it would be good to do a review together!

Update/bonus: TLS client auth certs can now be automated as well!

@mholt mholt added the in progress 🏃‍♂️ Being actively worked on label Mar 27, 2020
@mholt mholt added this to the 2.1 milestone Mar 27, 2020
@mholt mholt added the do not merge Not ready yet! label Mar 27, 2020
mholt added a commit that referenced this pull request Apr 9, 2020
We'll need that context in v2.1 when the transport can manage its own
client certificates; see #3198
@mholt mholt removed in progress 🏃‍♂️ Being actively worked on do not merge Not ready yet! labels Apr 17, 2020
@mholt mholt changed the title pki: Embedded ACME server (#3021) pki: Embedded ACME server Apr 17, 2020
# Conflicts:
#	go.mod
#	go.sum
@mholt mholt merged commit 184e8e9 into master May 5, 2020
2 checks passed
@mholt mholt deleted the smallstep-acme branch May 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

Successfully merging this pull request may close these issues.

None yet

1 participant