m/c/metroctl: takeownership: use cluster resolver

This updates takeownership to use the new cluster resolver.

Change-Id: I9fd546eb07a8909dc6c7fafd682ad6c4ab936151
Reviewed-on: https://review.monogon.dev/c/monogon/+/838
Reviewed-by: Sergiusz Bazanski <serge@monogon.tech>
Tested-by: Jenkins CI
diff --git a/metropolis/cli/metroctl/credentials.go b/metropolis/cli/metroctl/credentials.go
index a8885bb..2160bea 100644
--- a/metropolis/cli/metroctl/credentials.go
+++ b/metropolis/cli/metroctl/credentials.go
@@ -12,33 +12,43 @@
 
 var noCredentialsError = errors.New("owner certificate or key does not exist")
 
-// getCredentials returns Metropolis credentials (if any) from the current
+// getOwnerKey returns the cluster owner's key, if one exists, from the current
 // metroctl config directory.
-func getCredentials() (cert *x509.Certificate, key ed25519.PrivateKey, err error) {
+func getOwnerKey() (ed25519.PrivateKey, error) {
 	ownerPrivateKeyPEM, err := os.ReadFile(filepath.Join(flags.configPath, "owner-key.pem"))
 	if os.IsNotExist(err) {
-		return nil, nil, noCredentialsError
+		return nil, noCredentialsError
 	} else if err != nil {
-		return nil, nil, fmt.Errorf("failed to load owner private key: %w", err)
+		return nil, fmt.Errorf("failed to load owner private key: %w", err)
 	}
 	block, _ := pem.Decode(ownerPrivateKeyPEM)
 	if block == nil {
-		return nil, nil, errors.New("owner-key.pem contains invalid PEM armoring")
+		return nil, errors.New("owner-key.pem contains invalid PEM armoring")
 	}
 	if block.Type != ownerKeyType {
-		return nil, nil, fmt.Errorf("owner-key.pem contains a PEM block that's not a %v", ownerKeyType)
+		return nil, fmt.Errorf("owner-key.pem contains a PEM block that's not a %v", ownerKeyType)
 	}
 	if len(block.Bytes) != ed25519.PrivateKeySize {
-		return nil, nil, errors.New("owner-key.pem contains a non-Ed25519 key")
+		return nil, errors.New("owner-key.pem contains a non-Ed25519 key")
 	}
-	key = block.Bytes
+	return block.Bytes, nil
+}
+
+// getCredentials returns Metropolis credentials (if any) from the current
+// metroctl config directory.
+func getCredentials() (cert *x509.Certificate, key ed25519.PrivateKey, err error) {
+	key, err = getOwnerKey()
+	if err != nil {
+		return nil, nil, err
+	}
+
 	ownerCertPEM, err := os.ReadFile(filepath.Join(flags.configPath, "owner.pem"))
 	if os.IsNotExist(err) {
 		return nil, nil, noCredentialsError
 	} else if err != nil {
 		return nil, nil, fmt.Errorf("failed to load owner certificate: %w", err)
 	}
-	block, _ = pem.Decode(ownerCertPEM)
+	block, _ := pem.Decode(ownerCertPEM)
 	if block == nil {
 		return nil, nil, errors.New("owner.pem contains invalid PEM armoring")
 	}
diff --git a/metropolis/cli/metroctl/takeownership.go b/metropolis/cli/metroctl/takeownership.go
index 975bd38..1b05500 100644
--- a/metropolis/cli/metroctl/takeownership.go
+++ b/metropolis/cli/metroctl/takeownership.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"crypto/ed25519"
 	"encoding/pem"
 	"log"
 	"net"
@@ -11,7 +10,6 @@
 	"path/filepath"
 
 	"github.com/spf13/cobra"
-	"google.golang.org/grpc"
 	clientauthentication "k8s.io/client-go/pkg/apis/clientauthentication/v1"
 	"k8s.io/client-go/tools/clientcmd"
 	clientapi "k8s.io/client-go/tools/clientcmd/api"
@@ -37,38 +35,24 @@
 	if len(flags.clusterEndpoints) != 1 {
 		log.Fatalf("takeownership requires a single cluster endpoint to be provided with the --endpoints parameter.")
 	}
-	clusterEp := flags.clusterEndpoints[0]
 
-	ctx := clicontext.WithInterrupt(context.Background())
-	ownerPrivateKeyPEM, err := os.ReadFile(filepath.Join(flags.configPath, "owner-key.pem"))
-	if os.IsNotExist(err) {
+	// Retrieve the cluster owner's private key, and use it to construct
+	// ephemeral credentials. Then, dial the cluster.
+	opk, err := getOwnerKey()
+	if err == noCredentialsError {
 		log.Fatalf("Owner key does not exist. takeownership needs to be executed on the same system that has previously installed the cluster using metroctl install.")
-	} else if err != nil {
-		log.Fatalf("Failed to load owner private key: %v", err)
 	}
-	block, _ := pem.Decode(ownerPrivateKeyPEM)
-	if block == nil {
-		log.Fatalf("owner-key.pem contains invalid PEM")
+	if err != nil {
+		log.Fatalf("Couldn't get owner's key: %v", err)
 	}
-	if block.Type != ownerKeyType {
-		log.Fatalf("owner-key.pem contains a PEM block that's not a %v", ownerKeyType)
+	ctx := clicontext.WithInterrupt(context.Background())
+	cc, err := dialCluster(ctx, opk, nil, flags.proxyAddr, flags.clusterEndpoints)
+	if err != nil {
+		log.Fatalf("While dialing the cluster: %v", err)
 	}
-	if len(block.Bytes) != ed25519.PrivateKeySize {
-		log.Fatal("owner-key.pem contains non-Ed25519 key")
-	}
-	ownerPrivateKey := ed25519.PrivateKey(block.Bytes)
+	aaa := apb.NewAAAClient(cc)
 
-	ephCreds, err := rpc.NewEphemeralCredentials(ownerPrivateKey, nil)
-	if err != nil {
-		log.Fatalf("Failed to create ephemeral credentials: %v", err)
-	}
-	client, err := grpc.Dial(net.JoinHostPort(clusterEp, node.CuratorServicePort.PortString()), grpc.WithTransportCredentials(ephCreds))
-	if err != nil {
-		log.Fatalf("Failed to create client to given node address: %v", err)
-	}
-	defer client.Close()
-	aaa := apb.NewAAAClient(client)
-	ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, ownerPrivateKey)
+	ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, opk)
 	if err != nil {
 		log.Fatalf("Failed to retrive owner certificate from cluster: %v", err)
 	}
@@ -115,8 +99,10 @@
 	config.Clusters["metropolis"] = &clientapi.Cluster{
 		// MVP: This is insecure, but making this work would be wasted effort
 		// as all of it will be replaced by the identity system.
+		// TODO(issues/144): adjust cluster endpoints once have functioning roles
+		// implemented.
 		InsecureSkipTLSVerify: true,
-		Server:                "https://" + net.JoinHostPort(clusterEp, node.KubernetesAPIWrappedPort.PortString()),
+		Server:                "https://" + net.JoinHostPort(flags.clusterEndpoints[0], node.KubernetesAPIWrappedPort.PortString()),
 	}
 
 	config.Contexts["metropolis"] = &clientapi.Context{