Skip to content

Commit

Permalink
feat: setup pwctl bridge with config file and passphrases
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Mar 7, 2019
1 parent c1e2924 commit 8a560b6
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 37 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
entrypoint/out/
vendor/
*~
*#
Expand Down
18 changes: 9 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subs
GOPATH ?= $(HOME)/go
BIN = $(GOPATH)/bin/pathwar.pw
SOURCES = $(call rwildcard, ./, *.go)
ENTRYPOINT_SOURCES = ./entrypoint/main.go
PWCTL_SOURCES = $(call rwildcard,pwctl//,*.go)
OUR_SOURCES = $(filter-out $(call rwildcard,vendor//,*.go),$(SOURCES))
PROTOS = $(call rwildcard, ./, *.proto)
OUR_PROTOS = $(filter-out $(call rwildcard,vendor//,*.proto),$(PROTOS))
GENERATED_PB_FILES = \
$(patsubst %.proto,%.pb.go,$(PROTOS)) \
$(call rwildcard ./, *.gen.go)
ENTRYPOINT_OUT_FILES = \
./entrypoint/out/entrypoint-linux-amd64
PWCTL_OUT_FILES = \
./pwctl/out/pwctl-linux-amd64
GENERATED_FILES = \
$(GENERATED_PB_FILES) \
$(ENTRYPOINT_OUT_FILES)
$(PWCTL_OUT_FILES)
PROTOC_OPTS = -I/protobuf:vendor:.
RUN_OPTS ?=

Expand All @@ -44,7 +44,7 @@ run: $(BIN)

.PHONY: install
install: $(BIN)
$(BIN): .proto.generated $(ENTRYPOINT_OUT_FILES) $(OUR_SOURCES)
$(BIN): .proto.generated $(PWCTL_OUT_FILES) $(OUR_SOURCES)
go install -v

.PHONY: clean
Expand All @@ -67,7 +67,7 @@ generate: .proto.generated
--user="$(shell id -u)" \
--volume="$(PWD):/go/src/pathwar.pw" \
--workdir="/go/src/pathwar.pw" \
--entrypoint="sh" \
--pwctl="sh" \
--rm \
pathwar/protoc:v1 \
-xec "make _proto_generate"
Expand All @@ -76,9 +76,9 @@ generate: .proto.generated
.PHONY: _generate
_proto_generate: $(GENERATED_PB_FILES)

$(ENTRYPOINT_OUT_FILES): $(ENTRYPOINT_SOURCES)
mkdir -p ./entrypoint/out
GOOS=linux GOARCH=amd64 go build -o ./entrypoint/out/entrypoint-linux-amd64 $<
$(PWCTL_OUT_FILES): $(PWCTL_SOURCES)
mkdir -p ./pwctl/out
GOOS=linux GOARCH=amd64 go build -o ./pwctl/out/pwctl-linux-amd64 ./pwctl/

.PHONY: test
test: .proto.generated
Expand Down
21 changes: 0 additions & 21 deletions entrypoint/main.go

This file was deleted.

34 changes: 28 additions & 6 deletions hypervisor/cmd_hypervisor_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -22,6 +23,7 @@ import (
"go.uber.org/zap"

"pathwar.pw/pkg/cli"
pwctlconfig "pathwar.pw/pwctl/config"
)

type runOptions struct {
Expand Down Expand Up @@ -88,7 +90,7 @@ func runRun(opts runOptions) error {
nat.Port("80/tcp"): {},
},
// Hostname: ""
Entrypoint: strslice.StrSlice{"/pathwar"},
Entrypoint: strslice.StrSlice{"/bin/pwctl", "entrypoint"},
Cmd: append(imageInspect.Config.Entrypoint, imageInspect.Config.Cmd...),
Labels: map[string]string{createdByPathwarLabel: "true"},
}
Expand All @@ -108,7 +110,6 @@ func runRun(opts runOptions) error {
// FIXME: create a limited network config
// FIXME: restrict resources (cgroups, etc.)
// FIXME: configure env
// FIXME: copy tokens somewhere safe in the image

cont, err := cli.ContainerCreate(ctx, containerConfig, hostConfig, nil, "")
if err != nil {
Expand All @@ -120,17 +121,27 @@ func runRun(opts runOptions) error {
}
}

// inject tools in container
pwctlConfig := pwctlconfig.Config{
Passphrases: []string{
randString(10),
randString(10),
randString(10),
},
}
// if !pwctlConfig.Validate() ...
pwctlConfigJSON, _ := json.Marshal(pwctlConfig)

// inject tools & config in container
// FIXME: support alternative architectures -> using copyFromContainer with a dedicated image?
var buf bytes.Buffer
var entrypointBox = packr.New("entrypoint-binaries", "../entrypoint/out")
binary, err := entrypointBox.Find("entrypoint-linux-amd64")
var pwctlBox = packr.New("pwctl-binaries", "../pwctl/out")
binary, err := pwctlBox.Find("pwctl-linux-amd64")
if err != nil {
return err
}
tw := tar.NewWriter(&buf)
if err := tw.WriteHeader(&tar.Header{
Name: "pathwar",
Name: "/bin/pwctl",
Mode: 0755,
Size: int64(len(binary)),
}); err != nil {
Expand All @@ -139,6 +150,17 @@ func runRun(opts runOptions) error {
if _, err := tw.Write(binary); err != nil {
return err
}
if err := tw.WriteHeader(&tar.Header{
Name: "/pwctl.json",
Mode: 0755,
Size: int64(len(pwctlConfigJSON)),
// FIXME: chown it to container's default user
}); err != nil {
return err
}
if _, err := tw.Write(pwctlConfigJSON); err != nil {
return err
}
if err := tw.Close(); err != nil {
return err
}
Expand Down
30 changes: 30 additions & 0 deletions hypervisor/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package hypervisor

import "math/rand"

// from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)

func randString(n int) string {
b := make([]byte, n)
// A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = rand.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}

return string(b)
}
1 change: 1 addition & 0 deletions pwctl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/out/
21 changes: 21 additions & 0 deletions pwctl/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"encoding/json"
"io/ioutil"

pwctlconfig "pathwar.pw/pwctl/config"
)

func getConfig() (*pwctlconfig.Config, error) {
// load config file
configJSON, err := ioutil.ReadFile("/pwctl.json")
if err != nil {
return nil, err
}
var config pwctlconfig.Config
if err := json.Unmarshal(configJSON, &config); err != nil {
return nil, err
}
return &config, nil
}
12 changes: 12 additions & 0 deletions pwctl/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package config

import "encoding/json"

type Config struct {
Passphrases []string
}

func (c Config) String() string {
out, _ := json.Marshal(c)
return string(out)
}
85 changes: 85 additions & 0 deletions pwctl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package main

import (
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"syscall"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func main() {
rootCmd := &cobra.Command{
Use: os.Args[0],
}
rootCmd.PersistentFlags().BoolP("help", "h", false, "print usage")
rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
return nil
}
rootCmd.AddCommand(&cobra.Command{
Use: "entrypoint",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// FIXME: prepare the level
// FIXME: add a self-destruct mode that allow having root access only at runtime
// FIXME: lock to block other commands
binary, err := exec.LookPath(args[0])
if err != nil {
return err
}
env := os.Environ()
if err := syscall.Exec(binary, args, env); err != nil {
return err
}
return nil
},
})
rootCmd.AddCommand(&cobra.Command{
Use: "env",
RunE: func(cmd *cobra.Command, args []string) error {
for _, line := range os.Environ() {
fmt.Println(line)
}
return nil
},
})
rootCmd.AddCommand(&cobra.Command{
Use: "config",
RunE: func(cmd *cobra.Command, args []string) error {
config, err := getConfig()
if err != nil {
return err
}
out, _ := json.Marshal(config)
fmt.Println(string(out))
return nil
},
})
rootCmd.AddCommand(&cobra.Command{
Use: "passphrase",
RunE: func(cmd *cobra.Command, args []string) error {
config, err := getConfig()
if err != nil {
return err
}
// FIXME: parse index from CLI
fmt.Println(config.Passphrases[0])
return nil
},
})
args := os.Args[1:]
if args[0] == "entrypoint" && len(args) > 1 && args[1] != "--" {
args = append([]string{"entrypoint", "--"}, args[1:]...)
}
rootCmd.SetArgs(args)
viper.AutomaticEnv()
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
if err := rootCmd.Execute(); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}

0 comments on commit 8a560b6

Please sign in to comment.