How fabrica-util Handles Certificate Management for Secure Microservice Communication
The fabrica-util security package provides a lightweight, zero-dependency certificate lifecycle using ed25519 keys, supporting self-signed X.509 generation, PEM import/export, and cryptographic signing for mutual TLS and service-to-service authentication.
fabrica-util is a Go utility library developed by go-pantheon that delivers a complete certificate management solution within its security/certificate package. The implementation relies exclusively on Go's standard library to generate ed25519 key pairs, create self-signed X.509 certificates, and handle PEM-encoded transport—making it ideal for containerized microservices requiring fast startup times and minimal attack surfaces.
Certificate Lifecycle Overview
The security/certificate package in security/certificate/ed25519.go orchestrates a six-step workflow that covers the full spectrum of certificate operations needed for secure microservice communication:
- Key Generation: The
GenKeyPairfunction (lines 38-48) invokesed25519.GenerateKeyto produce cryptographically secure private and public keys. - Certificate Creation:
CreateSelfSignedCert(lines 51-94) constructs anx509.Certificatetemplate with configurable subject fields and validity periods, then signs it with the generated key pair. - PEM Export: Utilities like
ExportPriToPEM(lines 55-67) andExportPubToPEM(lines 70-82) encode keys into PKCS#8 and PKIX PEM blocks for transport. - PEM Import:
ImportPriFromPEM(lines 95-113),ImportPubFromPEM(lines 115-131), andImportCertFromPEM(lines 235-247) parse PEM data back into native Go types. - Validity Verification:
VerifyCert(lines 140-152) checks the current time against the certificate'sNotBeforeandNotAfterfields. - Cryptographic Signing:
SignMessageandVerifyMessage(orSignandVerify) enable application-level proof-of-possession by signing arbitrary payloads with the private key.
Generating Self-Signed Certificates with Ed25519
Microservices bootstrap their identity using ed25519-based self-signed certificates. The CreateSelfSignedCert function accepts a pkix.Name for subject configuration and a validity duration in days.
package main
import (
"crypto/x509/pkix"
"log"
"github.com/go-pantheon/fabrica-util/security/certificate"
)
func main() {
// Create a self-signed cert valid for 365 days
cert, err := certificate.CreateSelfSignedCert(pkix.Name{
CommonName: "service.my-domain.local",
Organization: []string{"MyOrg"},
Country: []string{"US"},
}, 365)
if err != nil {
log.Fatalf("cert creation failed: %v", err)
}
// Access the PEM-encoded certificate
_ = cert.CertPEM
}
This process leverages GenKeyPair internally to generate the ed25519 key pair before constructing the X.509 structure. The resulting certificate includes proper key usage extensions for digital signatures and key encipherment.
Importing and Exporting PEM Data
For inter-service communication, certificates and keys must serialize to PEM format for transport across network boundaries or storage in configuration systems.
Exporting Keys for Transport
The package provides distinct export functions for private and public keys. ExportPriToPEM encodes the ed25519 private key into a PKCS#8 PEM block, while ExportPubToPEM handles PKIX format for public keys:
// Export PEM for transport or TLS configuration
privPEM, err := certificate.ExportPriToPEM(cert.KeyPair.Pri)
if err != nil {
log.Fatal(err)
}
pubPEM, err := certificate.ExportPubToPEM(cert.KeyPair.Pub)
if err != nil {
log.Fatal(err)
}
Parsing PEM Back to Native Types
On the receiving side, microservices parse PEM blobs back into usable cryptographic primitives:
pri, err := certificate.ImportPriFromPEM(priPEM)
if err != nil {
log.Fatalf("import private key: %v", err)
}
pub, err := certificate.ImportPubFromPEM(pubPEM)
if err != nil {
log.Fatalf("import public key: %v", err)
}
cert, err := certificate.ImportCertFromPEM(certPEM)
if err != nil {
log.Fatalf("import certificate: %v", err)
}
Validating Certificates and Signatures
Before establishing trust, services must verify both temporal validity and cryptographic ownership.
Time-Based Validity Checks
The VerifyCert function validates that the current time falls within the certificate's validity window:
if err := certificate.VerifyCert(cert); err != nil {
log.Fatalf("certificate not valid: %v", err)
}
Message Signing for Proof of Possession
To prove ownership of the private key associated with a certificate, services can sign challenge messages. The Sign function produces Ed25519 signatures, while Verify validates them against the public key:
msg := []byte("authentication-challenge")
sig, err := certificate.Sign(pri, msg)
if err != nil {
log.Fatalf("signing failed: %v", err)
}
ok := certificate.Verify(pub, msg, sig.Sign)
log.Printf("signature valid: %t", ok)
This mechanism supports JWT-style authentication flows where services demonstrate possession of their certificate-bound keys without transmitting the private key material.
Enabling Mutual TLS in Microservices
The PEM-encoded certificates integrate directly with Go's standard tls package for mutual TLS (mTLS) implementations. Microservices load their identity into tls.Config and configure client certificate requirements:
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{
{
Certificate: [][]byte{certPEM},
PrivateKey: pri,
},
},
ClientAuth: tls.RequireAndVerifyClientCert,
RootCAs: x509.NewCertPool(),
}
tlsConfig.RootCAs.AppendCertsFromPEM(trustedCertPEM)
The Certificates field accepts the PEM-encoded certificate and corresponding private key imported via the fabrica-util package. Setting ClientAuth to tls.RequireAndVerifyClientCert mandates that connecting services present valid certificates, creating a zero-trust communication mesh.
Summary
- fabrica-util provides a complete certificate lifecycle in
security/certificate/ed25519.gousing only Go standard library components. - The package generates ed25519 key pairs and self-signed X.509 certificates via
CreateSelfSignedCertandGenKeyPair. - PEM import/export functions enable secure transport of cryptographic material between services without external dependencies.
- Validity checking and message signing utilities support both TLS-level and application-level security verification.
- The lightweight implementation suits containerized microservices requiring fast startup and minimal resource overhead.
Frequently Asked Questions
What cryptographic algorithm does fabrica-util use for certificate keys?
The package exclusively uses ed25519 (Edwards-curve Digital Signature Algorithm) for all key generation and signing operations. This modern elliptic-curve algorithm provides strong security with compact key sizes and fast performance, implemented through Go's standard crypto/ed25519 package.
Can fabrica-util certificates be used for mutual TLS (mTLS)?
Yes. The security/certificate package generates standard X.509 certificates that integrate directly with Go's tls.Config. Services can load the PEM-encoded certificates and private keys into the Certificates field and configure ClientAuth: tls.RequireAndVerifyClientCert to enforce mutual authentication between microservices.
Does the security package require external dependencies?
No. The implementation relies solely on Go's standard library, including crypto/ed25519, crypto/x509, crypto/x509/pkix, and encoding/pem. This zero-dependency design minimizes the attack surface and eliminates version conflicts in containerized deployments.
How does fabrica-util handle certificate expiration checking?
The VerifyCert function (lines 140-152 in ed25519.go) automatically checks the current system time against the certificate's NotBefore and NotAfter fields. This validation ensures that services reject expired or prematurely used certificates before establishing cryptographic trust.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →