Lorenz Brun | a9b455f | 2021-12-07 03:53:22 +0100 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| 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" |
| 14 | |
| 15 | apb "source.monogon.dev/metropolis/proto/api" |
| 16 | |
| 17 | clicontext "source.monogon.dev/metropolis/cli/pkg/context" |
| 18 | "source.monogon.dev/metropolis/node" |
| 19 | "source.monogon.dev/metropolis/node/core/rpc" |
| 20 | ) |
| 21 | |
| 22 | var 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 |
| 26 | cluster to issue an owner certificate to for the owner key generated by a |
| 27 | previous 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 | |
| 33 | func 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 | |
| 53 | client, err := rpc.NewEphemeralClient(net.JoinHostPort(args[0], node.CuratorServicePort.PortString()), ownerPrivateKey, nil) |
| 54 | if err != nil { |
| 55 | log.Fatalf("Failed to create client to given node address: %v", err) |
| 56 | } |
| 57 | defer client.Close() |
| 58 | aaa := apb.NewAAAClient(client) |
| 59 | ownerCert, err := rpc.RetrieveOwnerCertificate(ctx, aaa, ownerPrivateKey) |
| 60 | if err != nil { |
| 61 | log.Fatalf("Failed to retrive owner certificate from cluster: %v", err) |
| 62 | } |
| 63 | ownerCertPEM := pem.Block{ |
| 64 | Type: "CERTIFICATE", |
| 65 | Bytes: ownerCert.Certificate[0], |
| 66 | } |
| 67 | if err := os.WriteFile(filepath.Join(xdg.ConfigHome, "metroctl/owner.pem"), pem.EncodeToMemory(&ownerCertPEM), 0644); err != nil { |
| 68 | log.Printf("Failed to store retrieved owner certificate: %v", err) |
| 69 | 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.") |
| 70 | } |
| 71 | log.Print("Successfully retrieved owner credentials! You now own this cluster.") |
| 72 | } |
| 73 | |
| 74 | func init() { |
| 75 | rootCmd.AddCommand(takeownershipCommand) |
| 76 | } |