Skip to content

abursavich/dynamictls

Repository files navigation

DynamicTLS

License GoDev Reference Go Report Card Build Status Coverage Status

DynamicTLS watches the filesystem and updates TLS configuration when certificate changes occur.

It provides simple integrations with HTTP/1.1, HTTP/2, gRPC, and Prometheus.

Examples

HTTP Server

// create metrics
observer, err := tlsprom.NewObserver(
    tlsprom.WithHTTP(),
    tlsprom.WithServer(),
)
check(err)
prometheus.MustRegister(observer)

// create TLS config
cfg, err := dynamictls.NewConfig(
    dynamictls.WithObserver(observer),
    dynamictls.WithCertificate(primaryCertFile, primaryKeyFile),
    dynamictls.WithCertificate(secondaryCertFile, secondaryKeyFile),
    dynamictls.WithRootCAs(caFile),
    dynamictls.WithHTTP(), // NB: adds HTTP/2 and HTTP/1.1 protocols
)
check(err)
defer cfg.Close()

// listen and serve
lis, err := cfg.Listen(context.Background(), "tcp", addr)
check(err)
check(http.Serve(lis, http.DefaultServeMux))

HTTP Client

// create metrics
observer, err := tlsprom.NewObserver(
    tlsprom.WithHTTP(),
    tlsprom.WithClient(),
)
check(err)
prometheus.MustRegister(observer)

// create TLS config
cfg, err := dynamictls.NewConfig(
    dynamictls.WithObserver(observer),
    dynamictls.WithBase(&tls.Config{
        MinVersion: tls.VersionTLS12,
    }),
    dynamictls.WithCertificate(certFile, keyFile),
    dynamictls.WithRootCAs(caFile),
    dynamictls.WithHTTP(), // NB: adds HTTP/2 and HTTP/1.1 protocols
)
check(err)
defer cfg.Close()

// create HTTP client
client := &http.Client{
    Transport: &http.Transport{
        DialTLSContext:    cfg.Dial, // NB: DialTLSContext added in go 1.14
        ForceAttemptHTTP2: true,     // NB: required if using a custom dialer with HTTP/2
    },
}
defer client.CloseIdleConnections()

gRPC Server

// create metrics
observer, err := tlsprom.NewObserver(
    tlsprom.WithGRPC(),
    tlsprom.WithServer(),
)
check(err)
prometheus.MustRegister(observer)

// create TLS config
cfg, err := dynamictls.NewConfig(
    dynamictls.WithObserver(observer),
    dynamictls.WithBase(&tls.Config{
        ClientAuth: tls.RequireAndVerifyClientCert,
        MinVersion: tls.VersionTLS13,
    }),
    dynamictls.WithCertificate(certFile, keyFile),
    dynamictls.WithRootCAs(caFile), // NB: metrics use RootCAs to verify local cert expiration
    dynamictls.WithClientCAs(caFile),
    dynamictls.WithHTTP2(),
)
check(err)
defer cfg.Close()

// create server with credentials
creds, err := grpctls.NewCredentials(cfg)
check(err)
srv := grpc.NewServer(grpc.Creds(creds))
pb.RegisterTestServiceServer(srv, &testServer{})

// listen and serve
lis, err := net.Listen("tcp", addr) // NB: use plain listener
check(err)
check(srv.Serve(lis))

gRPC Client

// create metrics
observer, err := tlsprom.NewObserver(
    tlsprom.WithGRPC(),
    tlsprom.WithClient(),
)
check(err)
prometheus.MustRegister(observer)

// create TLS config
cfg, err := dynamictls.NewConfig(
    dynamictls.WithObserver(observer),
    dynamictls.WithBase(&tls.Config{
        MinVersion: tls.VersionTLS13,
    }),
    dynamictls.WithCertificate(certFile, keyFile),
    dynamictls.WithRootCAs(caFile),
    dynamictls.WithHTTP2(),
)
check(err)
defer cfg.Close()

// create client with credentials
creds, err := grpctls.NewCredentials(cfg)
check(err)
conn, err := grpc.Dial(
    addr,
    grpc.WithTransportCredentials(creds),
    grpc.WithDefaultCallOptions(grpc.WaitForReady(true)),
)
check(err)
defer conn.Close()
client := pb.NewTestServiceClient(conn)