blob: 93e4b467af1b5b02b56758d4e37cef97e71ceed3 [file] [log] [blame]
package rpc
import (
"context"
"crypto/ed25519"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"testing"
"source.monogon.dev/metropolis/node/core/identity"
"source.monogon.dev/metropolis/pkg/pki"
)
// NewEphemeralClusterCredentials creates a set of TLS certificates for use in a
// test Metropolis cluster. These are a CA certificate, a Manager certificate
// and an arbitrary amount of Node certificates (per the nodes argument).
//
// All of these are ephemeral, ie. not stored anywhere - including the CA
// certificate. This function is for use by tests which want to bring up a
// minimum set of PKI credentials for a fake Metropolis cluster.
func NewEphemeralClusterCredentials(t *testing.T, nodes int) *EphemeralClusterCredentials {
ctx := context.Background()
t.Helper()
ns := pki.Namespaced("unused")
caCert := pki.Certificate{
Namespace: &ns,
Issuer: pki.SelfSigned,
Template: identity.CACertificate("test cluster ca"),
Mode: pki.CertificateEphemeral,
}
caBytes, err := caCert.Ensure(ctx, nil)
if err != nil {
t.Fatalf("Could not ensure CA certificate: %v", err)
}
ca, err := x509.ParseCertificate(caBytes)
if err != nil {
t.Fatalf("Could not parse new CA certificate: %v", err)
}
managerCert := pki.Certificate{
Namespace: &ns,
Issuer: &caCert,
Template: identity.UserCertificate("owner"),
Mode: pki.CertificateEphemeral,
}
managerBytes, err := managerCert.Ensure(ctx, nil)
if err != nil {
t.Fatalf("Could not ensure manager certificate: %v", err)
}
res := &EphemeralClusterCredentials{
Nodes: make([]*identity.NodeCredentials, nodes),
Manager: tls.Certificate{
Certificate: [][]byte{managerBytes},
PrivateKey: managerCert.PrivateKey,
},
CA: ca,
}
for i := 0; i < nodes; i++ {
npk, npr, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("Could not generate node keypair: %v", err)
}
nodeCert := pki.Certificate{
Namespace: &ns,
Issuer: &caCert,
Template: identity.NodeCertificate(npk),
Mode: pki.CertificateEphemeral,
PublicKey: npk,
Name: "",
}
nodeBytes, err := nodeCert.Ensure(ctx, nil)
if err != nil {
t.Fatalf("Could not ensure node certificate: %v", err)
}
node, err := identity.NewNodeCredentials(npr, nodeBytes, caBytes)
if err != nil {
t.Fatalf("Could not build node credentials: %v", err)
}
res.Nodes[i] = node
}
return res
}
// EphemeralClusterCredentials are TLS/PKI credentials for use in a Metropolis
// test cluster.
type EphemeralClusterCredentials struct {
// Nodes are the node credentials for the cluster. Each contains a private
// key and x509 certificate authenticating the bearer as a Metropolis node.
Nodes []*identity.NodeCredentials
// Manager TLS certificate for the cluster. Contains a private key and x509
// certificate authenticating the bearer as a Metropolis manager.
Manager tls.Certificate
// CA is the x509 certificate of the CA certificate for the cluster. Manager and
// Node certificates are signed by this CA.
CA *x509.Certificate
}