cli: Allow accepting requests over HTTPS (#423)

* Add TLS support to tusd

* Adds `-tls-certificate`, `-tls-key`, and `-tls-mode` flags
* Alter printed URL to reflect protocol in use
* For non-TLS, do an eary-exit if http.Serve() returns
* Configure TLS for the following modes
    * TLSv1.3-only
    * (default) TLSv1.3+TLSv1.2, with recommended ciphersuites from Mozilla + matching RSA key transport modes
    * TLSv1.2 only, with only 256-bit AES ciphersuites
* All modes disable HTTP/2, given that it’s not supported in non-TLS mode
* Update documentation

* * Remove RSA-based key transport ciphersuites as they don’t support forward secrecy

* Improve the TLS/HTTPS example in the usage documentation

Signed-off-by: Joey Coleman <joey.coleman@kirasystems.com>

* Update docs further to a) record that the key file must be unencrypted, and b) clean up the RSA-based ciphersuite comments.
This commit is contained in:
Joey Coleman 2020-09-29 09:19:10 -04:00 committed by GitHub
parent ed85c526cb
commit f4d1b7c443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 5 deletions

View File

@ -40,6 +40,9 @@ var Flags struct {
BehindProxy bool
VerboseOutput bool
S3TransferAcceleration bool
TLSCertFile string
TLSKeyFile string
TLSMode string
}
func ParseFlags() {
@ -73,6 +76,9 @@ func ParseFlags() {
flag.BoolVar(&Flags.BehindProxy, "behind-proxy", false, "Respect X-Forwarded-* and similar headers which may be set by proxies")
flag.BoolVar(&Flags.VerboseOutput, "verbose", true, "Enable verbose logging output")
flag.BoolVar(&Flags.S3TransferAcceleration, "s3-transfer-acceleration", false, "Use AWS S3 transfer acceleration endpoint (requires -s3-bucket option and Transfer Acceleration property on S3 bucket to be set)")
flag.StringVar(&Flags.TLSCertFile, "tls-certificate", "", "Path to the file containing the x509 TLS certificate to be used. The file should also contain any intermediate certificates and the CA certificate.")
flag.StringVar(&Flags.TLSKeyFile, "tls-key", "", "Path to the file containing the key for the TLS certificate.")
flag.StringVar(&Flags.TLSMode, "tls-mode", "tls12", "Specify which TLS mode to use; valid modes are tls13, tls12, and tls12-strong.")
flag.Parse()
SetEnabledHooks()

View File

@ -1,6 +1,7 @@
package cli
import (
"crypto/tls"
"net"
"net/http"
"strings"
@ -9,6 +10,12 @@ import (
"github.com/tus/tusd/pkg/handler"
)
const (
TLS13 = "tls13"
TLS12 = "tls12"
TLS12STRONG = "tls12-strong"
)
// Setups the different components, starts a Listener and give it to
// http.Serve().
//
@ -88,11 +95,68 @@ func Serve() {
stderr.Fatalf("Unable to create listener: %s", err)
}
if Flags.HttpSock == "" {
stdout.Printf("You can now upload files to: http://%s%s", address, basepath)
protocol := "http"
if Flags.TLSCertFile != "" && Flags.TLSKeyFile != "" {
protocol = "https"
}
if err = http.Serve(listener, nil); err != nil {
if Flags.HttpSock == "" {
stdout.Printf("You can now upload files to: %s://%s%s", protocol, address, basepath)
}
// If we're not using TLS just start the server and, if http.Serve() returns, just return.
if protocol == "http" {
if err = http.Serve(listener, nil); err != nil {
stderr.Fatalf("Unable to serve: %s", err)
}
return
}
// Fall-through for TLS mode.
server := &http.Server{}
switch Flags.TLSMode {
case TLS13:
server.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS13}
case TLS12:
// Ciphersuite selection comes from
// https://ssl-config.mozilla.org/#server=go&version=1.14.4&config=intermediate&guideline=5.6
// 128-bit AES modes remain as TLSv1.3 is enabled in this mode, and TLSv1.3 compatibility requires an AES-128 ciphersuite.
server.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
PreferServerCipherSuites: true,
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,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
},
}
case TLS12STRONG:
// Ciphersuite selection as above, but intersected with
// https://github.com/denji/golang-tls#perfect-ssl-labs-score-with-go
// TLSv1.3 is disabled as it requires an AES-128 ciphersuite.
server.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS12,
PreferServerCipherSuites: true,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
},
}
default:
stderr.Fatalf("Invalid TLS mode chosen. Recommended valid modes are tls13, tls12 (default), and tls12-strong")
}
// Disable HTTP/2; the default non-TLS mode doesn't support it
server.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0)
if err = server.ServeTLS(listener, Flags.TLSCertFile, Flags.TLSKeyFile); err != nil {
stderr.Fatalf("Unable to serve: %s", err)
}
}

View File

@ -2,7 +2,9 @@
### How can I access tusd using HTTPS?
The tusd binary, once executed, listens on the provided port for only non-encrypted HTTP requests and *does not accept* HTTPS connections. This decision has been made to limit the functionality inside this repository which has to be developed, tested and maintained. If you want to send requests to tusd in a secure fashion - what we absolutely encourage, we recommend you to utilize a reverse proxy in front of tusd which accepts incoming HTTPS connections and forwards them to tusd using plain HTTP. More information about this topic, including sample configurations for Nginx and Apache, can be found in [issue #86](https://github.com/tus/tusd/issues/86#issuecomment-269569077) and in the [Apache example configuration](/examples/apache2.conf).
Enable HTTPS by using the `-tls-certificate` and `-tls-key` flags. Note that the support for HTTPS is limited to a small subset of the many possible TLS configuration options. Available options are TLSv1.3-only; TLSv1.3+TLSv1.2 with support cipher suites per the guidelines on [Mozilla's SSL Configuration Generator](https://ssl-config.mozilla.org/#server=go&version=1.14.4&config=intermediate&guideline=5.6); and TLSv1.2 with 256-bit AES ciphers only. Also note that the key file must not be encrypted/require a passphrase.
If your needs are more complex than provided for here, you will need to use a reverse proxy in front of tusd. This includes further fine-tuning of ciphers, and the addition of things like HSTS headers. More information about this topic, including sample configurations for Nginx and Apache, can be found in [issue #86](https://github.com/tus/tusd/issues/86#issuecomment-269569077) and in the [Apache example configuration](/examples/apache2.conf); rationale for why HTTPS is supported at all can be found in [issue #418](https://github.com/tus/tusd/issues/418).
### Can I run tusd behind a reverse proxy?

View File

@ -67,6 +67,26 @@ $ tusd -gcs-bucket=my-test-bucket.com
[tusd] Using /metrics as the metrics path.
```
TLS support for HTTPS connections can be enabled by supplying a certificate and private key. Note that the certificate file must include the entire chain of certificates up to the CA certificate. The default configuration supports TLSv1.2 and TLSv1.3. It is possible to use only TLSv1.3 with `-tls-mode=tls13`; alternately, it is possible to disable TLSv1.3 and use only 256-bit AES ciphersuites with `-tls-mode=tls12-strong`. The following example generates a self-signed certificate for `localhost` and then uses it to serve files on the loopback address; that this certificate is not appropriate for production use. Note also that the key file must not be encrypted/require a passphrase.
```
$ openssl req -x509 -new -newkey rsa:4096 -nodes -sha256 -days 3650 -keyout localhost.key -out localhost.pem -subj "/CN=localhost"
Generating a 4096 bit RSA private key
........................++
..........................................++
writing new private key to 'localhost.key'
-----
$ tusd -upload-dir=./data -host=127.0.0.1 -port=8443 -tls-certificate=localhost.pem -tls-key=localhost.key
[tusd] Using './data' as directory storage.
[tusd] Using 0.00MB as maximum size.
[tusd] Using 127.0.0.1:8443 as address to listen.
[tusd] Using /files/ as the base path.
[tusd] Using /metrics as the metrics path.
[tusd] Supported tus extensions: creation,creation-with-upload,termination,concatenation,creation-defer-length
[tusd] You can now upload files to: https://127.0.0.1:8443/files/
```
Besides these simple examples, tusd can be easily configured using a variety of command line
options:
@ -86,7 +106,7 @@ Usage of tusd:
-hooks-dir string
Directory to search for available hooks scripts
-hooks-enabled-events string
Comma separated list of enabled hook events (e.g. post-create,post-finish). Leave empty to enable all events (default "pre-create,post-create,post-receive,post-terminate,post-finish")
Comma separated list of enabled hook events (e.g. post-create,post-finish). Leave empty to enable default events (default "pre-create,post-create,post-receive,post-terminate,post-finish")
-hooks-grpc string
An gRPC endpoint to which hook events will be sent to
-hooks-grpc-backoff int
@ -97,6 +117,8 @@ Usage of tusd:
An HTTP endpoint to which hook events will be sent to
-hooks-http-backoff int
Number of seconds to wait before retrying each retry (default 1)
-hooks-http-forward-headers string
List of HTTP request headers to be forwarded from the client request to the hook endpoint
-hooks-http-retry int
Number of times to retry on a 500 or network timeout (default 3)
-hooks-plugin string
@ -117,8 +139,18 @@ Usage of tusd:
Endpoint to use S3 compatible implementations like minio (requires s3-bucket to be pass)
-s3-object-prefix string
Prefix for S3 object names
-s3-part-size int
Size in bytes of the individual upload requests made to the S3 API. Defaults to 50MiB (experimental and may be removed in the future) (default 52428800)
-s3-transfer-acceleration
Use AWS S3 transfer acceleration endpoint (requires -s3-bucket option and Transfer Acceleration property on S3 bucket to be set)
-timeout int
Read timeout for connections in milliseconds. A zero value means that reads will not timeout (default 6000)
-tls-certificate string
Path to the file containing the x509 TLS certificate to be used. The file should also contain any intermediate certificates and the CA certificate.
-tls-key string
Path to the file containing the key for the TLS certificate.
-tls-mode string
Specify which TLS mode to use; valid modes are tls13, tls12, and tls12-strong. (default "tls12")
-unix-sock string
If set, will listen to a UNIX socket at this location instead of a TCP socket
-upload-dir string