Hardened tls cipher suits and added option for tls min version (#315)

* handlers.go: Added parameter for TLS min version

rest-server/main.go: Added parameter handling for TLS min version

rest-server/main.go: Added crypto.tls, implemented and configured tlsConfig object

* tls min version parameter documentation

* Added changelog documentation

* README.md: Fixed typo

main.go: Added error for unknown TLS min versions

main.go: Changed CurvePreferences in TLS config to Go default

main.go: Removed handling for TLS min versions 1.0 and 1.1

Signed-off-by: darkspir <forgejo.darkspir@teemitmil.ch>

* main.go: Improved TLSMinVer parameter documentation

* README.md: Improved --tls-min-ver parameter documentation

* main.go: Changed --tls-min-ver parameter documentation again

* main.go: Added allowed versions in Error Unsupported TLS min version

* update rest-server help output in readme

---------

Signed-off-by: darkspir <forgejo.darkspir@teemitmil.ch>
Co-authored-by: Michael Eischer <michael.eischer@fau.de>
This commit is contained in:
DarkSpir 2025-04-14 19:09:57 +00:00 committed by GitHub
parent dbf5253ac2
commit 2b6f0b39fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 56 additions and 22 deletions

View file

@ -32,24 +32,27 @@ Usage:
rest-server [flags] rest-server [flags]
Flags: Flags:
--append-only enable append only mode --append-only enable append only mode
--cpu-profile string write CPU profile to file --cpu-profile string write CPU profile to file
--debug output debug messages --debug output debug messages
-h, --help help for rest-server --group-accessible-repos let filesystem group be able to access repo files
--htpasswd-file string location of .htpasswd file (default: "<data directory>/.htpasswd") -h, --help help for rest-server
--listen string listen address (default ":8000") --htpasswd-file string location of .htpasswd file (default: "<data directory>/.htpasswd)"
--log filename write HTTP requests in the combined log format to the specified filename --listen string listen address (default ":8000")
--max-size int the maximum size of the repository in bytes --log filename write HTTP requests in the combined log format to the specified filename (use "-" for logging to stdout)
--no-auth disable .htpasswd authentication --max-size int the maximum size of the repository in bytes
--no-verify-upload do not verify the integrity of uploaded data. DO NOT enable unless the rest-server runs on a very low-power device --no-auth disable .htpasswd authentication
--path string data directory (default "/tmp/restic") --no-verify-upload do not verify the integrity of uploaded data. DO NOT enable unless the rest-server runs on a very low-power device
--private-repos users can only access their private repo --path string data directory (default "/tmp/restic")
--prometheus enable Prometheus metrics --private-repos users can only access their private repo
--prometheus-no-auth disable auth for Prometheus /metrics endpoint --prometheus enable Prometheus metrics
--tls turn on TLS support --prometheus-no-auth disable auth for Prometheus /metrics endpoint
--tls-cert string TLS certificate path --proxy-auth-username string specifies the HTTP header containing the username for proxy-based authentication
--tls-key string TLS key path --tls turn on TLS support
-v, --version version for rest-server --tls-cert string TLS certificate path
--tls-key string TLS key path
--tls-min-ver string TLS min version, one of (1.2|1.3) (default "1.2")
-v, --version version for rest-server
``` ```
By default the server persists backup data in the OS temporary directory (`/tmp/restic` on Linux/BSD and others, in `%TEMP%\\restic` in Windows, etc). **If `rest-server` is launched using the default path, all backups will be lost**. To start the server with a custom persistence directory and with authentication disabled: By default the server persists backup data in the OS temporary directory (`/tmp/restic` on Linux/BSD and others, in `%TEMP%\\restic` in Windows, etc). **If `rest-server` is launched using the default path, all backups will be lost**. To start the server with a custom persistence directory and with authentication disabled:
@ -68,7 +71,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`. 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`.
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,6 @@
Enhancement: Hardened tls settings
rest-server now uses a secure tls cipher suit set and the minimal TLS version
can be set with the option `--tls-min-ver`
https://github.com/restic/rest-server/pull/315

View file

@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"log" "log"
@ -45,8 +46,9 @@ func newRestServerApp() *restServerApp {
Version: fmt.Sprintf("rest-server %s compiled with %v on %v/%v\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH), Version: fmt.Sprintf("rest-server %s compiled with %v on %v/%v\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH),
}, },
Server: restserver.Server{ Server: restserver.Server{
Path: filepath.Join(os.TempDir(), "restic"), Path: filepath.Join(os.TempDir(), "restic"),
Listen: ":8000", Listen: ":8000",
TLSMinVer: "1.2",
}, },
} }
rv.CmdRoot.RunE = rv.runRoot rv.CmdRoot.RunE = rv.runRoot
@ -61,6 +63,7 @@ func newRestServerApp() *restServerApp {
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.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.BoolVar(&rv.Server.NoAuth, "no-auth", rv.Server.NoAuth, "disable authentication") flags.BoolVar(&rv.Server.NoAuth, "no-auth", rv.Server.NoAuth, "disable authentication")
flags.StringVar(&rv.Server.HtpasswdPath, "htpasswd-file", rv.Server.HtpasswdPath, "location of .htpasswd file (default: \"<data directory>/.htpasswd)\"") flags.StringVar(&rv.Server.HtpasswdPath, "htpasswd-file", rv.Server.HtpasswdPath, "location of .htpasswd file (default: \"<data directory>/.htpasswd)\"")
flags.StringVar(&rv.Server.ProxyAuthUsername, "proxy-auth-username", rv.Server.ProxyAuthUsername, "specifies the HTTP header containing the username for proxy-based authentication") flags.StringVar(&rv.Server.ProxyAuthUsername, "proxy-auth-username", rv.Server.ProxyAuthUsername, "specifies the HTTP header containing the username for proxy-based authentication")
@ -176,8 +179,29 @@ func (app *restServerApp) runRoot(_ *cobra.Command, _ []string) error {
app.listenerAddress = listener.Addr() app.listenerAddress = listener.Addr()
app.listenerAddressMu.Unlock() app.listenerAddressMu.Unlock()
tlscfg := &tls.Config{
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
},
}
switch app.Server.TLSMinVer {
case "1.2":
tlscfg.MinVersion = tls.VersionTLS12
case "1.3":
tlscfg.MinVersion = tls.VersionTLS13
default:
return fmt.Errorf("Unsupported TLS min version: %s. Allowed versions are 1.2 or 1.3", app.Server.TLSMinVer)
}
srv := &http.Server{ srv := &http.Server{
Handler: handler, Handler: handler,
TLSConfig: tlscfg,
} }
// run server in background // run server in background

View file

@ -22,6 +22,7 @@ type Server struct {
CPUProfile string CPUProfile string
TLSKey string TLSKey string
TLSCert string TLSCert string
TLSMinVer string
TLS bool TLS bool
NoAuth bool NoAuth bool
ProxyAuthUsername string ProxyAuthUsername string