blob: a264644cec8be70fc5bae3d19b48fb31a0963e6d [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"
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
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
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
74func init() {
75 rootCmd.AddCommand(takeownershipCommand)
76}