Implement TLS client authentication

This commit is contained in:
Michael Zimmermann 2022-06-22 12:15:18 +02:00
parent ad130de021
commit 0171dcf297
5 changed files with 28 additions and 1 deletions

View file

@ -10,6 +10,7 @@ Kenny Keslar <r3dey3@r3dey3.com>
Konrad Wojas <github@m.wojas.nl> Konrad Wojas <github@m.wojas.nl>
Matthew Holt <mholt@users.noreply.github.com> Matthew Holt <mholt@users.noreply.github.com>
Mebus <mebus.inbox@googlemail.com> Mebus <mebus.inbox@googlemail.com>
Michael Zimmermann <sigmaepsilon92@gmail.com>
Wayne Scott <wsc9tt@gmail.com> Wayne Scott <wsc9tt@gmail.com>
Zlatko Čalušić <zcalusic@bitsync.net> Zlatko Čalušić <zcalusic@bitsync.net>
cgonzalez <chgonzalezg@gmail.com> cgonzalez <chgonzalezg@gmail.com>

View file

@ -49,6 +49,7 @@ Flags:
--prometheus-no-auth disable auth for Prometheus /metrics endpoint --prometheus-no-auth disable auth for Prometheus /metrics endpoint
--proxy-auth-username string specifies the HTTP header containing the username for proxy-based authentication --proxy-auth-username string specifies the HTTP header containing the username for proxy-based authentication
--tls turn on TLS support --tls turn on TLS support
--tls-ca string TLS CA certificate path
--tls-cert string TLS certificate path --tls-cert string TLS certificate path
--tls-key string TLS key path --tls-key string TLS key path
--tls-min-ver string TLS min version, one of (1.2|1.3) (default "1.2") --tls-min-ver string TLS min version, one of (1.2|1.3) (default "1.2")
@ -71,7 +72,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. 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` and set the minimum TLS version to 1.3 using `--tls-min-ver 1.3`. 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` and set the minimum TLS version to 1.3 using `--tls-min-ver 1.3`. Additionally, client authentication can be enabled by passing a CA certificate to `--tls-cacert`.
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: 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:

View file

@ -0,0 +1,7 @@
Enhancement: 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

View file

@ -3,8 +3,10 @@ package main
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"net" "net"
"net/http" "net/http"
@ -61,6 +63,7 @@ func newRestServerApp() *restServerApp {
flags.Int64Var(&rv.Server.MaxRepoSize, "max-size", rv.Server.MaxRepoSize, "the maximum size of the repository in bytes") flags.Int64Var(&rv.Server.MaxRepoSize, "max-size", rv.Server.MaxRepoSize, "the maximum size of the repository in bytes")
flags.StringVar(&rv.Server.Path, "path", rv.Server.Path, "data directory") flags.StringVar(&rv.Server.Path, "path", rv.Server.Path, "data directory")
flags.BoolVar(&rv.Server.TLS, "tls", rv.Server.TLS, "turn on TLS support") flags.BoolVar(&rv.Server.TLS, "tls", rv.Server.TLS, "turn on TLS support")
flags.StringVar(&rv.Server.TLSCACert, "tls-cacert", rv.Server.TLSCACert, "TLS CA certificate path")
flags.StringVar(&rv.Server.TLSCert, "tls-cert", rv.Server.TLSCert, "TLS certificate path") flags.StringVar(&rv.Server.TLSCert, "tls-cert", rv.Server.TLSCert, "TLS certificate path")
flags.StringVar(&rv.Server.TLSKey, "tls-key", rv.Server.TLSKey, "TLS key path") flags.StringVar(&rv.Server.TLSKey, "tls-key", rv.Server.TLSKey, "TLS key path")
flags.StringVar(&rv.Server.TLSMinVer, "tls-min-ver", rv.Server.TLSMinVer, "TLS min version, one of (1.2|1.3)") flags.StringVar(&rv.Server.TLSMinVer, "tls-min-ver", rv.Server.TLSMinVer, "TLS min version, one of (1.2|1.3)")
@ -199,6 +202,20 @@ func (app *restServerApp) runRoot(_ *cobra.Command, _ []string) error {
return fmt.Errorf("Unsupported TLS min version: %s. Allowed versions are 1.2 or 1.3", app.Server.TLSMinVer) return fmt.Errorf("Unsupported TLS min version: %s. Allowed versions are 1.2 or 1.3", app.Server.TLSMinVer)
} }
if app.Server.TLSCACert != "" {
log.Printf("TLS Client Authentication enabled, CA cert %s", app.Server.TLSCACert)
caCert, err := ioutil.ReadFile(app.Server.TLSCACert)
if err != nil {
return fmt.Errorf("unable to read CA certificate: %w", err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlscfg.ClientAuth = tls.RequireAndVerifyClientCert
tlscfg.ClientCAs = caCertPool
}
srv := &http.Server{ srv := &http.Server{
Handler: handler, Handler: handler,
TLSConfig: tlscfg, TLSConfig: tlscfg,

View file

@ -20,6 +20,7 @@ type Server struct {
Listen string Listen string
Log string Log string
CPUProfile string CPUProfile string
TLSCACert string
TLSKey string TLSKey string
TLSCert string TLSCert string
TLSMinVer string TLSMinVer string