caddyserver / certmagic

Automatic HTTPS for any Go program: fully-managed TLS certificate issuance and renewal
https://pkg.go.dev/github.com/caddyserver/certmagic?tab=doc
Apache License 2.0
4.89k stars 278 forks source link

Is FallbackServerName still experimental? #278

Closed goksan closed 3 months ago

goksan commented 3 months ago

What is your question?

Is FallbackServerName still experimental? https://github.com/caddyserver/certmagic/blob/c61a4feb395e0b459f51c4b2ddf82e77e50d0198/config.go#L76-L81

Include any other information or discussion.

I want to serve a domain cert despite visiting via an IP address, like in this issue.

A proposed solution in that thread overrides the ServerName for known IP addresses and that works great, but in my case the IP(s) are unknown.

Simply removing the IP check from the proposed solution and unconditionally overriding the ServerName would cause TLS-ALPN challenges to fail.

What have you already tried?

I have 2 (seemingly) working solutions

Set FallbackServerName, it seems to work well for my use case, but it's listed as experimental.

Override ServerName only where SupportedProtos does not include acme-tls/1

tlsCfg := certm.TLSConfig()
getCrt := tlsCfg.GetCertificate
tlsCfg.GetCertificate = func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
    acmeTLS := false
        for _, proto := range clientHello.SupportedProtos {
            if proto == acmez.ACMETLS1Protocol {
                acmeTLS = true
            }
        }

        if !acmeTLS {
            clientHello.ServerName = "domain.com"
        }
    return getCrt(hello)
}
mholt commented 3 months ago

Been a while, but IIRC, even without setting FallbackServerName or using the linked workaround, CertMagic should still at least be able to serve up IP certificates in response to a handshake without a ServerName.

but in my case the IP(s) are unknown.

Do you mean, that you can't tell the server to manage a certificate for an IP address, because you don't know the IP address?

If you don't know the domain names (or IPs, whatever the SANs are) before starting the server, you need On-Demand TLS (or you have to reload the config once you do know the server name / IP).

Most of CertMagic and TLS handshake stuff is the same whether it's IP or DNS, it's just the nuances of getting an IP certificate are more tricky than that of DNS names.

goksan commented 3 months ago

Ah it was a silly error on my part, I was inadvertently setting the ServerName to "" and breaking the acme-tls/1 challenge when I thought I was setting ServerName to the value of the discovered domain.

I don't need to use FallbackServerName or to check for acme-tls/1, I was unknowingly working around my error 😅

Problem solved!

If you don't know the domain names (or IPs, whatever the SANs are) before starting the server, you need On-Demand TLS (or you have to reload the config once you do know the server name / IP).

As a side note if you're interested - I wasn't aware of this at the time, I only came across it yesterday. I have been calling ManageSync with a single domain off the back of a HTML form submission to achieve something similar. I'm only provisioning a single cert for the user when they first install the application and prefer the UX of a longer form submission vs a longer initial handshake for this particular use case. Good to know it's there though if I need it in future.

mholt commented 3 months ago

Glad you figured it out then :+1: