mirror of
https://github.com/cloudflare/redoctober.git
synced 2025-12-23 06:15:45 +00:00
Add the ability to listen to systemd-provided sockets.
Add a new flag, -systemdfds, which causes Red October to expect to be provisioned on launch with file descriptors for sockets opened by systemd. This is useful for socket activation, but also allows systemd to bind privileged ports for us. I've included example systemd configuration files that successfully start Red October as a service user without admin rights but bound to 443 in a Jessie VM for me. They need to be installed where systemd expects them, which on Jessie is /etc/systemd/system/redoctober.service and /etc/systemd/system/sockets.target.wants/redoctober.socket.
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/redoctober/core"
|
||||
"github.com/coreos/go-systemd/activation"
|
||||
)
|
||||
|
||||
// List of URLs to register and their related functions
|
||||
@@ -82,7 +83,7 @@ func queueRequest(process chan<- userRequest, requestType string, w http.Respons
|
||||
//
|
||||
// Returns a valid http.Server handling redoctober JSON requests (and
|
||||
// its associated listener) or an error
|
||||
func NewServer(process chan<- userRequest, staticPath, addr, certPath, keyPath, caPath string) (*http.Server, *net.Listener, error) {
|
||||
func NewServer(process chan<- userRequest, staticPath, addr, certPath, keyPath, caPath string, useSystemdSocket bool) (*http.Server, *net.Listener, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Error loading certificate (%s, %s): %s", certPath, keyPath, err)
|
||||
@@ -122,13 +123,25 @@ func NewServer(process chan<- userRequest, staticPath, addr, certPath, keyPath,
|
||||
config.ClientCAs = rootPool
|
||||
}
|
||||
|
||||
conn, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Error starting TCP listener on %s: %s\n", addr, err)
|
||||
var lstnr net.Listener
|
||||
if useSystemdSocket {
|
||||
listenFDs, err := activation.Listeners(true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(listenFDs) != 1 {
|
||||
log.Fatal("Unexpected number of socket activation FDs!")
|
||||
}
|
||||
lstnr = listenFDs[0]
|
||||
} else {
|
||||
conn, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Error starting TCP listener on %s: %s\n", addr, err)
|
||||
}
|
||||
|
||||
lstnr = tls.NewListener(conn, &config)
|
||||
|
||||
}
|
||||
|
||||
lstnr := tls.NewListener(conn, &config)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// queue up post URIs
|
||||
@@ -198,12 +211,13 @@ func main() {
|
||||
var staticPath = flag.String("static", "", "Path to override built-in index.html")
|
||||
var vaultPath = flag.String("vaultpath", "diskrecord.json", "Path to the the disk vault")
|
||||
var addr = flag.String("addr", "localhost:8080", "Server and port separated by :")
|
||||
var useSystemdSocket = flag.Bool("systemdfds", false, "Use systemd socket activation to listen on a file. Useful for binding privileged sockets.")
|
||||
var certPath = flag.String("cert", "", "Path of TLS certificate in PEM format")
|
||||
var keyPath = flag.String("key", "", "Path of TLS private key in PEM format")
|
||||
var caPath = flag.String("ca", "", "Path of TLS CA for client authentication (optional)")
|
||||
flag.Parse()
|
||||
|
||||
if *vaultPath == "" || *addr == "" || *certPath == "" || *keyPath == "" {
|
||||
if *vaultPath == "" || (*addr == "" && *useSystemdSocket == false) || *certPath == "" || *keyPath == "" {
|
||||
fmt.Fprint(os.Stderr, usage)
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
@@ -243,7 +257,7 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
s, l, err := NewServer(process, *staticPath, *addr, *certPath, *keyPath, *caPath)
|
||||
s, l, err := NewServer(process, *staticPath, *addr, *certPath, *keyPath, *caPath, *useSystemdSocket)
|
||||
if err != nil {
|
||||
log.Fatalf("Error starting redoctober server: %s\n", err)
|
||||
}
|
||||
|
||||
26
redoctober.service
Normal file
26
redoctober.service
Normal file
@@ -0,0 +1,26 @@
|
||||
# An example service file for systemd-managed Red October, for use
|
||||
# with the accompanying socket file. Useful for running as an
|
||||
# unprivileged user while binding to a privileged port, for example.
|
||||
|
||||
[Unit]
|
||||
Description='Red October'
|
||||
|
||||
Requires=network.target
|
||||
After=multi-user.target
|
||||
|
||||
[Exec]
|
||||
User=redoctober
|
||||
Group=redoctober
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/sbin/redoctober -vaultpath=/etc/redoctober/diskrecord.json -cert=/etc/redoctober/cert/server.crt -key=/etc/redoctober/cert/server.pem -systemdfds
|
||||
User=redoctober
|
||||
Group=redoctober
|
||||
SyslogIdentifier=redoctober
|
||||
StandardOutput=syslog
|
||||
StandardError=inherit
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
10
redoctober.socket
Normal file
10
redoctober.socket
Normal file
@@ -0,0 +1,10 @@
|
||||
# Example socket file, instructing systemd to bind 443. Used by the
|
||||
# corresponding redoctober.service target to launch a socket-activated
|
||||
# Red October instance that can run unprivileged but bind to a
|
||||
# privileged port.
|
||||
|
||||
[Socket]
|
||||
ListenStream=127.0.0.1:443
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
Reference in New Issue
Block a user