add option to secify tls cert and tls key as params

fix  #35
This commit is contained in:
n0npax 2017-11-23 20:07:39 +01:00 committed by Zlatko Čalušić
parent 1bc1698f4e
commit b786c5d1cc
4 changed files with 111 additions and 9 deletions

View file

@ -74,6 +74,9 @@ Flags:
--path string data directory (default "/tmp/restic") --path string data directory (default "/tmp/restic")
--prometheus enable Prometheus metrics --prometheus enable Prometheus metrics
--tls turn on TLS support --tls turn on TLS support
--tls-cert string TLS certificate path
--tls-key string TLS key path
``` ```
By default the server persists backup data in `/tmp/restic`. Start the server with a custom persistence directory: By default the server persists backup data in `/tmp/restic`. Start the server with a custom persistence directory:
@ -88,7 +91,7 @@ The server uses an `.htpasswd` file to specify users. You can create such a fil
htpasswd -s -c .htpasswd username htpasswd -s -c .htpasswd username
``` ```
By default the server uses HTTP protocol. This is not very secure since with Basic Authentication, username and passwords will travel in cleartext in every request. In order to enable TLS support just add the `-tls` argument and add a private and public key at the root of your persistence directory. By default the server uses HTTP protocol. This is not very secure since with Basic Authentication, username and passwords will travel in cleartext in every request. In order to enable TLS support just add the `-tls` argument and add a private and public key at the root of your persistence directory. You may also specify private and public keys by --tls-cert and --tls-key
Signed certificate is required by the restic backend, but if you just want to test the feature you can generate unsigned keys with the following commands: Signed certificate is required by the restic backend, but if you just want to test the feature you can generate unsigned keys with the following commands:

View file

@ -1,15 +1,15 @@
package main package main
import ( import (
"errors"
restserver "github.com/restic/rest-server"
"github.com/spf13/cobra"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"runtime/pprof" "runtime/pprof"
restserver "github.com/restic/rest-server"
"github.com/spf13/cobra"
) )
// cmdRoot is the base command when no other command has been specified. // cmdRoot is the base command when no other command has been specified.
@ -29,12 +29,35 @@ func init() {
flags.StringVar(&restserver.Config.Log, "log", restserver.Config.Log, "log HTTP requests in the combined log format") flags.StringVar(&restserver.Config.Log, "log", restserver.Config.Log, "log HTTP requests in the combined log format")
flags.StringVar(&restserver.Config.Path, "path", restserver.Config.Path, "data directory") flags.StringVar(&restserver.Config.Path, "path", restserver.Config.Path, "data directory")
flags.BoolVar(&restserver.Config.TLS, "tls", restserver.Config.TLS, "turn on TLS support") flags.BoolVar(&restserver.Config.TLS, "tls", restserver.Config.TLS, "turn on TLS support")
flags.StringVar(&restserver.Config.TLSCert, "tls-cert", restserver.Config.TLSCert, "TLS certificate path")
flags.StringVar(&restserver.Config.TLSKey, "tls-key", restserver.Config.TLSKey, "TLS key path")
flags.BoolVar(&restserver.Config.AppendOnly, "append-only", restserver.Config.AppendOnly, "enable append only mode") flags.BoolVar(&restserver.Config.AppendOnly, "append-only", restserver.Config.AppendOnly, "enable append only mode")
flags.BoolVar(&restserver.Config.Prometheus, "prometheus", restserver.Config.Prometheus, "enable Prometheus metrics") flags.BoolVar(&restserver.Config.Prometheus, "prometheus", restserver.Config.Prometheus, "enable Prometheus metrics")
} }
var version = "manually" var version = "manually"
func tlsSettings() (bool, string, string, error) {
var key, cert string
enabledTLS := restserver.Config.TLS
if !enabledTLS && (restserver.Config.TLSKey != "" || restserver.Config.TLSCert != "") {
return false, "", "", errors.New("requires enabled TLS")
} else if !enabledTLS {
return false, "", "", nil
}
if restserver.Config.TLSKey != "" {
key = restserver.Config.TLSKey
} else {
key = filepath.Join(restserver.Config.Path, "private_key")
}
if restserver.Config.TLSCert != "" {
cert = restserver.Config.TLSCert
} else {
cert = filepath.Join(restserver.Config.Path, "public_key")
}
return enabledTLS, key, cert, nil
}
func runRoot(cmd *cobra.Command, args []string) error { func runRoot(cmd *cobra.Command, args []string) error {
log.SetFlags(0) log.SetFlags(0)
@ -65,22 +88,24 @@ func runRoot(cmd *cobra.Command, args []string) error {
log.Println("Authentication enabled") log.Println("Authentication enabled")
} }
if !restserver.Config.TLS { enabledTLS, privateKey, publicKey, err := tlsSettings()
if err != nil {
return err
}
if !enabledTLS {
log.Printf("Starting server on %s\n", restserver.Config.Listen) log.Printf("Starting server on %s\n", restserver.Config.Listen)
err = http.ListenAndServe(restserver.Config.Listen, handler) err = http.ListenAndServe(restserver.Config.Listen, handler)
} else { } else {
privateKey := filepath.Join(restserver.Config.Path, "private_key")
publicKey := filepath.Join(restserver.Config.Path, "public_key")
log.Println("TLS enabled") log.Println("TLS enabled")
log.Printf("Private key: %s", privateKey) log.Printf("Private key: %s", privateKey)
log.Printf("Public key: %s", publicKey) log.Printf("Public key(certificate): %s", publicKey)
log.Printf("Starting server on %s\n", restserver.Config.Listen) log.Printf("Starting server on %s\n", restserver.Config.Listen)
err = http.ListenAndServeTLS(restserver.Config.Listen, publicKey, privateKey, handler) err = http.ListenAndServeTLS(restserver.Config.Listen, publicKey, privateKey, handler)
} }
return err return err
} }
func main() { func main() {
if err := cmdRoot.Execute(); err != nil { if err := cmdRoot.Execute(); err != nil {
log.Fatalf("error: %v", err) log.Fatalf("error: %v", err)

View file

@ -0,0 +1,72 @@
package main
import (
restserver "github.com/restic/rest-server"
"testing"
)
func TestTLSSettings(t *testing.T) {
type expected struct {
TLSKey string
TLSCert string
Error bool
}
type passed struct {
Path string
TLS bool
TLSKey string
TLSCert string
}
var tests = []struct {
passed passed
expected expected
}{
{passed{TLS: false}, expected{"", "", false}},
{passed{TLS: true}, expected{"/tmp/restic/private_key", "/tmp/restic/public_key", false}},
{passed{Path: "/tmp", TLS: true}, expected{"/tmp/private_key", "/tmp/public_key", false}},
{passed{Path: "/tmp", TLS: true, TLSKey: "/etc/restic/key", TLSCert: "/etc/restic/cert"}, expected{"/etc/restic/key", "/etc/restic/cert", false}},
{passed{Path: "/tmp", TLS: false, TLSKey: "/etc/restic/key", TLSCert: "/etc/restic/cert"}, expected{"", "", true}},
{passed{Path: "/tmp", TLS: false, TLSKey: "/etc/restic/key"}, expected{"", "", true}},
{passed{Path: "/tmp", TLS: false, TLSCert: "/etc/restic/cert"}, expected{"", "", true}},
}
defaultConfig := restserver.Config
for _, test := range tests {
t.Run("", func(t *testing.T) {
defer func() { restserver.Config = defaultConfig }()
if test.passed.Path != "" {
restserver.Config.Path = test.passed.Path
}
restserver.Config.TLS = test.passed.TLS
restserver.Config.TLSKey = test.passed.TLSKey
restserver.Config.TLSCert = test.passed.TLSCert
gotTLS, gotKey, gotCert, err := tlsSettings()
if err != nil && !test.expected.Error {
t.Fatalf("tls_settings returned err (%v)", err)
}
if test.expected.Error {
if err == nil {
t.Fatalf("Error not returned properly (%v)", test)
} else {
return
}
}
if gotTLS != test.passed.TLS {
t.Errorf("TLS enabled, want (%v), got (%v)", test.passed.TLS, gotTLS)
}
wantKey := test.expected.TLSKey
if gotKey != wantKey {
t.Errorf("wrong TLSPrivPath path, want (%v), got (%v)", wantKey, gotKey)
}
wantCert := test.expected.TLSCert
if gotCert != wantCert {
t.Errorf("wrong TLSCertPath path, want (%v), got (%v)", wantCert, gotCert)
}
})
}
}

2
mux.go
View file

@ -19,6 +19,8 @@ var Config = struct {
Log string Log string
CPUProfile string CPUProfile string
TLS bool TLS bool
TLSKey string
TLSCert string
AppendOnly bool AppendOnly bool
Prometheus bool Prometheus bool
Debug bool Debug bool