mtls

package
v0.29.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package mtls builds mutual-TLS configs for Panel↔Agent gRPC. The CA is the trust anchor: the Agent (server) requires a Panel client cert signed by the CA, and the Panel (client) verifies the Agent's server cert against the CA using a fixed logical ServerName, so trust is decoupled from each node's network address.

Index

Constants

View Source
const (
	AgentServerName = "kraken-agent"
	PanelServerName = "kraken-panel"
	CAName          = "kraken-ca"
)

Logical certificate identities (SANs) baked into issued certs. The Panel pins AgentServerName when dialing, regardless of the node's host:port.

View Source
const DefaultAgentCertTTL = 90 * 24 * time.Hour

DefaultAgentCertTTL is how long an enrolled Agent certificate is valid.

View Source
const DefaultPanelClientCertTTL = 5 * 365 * 24 * time.Hour

DefaultPanelClientCertTTL is how long an auto-issued Panel client cert is valid. Long-lived because the Panel binds its own lifecycle to it and rotates on restart when the file is deleted, not on any external schedule.

Variables

This section is empty.

Functions

func AgentIdentityFromCert added in v0.21.0

func AgentIdentityFromCert(cert *x509.Certificate) string

AgentIdentityFromCert extracts the Panel-minted identity from an agent cert's URI SANs. Empty when the cert predates per-agent identities.

func AgentIdentityURI added in v0.21.0

func AgentIdentityURI(id string) string

AgentIdentityURI renders a Panel-minted agent identity as the URI SAN string embedded in issued agent certs.

func CAFingerprintPEM added in v0.16.0

func CAFingerprintPEM(pemBytes []byte) (string, error)

CAFingerprintPEM returns the full SHA-256 fingerprint (64 hex chars) of the first certificate in pemBytes. This is the pinning identity embedded in Panel-generated deploy commands and checked by the Agent's remote-enroll path, so unlike FingerprintPEM it must carry the whole digest.

func ClientTLS

func ClientTLS(certFile, keyFile, caFile, serverName string) (*tls.Config, error)

ClientTLS builds the Panel's client-side config: it presents certFile/keyFile and verifies the server's cert against caFile using serverName (typically AgentServerName).

func ClientTLSFromBytes added in v0.5.1

func ClientTLSFromBytes(certPEM, keyPEM, caPEM []byte, serverName string) (*tls.Config, error)

ClientTLSFromBytes is the byte-slice counterpart to ClientTLS. Used when the Panel auto-issues its client cert against its own CA at startup and keeps the bundle in memory rather than round-tripping through a filesystem the distroless-nonroot process may not have write access to.

func FingerprintCert added in v0.21.0

func FingerprintCert(cert *x509.Certificate) string

FingerprintCert is FingerprintPEM for an already-parsed certificate.

func FingerprintPEM added in v0.6.0

func FingerprintPEM(pemBytes []byte) string

FingerprintPEM returns a short SHA-256 fingerprint of the first certificate in pemBytes — enough hex to compare identities across Panel and Agent logs.

func GenerateCA

func GenerateCA() (certPEM, keyPEM []byte, err error)

GenerateCA creates a self-signed CA keypair and returns the cert and key as PEM. The Panel holds these to sign Agent enrollment requests.

func IssuePanelClientCert added in v0.5.0

func IssuePanelClientCert(caCertPEM, caKeyPEM []byte, ttl time.Duration) (certPEM, keyPEM []byte, err error)

IssuePanelClientCert generates a fresh ECDSA keypair for the Panel and returns a client certificate signed by the given CA. The cert carries the PanelServerName CN + ClientAuth EKU so an Agent (which trusts the same CA and requires client auth) accepts the Panel's outbound mTLS handshake.

This is the symmetric counterpart to SignAgentCSR: an Agent cert is server- auth + client-auth (Agent listens and Panel connects), a Panel cert is client-auth only (Panel connects out).

func IssuePanelServerCert added in v0.21.0

func IssuePanelServerCert(caCertPEM, caKeyPEM []byte, ttl time.Duration) (certPEM, keyPEM []byte, err error)

IssuePanelServerCert generates a keypair for the Panel's reverse-tunnel listener and returns a server certificate signed by the CA. Agents dialing the tunnel verify it against the same CA with ServerName=PanelServerName, so trust stays decoupled from the Panel's network address — the mirror image of how the Panel pins AgentServerName when dialing out.

func NewAgentKeyAndCSR

func NewAgentKeyAndCSR(hosts []string) (keyPEM, csrPEM []byte, err error)

NewAgentKeyAndCSR generates an ECDSA P-256 key and a certificate-signing request for an Agent server cert. The CSR always requests the logical AgentServerName plus loopback, and any extra hosts (DNS names or IPs) given.

func RequirePeerCN added in v0.26.1

func RequirePeerCN(wantCN string) func(tls.ConnectionState) error

RequirePeerCN returns a tls.Config.VerifyConnection hook that, on top of the CA-chain verification RequireAndVerifyClientCert already did, insists the verified client leaf's Subject CommonName equals wantCN.

This is the load-bearing authorization for the Agent's gRPC listener. The CA is a *shared* trust anchor: it signs the Panel's client cert AND every Agent's server cert, and Agent certs carry ClientAuth EKU (they need it to dial the reverse tunnel). Chain-validation alone therefore accepts any Agent's own cert as a client — so a single stolen/enrolled Agent cert could drive the full NodeService (UpdateAgent → arbitrary binary → RCE) on every other node. The CN is authoritative because the signer sets it (SignAgentCSR* hardcodes it and never copies the CSR subject), so an enrollee cannot forge PanelServerName.

func SANHosts added in v0.6.0

func SANHosts(pemBytes []byte) []string

SANHosts returns the DNS + IP SANs of the first certificate in pemBytes, in cert order (DNS names first). Empty on parse failure.

func ServerTLS

func ServerTLS(certFile, keyFile, caFile string) (*tls.Config, error)

ServerTLS builds the Agent's direct-listener server config: it presents certFile/keyFile, requires a client cert signed by caFile, AND authorizes the client by identity — only the Panel (CN=PanelServerName) may connect. Without that last check any peer Agent's cert would authenticate (see RequirePeerCN).

func ServerTLSFromBytes added in v0.21.0

func ServerTLSFromBytes(certPEM, keyPEM, caPEM []byte) (*tls.Config, error)

ServerTLSFromBytes is the byte-slice counterpart to ServerTLS — used for the Panel's reverse-tunnel listener, whose server cert is auto-issued in memory at startup (same rationale as ClientTLSFromBytes).

func SignAgentCSR

func SignAgentCSR(caCertPEM, caKeyPEM, csrPEM []byte, ttl time.Duration) ([]byte, error)

SignAgentCSR verifies csrPEM and issues an Agent server certificate signed by the CA (caCertPEM/caKeyPEM), valid for ttl. The issued cert always carries the AgentServerName SAN (the Panel pins it when dialing) and server+client-auth EKUs. This is the core of the bootstrap/enrollment + rotation flow.

func SignAgentCSRWithIdentity added in v0.21.0

func SignAgentCSRWithIdentity(caCertPEM, caKeyPEM, csrPEM []byte, ttl time.Duration, identity string) ([]byte, error)

SignAgentCSRWithIdentity is SignAgentCSR plus a Panel-minted per-agent identity, embedded as a URI SAN (see AgentIdentityURI). The identity is authoritative on the Panel side — it is never taken from the CSR — and is what a reverse-tunnel handshake later maps back to a node record. An empty identity issues a legacy cert with no URI SAN.

func SummarizeCert added in v0.6.0

func SummarizeCert(cert *x509.Certificate) string

SummarizeCert renders the identity of a certificate on one log-friendly line: CN, issuer, serial, fingerprint, validity window, and SANs.

func SummarizePEM added in v0.6.0

func SummarizePEM(pemBytes []byte) string

SummarizePEM is SummarizeCert for raw PEM input.

func VerifyCAFingerprint added in v0.16.0

func VerifyCAFingerprint(pemBytes []byte, pinned string) error

VerifyCAFingerprint checks pemBytes against a pinned fingerprint as produced by CAFingerprintPEM. The comparison is case-insensitive and tolerates a "sha256:" prefix so operators can paste either spelling.

func VerifyPEM added in v0.6.0

func VerifyPEM(certPEM, caPEM []byte) error

VerifyPEM reports whether the first cert in certPEM chains to the CA(s) in caPEM and is valid right now. Used at startup to catch a stale bundle (cert enrolled under a previous CA, or expired) before the first handshake fails.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL