m/cli/metroctl: factor out some helper functions

We will need these to create metroctl-compatible configs from
//metropolis/cluster/launch.

Change-Id: I2705afefb62b7e1b35c87d9753c4ca9c7f534c26
Reviewed-on: https://review.monogon.dev/c/monogon/+/1324
Tested-by: Jenkins CI
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/metropolis/cli/metroctl/install.go b/metropolis/cli/metroctl/install.go
index 07faad4..e43e07c 100644
--- a/metropolis/cli/metroctl/install.go
+++ b/metropolis/cli/metroctl/install.go
@@ -4,13 +4,10 @@
 	"bytes"
 	"context"
 	"crypto/ed25519"
-	"crypto/rand"
 	_ "embed"
-	"encoding/pem"
 	"io"
 	"log"
 	"os"
-	"path/filepath"
 
 	"github.com/spf13/cobra"
 
@@ -41,9 +38,6 @@
 // the --endpoints flag.
 var bootstrap bool
 
-// A PEM block type for a Metropolis initial owner private key
-const ownerKeyType = "METROPOLIS INITIAL OWNER PRIVATE KEY"
-
 //go:embed metropolis/installer/kernel.efi
 var installer []byte
 
@@ -81,39 +75,15 @@
 
 	var params *api.NodeParameters
 	if bootstrap {
-		var ownerPublicKey ed25519.PublicKey
-		ownerPrivateKeyPEM, err := os.ReadFile(filepath.Join(flags.configPath, "owner-key.pem"))
-		if os.IsNotExist(err) {
-			pub, priv, err := ed25519.GenerateKey(rand.Reader)
-			if err != nil {
-				log.Fatalf("Failed to generate owner private key: %v", err)
-			}
-			pemPriv := pem.EncodeToMemory(&pem.Block{Type: ownerKeyType, Bytes: priv})
-			if err := os.WriteFile(filepath.Join(flags.configPath, "owner-key.pem"), pemPriv, 0600); err != nil {
-				log.Fatalf("Failed to store owner private key: %v", err)
-			}
-			ownerPublicKey = pub
-		} else if err != nil {
-			log.Fatalf("Failed to load owner private key: %v", err)
-		} else {
-			block, _ := pem.Decode(ownerPrivateKeyPEM)
-			if block == nil {
-				log.Fatalf("owner-key.pem contains invalid PEM")
-			}
-			if block.Type != ownerKeyType {
-				log.Fatalf("owner-key.pem contains a PEM block that's not a %v", ownerKeyType)
-			}
-			if len(block.Bytes) != ed25519.PrivateKeySize {
-				log.Fatal("owner-key.pem contains non-Ed25519 key")
-			}
-			ownerPrivateKey := ed25519.PrivateKey(block.Bytes)
-			ownerPublicKey = ownerPrivateKey.Public().(ed25519.PublicKey)
+		priv, err := core.GetOrMakeOwnerKey(flags.configPath)
+		if err != nil {
+			log.Fatalf("Failed to generate or get owner key: %v", err)
 		}
-
+		pub := priv.Public().(ed25519.PublicKey)
 		params = &api.NodeParameters{
 			Cluster: &api.NodeParameters_ClusterBootstrap_{
 				ClusterBootstrap: &api.NodeParameters_ClusterBootstrap{
-					OwnerPublicKey: ownerPublicKey,
+					OwnerPublicKey: pub,
 				},
 			},
 		}