3.9 KiB
Proposal
Why
The previous change (advertise-valid-ipps-certificate) made the container
generate a certificate with the right subject alternative names, but clients
still get a certificate they do not trust. From the workstation,
curl https://podp.local:631/ fails with SSL certificate problem: unable to get local issuer certificate, and the certificate the server presents has
CN=host.containers.internal — not the certificate the entrypoint installed.
The reasoning in the previous change ("CUPS 2.4 keeps serving
ServerCertificate, so also write <host name>.crt") was wrong. Reading the
CUPS 2.4.2 sources:
ServerCertificate/ServerKeyare no longer supported. Incupsd.confthey log "Please move … to the cups-files.conf file"; incups-files.confthey log "is no longer supported" and are ignored (scheduler/conf.c). The certificate directory isServerKeychain(defaultssl→/etc/cups/ssl).- On a server TLS handshake,
_httpTLSStart()(cups/tls-openssl.c) ignores the requested (SNI) name. It takes the local socket address the client connected to, reverse-resolves it, and loads<name>.crtfrom the keychain directory. A name that is not alphanumeric,-or.is mangled to_(http_make_path()), and a numeric IPv6 result is used verbatim because CUPS only rejects numeric names that start with a digit.
So with host networking the client's connection to the LAN address
192.168.100.20 makes cupsd look for /etc/cups/ssl/host.containers.internal.crt
(the name Podman writes into /etc/hosts for the host address). That file did
not exist — only <host name>.crt and <Avahi FQDN>.crt were written — so cupsd
minted its own, which does not cover podp.local. IPv6 connections get a
certificate named after the IPv6 literal for the same reason. The previous
change's verification only checked localhost, where cupsd falls back to the
default common name and happened to find the copy.
What Changes
- Derive the certificate copies from what cupsd actually looks up: write
<name>.crt/<name>.keyfor every DNS name in the SAN list and for every local address (the address literal, mangled the wayhttp_make_path()does, plus whatever name the address reverse-resolves to). This covers the Podmanhost.containers.internalname for the LAN address and the IPv6 literals. - Keep the SAN list and the regeneration logic unchanged: the certificate content was already correct and reissuing it is not desirable.
- Correct the comments, the README and the spec so they no longer claim
ServerCertificateis what makes cupsd serve our certificate. The directive is kept only for CUPS versions older than 2.4.
Non-goals: generating a publicly trusted certificate or a private CA, adding the
local addresses to the certificate's IP SANs (that needs CERT_EXTRA_NAMES and
is out of scope), and changing the plain _ipp service.
Capabilities
New Capabilities
Modified Capabilities
printserver/cups: the requirement that the secure AirPrint certificate matches the advertised name gains a scenario for serving that certificate for the address a client connected to, not only for the name it asked for.
Impact
entrypoint.sh:install_default_cert_copynow enumerates the local addresses and cupsd's filename mangling;ensure_cupsd_cert_directivescomment corrected.README.md: certificate section explains how CUPS selects the certificate.openspec/specs/printserver/cups/spec.md: one scenario added to the certificate requirement.- Clients: fully validating clients (macOS/iOS AirPrint,
curl) complete the secure connection once they trust the certificate; plain IPP is unaffected. - Existing deployments: an existing
/etc/cupsvolume is fixed on the next start; the certificate itself is not reissued, so clients that already trust it keep trusting it.