isle/go/cmd/entrypoint/nebula.go

136 lines
3.0 KiB
Go

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)
}
currBoostrap, err := ctx.getDaemonRPC().GetBootstrap(ctx)
if err != nil {
return nil, fmt.Errorf("calling GetBootstrap: %w", err)
}
var (
hosts = currBoostrap.HostsOrdered()
caPublicCreds = currBoostrap.CAPublicCredentials
)
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,
)
},
}