WIP
Currently a bit stuck on getting the IPMask to `nebula.NewHostCert`. Probably the best way would be to limit number of CIDRs to just 1 for now, and include that in the `nebula.CACert`. Or maybe we can just provide a way to parse it out of the `ca.crt`. Either way CIDRs should get removed from `admin.CreationParams`.
This commit is contained in:
parent
15c5c904a2
commit
3f3ad43cb2
@ -6,7 +6,9 @@ import (
|
||||
"cryptic-net/nebula"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func readAdmin(path string) (admin.Admin, error) {
|
||||
@ -30,6 +32,98 @@ func readAdmin(path string) (admin.Admin, error) {
|
||||
return admin.FromReader(f)
|
||||
}
|
||||
|
||||
var subCmdAdminCreateNetwork = subCmd{
|
||||
name: "create-network",
|
||||
descr: "Creates a new cryptic-net network, outputting the resulting admin.tgz to stdout",
|
||||
do: func(subCmdCtx subCmdCtx) error {
|
||||
|
||||
flags := subCmdCtx.flagSet(false)
|
||||
|
||||
daemonYmlPath := flags.StringP(
|
||||
"config-path", "c", "",
|
||||
"Optional path to a daemon.yml file to load configuration from.",
|
||||
)
|
||||
|
||||
dumpConfig := flags.Bool(
|
||||
"dump-config", false,
|
||||
"Write the default configuration file to stdout and exit.",
|
||||
)
|
||||
|
||||
domain := flags.StringP(
|
||||
"domain", "d", "",
|
||||
"Domain name that should be used as the root domain in the network.",
|
||||
)
|
||||
|
||||
ipCIDRStrs := flags.StringP(
|
||||
"ip-cidrs", "i", "",
|
||||
"Comma-separated list of CIDRs which denote what IPs hosts on the network can be assigned.",
|
||||
)
|
||||
|
||||
if err := flags.Parse(subCmdCtx.args); err != nil {
|
||||
return fmt.Errorf("parsing flags: %w", err)
|
||||
}
|
||||
|
||||
env := subCmdCtx.env
|
||||
|
||||
if *dumpConfig {
|
||||
return writeBuiltinDaemonYml(env, os.Stdout)
|
||||
}
|
||||
|
||||
if *domain == "" {
|
||||
return errors.New("--domain is required")
|
||||
}
|
||||
|
||||
*domain = strings.TrimRight(strings.TrimLeft(*domain, "."), ".")
|
||||
|
||||
var (
|
||||
ipCIDRs []*net.IPNet
|
||||
thisIP net.IP
|
||||
)
|
||||
|
||||
for _, ipCIDRStr := range strings.Split(*ipCIDRStrs, ",") {
|
||||
|
||||
ipCIDRStr = strings.TrimSpace(ipCIDRStr)
|
||||
if ipCIDRStr == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
ip, ipCIDR, err := net.ParseCIDR(ipCIDRStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse CIDR %q: %w", ipCIDRStr, err)
|
||||
}
|
||||
|
||||
thisIP = ip // we just need one IP from a CIDR, it doesn't matter which.
|
||||
ipCIDRs = append(ipCIDRs, ipCIDR)
|
||||
}
|
||||
|
||||
runtimeDirPath := env.RuntimeDirPath
|
||||
|
||||
fmt.Fprintf(os.Stderr, "will use runtime directory %q for temporary state\n", runtimeDirPath)
|
||||
|
||||
if err := os.MkdirAll(runtimeDirPath, 0700); err != nil {
|
||||
return fmt.Errorf("creating directory %q: %w", runtimeDirPath, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
fmt.Fprintf(os.Stderr, "cleaning up runtime directory %q\n", runtimeDirPath)
|
||||
if err := os.RemoveAll(runtimeDirPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error removing temporary directory %q: %v", runtimeDirPath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := writeMergedDaemonYml(env, *daemonYmlPath); err != nil {
|
||||
return fmt.Errorf("merging and writing daemon.yml file: %w", err)
|
||||
}
|
||||
|
||||
daemon := env.ThisDaemon()
|
||||
|
||||
if len(daemon.Storage.Allocations) < 3 {
|
||||
return fmt.Errorf("daemon.yml with at least 3 allocations was not provided")
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
var subCmdAdminMakeBootstrap = subCmd{
|
||||
name: "make-bootstrap",
|
||||
descr: "Creates a new bootstrap.tgz file for a particular host and writes it to stdout",
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -17,11 +16,8 @@ import (
|
||||
crypticnet "cryptic-net"
|
||||
"cryptic-net/bootstrap"
|
||||
"cryptic-net/garage"
|
||||
"cryptic-net/yamlutil"
|
||||
|
||||
"github.com/cryptic-io/pmux/pmuxlib"
|
||||
"github.com/imdario/mergo"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// The daemon sub-command deals with starting an actual cryptic-net daemon
|
||||
@ -46,42 +42,6 @@ import (
|
||||
//
|
||||
// * (On exit) cleans up the runtime directory.
|
||||
|
||||
func writeDaemonYml(userDaemonYmlPath, builtinDaemonYmlPath, runtimeDirPath string) error {
|
||||
|
||||
var fullDaemonYml map[string]interface{}
|
||||
|
||||
if err := yamlutil.LoadYamlFile(&fullDaemonYml, builtinDaemonYmlPath); err != nil {
|
||||
return fmt.Errorf("parsing builtin daemon.yml file: %w", err)
|
||||
}
|
||||
|
||||
if userDaemonYmlPath != "" {
|
||||
|
||||
var daemonYml map[string]interface{}
|
||||
if err := yamlutil.LoadYamlFile(&daemonYml, userDaemonYmlPath); err != nil {
|
||||
return fmt.Errorf("parsing %q: %w", userDaemonYmlPath, err)
|
||||
}
|
||||
|
||||
err := mergo.Merge(&fullDaemonYml, daemonYml, mergo.WithOverride)
|
||||
if err != nil {
|
||||
return fmt.Errorf("merging contents of file %q: %w", userDaemonYmlPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
fullDaemonYmlB, err := yaml.Marshal(fullDaemonYml)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("yaml marshaling daemon config: %w", err)
|
||||
}
|
||||
|
||||
daemonYmlPath := filepath.Join(runtimeDirPath, "daemon.yml")
|
||||
|
||||
if err := ioutil.WriteFile(daemonYmlPath, fullDaemonYmlB, 0400); err != nil {
|
||||
return fmt.Errorf("writing daemon.yml file to %q: %w", daemonYmlPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyBootstrapToDataDir(env *crypticnet.Env, r io.Reader) error {
|
||||
|
||||
path := env.DataDirBootstrapPath()
|
||||
@ -284,28 +244,8 @@ var subCmdDaemon = subCmd{
|
||||
|
||||
env := subCmdCtx.env
|
||||
|
||||
s3Client, err := env.Bootstrap.GlobalBucketS3APIClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating client for global bucket: %w", err)
|
||||
}
|
||||
|
||||
appDirPath := env.AppDirPath
|
||||
|
||||
builtinDaemonYmlPath := filepath.Join(appDirPath, "etc", "daemon.yml")
|
||||
|
||||
if *dumpConfig {
|
||||
|
||||
builtinDaemonYml, err := os.ReadFile(builtinDaemonYmlPath)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading default daemon.yml at %q: %w", builtinDaemonYmlPath, err)
|
||||
}
|
||||
|
||||
if _, err := os.Stdout.Write(builtinDaemonYml); err != nil {
|
||||
return fmt.Errorf("writing default daemon.yml to stdout: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return writeBuiltinDaemonYml(env, os.Stdout)
|
||||
}
|
||||
|
||||
runtimeDirPath := env.RuntimeDirPath
|
||||
@ -360,8 +300,8 @@ var subCmdDaemon = subCmd{
|
||||
}
|
||||
}
|
||||
|
||||
if err := writeDaemonYml(*daemonYmlPath, builtinDaemonYmlPath, runtimeDirPath); err != nil {
|
||||
return fmt.Errorf("generating daemon.yml file: %w", err)
|
||||
if err := writeMergedDaemonYml(env, *daemonYmlPath); err != nil {
|
||||
return fmt.Errorf("merging and writing daemon.yml file: %w", err)
|
||||
}
|
||||
|
||||
{
|
||||
@ -412,6 +352,14 @@ var subCmdDaemon = subCmd{
|
||||
|
||||
for {
|
||||
|
||||
// create s3Client anew on every loop, in case the topology has
|
||||
// changed and we should be connecting to a different garage
|
||||
// endpoint.
|
||||
s3Client, err := env.Bootstrap.GlobalBucketS3APIClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating client for global bucket: %w", err)
|
||||
}
|
||||
|
||||
if err := runDaemonPmuxOnce(env, s3Client); errors.Is(err, context.Canceled) {
|
||||
return nil
|
||||
|
||||
|
72
go-workspace/src/cmd/entrypoint/daemon_yml.go
Normal file
72
go-workspace/src/cmd/entrypoint/daemon_yml.go
Normal file
@ -0,0 +1,72 @@
|
||||
package entrypoint
|
||||
|
||||
import (
|
||||
crypticnet "cryptic-net"
|
||||
"cryptic-net/yamlutil"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func builtinDaemonYmlPath(env *crypticnet.Env) string {
|
||||
return filepath.Join(env.AppDirPath, "etc", "daemon.yml")
|
||||
}
|
||||
|
||||
func writeBuiltinDaemonYml(env *crypticnet.Env, w io.Writer) error {
|
||||
|
||||
builtinDaemonYmlPath := builtinDaemonYmlPath(env)
|
||||
|
||||
builtinDaemonYml, err := os.ReadFile(builtinDaemonYmlPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading default daemon.yml at %q: %w", builtinDaemonYmlPath, err)
|
||||
}
|
||||
|
||||
if _, err := w.Write(builtinDaemonYml); err != nil {
|
||||
return fmt.Errorf("writing default daemon.yml: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeMergedDaemonYml(env *crypticnet.Env, userDaemonYmlPath string) error {
|
||||
|
||||
builtinDaemonYmlPath := builtinDaemonYmlPath(env)
|
||||
|
||||
var fullDaemonYml map[string]interface{}
|
||||
|
||||
if err := yamlutil.LoadYamlFile(&fullDaemonYml, builtinDaemonYmlPath); err != nil {
|
||||
return fmt.Errorf("parsing builtin daemon.yml file: %w", err)
|
||||
}
|
||||
|
||||
if userDaemonYmlPath != "" {
|
||||
|
||||
var daemonYml map[string]interface{}
|
||||
if err := yamlutil.LoadYamlFile(&daemonYml, userDaemonYmlPath); err != nil {
|
||||
return fmt.Errorf("parsing %q: %w", userDaemonYmlPath, err)
|
||||
}
|
||||
|
||||
err := mergo.Merge(&fullDaemonYml, daemonYml, mergo.WithOverride)
|
||||
if err != nil {
|
||||
return fmt.Errorf("merging contents of file %q: %w", userDaemonYmlPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
fullDaemonYmlB, err := yaml.Marshal(fullDaemonYml)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("yaml marshaling daemon config: %w", err)
|
||||
}
|
||||
|
||||
daemonYmlPath := filepath.Join(env.RuntimeDirPath, "daemon.yml")
|
||||
|
||||
if err := ioutil.WriteFile(daemonYmlPath, fullDaemonYmlB, 0400); err != nil {
|
||||
return fmt.Errorf("writing daemon.yml file to %q: %w", daemonYmlPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -14,15 +14,6 @@ import (
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
// TODO this should one day not be hardcoded
|
||||
var ipCIDRMask = func() net.IPMask {
|
||||
_, ipNet, err := net.ParseCIDR("10.10.0.0/16")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ipNet.Mask
|
||||
}()
|
||||
|
||||
// HostCert contains the certificate and private key files which will need to
|
||||
// be present on a particular host. Each file is PEM encoded.
|
||||
type HostCert struct {
|
||||
@ -122,7 +113,7 @@ func NewHostCert(
|
||||
|
||||
// NewCACert generates a CACert. The domain should be the network's root domain,
|
||||
// and is included in the signing certificate's Name field.
|
||||
func NewCACert(domain string) (CACert, error) {
|
||||
func NewCACert(domain string, ipCIDRS []*net.IPNet) (CACert, error) {
|
||||
|
||||
pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
@ -135,6 +126,7 @@ func NewCACert(domain string) (CACert, error) {
|
||||
caCrt := cert.NebulaCertificate{
|
||||
Details: cert.NebulaCertificateDetails{
|
||||
Name: fmt.Sprintf("%s cryptic-net root cert", domain),
|
||||
Ips: ipCIDRS,
|
||||
NotBefore: now,
|
||||
NotAfter: expireAt,
|
||||
PublicKey: pubKey,
|
||||
|
Loading…
Reference in New Issue
Block a user