blob: 17ed1213f8c405ae759a61f882846e8a8006b424 [file] [log] [blame]
Lorenz Bruna9b455f2021-12-07 03:53:22 +01001package main
2
3import (
4 "context"
5 "crypto/ed25519"
6 "encoding/pem"
7 "log"
8 "net"
9 "os"
10 "path/filepath"
11
12 "github.com/adrg/xdg"
13 "github.com/spf13/cobra"
Serge Bazanski399ce552022-03-29 12:52:42 +020014 "google.golang.org/grpc"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010015
Lorenz Bruna9b455f2021-12-07 03:53:22 +010016 clicontext "source.monogon.dev/metropolis/cli/pkg/context"
17 "source.monogon.dev/metropolis/node"
18 "source.monogon.dev/metropolis/node/core/rpc"
Serge Bazanskidc1bec42021-12-16 17:38:53 +010019 apb "source.monogon.dev/metropolis/proto/api"
Lorenz Bruna9b455f2021-12-07 03:53:22 +010020)
21
22var takeownershipCommand = &cobra.Command{
23 Use: "takeownership <node-addr>",
24 Short: "Takes ownership of a new Metropolis cluster",
25 Long: `This takes ownership of a new Metropolis cluster by asking the new
26cluster to issue an owner certificate to for the owner key generated by a
27previous invocation of metroctl install on this machine.`,
28 Example: "takeownership 192.0.2.1",
29 Args: cobra.ExactArgs(1), // One positional argument: the node address
30 Run: doTakeOwnership,
31}
32
33func doTakeOwnership(cmd *cobra.Command, args []string) {
34 ctx := clicontext.WithInterrupt(context.Background())
35 ownerPrivateKeyPEM, err := os.ReadFile(filepath.Join(xdg.ConfigHome, "metroctl/owner-key.pem"))
36 if os.IsNotExist(err) {
37 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.")
38 } else if err != nil {
39 log.Fatalf("Failed to load owner private key: %v", err)
40 }
41 block, _ := pem.Decode(ownerPrivateKeyPEM)
42 if block == nil {
43 log.Fatalf("owner-key.pem contains invalid PEM")
44 }
45 if block.Type != ownerKeyType {
46 log.Fatalf("owner-key.pem contains a PEM block that's not a %v", ownerKeyType)
47 }
48 if len(block.Bytes) != ed25519.PrivateKeySize {
49 log.Fatal("owner-key.pem contains non-Ed25519 key")
50 }
51 ownerPrivateKey := ed25519.PrivateKey(block.Bytes)
52
Serge Bazanski399ce552022-03-29 12:52:42 +020053 ephCreds, err := rpc.NewEphemeralCredentials(ownerPrivateKey, nil)
54 if err != nil {
55 log.Fatalf("Failed to create ephemeral credentials: %v", err)
56 }
57 client, err := grpc.Dial(net.JoinHostPort(args[0], node.CuratorServicePort.PortString()), grpc.WithTransportCredentials(ephCreds))
Lorenz Bruna9b455f2021-12-07 03:53:22 +010058 if err != nil {
59 log.Fatalf("Failed to create client to given node address: %v", err)
60 }
61 defer client.Close()
62 aaa := apb.NewAAAClient(client)
63 ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, ownerPrivateKey)
64 if err != nil {
65 log.Fatalf("Failed to retrive owner certificate from cluster: %v", err)
66 }
67 ownerCertPEM := pem.Block{
68 Type: "CERTIFICATE",
69 Bytes: ownerCert.Certificate[0],
70 }
71 if err := os.WriteFile(filepath.Join(xdg.ConfigHome, "metroctl/owner.pem"), pem.EncodeToMemory(&ownerCertPEM), 0644); err != nil {
72 log.Printf("Failed to store retrieved owner certificate: %v", err)
73 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.")
74 }
75 log.Print("Successfully retrieved owner credentials! You now own this cluster.")
76}
77
78func init() {
79 rootCmd.AddCommand(takeownershipCommand)
80}