Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement TLS client authentication #193

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Kenny Keslar <[email protected]>
Konrad Wojas <[email protected]>
Matthew Holt <[email protected]>
Mebus <[email protected]>
Michael Zimmermann <[email protected]>
Wayne Scott <[email protected]>
Zlatko Čalušić <[email protected]>
cgonzalez <[email protected]>
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:

Expand Down
7 changes: 7 additions & 0 deletions changelog/unreleased/issue-73
Original file line number Diff line number Diff line change
@@ -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
28 changes: 27 additions & 1 deletion cmd/rest-server/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package main

import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Server struct {
Listen string
Log string
CPUProfile string
TLSCACert string
TLSKey string
TLSCert string
TLS bool
Expand Down