m/node: pass node identity into k8s

This plumbs through the node identity to K8s as an identity.Node
object and gets rid of the os.Hostname invocation that passed around
this data out-of-band. It also changes everything in its path to use
the newer identity.Node object instead of a plain string so that the
Metropolis Identity CA is more accessible.

Change-Id: I6db8e1db7e333c0ea364aefd61c27bf50acc25f3
Reviewed-on: https://review.monogon.dev/c/monogon/+/505
Reviewed-by: Sergiusz Bazanski <serge@monogon.tech>
diff --git a/metropolis/node/core/main.go b/metropolis/node/core/main.go
index 0a63d48..afe1d7b 100644
--- a/metropolis/node/core/main.go
+++ b/metropolis/node/core/main.go
@@ -203,7 +203,7 @@
 				StorageRoot: root,
 				Network:     networkSvc,
 				KPKI:        kpki,
-				NodeID:      status.Credentials.ID(),
+				Node:        &status.Credentials.Node,
 			})
 			if err := supervisor.Run(ctx, "role", rs.Run); err != nil {
 				close(trapdoor)
diff --git a/metropolis/node/core/roleserve/BUILD.bazel b/metropolis/node/core/roleserve/BUILD.bazel
index 273cbd5..06e6e10 100644
--- a/metropolis/node/core/roleserve/BUILD.bazel
+++ b/metropolis/node/core/roleserve/BUILD.bazel
@@ -11,6 +11,7 @@
     visibility = ["//visibility:public"],
     deps = [
         "//metropolis/node/core/curator/proto/api:go_default_library",
+        "//metropolis/node/core/identity:go_default_library",
         "//metropolis/node/core/localstorage:go_default_library",
         "//metropolis/node/core/network:go_default_library",
         "//metropolis/node/kubernetes:go_default_library",
diff --git a/metropolis/node/core/roleserve/cluster_agent.go b/metropolis/node/core/roleserve/cluster_agent.go
index 5e9c45d..842b841 100644
--- a/metropolis/node/core/roleserve/cluster_agent.go
+++ b/metropolis/node/core/roleserve/cluster_agent.go
@@ -35,7 +35,7 @@
 		supervisor.Logger(ctx).Infof("New external address (%s), submitting update to cluster...", external.String())
 
 		_, err = s.curator.UpdateNodeStatus(ctx, &ipb.UpdateNodeStatusRequest{
-			NodeId: s.NodeID,
+			NodeId: s.Node.ID(),
 			Status: &cpb.NodeStatus{
 				ExternalAddress: external.String(),
 			},
diff --git a/metropolis/node/core/roleserve/kubernetes_worker.go b/metropolis/node/core/roleserve/kubernetes_worker.go
index 8271259..027e0ec 100644
--- a/metropolis/node/core/roleserve/kubernetes_worker.go
+++ b/metropolis/node/core/roleserve/kubernetes_worker.go
@@ -49,6 +49,7 @@
 			KPKI:    s.KPKI,
 			Root:    s.StorageRoot,
 			Network: s.Network,
+			Node:    s.Node,
 		})
 		if err := supervisor.Run(ctx, "run", kubeSvc.Run); err != nil {
 			return fmt.Errorf("failed to start kubernetes service: %w", err)
diff --git a/metropolis/node/core/roleserve/roleserve.go b/metropolis/node/core/roleserve/roleserve.go
index d7e3d2f..57e6a7a 100644
--- a/metropolis/node/core/roleserve/roleserve.go
+++ b/metropolis/node/core/roleserve/roleserve.go
@@ -22,6 +22,7 @@
 	"google.golang.org/grpc"
 
 	cpb "source.monogon.dev/metropolis/node/core/curator/proto/api"
+	"source.monogon.dev/metropolis/node/core/identity"
 	"source.monogon.dev/metropolis/node/core/localstorage"
 	"source.monogon.dev/metropolis/node/core/network"
 	"source.monogon.dev/metropolis/node/kubernetes"
@@ -51,8 +52,8 @@
 	// this will probably be provisioned by the Kubernetes workload itself.
 	KPKI *pki.PKI
 
-	// NodeID is the node ID on which the roleserver is running.
-	NodeID string
+	// Node is the node identity on which the roleserver is running.
+	Node *identity.Node
 }
 
 // Service is the roleserver/“Role Server” service. See the package-level
@@ -158,7 +159,7 @@
 func (s *Service) runUpdater(ctx context.Context) error {
 	srv, err := s.curator.Watch(ctx, &cpb.WatchRequest{Kind: &cpb.WatchRequest_NodeInCluster_{
 		NodeInCluster: &cpb.WatchRequest_NodeInCluster{
-			NodeId: s.NodeID,
+			NodeId: s.Node.ID(),
 		},
 	}})
 	if err != nil {
@@ -174,7 +175,7 @@
 		}
 		supervisor.Logger(ctx).Infof("Received node event: %+v", ev)
 		for _, node := range ev.Nodes {
-			if node.Id != s.NodeID {
+			if node.Id != s.Node.ID() {
 				continue
 			}
 			s.kwC <- node
diff --git a/metropolis/node/kubernetes/BUILD.bazel b/metropolis/node/kubernetes/BUILD.bazel
index cec9a6e..a162bcc 100644
--- a/metropolis/node/kubernetes/BUILD.bazel
+++ b/metropolis/node/kubernetes/BUILD.bazel
@@ -15,6 +15,7 @@
     visibility = ["//metropolis/node:__subpackages__"],
     deps = [
         "//metropolis/node:go_default_library",
+        "//metropolis/node/core/identity:go_default_library",
         "//metropolis/node/core/localstorage:go_default_library",
         "//metropolis/node/core/network:go_default_library",
         "//metropolis/node/core/network/dns:go_default_library",
diff --git a/metropolis/node/kubernetes/service.go b/metropolis/node/kubernetes/service.go
index fe701e6..1af7607 100644
--- a/metropolis/node/kubernetes/service.go
+++ b/metropolis/node/kubernetes/service.go
@@ -20,7 +20,6 @@
 	"context"
 	"fmt"
 	"net"
-	"os"
 	"time"
 
 	"google.golang.org/grpc/codes"
@@ -29,6 +28,7 @@
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/clientcmd"
 
+	"source.monogon.dev/metropolis/node/core/identity"
 	"source.monogon.dev/metropolis/node/core/localstorage"
 	"source.monogon.dev/metropolis/node/core/network"
 	"source.monogon.dev/metropolis/node/core/network/dns"
@@ -48,6 +48,7 @@
 	KPKI    *pki.PKI
 	Root    *localstorage.Root
 	Network *network.Service
+	Node    *identity.Node
 }
 
 type Service struct {
@@ -90,11 +91,6 @@
 
 	informerFactory := informers.NewSharedInformerFactory(clientSet, 5*time.Minute)
 
-	hostname, err := os.Hostname()
-	if err != nil {
-		return fmt.Errorf("failed to get hostname: %w", err)
-	}
-
 	// Sub-runnable which starts all parts of Kubernetes that depend on the
 	// machine's external IP address. If it changes, the runnable will exit.
 	// TODO(q3k): test this
@@ -122,7 +118,7 @@
 		}
 
 		kubelet := kubeletService{
-			NodeName:           hostname,
+			NodeName:           s.c.Node.ID(),
 			ClusterDNS:         []net.IP{address},
 			KubeletDirectory:   &s.c.Root.Data.Kubernetes.Kubelet,
 			EphemeralDirectory: &s.c.Root.Ephemeral,
@@ -154,14 +150,14 @@
 	}
 
 	csiProvisioner := csiProvisionerServer{
-		NodeName:         hostname,
+		NodeName:         s.c.Node.ID(),
 		Kubernetes:       clientSet,
 		InformerFactory:  informerFactory,
 		VolumesDirectory: &s.c.Root.Data.Volumes,
 	}
 
 	clusternet := clusternet.Service{
-		NodeName:        hostname,
+		NodeName:        s.c.Node.ID(),
 		Kubernetes:      clientSet,
 		ClusterNet:      s.c.ClusterNet,
 		InformerFactory: informerFactory,