add mTLS
This commit is contained in:
parent
84040af9a2
commit
0ef6d7f682
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIMaSy7CGp7A69DLcmREodmwU8Z06eJw5KxVMByIkVw+xoAoGCCqGSM49
|
||||
AwEHoUQDQgAEMlHIUMNtdUeoT2k+s0qGuEKcn5/MxTQsvTHn2UtV6llpKzEJwt8P
|
||||
Xq9wJgKY92KJIVunncJfWH03Pt46w3rsXQ==
|
||||
-----END EC PRIVATE KEY-----
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBnDCCAUGgAwIBAgIINzq1sRDfD4UwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ
|
||||
bG9jYWxob3N0MB4XDTIzMDUwMzA1MTc1NFoXDTMzMDQzMDA1MjI1NFowFDESMBAG
|
||||
A1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMlHIUMNt
|
||||
dUeoT2k+s0qGuEKcn5/MxTQsvTHn2UtV6llpKzEJwt8PXq9wJgKY92KJIVunncJf
|
||||
WH03Pt46w3rsXaN9MHswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUF
|
||||
BwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQvGKzbHLBJ
|
||||
gQRkitLTkbuzl8Yd7DAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCgYIKoZI
|
||||
zj0EAwIDSQAwRgIhAOVxPVGEjsRZ70QMfNsD2gfjrPguOVZZ6sgzKsVB38BuAiEA
|
||||
0l2us3+vY1c5TARSVTk6OMmTCJrNYlBjYQP7BbWy6HQ=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "87600h"
|
||||
},
|
||||
"profiles": {
|
||||
"rootca": {
|
||||
"usages": [
|
||||
"signing",
|
||||
"digital signature",
|
||||
"key encipherment",
|
||||
"cert sign",
|
||||
"crl sign",
|
||||
"server auth",
|
||||
"client auth"
|
||||
],
|
||||
"ca_constraint": {
|
||||
"is_ca": true
|
||||
},
|
||||
"expiry": "87600h"
|
||||
},
|
||||
"server": {
|
||||
"usages": [
|
||||
"signing",
|
||||
"digital signing",
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
],
|
||||
"expiry": "87600h"
|
||||
},
|
||||
"client": {
|
||||
"usages": [
|
||||
"signing",
|
||||
"digital signature",
|
||||
"key encipherment",
|
||||
"client auth"
|
||||
],
|
||||
"expiry": "87600h"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEILI/RrEZWQ1sOKQSpISjVjzjfnys4SbD53TKVOjCxgNZoAoGCCqGSM49
|
||||
AwEHoUQDQgAEZDh+LpU9TmChPAocLxlfgCUwa4TBZnsf/NcwOyo2HupLj4Pha63V
|
||||
kvbg2DSLFF+Fe4HoSiTWpq4Kwd8dnBxrkA==
|
||||
-----END EC PRIVATE KEY-----
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBmTCCAUCgAwIBAgIUYF9Sr1vgTtG1L5BBlj6yGrPpI0kwCgYIKoZIzj0EAwIw
|
||||
FDESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTIzMDUwMzA1MTgwMFoXDTMzMDQzMDA1
|
||||
MTgwMFowFDESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAEZDh+LpU9TmChPAocLxlfgCUwa4TBZnsf/NcwOyo2HupLj4Pha63Vkvbg
|
||||
2DSLFF+Fe4HoSiTWpq4Kwd8dnBxrkKNwMG4wDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAMk3Lo4DM5j
|
||||
EubUazT8r2BuMjs6MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAKBggqhkjO
|
||||
PQQDAgNHADBEAiAGxGpa2fdAC/2uchVei6AZNJhPTTEhgTVQ9F51kqrjuAIgD6UA
|
||||
2puaVsOnIzKIUxZFY7zhOgZYU7O7sdNCfZX8ic0=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"hosts": ["localhost", "127.0.0.1"],
|
||||
"key": {
|
||||
"algo": "ecdsa",
|
||||
"size": 256
|
||||
},
|
||||
"CN": "localhost",
|
||||
"names": []
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
# https://github.com/cloudflare/cfssl
|
||||
# https://rob-blackbourn.medium.com/how-to-use-cfssl-to-create-self-signed-certificates-d55f76ba5781
|
||||
cfssl selfsign -config cfssl.json --profile rootca "Root CA" csr.json | cfssljson -bare ca
|
||||
cfssl genkey csr.json | cfssljson -bare server
|
||||
cfssl genkey csr.json | cfssljson -bare client
|
||||
cfssl sign -ca ca.pem -ca-key ca-key.pem -config cfssl.json -profile server server.csr | cfssljson -bare server
|
||||
cfssl sign -ca ca.pem -ca-key ca-key.pem -config cfssl.json -profile client client.csr | cfssljson -bare client
|
||||
rm ./*.csr
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIBMUH4C8W0a0V4C7TQ0PowlIEPyz/j3AaffAOu6UmHNloAoGCCqGSM49
|
||||
AwEHoUQDQgAESCljhOQJWwvupZtt2HGPty6XJvuyqf7RpxheHTx5rWmEnLeI7DYK
|
||||
DhKlIzDeH7Opf4rQrqOECxknfxf355/08A==
|
||||
-----END EC PRIVATE KEY-----
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBmjCCAUCgAwIBAgIUfqrcRuTGIZsXgJguUp2R/dw0dzgwCgYIKoZIzj0EAwIw
|
||||
FDESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTIzMDUwMzA1MTgwMFoXDTMzMDQzMDA1
|
||||
MTgwMFowFDESMBAGA1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAESCljhOQJWwvupZtt2HGPty6XJvuyqf7RpxheHTx5rWmEnLeI7DYKDhKl
|
||||
IzDeH7Opf4rQrqOECxknfxf355/08KNwMG4wDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFJL7liSFyGC6
|
||||
f85d6ic2cgsqBLJSMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAKBggqhkjO
|
||||
PQQDAgNIADBFAiEAq3vKTlnGRw3EysUyNzAaYATDkspyKFnoQ+ItjGq4ixACICpN
|
||||
tsAyZ4rKQNy0ZGbbUIncM7MY7S+zDAMz8P1Y9YtT
|
||||
-----END CERTIFICATE-----
|
|
@ -2,6 +2,8 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
@ -18,7 +20,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
const defaultAddress = "localhost:50001"
|
||||
|
@ -37,14 +39,7 @@ func main() {
|
|||
_ = logger.Sync()
|
||||
}()
|
||||
|
||||
example := ""
|
||||
flag.StringVar(
|
||||
&example,
|
||||
"example",
|
||||
exampleUnary,
|
||||
fmt.Sprintf("%s or %s (default: %s)", exampleUnary, exampleBidirectional, exampleUnary),
|
||||
)
|
||||
flag.Parse()
|
||||
example := parseExample()
|
||||
|
||||
conn, err := newConn()
|
||||
if err != nil {
|
||||
|
@ -70,18 +65,57 @@ func main() {
|
|||
case exampleBidirectional:
|
||||
sayHelloBidirectional(ctx, client, logger)
|
||||
default:
|
||||
logger.Fatal("example doesn't exist", zap.String("example", example))
|
||||
logger.Error("example doesn't exist", zap.String("example", example))
|
||||
}
|
||||
}
|
||||
|
||||
func parseExample() string {
|
||||
example := ""
|
||||
flag.StringVar(
|
||||
&example,
|
||||
"example",
|
||||
exampleUnary,
|
||||
fmt.Sprintf("%s or %s (default: %s)", exampleUnary, exampleBidirectional, exampleUnary),
|
||||
)
|
||||
flag.Parse()
|
||||
return example
|
||||
}
|
||||
|
||||
func newConn() (*grpc.ClientConn, error) {
|
||||
transport, err := newTransportCredentials()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return grpc.Dial(
|
||||
"localhost:50001",
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithTransportCredentials(transport),
|
||||
grpc.WithBlock(),
|
||||
)
|
||||
}
|
||||
|
||||
func newTransportCredentials() (credentials.TransportCredentials, error) {
|
||||
cert, err := tls.LoadX509KeyPair("./certs/client.pem", "./certs/client-key.pem")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load client cert: %w", err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile("./certs/ca.pem")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load CA file: %w", err)
|
||||
}
|
||||
|
||||
capool := x509.NewCertPool()
|
||||
if !capool.AppendCertsFromPEM(data) {
|
||||
return nil, errors.New("couldn't add ca cart to cert pool")
|
||||
}
|
||||
|
||||
return credentials.NewTLS(&tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: capool,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func sayHello(ctx context.Context, client proto.GreeterClient, logger *zap.Logger) {
|
||||
reply, err := client.SayHello(ctx, &proto.HelloRequest{Name: uuid.NewString()})
|
||||
if err != nil {
|
||||
|
@ -91,6 +125,7 @@ func sayHello(ctx context.Context, client proto.GreeterClient, logger *zap.Logge
|
|||
}
|
||||
|
||||
func sayHelloBidirectional(ctx context.Context, client proto.GreeterClient, logger *zap.Logger) {
|
||||
// ctx is used in the 2nd goroutine to close the stream client
|
||||
//nolint:contextcheck
|
||||
streamClient, err := client.SayHelloBidirectionalStream(context.Background())
|
||||
if err != nil {
|
||||
|
@ -122,9 +157,7 @@ func sayHelloBidirectional(ctx context.Context, client proto.GreeterClient, logg
|
|||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer func() {
|
||||
ticker.Stop()
|
||||
}()
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
|
|
|
@ -2,6 +2,8 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -19,10 +21,11 @@ import (
|
|||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const defaultAddress = "localhost:50001"
|
||||
const defaultAddress = ":50001"
|
||||
|
||||
func main() {
|
||||
logger, err := internal.NewLogger()
|
||||
|
@ -54,10 +57,7 @@ func main() {
|
|||
srv.GracefulStop()
|
||||
}(srv, logger)
|
||||
|
||||
logger.Info(
|
||||
"listening and serving",
|
||||
zap.String("address", srv.lis.Addr().String()),
|
||||
)
|
||||
logger.Info("listening and serving", zap.String("address", srv.lis.Addr().String()))
|
||||
|
||||
if err = srv.Serve(); err != nil {
|
||||
logger.Fatal("something went wrong while serving", zap.Error(err))
|
||||
|
@ -72,6 +72,11 @@ type server struct {
|
|||
}
|
||||
|
||||
func newServer(address string, logger *zap.Logger) (*server, error) {
|
||||
transport, err := newTransportCredentials()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lis, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -80,6 +85,7 @@ func newServer(address string, logger *zap.Logger) (*server, error) {
|
|||
grpc_zap.ReplaceGrpcLoggerV2(logger)
|
||||
|
||||
srv := grpc.NewServer(
|
||||
grpc.Creds(transport),
|
||||
grpc.ChainUnaryInterceptor(
|
||||
grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandler(createPanicHandler(logger))),
|
||||
grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
|
||||
|
@ -109,6 +115,29 @@ func (s *server) GracefulStop() {
|
|||
s.grpcSrv.GracefulStop()
|
||||
}
|
||||
|
||||
func newTransportCredentials() (credentials.TransportCredentials, error) {
|
||||
cert, err := tls.LoadX509KeyPair("./certs/server.pem", "./certs/server-key.pem")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load server cert: %w", err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile("./certs/ca.pem")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load CA file: %w", err)
|
||||
}
|
||||
|
||||
capool := x509.NewCertPool()
|
||||
if !capool.AppendCertsFromPEM(data) {
|
||||
return nil, errors.New("couldn't add ca cart to cert pool")
|
||||
}
|
||||
|
||||
return credentials.NewTLS(&tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ClientCAs: capool,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func createPanicHandler(logger *zap.Logger) grpc_recovery.RecoveryHandlerFunc {
|
||||
return func(p interface{}) error {
|
||||
logger.Panic(fmt.Sprintf("%v", p), zap.Stack("stack"))
|
||||
|
@ -120,8 +149,6 @@ type greeterServer struct {
|
|||
proto.UnimplementedGreeterServer
|
||||
}
|
||||
|
||||
var _ proto.GreeterServer = (*greeterServer)(nil)
|
||||
|
||||
func (g *greeterServer) SayHello(_ context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) {
|
||||
return &proto.HelloReply{
|
||||
Message: buildHelloMsg(r.GetName()),
|
||||
|
|
Loading…
Reference in New Issue