blob: 70173d8627b3fb014ebf78f03b48c5e94566afbf [file] [log] [blame]
Serge Bazanskid7d6e022021-09-01 15:03:06 +02001package rpc
2
3import (
4 "context"
5 "crypto/ed25519"
6 "crypto/rand"
7 "crypto/tls"
8 "crypto/x509"
9 "fmt"
10 "math/big"
11 "time"
12
Serge Bazanskid7d6e022021-09-01 15:03:06 +020013 "google.golang.org/grpc/credentials"
Serge Bazanski636032e2022-01-26 14:21:33 +010014 "google.golang.org/grpc/status"
Serge Bazanskid7d6e022021-09-01 15:03:06 +020015
Serge Bazanski3379a5d2021-09-09 12:56:40 +020016 "source.monogon.dev/metropolis/node/core/identity"
Serge Bazanskid7d6e022021-09-01 15:03:06 +020017 "source.monogon.dev/metropolis/pkg/pki"
18 apb "source.monogon.dev/metropolis/proto/api"
19)
20
Serge Bazanski3379a5d2021-09-09 12:56:40 +020021type verifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
22
23func verifyClusterCertificate(ca *x509.Certificate) verifyPeerCertificate {
24 return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
25 if len(rawCerts) != 1 {
26 return fmt.Errorf("server presented %d certificates, wanted exactly one", len(rawCerts))
27 }
28 serverCert, err := x509.ParseCertificate(rawCerts[0])
29 if err != nil {
30 return fmt.Errorf("server presented unparseable certificate: %w", err)
31 }
32 if _, err := identity.VerifyNodeInCluster(serverCert, ca); err != nil {
33 return fmt.Errorf("node certificate verification failed: %w", err)
34 }
35
36 return nil
37 }
38}
39
Serge Bazanski399ce552022-03-29 12:52:42 +020040// NewEphemeralCredentials returns gRPC TransportCredentials that can be used to
41// dial a cluster without authenticating with a certificate, but instead
42// authenticating by proving the possession of a private key, via an ephemeral
43// self-signed certificate.
Serge Bazanskid7d6e022021-09-01 15:03:06 +020044//
Serge Bazanski399ce552022-03-29 12:52:42 +020045// Currently these credentials are used in two flows:
46//
47// 1. Registration of nodes into a cluster, after which a node receives a proper
48// node certificate
49//
50// 2. Escrow of initial owner credentials into a proper manager
51// certificate
Serge Bazanskid7d6e022021-09-01 15:03:06 +020052//
Serge Bazanski3379a5d2021-09-09 12:56:40 +020053// If 'ca' is given, the remote side will be cryptographically verified to be a
54// node that's part of the cluster represented by the ca. Otherwise, no
55// verification is performed and this function is unsafe.
Serge Bazanski399ce552022-03-29 12:52:42 +020056func NewEphemeralCredentials(private ed25519.PrivateKey, ca *x509.Certificate) (credentials.TransportCredentials, error) {
Serge Bazanskid7d6e022021-09-01 15:03:06 +020057 template := x509.Certificate{
58 SerialNumber: big.NewInt(1),
59 NotBefore: time.Now(),
60 NotAfter: pki.UnknownNotAfter,
61
Serge Bazanski3379a5d2021-09-09 12:56:40 +020062 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
Serge Bazanskid7d6e022021-09-01 15:03:06 +020063 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
64 BasicConstraintsValid: true,
65 }
66 certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, private.Public(), private)
67 if err != nil {
68 return nil, fmt.Errorf("when generating self-signed certificate: %w", err)
69 }
70 certificate := tls.Certificate{
71 Certificate: [][]byte{certificateBytes},
72 PrivateKey: private,
73 }
Serge Bazanski399ce552022-03-29 12:52:42 +020074 return NewAuthenticatedCredentials(certificate, ca), nil
Serge Bazanski3379a5d2021-09-09 12:56:40 +020075}
Serge Bazanskid7d6e022021-09-01 15:03:06 +020076
Serge Bazanski399ce552022-03-29 12:52:42 +020077// NewAuthenticatedCredentials returns gRPC TransportCredentials that can be
78// used to dial a cluster with a given TLS certificate (from node or manager
79// credentials).
80//
81// If 'ca' is given, the remote side will be cryptographically verified to be a
82// node that's part of the cluster represented by the ca. Otherwise, no
83// verification is performed and this function is unsafe.
84func NewAuthenticatedCredentials(cert tls.Certificate, ca *x509.Certificate) credentials.TransportCredentials {
85 config := &tls.Config{
86 Certificates: []tls.Certificate{cert},
87 InsecureSkipVerify: true,
88 }
89 if ca != nil {
90 config.VerifyPeerCertificate = verifyClusterCertificate(ca)
91 }
92 return credentials.NewTLS(config)
Serge Bazanskid7d6e022021-09-01 15:03:06 +020093}
94
95// RetrieveOwnerCertificates uses AAA.Escrow to retrieve a cluster manager
96// certificate for the initial owner of the cluster, authenticated by the
97// public/private key set in the clusters NodeParameters.ClusterBoostrap.
98//
99// The retrieved certificate can be used to dial further cluster RPCs.
100func RetrieveOwnerCertificate(ctx context.Context, aaa apb.AAAClient, private ed25519.PrivateKey) (*tls.Certificate, error) {
101 srv, err := aaa.Escrow(ctx)
102 if err != nil {
Serge Bazanski636032e2022-01-26 14:21:33 +0100103 if st, ok := status.FromError(err); ok {
104 return nil, status.Errorf(st.Code(), "Escrow call failed: %s", st.Message())
105 }
106 return nil, err
Serge Bazanskid7d6e022021-09-01 15:03:06 +0200107 }
108 if err := srv.Send(&apb.EscrowFromClient{
109 Parameters: &apb.EscrowFromClient_Parameters{
110 RequestedIdentityName: "owner",
111 PublicKey: private.Public().(ed25519.PublicKey),
112 },
113 }); err != nil {
114 return nil, fmt.Errorf("when sending client parameters: %w", err)
115 }
116 resp, err := srv.Recv()
117 if err != nil {
118 return nil, fmt.Errorf("when receiving server message: %w", err)
119 }
120 if len(resp.EmittedCertificate) == 0 {
121 return nil, fmt.Errorf("expected certificate, instead got needed proofs: %+v", resp.Needed)
122 }
123
124 return &tls.Certificate{
125 Certificate: [][]byte{resp.EmittedCertificate},
126 PrivateKey: private,
127 }, nil
128}