blob: 503248ac8c948efd495c7f722387eea3aba4d367 [file] [log] [blame]
package main
import (
"context"
"crypto/ed25519"
"encoding/pem"
"log"
"net"
"os"
"path/filepath"
"github.com/adrg/xdg"
"github.com/spf13/cobra"
clicontext "source.monogon.dev/metropolis/cli/pkg/context"
"source.monogon.dev/metropolis/node"
"source.monogon.dev/metropolis/node/core/rpc"
apb "source.monogon.dev/metropolis/proto/api"
)
var takeownershipCommand = &cobra.Command{
Use: "takeownership <node-addr>",
Short: "Takes ownership of a new Metropolis cluster",
Long: `This takes ownership of a new Metropolis cluster by asking the new
cluster to issue an owner certificate to for the owner key generated by a
previous invocation of metroctl install on this machine.`,
Example: "takeownership 192.0.2.1",
Args: cobra.ExactArgs(1), // One positional argument: the node address
Run: doTakeOwnership,
}
func doTakeOwnership(cmd *cobra.Command, args []string) {
ctx := clicontext.WithInterrupt(context.Background())
ownerPrivateKeyPEM, err := os.ReadFile(filepath.Join(xdg.ConfigHome, "metroctl/owner-key.pem"))
if os.IsNotExist(err) {
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 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)
client, err := rpc.NewEphemeralClient(net.JoinHostPort(args[0], node.CuratorServicePort.PortString()), ownerPrivateKey, nil)
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)
if err != nil {
log.Fatalf("Failed to retrive owner certificate from cluster: %v", err)
}
ownerCertPEM := pem.Block{
Type: "CERTIFICATE",
Bytes: ownerCert.Certificate[0],
}
if err := os.WriteFile(filepath.Join(xdg.ConfigHome, "metroctl/owner.pem"), pem.EncodeToMemory(&ownerCertPEM), 0644); err != nil {
log.Printf("Failed to store retrieved owner certificate: %v", err)
log.Fatalln("Sorry, the cluster has been lost as taking ownership cannot be repeated. Fix the reason the file couldn't be written and reinstall the node.")
}
log.Print("Successfully retrieved owner credentials! You now own this cluster.")
}
func init() {
rootCmd.AddCommand(takeownershipCommand)
}