2023-08-27 14:09:03 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-07-13 14:08:13 +00:00
|
|
|
"errors"
|
2023-08-27 14:09:03 +00:00
|
|
|
"fmt"
|
2024-07-12 14:11:42 +00:00
|
|
|
"isle/nebula"
|
2023-08-27 14:09:03 +00:00
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
2024-07-13 14:08:13 +00:00
|
|
|
var subCmdNebulaCreateCert = subCmd{
|
|
|
|
name: "create-cert",
|
|
|
|
descr: "Creates a signed nebula certificate file for an existing host and writes it to stdout",
|
2024-09-04 20:35:29 +00:00
|
|
|
do: func(ctx subCmdCtx) error {
|
2024-07-13 14:08:13 +00:00
|
|
|
|
2024-09-23 18:50:45 +00:00
|
|
|
var hostName hostNameFlag
|
|
|
|
hostNameF := ctx.flags.VarPF(
|
2024-07-22 08:42:25 +00:00
|
|
|
&hostName,
|
2024-07-22 14:37:22 +00:00
|
|
|
"hostname", "n",
|
2024-07-13 14:08:13 +00:00
|
|
|
"Name of the host to generate a certificate for",
|
|
|
|
)
|
|
|
|
|
2024-09-23 18:50:45 +00:00
|
|
|
pubKeyPath := ctx.flags.StringP(
|
2024-07-13 14:08:13 +00:00
|
|
|
"public-key-path", "p", "",
|
|
|
|
`Path to PEM file containing public key which will be embedded in the cert.`,
|
|
|
|
)
|
|
|
|
|
2024-09-23 18:50:45 +00:00
|
|
|
ctx, err := ctx.withParsedFlags()
|
|
|
|
if err != nil {
|
2024-07-13 14:08:13 +00:00
|
|
|
return fmt.Errorf("parsing flags: %w", err)
|
|
|
|
}
|
|
|
|
|
2024-07-14 11:11:18 +00:00
|
|
|
if !hostNameF.Changed || *pubKeyPath == "" {
|
2024-07-14 12:28:01 +00:00
|
|
|
return errors.New("--hostname and --pub-key-path are required")
|
2024-07-13 14:08:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:49:35 +00:00
|
|
|
res, err := ctx.getDaemonRPC().CreateNebulaCertificate(
|
2024-09-04 20:46:38 +00:00
|
|
|
ctx, hostName.V, hostPub,
|
2024-07-13 14:08:13 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("calling CreateNebulaCertificate: %w", err)
|
|
|
|
}
|
|
|
|
|
2024-09-07 11:52:32 +00:00
|
|
|
nebulaHostCertPEM, err := res.Unwrap().MarshalToPEM()
|
2024-07-13 14:08:13 +00:00
|
|
|
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
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-08-27 14:09:03 +00:00
|
|
|
var subCmdNebulaShow = subCmd{
|
|
|
|
name: "show",
|
2024-06-10 16:56:36 +00:00
|
|
|
descr: "Writes nebula network information to stdout in JSON format",
|
2024-11-09 16:39:49 +00:00
|
|
|
do: doWithOutput(func(ctx subCmdCtx) (any, error) {
|
2024-09-23 18:50:45 +00:00
|
|
|
ctx, err := ctx.withParsedFlags()
|
|
|
|
if err != nil {
|
2024-11-09 16:39:49 +00:00
|
|
|
return nil, fmt.Errorf("parsing flags: %w", err)
|
2023-08-27 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
2024-09-04 20:35:29 +00:00
|
|
|
hosts, err := ctx.getHosts()
|
2023-08-27 14:09:03 +00:00
|
|
|
if err != nil {
|
2024-11-09 16:39:49 +00:00
|
|
|
return nil, fmt.Errorf("getting hosts: %w", err)
|
2023-08-27 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
2024-11-14 20:49:35 +00:00
|
|
|
caPublicCreds, err := ctx.getDaemonRPC().GetNebulaCAPublicCredentials(ctx)
|
2024-07-12 14:11:42 +00:00
|
|
|
if err != nil {
|
2024-11-09 16:39:49 +00:00
|
|
|
return nil, fmt.Errorf("calling GetNebulaCAPublicCredentials: %w", err)
|
2024-07-12 14:11:42 +00:00
|
|
|
}
|
|
|
|
|
2024-07-13 14:08:13 +00:00
|
|
|
caCert := caPublicCreds.Cert
|
|
|
|
caCertDetails := caCert.Unwrap().Details
|
2023-08-27 14:09:03 +00:00
|
|
|
|
2024-07-13 14:08:13 +00:00
|
|
|
if len(caCertDetails.Subnets) != 1 {
|
2024-11-09 16:39:49 +00:00
|
|
|
return nil, fmt.Errorf(
|
2023-08-27 14:09:03 +00:00
|
|
|
"malformed ca.crt, contains unexpected subnets %#v",
|
2024-07-13 14:08:13 +00:00
|
|
|
caCertDetails.Subnets,
|
2023-08-27 14:09:03 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-07-13 14:08:13 +00:00
|
|
|
subnet := caCertDetails.Subnets[0]
|
2023-08-27 14:09:03 +00:00
|
|
|
|
|
|
|
type outLighthouse struct {
|
2024-06-10 16:56:36 +00:00
|
|
|
PublicAddr string
|
|
|
|
IP string
|
2023-08-27 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out := struct {
|
2024-07-13 14:08:13 +00:00
|
|
|
CACert nebula.Certificate
|
2024-06-10 16:56:36 +00:00
|
|
|
SubnetCIDR string
|
|
|
|
Lighthouses []outLighthouse
|
2023-08-27 14:09:03 +00:00
|
|
|
}{
|
2024-07-13 14:08:13 +00:00
|
|
|
CACert: caCert,
|
2023-08-27 14:09:03 +00:00
|
|
|
SubnetCIDR: subnet.String(),
|
|
|
|
}
|
|
|
|
|
2024-09-07 11:52:32 +00:00
|
|
|
for _, h := range hosts {
|
2023-08-27 14:09:03 +00:00
|
|
|
if h.Nebula.PublicAddr == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
out.Lighthouses = append(out.Lighthouses, outLighthouse{
|
|
|
|
PublicAddr: h.Nebula.PublicAddr,
|
|
|
|
IP: h.IP().String(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-11-09 16:39:49 +00:00
|
|
|
return out, nil
|
|
|
|
}),
|
2023-08-27 14:09:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var subCmdNebula = subCmd{
|
|
|
|
name: "nebula",
|
|
|
|
descr: "Sub-commands related to the nebula VPN",
|
2024-09-04 20:35:29 +00:00
|
|
|
do: func(ctx subCmdCtx) error {
|
|
|
|
return ctx.doSubCmd(
|
2024-07-13 14:08:13 +00:00
|
|
|
subCmdNebulaCreateCert,
|
2023-08-27 14:09:03 +00:00
|
|
|
subCmdNebulaShow,
|
|
|
|
)
|
|
|
|
},
|
|
|
|
}
|