diff --git a/AUTHORS b/AUTHORS index bf565389..bd75f8b1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ Kenny Keslar Konrad Wojas Matthew Holt Mebus +Michael Zimmermann Wayne Scott Zlatko Čalušić cgonzalez diff --git a/README.md b/README.md index 93eeb04b..7ff1713d 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ Flags: --prometheus enable Prometheus metrics --prometheus-no-auth disable auth for Prometheus /metrics endpoint --tls turn on TLS support + --tls-ca string TLS CA certificate path --tls-cert string TLS certificate path --tls-key string TLS key path -v, --version version for rest-server @@ -68,7 +69,7 @@ If you want to disable authentication, you must add the `--no-auth` flag. If thi NOTE: In older versions of rest-server (up to 0.9.7), this flag does not exist and the server disables authentication if `.htpasswd` is missing or cannot be opened. -By default the server uses HTTP protocol. This is not very secure since with Basic Authentication, user name and passwords will be sent in clear text 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`. +By default the server uses HTTP protocol. This is not very secure since with Basic Authentication, user name and passwords will be sent in clear text 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`. Additionally, client authentication can be enabled by passing a CA certificate to `--tls-ca`. Signed certificate is normally required by the restic backend, but if you just want to test the feature you can generate password-less unsigned keys with the following command: diff --git a/changelog/unreleased/issue-73 b/changelog/unreleased/issue-73 new file mode 100644 index 00000000..3ce2cc6b --- /dev/null +++ b/changelog/unreleased/issue-73 @@ -0,0 +1,7 @@ +Feature: TLS Client Authentication + +It is now possible to require clients to provide a certificate that was signed +by a certain CA. + +https://github.com/restic/rest-server/issues/73 +https://github.com/restic/rest-server/pull/193 diff --git a/cmd/rest-server/main.go b/cmd/rest-server/main.go index 8ed850b6..1914e116 100644 --- a/cmd/rest-server/main.go +++ b/cmd/rest-server/main.go @@ -1,8 +1,11 @@ package main import ( + "crypto/tls" + "crypto/x509" "errors" "fmt" + "io/ioutil" "log" "net/http" "os" @@ -44,6 +47,7 @@ func init() { flags.Int64Var(&server.MaxRepoSize, "max-size", server.MaxRepoSize, "the maximum size of the repository in bytes") flags.StringVar(&server.Path, "path", server.Path, "data directory") flags.BoolVar(&server.TLS, "tls", server.TLS, "turn on TLS support") + flags.StringVar(&server.TLSCACert, "tls-cacert", server.TLSCACert, "TLS CA certificate path") flags.StringVar(&server.TLSCert, "tls-cert", server.TLSCert, "TLS certificate path") flags.StringVar(&server.TLSKey, "tls-key", server.TLSKey, "TLS key path") flags.BoolVar(&server.NoAuth, "no-auth", server.NoAuth, "disable .htpasswd authentication") @@ -140,7 +144,29 @@ func runRoot(cmd *cobra.Command, args []string) error { err = http.Serve(listener, handler) } else { log.Printf("TLS enabled, private key %s, pubkey %v", privateKey, publicKey) - err = http.ServeTLS(listener, handler, publicKey, privateKey) + + httpServer := &http.Server{ + Handler: handler, + } + + if server.TLSCACert != "" { + log.Printf("TLS Client Authentication enabled, CA cert %s", server.TLSCACert) + + caCert, err := ioutil.ReadFile(server.TLSCACert) + if err != nil { + return fmt.Errorf("unable to read CA certificate: %w", err) + } + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + tlsConfig := &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, + } + httpServer.TLSConfig = tlsConfig + } + + err = httpServer.ServeTLS(listener, publicKey, privateKey) } return err diff --git a/handlers.go b/handlers.go index f1f3954c..de6e96fc 100644 --- a/handlers.go +++ b/handlers.go @@ -19,6 +19,7 @@ type Server struct { Listen string Log string CPUProfile string + TLSCACert string TLSKey string TLSCert string TLS bool