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