m/node: fix etcd join data assigned to first node

We accidentall populated the node's etcd role with curator/node
certificates instead of etcd certificates. We fix this, also moving out
the EnableConsensusMember call to the roleserver, putting it next to
EnableKubernetesWorker.

Change-Id: I2a9bce889a2fda032798e370be06cdc2c5078ac9
Reviewed-on: https://review.monogon.dev/c/monogon/+/780
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/node/core/curator/bootstrap.go b/metropolis/node/core/curator/bootstrap.go
index 4b0b743..7566a43 100644
--- a/metropolis/node/core/curator/bootstrap.go
+++ b/metropolis/node/core/curator/bootstrap.go
@@ -2,13 +2,11 @@
 
 import (
 	"context"
-	"crypto/x509"
 	"fmt"
 
 	clientv3 "go.etcd.io/etcd/client/v3"
 	"google.golang.org/protobuf/proto"
 
-	"source.monogon.dev/metropolis/node/core/consensus"
 	"source.monogon.dev/metropolis/node/core/consensus/client"
 	ppb "source.monogon.dev/metropolis/node/core/curator/proto/private"
 	"source.monogon.dev/metropolis/node/core/identity"
@@ -64,33 +62,6 @@
 		return
 	}
 
-	nodeCertX509, err := x509.ParseCertificate(nodeCertBytes)
-	if err != nil {
-		err = fmt.Errorf("when parsing node cert: %w", err)
-		return
-	}
-
-	caCertX509, err := x509.ParseCertificate(caCertBytes)
-	if err != nil {
-		err = fmt.Errorf("when parsing CA cert: %w", err)
-		return
-	}
-
-	w := pkiCA.WatchCRL(etcd)
-	defer w.Close()
-	crl, err := w.Get(ctx)
-	if err != nil {
-		err = fmt.Errorf("when retreiving CRL: %w", err)
-		return
-	}
-
-	node.EnableConsensusMember(&consensus.JoinCluster{
-		CACertificate:   caCertX509,
-		NodeCertificate: nodeCertX509,
-		ExistingNodes:   nil,
-		InitialCRL:      crl,
-	})
-
 	nodePath, err := node.etcdNodePath()
 	if err != nil {
 		return nil, nil, fmt.Errorf("failed to get node key: %w", err)
diff --git a/metropolis/node/core/roleserve/worker_controlplane.go b/metropolis/node/core/roleserve/worker_controlplane.go
index f1ddadf..6f524ee 100644
--- a/metropolis/node/core/roleserve/worker_controlplane.go
+++ b/metropolis/node/core/roleserve/worker_controlplane.go
@@ -192,7 +192,7 @@
 
 				// Otherwise, try to interpret node roles if available.
 				if lr != nil && cm != nil {
-					supervisor.Logger(ctx).Infof("Using role assigned by cluter...")
+					supervisor.Logger(ctx).Infof("Using role assigned by cluster...")
 					role := lr.ConsensusMember
 					if role == nil {
 						supervisor.Logger(ctx).Infof("Not a control plane node.")
@@ -311,7 +311,16 @@
 				// TODO(q3k): collapse the curator bootstrap shenanigans into a single function.
 				npub := b.nodePrivateKey.Public().(ed25519.PublicKey)
 				jpub := b.nodePrivateJoinKey.Public().(ed25519.PublicKey)
+
 				n := curator.NewNodeForBootstrap(b.clusterUnlockKey, npub, jpub)
+
+				// The first node always runs consensus.
+				join, err := st.AddNode(ctx, npub)
+				if err != nil {
+					return fmt.Errorf("when retrieving node join data from consensus: %w", err)
+				}
+
+				n.EnableConsensusMember(join)
 				n.EnableKubernetesWorker()
 
 				var nodeCert []byte