Harden a server & client¶
Recipes for the common production shapes: advertising ALPN, trusting a private CA on both ends, and letting one certificate serve several transports with targeted overrides.
Advertise ALPN protocols¶
ServerConfig
takes a variadic list of ALPN protocol identifiers. Pass "h2" first to prefer
HTTP/2, or "h2" alone for a raw gRPC TLS listener:
// HTTP server: prefer HTTP/2, fall back to HTTP/1.1
httpCfg, err := pair.ServerConfig("h2", "http/1.1")
// gRPC TLS listener: HTTP/2 only
grpcCfg, err := pair.ServerConfig("h2")
With no arguments the returned config leaves NextProtos unset and the standard
library negotiates as normal.
Trust a private CA on both ends¶
When a server presents a certificate signed by an internal or self-signed CA, the
client must be told to trust it.
CertPool builds an
*x509.CertPool from one or more PEM files, and
ClientConfig wires
that pool into the hardened config for you:
// Client trusts the private CA (and only it, unless combined with system roots).
clientCfg, err := tls.ClientConfig("/etc/certs/ca.pem")
if err != nil {
log.Fatal(err)
}
ClientConfig returns an error if a CA file is missing or contains no certificates,
so a broken trust anchor is caught at construction. Pass the same CA file the
servers were issued from to share one trust anchor across your gRPC, HTTP and gateway
clients.
To build a pool directly — for example to set RootCAs on a config you own:
One certificate, several transports¶
A service often terminates TLS on more than one listener (HTTP, gRPC, a gateway). You
usually want a single shared certificate, with the option to override it per
transport.
ResolvePair performs
that merge on already-materialised typed values — no config-lookup interface required:
shared := tls.Pair{Enabled: true, Cert: "/etc/certs/shared.pem", Key: "/etc/certs/shared-key.pem"}
// The gRPC listener overrides only the certificate; everything else
// falls back to the shared pair.
grpcSpecific := tls.Pair{Cert: "/etc/certs/grpc.pem"}
grpcPair := tls.ResolvePair(shared, grpcSpecific, tls.PairOverrides{
Cert: true, // only Cert was explicitly set for gRPC
})
// grpcPair.Enabled == true (shared), grpcPair.Cert == "/etc/certs/grpc.pem",
// grpcPair.Key == "/etc/certs/shared-key.pem" (shared)
The PairOverrides
mask records which fields the per-transport section actually set, so an unset
field never clobbers the shared value with a zero. You decide how a field counts as
"set" — a config key being present, a non-empty flag, an environment variable — and
express it as the boolean mask.
Decide TLS vs. plaintext at boot¶
Pair.Valid is the
single predicate for "is this pair usable for TLS":