package main import ( "errors" "fmt" "isle/nebula" "os" ) var subCmdNebulaCreateCert = subCmd{ name: "create-cert", descr: "Creates a signed nebula certificate file for an existing host and writes it to stdout", do: func(ctx subCmdCtx) error { var hostName hostNameFlag hostNameF := ctx.flags.VarPF( &hostName, "hostname", "n", "Name of the host to generate a certificate for", ) pubKeyPath := ctx.flags.StringP( "public-key-path", "p", "", `Path to PEM file containing public key which will be embedded in the cert.`, ) ctx, err := ctx.withParsedFlags() if err != nil { return fmt.Errorf("parsing flags: %w", err) } if !hostNameF.Changed || *pubKeyPath == "" { return errors.New("--hostname and --pub-key-path are required") } hostPubPEM, err := os.ReadFile(*pubKeyPath) if err != nil { return fmt.Errorf("reading public key from %q: %w", *pubKeyPath, err) } var hostPub nebula.EncryptingPublicKey if err := hostPub.UnmarshalNebulaPEM(hostPubPEM); err != nil { return fmt.Errorf("unmarshaling public key as PEM: %w", err) } res, err := ctx.getDaemonRPC().CreateNebulaCertificate( ctx, hostName.V, hostPub, ) if err != nil { return fmt.Errorf("calling CreateNebulaCertificate: %w", err) } nebulaHostCertPEM, err := res.Unwrap().MarshalToPEM() if err != nil { return fmt.Errorf("marshaling cert to PEM: %w", err) } if _, err := os.Stdout.Write([]byte(nebulaHostCertPEM)); err != nil { return fmt.Errorf("writing to stdout: %w", err) } return nil }, } var subCmdNebulaShow = subCmd{ name: "show", descr: "Writes nebula network information to stdout in JSON format", do: doWithOutput(func(ctx subCmdCtx) (any, error) { ctx, err := ctx.withParsedFlags() if err != nil { return nil, fmt.Errorf("parsing flags: %w", err) } hosts, err := ctx.getHosts() if err != nil { return nil, fmt.Errorf("getting hosts: %w", err) } caPublicCreds, err := ctx.getDaemonRPC().GetNebulaCAPublicCredentials(ctx) if err != nil { return nil, fmt.Errorf("calling GetNebulaCAPublicCredentials: %w", err) } caCert := caPublicCreds.Cert caCertDetails := caCert.Unwrap().Details if len(caCertDetails.Subnets) != 1 { return nil, fmt.Errorf( "malformed ca.crt, contains unexpected subnets %#v", caCertDetails.Subnets, ) } subnet := caCertDetails.Subnets[0] type outLighthouse struct { PublicAddr string IP string } out := struct { CACert nebula.Certificate SubnetCIDR string Lighthouses []outLighthouse }{ CACert: caCert, SubnetCIDR: subnet.String(), } for _, h := range hosts { if h.Nebula.PublicAddr == "" { continue } out.Lighthouses = append(out.Lighthouses, outLighthouse{ PublicAddr: h.Nebula.PublicAddr, IP: h.IP().String(), }) } return out, nil }), } var subCmdNebula = subCmd{ name: "nebula", descr: "Sub-commands related to the nebula VPN", do: func(ctx subCmdCtx) error { return ctx.doSubCmd( subCmdNebulaCreateCert, subCmdNebulaShow, ) }, }