Skip to content

Commit

Permalink
Added daemonization support.
Browse files Browse the repository at this point in the history
  • Loading branch information
abourget committed May 9, 2017
1 parent 2d2d949 commit 13a8815
Show file tree
Hide file tree
Showing 22 changed files with 1,137 additions and 1 deletion.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ You can also serve a secret that is already base64 encoded, as plain-text:
secrets-bridge print key
hello-world

## Daemonization

You can start `serve` as a daemon with:

secrets-bridge serve -d daemon.log -A -w -f bridge-conf

This will daemonize and log outputs to `daemon.log` (with `-d`), it
will enable SSH-Agent forwarding (`-A`), write (`-w`) the bridge
config to `bridge-conf` (with `-f`).

You can then kill that instance with:

secrets-bridge kill -c $(cat bridge-conf)

Et hop!


## Usage with Docker

Expand Down
59 changes: 58 additions & 1 deletion cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ import (
"log"
"net/http"
"os"
"os/signal"
"regexp"
"strings"
"syscall"
"time"

"github.com/abourget/secrets-bridge/pkg/agentfwd"
"github.com/abourget/secrets-bridge/pkg/bridge"
"github.com/abourget/secrets-bridge/pkg/secrets"
daemon "github.com/sevlyar/go-daemon"
"github.com/spf13/cobra"
"golang.org/x/net/websocket"
)
Expand All @@ -27,7 +30,7 @@ var serveCmd = &cobra.Command{
Use: "serve",
Short: "Serves an SSH Agent forwarder over the network, and secrets",
Long: ``,
Run: serve,
Run: serveDaemonized,
}

var caKeyStore string
Expand All @@ -37,6 +40,7 @@ var enableSSHAgent bool
var timeout int
var insecureMode bool
var writeConf bool
var daemonize string

func init() {
RootCmd.AddCommand(serveCmd)
Expand All @@ -46,12 +50,51 @@ func init() {

serveCmd.Flags().StringVarP(&caKeyStore, "ca-key-store", "", "", "Filenam where to read/store the CA Key if you want to reuse, to avoid changing the bridge conf, thus avoiding Docker rebuilds.")
serveCmd.Flags().BoolVarP(&enableSSHAgent, "ssh-agent-forwarder", "A", false, "Enable SSH Agent forwarder. Uses env's SSH_AUTH_SOCK.")
serveCmd.Flags().StringVarP(&daemonize, "daemonize", "d", "", "Daemonize after listening socket successfully opened. The parameter is the output file to log stdout / stderr.")
serveCmd.Flags().StringSliceVar(&secretLiterals, "secret", []string{}, "Literal secret, in the form `key=value`. 'key' can be prefixed by 'b64:' or 'b64u:' to denote that the 'value' is base64-encoded or base64-url-encoded")
serveCmd.Flags().StringSliceVar(&secretsFromFiles, "secret-from-file", []string{}, "Secret from the content of a file, in the form `key=filename`. 'key' can also be prefixed by 'b64:' and 'b64u:' to indicate the encoding of the file")
serveCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Timeout in `seconds` before the server exits. Defaults to 0 (indefinite)")
serveCmd.Flags().BoolVarP(&insecureMode, "insecure", "", false, "Do not check client certificate for incoming connections")
}

func serveDaemonized(cmd *cobra.Command, args []string) {
if daemonize == "" {
serve(cmd, args)
return
}

ctx := daemon.Context{
LogFileName: daemonize,
}
child, err := ctx.Reborn()
if err != nil {
log.Fatalln("Error setting up daemon:", err)
}

if child == nil {
log.Printf("Will daemonize upon successful socket listening. pid=%d\n", os.Getpid())

serve(cmd, args)
// WARN: with all those `Fatalln` in `serve`, it's possible
// `ctx.Release()` won't get called.
ctx.Release()
return
}

log.Printf("Setting up secrets-bridge daemon, pid=%d\n", child.Pid)

// Parent, waiting for Listen signal, then exits.
childReady := make(chan os.Signal, 5)
signal.Notify(childReady, syscall.SIGUSR1)
select {
case <-childReady:
log.Println("Setup successfully.")
return
case <-time.After(5 * time.Second):
log.Fatalln("Failed. Timed out")
}
}

func serve(cmd *cobra.Command, args []string) {
confFile := bridgeConfFilenameWithDefault()
var b *bridge.Bridge
Expand Down Expand Up @@ -200,6 +243,20 @@ func serve(cmd *cobra.Command, args []string) {
}()
}

if daemonize != "" {
time.Sleep(100 * time.Millisecond)
proc, err := os.FindProcess(os.Getppid())
if err != nil {
log.Fatalln("Couldn't find parent process id:", err)
}

log.Println("Daemonizing")

if err := proc.Signal(syscall.SIGUSR1); err != nil {
log.Fatalln("couldn't send SIGUSR1 signal to parent:", err)
}
}

<-done
}

Expand Down
27 changes: 27 additions & 0 deletions vendor/github.com/kardianos/osext/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions vendor/github.com/kardianos/osext/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions vendor/github.com/kardianos/osext/osext.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions vendor/github.com/kardianos/osext/osext_go18.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions vendor/github.com/kardianos/osext/osext_plan9.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions vendor/github.com/kardianos/osext/osext_procfs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 13a8815

Please sign in to comment.