metropolis/proto/common: add node label synchronization rules

This paves the way for a mechanism to synchronize Metropolis node labels
to Kubernetes node labels. This is just the API/Protobuf part.

Change-Id: Ia6f5dd91190d46495714ea56aa359c48e6a068d7
Reviewed-on: https://review.monogon.dev/c/monogon/+/3468
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/node/core/curator/state_cluster.go b/metropolis/node/core/curator/state_cluster.go
index 6cb0a3a..02e6891 100644
--- a/metropolis/node/core/curator/state_cluster.go
+++ b/metropolis/node/core/curator/state_cluster.go
@@ -20,8 +20,9 @@
 // Cluster is the cluster's configuration, as (un)marshaled to/from
 // common.ClusterConfiguration.
 type Cluster struct {
-	TPMMode               cpb.ClusterConfiguration_TPMMode
-	StorageSecurityPolicy cpb.ClusterConfiguration_StorageSecurityPolicy
+	TPMMode                             cpb.ClusterConfiguration_TPMMode
+	StorageSecurityPolicy               cpb.ClusterConfiguration_StorageSecurityPolicy
+	NodeLabelsToSynchronizeToKubernetes []*cpb.ClusterConfiguration_KubernetesConfig_NodeLabelsToSynchronize
 }
 
 // DefaultClusterConfiguration is the default cluster configuration for a newly
@@ -29,8 +30,9 @@
 // user.
 func DefaultClusterConfiguration() *Cluster {
 	return &Cluster{
-		TPMMode:               cpb.ClusterConfiguration_TPM_MODE_REQUIRED,
-		StorageSecurityPolicy: cpb.ClusterConfiguration_STORAGE_SECURITY_POLICY_NEEDS_ENCRYPTION_AND_AUTHENTICATION,
+		TPMMode:                             cpb.ClusterConfiguration_TPM_MODE_REQUIRED,
+		StorageSecurityPolicy:               cpb.ClusterConfiguration_STORAGE_SECURITY_POLICY_NEEDS_ENCRYPTION_AND_AUTHENTICATION,
+		NodeLabelsToSynchronizeToKubernetes: nil,
 	}
 }
 
@@ -162,6 +164,9 @@
 		TPMMode:               cc.TpmMode,
 		StorageSecurityPolicy: cc.StorageSecurityPolicy,
 	}
+	if kc := cc.KubernetesConfig; kc != nil {
+		c.NodeLabelsToSynchronizeToKubernetes = kc.NodeLabelsToSynchronize
+	}
 
 	return c, nil
 }
@@ -187,6 +192,9 @@
 	return &cpb.ClusterConfiguration{
 		TpmMode:               c.TPMMode,
 		StorageSecurityPolicy: c.StorageSecurityPolicy,
+		KubernetesConfig: &cpb.ClusterConfiguration_KubernetesConfig{
+			NodeLabelsToSynchronize: c.NodeLabelsToSynchronizeToKubernetes,
+		},
 	}, nil
 }
 
diff --git a/metropolis/proto/common/common.proto b/metropolis/proto/common/common.proto
index 758631f..1e8d748 100644
--- a/metropolis/proto/common/common.proto
+++ b/metropolis/proto/common/common.proto
@@ -319,6 +319,38 @@
         STORAGE_SECURITY_POLICY_NEEDS_INSECURE = 4;
     }
     StorageSecurityPolicy storage_security_policy = 2;
+
+    message KubernetesConfig {
+        message NodeLabelsToSynchronize {
+            // Node labels matching this regexp will be synchronized.
+            //
+            // For example, the following regex: `^[^/]*foo$` would match:
+            //  - foo: bar
+            //  - bar-foo: baz
+            // But wouldn't match:
+            //  - example.com/foo: bar
+            //
+            // Regexes are compiled using Go's regexp library, and must be anchored (with ^
+            // and $) by the user. An invalid regexp matches no label.
+            string regexp = 1;
+        }
+
+        // Rules to match Node labels that should be synchronized into Kubernetes
+        // node labels. A label matching any rule will be synchronized and managed by
+        // Metropolis. If a label stops matching a rule (ie., the rules gets modified
+        // so it doesn't match some label, or the label gets removed from the Node
+        // in Metropolis), the label will also be removed from the Kubernetes node.
+        //
+        // Users should be careful about not synchronizing labels that will collide
+        // with other Kubernetes node labels, as then that node's labels will not be
+        // synchronized at all as a safety precaution.
+        //
+        // Note: there are certain labels that Metropolis will always add to
+        // Kubernetes nodes, such as node-role.kubernetes.io/...  . These are not
+        // influenced by these rules.
+        repeated NodeLabelsToSynchronize node_labels_to_synchronize = 3;
+    }
+    KubernetesConfig kubernetes_config = 3;
 }
 
 // NodeTPMUsage describes whether a node has a TPM2.0 and if it is/should be