Thanks to visit codestin.com
Credit goes to github.com

Skip to content

httpcaddyfile: new tls_automate_names global option - #8015

Open
IslamElsayed wants to merge 1 commit into
caddyserver:masterfrom
IslamElsayed:caddyfile-tls-automate-names
Open

httpcaddyfile: new tls_automate_names global option#8015
IslamElsayed wants to merge 1 commit into
caddyserver:masterfrom
IslamElsayed:caddyfile-tls-automate-names

Conversation

@IslamElsayed

Copy link
Copy Markdown
Contributor

Assistance Disclosure

I used AI assistance throughout this PR — for exploring the existing tlsapp.go code, drafting the implementation and tests, and writing this description. I verified all of it myself: I read the surrounding code to work out why an automation policy was needed (see below), generated every expected adapt output from a build and checked each one by hand against what the config should say, and confirmed the tests actually fail when the implementation is broken in four different ways. The behaviour claims below are measured, not assumed.


Closes #7122.

The problem

Provisioning a certificate for a name you don't serve currently requires giving it a site block:

*.example.com {
}

foo.example.com {
	respond "Real site"
}

That gets the wildcard, but it also adds a route to the http app, so any name pointed at the server without its own site block — bar.example.com — gets an empty-but-valid response instead of no match. Wanting a certificate and wanting to serve a name are separate things, and the Caddyfile had no way to say only the first.

The change

{
	tls_automate_names *.example.com
}

foo.example.com {
	respond "Real site"
}

Per @francislavoie's suggestion on the issue. Adapting the two configs above, the tls app comes out identical — same policy, same subjects, same issuers — and the only difference is the route that is no longer there:

       "routes": [
         { "match": [{"host": ["foo.example.com"]}], "handle": [...], "terminal": true },
-        { "match": [{"host": ["*.example.com"]}], "terminal": true }
       ]
 ...
   "tls": {
+    "certificates": { "automate": ["*.example.com"] },
     "automation": { "policies": [
       { "subjects": ["foo.example.com", "*.example.com"], "issuers": [...] }
     ]}
   }

It also works with no site blocks at all, which #7122 and @felixauringer's comment both ask for — enough to keep certs renewed for a mail or XMPP server, or for names served by a layer 4 app:

{
	tls_automate_names mail.example.com xmpp.example.com
}
{"apps": {"tls": {"certificates": {"automate": ["mail.example.com", "xmpp.example.com"]}}}}

Notes on the implementation

The names need an automation policy, not just the automate loader. My first attempt only appended to the loader, and with email [email protected] set the wildcard silently came out with no issuers — it would not have used the configured ACME account. The catch-all policy that would normally carry global options gets dropped once every other policy names its subjects, so these names need a policy of their own; consolidation then folds it back into an identical one. This is what the tls_automate_names.caddyfiletest case pins, and it's the part most worth a careful look.

A policy is only created when it would carry something. Otherwise an inert {"subjects": [...]} with no issuers ends up in the output. I pulled the existing hasGlobalACMEDefaults expression out into a small helper to decide this, since newBaseAutomationPolicy's own "are there global options" check doesn't count email.

Names that can't get a public cert get the internal issuer, the same treatment a site block gives them.

A name that also has a site block stays listed here. It's redundant, and I'd initially planned to skip it (I said as much on the issue), but a site block for http:// only isn't managed by auto-HTTPS — dropping the name because some block exists could silently leave it without a certificate. Listing it twice is harmless; not listing it isn't. Happy to change this if you'd rather.

Repeating the option appends rather than replaces, so a long list can be split over lines.

On the name

I went with tls_automate_names (@francislavoie's suggestion) since @mholt's tls_certs/tls_certificates question was still open. Renaming is a one-line change plus the test filenames — say the word.

Testing

Three adapt tests: the issue's exact scenario, the no-site-block case, and internal/public name splitting with the option repeated. I checked they aren't vacuous by breaking the implementation four ways — dropping the internal split, never creating the policy, not adding to the loader, and making the parser overwrite instead of append — and confirming each mutation fails the tests that should catch it.

go test ./caddyconfig/... ./caddytest/... passes. TestACMEServerWithDefaults is flaky on my machine, but equally so on master (2 of 4 runs failed there, 1 of 3 on this branch), so it looks unrelated.

Docs for the new global option would need a PR to caddyserver/website — glad to write it once the name is settled.

Provisioning a certificate for a name that is not served requires giving
it a site block of its own:

    *.example.com {
    }

    foo.example.com {
            respond "Real site"
    }

That asks the tls app for the wildcard, but it also adds a route to the
http app, so every name pointed at the server that has no site block of
its own -- bar.example.com here -- gets an empty but valid response
rather than no match at all. Wanting a certificate and wanting to serve
a name are separate things, and the Caddyfile had no way to say only the
first.

Name them in the new global option instead:

    {
            tls_automate_names *.example.com
    }

    foo.example.com {
            respond "Real site"
    }

The names are added to the automate certificate loader and to an
automation policy built from the global options, so a name listed here
is managed exactly as it would be from a site block, with the same
issuers; the only difference in the adapted config is that no route is
added for it. Repeating the option appends rather than replaces, so a
long list can be split over several lines.

Names that cannot get a public certificate are given the internal
issuer, the same treatment a site block gives them. Names that already
appear in the automate list are skipped, but a name that also has a site
block is left listed here as well: a site block for http:// only is not
managed by auto-HTTPS, so dropping the name because a block exists could
silently leave it without a certificate.

The option needs no http app at all, so a config consisting only of
global options now adapts to a tls app on its own -- enough to keep
certificates renewed for a mail or XMPP server, or for names served by a
layer 4 app.

Closes caddyserver#7122
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Caddyfile syntax to automate certificate without adding corresponding HTTPS route

1 participant