Переглянути джерело

add tentative wg config generator

reid 2 роки тому
батько
коміт
dceb0f00d5
7 змінених файлів з 179 додано та 9 видалено
  1. 13 0
      config/config.go
  2. 17 2
      config/wireguard.go
  3. 5 2
      docker/docker.go
  4. 13 4
      docker/minio.go
  5. 122 0
      docker/wireguard.go
  6. 3 1
      go.mod
  7. 6 0
      go.sum

+ 13 - 0
config/config.go

@@ -68,6 +68,19 @@ func init() {
 			logger.Error(errmsg)
 			panic(errmsg)
 		}
+		// generate and insert wireguard keys
+		wgPriv, wgPub, err := WgKeyGen()
+		if err != nil {
+			logger.Error(fmt.Sprintf("%v",err))
+		} else {
+			err = UpdateConf(map[string]interface{}{
+				"Pubkey": wgPub,
+				"Privkey": wgPriv,
+			})
+			if err != nil {
+				logger.Error(fmt.Sprintf("%v",err))
+			}
+		}
 	}
 	defer file.Close()
 	// read the sysconfig to memory

+ 17 - 2
config/wireguard.go

@@ -1,14 +1,18 @@
 package config
 
 import (
+	"fmt"
 	"encoding/json"
+	"encoding/base64"
 	"goseg/defaults"
 	"goseg/structs"
 	"os"
 	"path/filepath"
+	
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
-// write a hardcoded default conf to disk
+// write a hardcoded default container conf to disk
 func CreateDefaultWGConf() error {
 	defaultConfig := defaults.WgConfig
 	path := filepath.Join(BasePath, "settings", "wireguard.json")
@@ -28,7 +32,7 @@ func CreateDefaultWGConf() error {
 	return nil
 }
 
-// write a conf to disk from version server info
+// write a container conf to disk from version server info
 func UpdateWGConf() error {
 	conf := Conf()
 	releaseChannel := conf.UpdateBranch
@@ -65,3 +69,14 @@ func UpdateWGConf() error {
 	}
 	return nil
 }
+
+// wireguard keypair gen
+func WgKeyGen() (privateKeyStr string, publicKeyStr string, err error) {
+	privateKey, err := wgtypes.GeneratePrivateKey()
+	if err != nil {
+		return "", "", fmt.Errorf("failed to generate private key: %v", err)
+	}
+	// derive pubkey and use startram encoding
+	publicKey := base64.StdEncoding.EncodeToString([]byte(privateKey.PublicKey().String() + "\n"))
+	return privateKey.String(), publicKey, nil
+}

+ 5 - 2
docker/docker.go

@@ -113,13 +113,16 @@ func GetContainerStats(containerName string) (structs.ContainerStats, error) {
 // contructs a container.Config, then runs through whether to boot/restart/etc
 // saves the current container state in memory after completion
 func StartContainer(containerName string, containerType string) (structs.ContainerState, error) {
+	// bundle of info about container
 	var containerState structs.ContainerState
+	// config params for container
 	var containerConfig container.Config
+	// host config for container
 	var hostConfig container.HostConfig
 	// switch on containerType to process containerConfig
 	switch containerType { 
 	case "vere":
-		// containerConfig, err := urbitContainerConf(containerName)
+		// containerConfig, HostConfig, err := urbitContainerConf(containerName)
 		_, err := urbitContainerConf(containerName)
 		if err != nil {
 			return containerState, err
@@ -135,7 +138,7 @@ func StartContainer(containerName string, containerType string) (structs.Contain
 			return containerState, err
 		}
 	case "miniomc":
-		_, err := mcContainerConf()
+		_, _, err := mcContainerConf()
 		if err != nil {
 			return containerState, err
 		}

+ 13 - 4
docker/minio.go

@@ -87,6 +87,7 @@ func minioContainerConf(containerName string) (container.Config, container.HostC
 		Cmd:        []string{command},
 		Env:        environment,
 	}
+	// always on wg nw
 	hostConfig = container.HostConfig{
 		NetworkMode: "container:wireguard",
 		Mounts:      mounts,
@@ -95,12 +96,13 @@ func minioContainerConf(containerName string) (container.Config, container.HostC
 }
 
 // miniomc container config builder
-func mcContainerConf() (container.Config, error) {
+func mcContainerConf() (container.Config, container.HostConfig, error) {
 	var containerConfig container.Config
+	var hostConfig container.HostConfig
 	// construct the container metadata from version server info
 	containerInfo, err := GetLatestContainerInfo("miniomc")
 	if err != nil {
-		return containerConfig, err
+		return containerConfig, hostConfig, err
 	}
 	desiredTag := containerInfo["tag"]
 	desiredHash := containerInfo["hash"]
@@ -108,7 +110,14 @@ func mcContainerConf() (container.Config, error) {
 	desiredImage := fmt.Sprintf("%s:%s@sha256:%s", desiredRepo, desiredTag, desiredHash)
 	// construct the container config struct
 	containerConfig = container.Config{
-		Image:      desiredImage,
+		Image:     desiredImage,
+		Entrypoint: []string{"/bin/bash"},
+		Tty:       true,
+		OpenStdin: true,
 	}
-	return containerConfig, nil
+	// always on wg nw
+	hostConfig = container.HostConfig{
+		NetworkMode: "container:wireguard",
+	}
+	return containerConfig, hostConfig, nil
 }

+ 122 - 0
docker/wireguard.go

@@ -1,10 +1,18 @@
 package docker
 
 import (
+	"context"
 	"fmt"
 	"goseg/config"
+	"io/ioutil"
 	"os"
 	"path/filepath"
+	"encoding/base64"
+	"strings"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/client"
+	"github.com/docker/docker/api/types"
+	// "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 func LoadWireguard() error {
@@ -30,3 +38,117 @@ func LoadWireguard() error {
 	config.UpdateContainerState("wireguard", info)
 	return nil
 }
+
+// wireguard container config builder
+func wgContainerConf() (container.Config, container.HostConfig, error) {
+	var containerConfig container.Config
+	var hostConfig container.HostConfig
+	// construct the container metadata from version server info
+	containerInfo, err := GetLatestContainerInfo("wireguard")
+	if err != nil {
+		return containerConfig, hostConfig, err
+	}
+	desiredTag := containerInfo["tag"]
+	desiredHash := containerInfo["hash"]
+	desiredRepo := containerInfo["repo"]
+	desiredImage := fmt.Sprintf("%s:%s@sha256:%s", desiredRepo, desiredTag, desiredHash)
+	// construct the container config struct
+	containerConfig = container.Config{
+		Image:     desiredImage,
+		Entrypoint: []string{"/bin/bash"},
+		Tty:       true,
+		OpenStdin: true,
+	}
+	// always on wg nw
+	hostConfig = container.HostConfig{
+		NetworkMode: "container:wireguard",
+	}
+	return containerConfig, hostConfig, nil
+}
+
+// wg client config builder
+func buildWgConf() (string, error) {
+	confB64 := config.StartramConfig.Conf
+	confBytes, err := base64.StdEncoding.DecodeString(confB64)
+	if err != nil {
+		return "", fmt.Errorf("Failed to decode remote WG base64: %v", err)
+	}
+	conf := string(confBytes)
+	configData := config.Conf()
+	res := strings.Replace(conf, "privkey", configData.Privkey, -1)
+	return res, nil
+}
+
+// write wg config if it doesn't exist or doesn't match
+func writeWgConf() error {
+	volumeExists := true
+	// read existing and build current conf
+	filePath := filepath.Join(config.DockerDir, "settings", "wireguard", "_data", "wg0.conf")
+	existingConf, err := ioutil.ReadFile(filePath)
+	if err != nil {
+		volumeExists = false
+	}
+	newConf, err := buildWgConf()
+	if err != nil {
+		return err
+	}
+	ctx := context.Background()
+	cli, err := client.NewClientWithOpts(client.FromEnv)
+	if err != nil {
+		return err
+	}
+	_, err = cli.VolumeInspect(ctx, "wireguard")
+	if err != nil {
+		volumeExists = false
+	}
+	// if theyre different, or if the volume doesnt exist, copy the new config to the volume
+	if string(existingConf) != newConf || !volumeExists {
+		err = ioutil.WriteFile("tmp/wg0.conf", []byte(newConf), 0644)
+		if err != nil {
+			return fmt.Errorf("Failed to write new WG config: %v", err)
+		}
+		// copy to volume
+		err = copyFileToVolume(filepath.Join("tmp","wg0.conf"), "/etc/wireguard/", "wireguard")
+		if err != nil {
+			return fmt.Errorf("Failed to copy WG config file to volume: %v", err)
+		}
+	}	
+	return nil
+}
+
+// write wg conf to volume
+func copyFileToVolume(filePath string, targetPath string, volumeName string) error {
+	ctx := context.Background()
+	cli, err := client.NewClientWithOpts(client.FromEnv)
+	if err != nil {
+		return err
+	}
+	// temp container to mount
+	resp, err := cli.ContainerCreate(ctx, &container.Config{
+		Image: "busybox",
+		Cmd:   []string{"tail", "-f", "/dev/null"},
+	}, &container.HostConfig{
+		Binds: []string{volumeName + ":" + targetPath},
+	}, nil, nil, "bb_temp")
+	if err != nil {
+		return err
+	}
+	if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
+		return err
+	}
+	file, err := os.Open(filepath.Join(filePath))
+	if err != nil {
+		return fmt.Errorf("failed to open wg0 file: %v", err)
+	}
+	defer file.Close()
+	// Copy the file to the volume via the temporary container
+	err = cli.CopyToContainer(ctx, resp.ID, targetPath, file, types.CopyToContainerOptions{})
+	if err != nil {
+		return err
+	}
+	// remove temporary container
+	if err := cli.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true}); err != nil {
+		return err
+	}
+	return nil
+}

+ 3 - 1
go.mod

@@ -26,10 +26,12 @@ require (
 	github.com/tklauser/go-sysconf v0.3.12 // indirect
 	github.com/tklauser/numcpus v0.6.1 // indirect
 	github.com/yusufpapurcu/wmi v1.2.3 // indirect
+	golang.org/x/crypto v0.8.0 // indirect
 	golang.org/x/mod v0.8.0 // indirect
-	golang.org/x/net v0.6.0 // indirect
+	golang.org/x/net v0.9.0 // indirect
 	golang.org/x/sys v0.11.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.6.0 // indirect
+	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
 	gotest.tools/v3 v3.5.0 // indirect
 )

+ 6 - 0
go.sum

@@ -53,6 +53,8 @@ github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
+golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
@@ -63,6 +65,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -89,6 +93,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
+golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=