blob: e4caece69ceb3a55341d13927a70afcbfcdd4ffb [file] [log] [blame]
Serge Bazanskiffbf3932023-07-24 13:02:42 +02001package util
Serge Bazanski3379a5d2021-09-09 12:56:40 +02002
3import (
4 "context"
5 "crypto/ed25519"
6 "crypto/rand"
7 "crypto/tls"
8 "crypto/x509"
9 "testing"
10
11 "source.monogon.dev/metropolis/node/core/identity"
12 "source.monogon.dev/metropolis/pkg/pki"
13)
14
15// NewEphemeralClusterCredentials creates a set of TLS certificates for use in a
16// test Metropolis cluster. These are a CA certificate, a Manager certificate
17// and an arbitrary amount of Node certificates (per the nodes argument).
18//
19// All of these are ephemeral, ie. not stored anywhere - including the CA
20// certificate. This function is for use by tests which want to bring up a
21// minimum set of PKI credentials for a fake Metropolis cluster.
22func NewEphemeralClusterCredentials(t *testing.T, nodes int) *EphemeralClusterCredentials {
23 ctx := context.Background()
24 t.Helper()
25
26 ns := pki.Namespaced("unused")
27 caCert := pki.Certificate{
28 Namespace: &ns,
29 Issuer: pki.SelfSigned,
30 Template: identity.CACertificate("test cluster ca"),
31 Mode: pki.CertificateEphemeral,
32 }
33 caBytes, err := caCert.Ensure(ctx, nil)
34 if err != nil {
35 t.Fatalf("Could not ensure CA certificate: %v", err)
36 }
37 ca, err := x509.ParseCertificate(caBytes)
38 if err != nil {
39 t.Fatalf("Could not parse new CA certificate: %v", err)
40 }
41
42 managerCert := pki.Certificate{
43 Namespace: &ns,
44 Issuer: &caCert,
45 Template: identity.UserCertificate("owner"),
46 Mode: pki.CertificateEphemeral,
47 }
48 managerBytes, err := managerCert.Ensure(ctx, nil)
49 if err != nil {
50 t.Fatalf("Could not ensure manager certificate: %v", err)
51 }
52 res := &EphemeralClusterCredentials{
53 Nodes: make([]*identity.NodeCredentials, nodes),
54 Manager: tls.Certificate{
55 Certificate: [][]byte{managerBytes},
56 PrivateKey: managerCert.PrivateKey,
57 },
58 CA: ca,
59 }
60
61 for i := 0; i < nodes; i++ {
62 npk, npr, err := ed25519.GenerateKey(rand.Reader)
63 if err != nil {
64 t.Fatalf("Could not generate node keypair: %v", err)
65 }
66 nodeCert := pki.Certificate{
67 Namespace: &ns,
68 Issuer: &caCert,
69 Template: identity.NodeCertificate(npk),
70 Mode: pki.CertificateEphemeral,
71 PublicKey: npk,
72 Name: "",
73 }
74 nodeBytes, err := nodeCert.Ensure(ctx, nil)
75 if err != nil {
76 t.Fatalf("Could not ensure node certificate: %v", err)
77 }
78 node, err := identity.NewNodeCredentials(npr, nodeBytes, caBytes)
79 if err != nil {
80 t.Fatalf("Could not build node credentials: %v", err)
81 }
82 res.Nodes[i] = node
83 }
84
85 return res
86}
87
88// EphemeralClusterCredentials are TLS/PKI credentials for use in a Metropolis
89// test cluster.
90type EphemeralClusterCredentials struct {
91 // Nodes are the node credentials for the cluster. Each contains a private
92 // key and x509 certificate authenticating the bearer as a Metropolis node.
93 Nodes []*identity.NodeCredentials
94 // Manager TLS certificate for the cluster. Contains a private key and x509
95 // certificate authenticating the bearer as a Metropolis manager.
96 Manager tls.Certificate
97 // CA is the x509 certificate of the CA certificate for the cluster. Manager and
98 // Node certificates are signed by this CA.
99 CA *x509.Certificate
100}