mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/httpserver: added tlsCipherSuites flag (#2468)
* lib/httpserver: added tlsCipherSuites flag * lib/httpserver: compare lower case strings * lib/httpserver: use EqualFold * lib/httpserver: used flagutil.NewArray, supported only strings cipher suites * lib/httpserver: updated flag description, added flag to documentation * Update lib/httpserver/httpserver.go Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
ebaa1c7ad5
commit
def0032c7d
3 changed files with 111 additions and 3 deletions
|
@ -1923,6 +1923,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li
|
||||||
Path to file with TLS certificate. Used only if -tls is set. Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated
|
Path to file with TLS certificate. Used only if -tls is set. Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated
|
||||||
-tlsKeyFile string
|
-tlsKeyFile string
|
||||||
Path to file with TLS key. Used only if -tls is set. The provided key file is automatically re-read every second, so it can be dynamically updated
|
Path to file with TLS key. Used only if -tls is set. The provided key file is automatically re-read every second, so it can be dynamically updated
|
||||||
|
-tlsCipherSuites
|
||||||
|
Cipher suites names for TLS encryption. For example, TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA. Used only if -tls flag is set
|
||||||
-version
|
-version
|
||||||
Show VictoriaMetrics version
|
Show VictoriaMetrics version
|
||||||
```
|
```
|
||||||
|
|
|
@ -30,9 +30,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tlsEnable = flag.Bool("tls", false, "Whether to enable TLS (aka HTTPS) for incoming requests. -tlsCertFile and -tlsKeyFile must be set if -tls is set")
|
tlsEnable = flag.Bool("tls", false, "Whether to enable TLS (aka HTTPS) for incoming requests. -tlsCertFile and -tlsKeyFile must be set if -tls is set")
|
||||||
tlsCertFile = flag.String("tlsCertFile", "", "Path to file with TLS certificate. Used only if -tls is set. Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated")
|
tlsCertFile = flag.String("tlsCertFile", "", "Path to file with TLS certificate. Used only if -tls is set. Prefer ECDSA certs instead of RSA certs as RSA certs are slower. The provided certificate file is automatically re-read every second, so it can be dynamically updated")
|
||||||
tlsKeyFile = flag.String("tlsKeyFile", "", "Path to file with TLS key. Used only if -tls is set. The provided key file is automatically re-read every second, so it can be dynamically updated")
|
tlsKeyFile = flag.String("tlsKeyFile", "", "Path to file with TLS key. Used only if -tls is set. The provided key file is automatically re-read every second, so it can be dynamically updated")
|
||||||
|
tlsCipherSuites = flagutil.NewArray("tlsCipherSuites", "Cipher suites names for TLS encryption. For example, TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA. Used only if -tls flag is set")
|
||||||
|
|
||||||
pathPrefix = flag.String("http.pathPrefix", "", "An optional prefix to add to all the paths handled by http server. For example, if '-http.pathPrefix=/foo/bar' is set, "+
|
pathPrefix = flag.String("http.pathPrefix", "", "An optional prefix to add to all the paths handled by http server. For example, if '-http.pathPrefix=/foo/bar' is set, "+
|
||||||
"then all the http requests will be handled on '/foo/bar/*' paths. This may be useful for proxied requests. "+
|
"then all the http requests will be handled on '/foo/bar/*' paths. This may be useful for proxied requests. "+
|
||||||
|
@ -100,10 +101,18 @@ func Serve(addr string, rh RequestHandler) {
|
||||||
var certLock sync.Mutex
|
var certLock sync.Mutex
|
||||||
var certDeadline uint64
|
var certDeadline uint64
|
||||||
var cert *tls.Certificate
|
var cert *tls.Certificate
|
||||||
|
var cipherSuites []uint16
|
||||||
c, err := tls.LoadX509KeyPair(*tlsCertFile, *tlsKeyFile)
|
c, err := tls.LoadX509KeyPair(*tlsCertFile, *tlsKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf("cannot load TLS cert from tlsCertFile=%q, tlsKeyFile=%q: %s", *tlsCertFile, *tlsKeyFile, err)
|
logger.Fatalf("cannot load TLS cert from tlsCertFile=%q, tlsKeyFile=%q: %s", *tlsCertFile, *tlsKeyFile, err)
|
||||||
}
|
}
|
||||||
|
if len(*tlsCipherSuites) != 0 {
|
||||||
|
collectedCipherSuites, err := collectCipherSuites(*tlsCipherSuites)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("cannot use TLS cipher suites from tlsCipherSuites=%q: %s", *tlsCipherSuites, err)
|
||||||
|
}
|
||||||
|
cipherSuites = collectedCipherSuites
|
||||||
|
}
|
||||||
cert = &c
|
cert = &c
|
||||||
cfg := &tls.Config{
|
cfg := &tls.Config{
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
|
@ -121,6 +130,7 @@ func Serve(addr string, rh RequestHandler) {
|
||||||
}
|
}
|
||||||
return cert, nil
|
return cert, nil
|
||||||
},
|
},
|
||||||
|
CipherSuites: cipherSuites,
|
||||||
}
|
}
|
||||||
ln = tls.NewListener(ln, cfg)
|
ln = tls.NewListener(ln, cfg)
|
||||||
}
|
}
|
||||||
|
@ -687,3 +697,21 @@ func GetRequestURI(r *http.Request) string {
|
||||||
}
|
}
|
||||||
return requestURI + delimiter + queryArgs
|
return requestURI + delimiter + queryArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func collectCipherSuites(definedCipherSuites []string) ([]uint16, error) {
|
||||||
|
var cipherSuites []uint16
|
||||||
|
|
||||||
|
supportedCipherSuites := tls.CipherSuites()
|
||||||
|
supportedCipherSuitesMap := make(map[string]uint16, len(supportedCipherSuites))
|
||||||
|
for _, scf := range supportedCipherSuites {
|
||||||
|
supportedCipherSuitesMap[strings.ToLower(scf.Name)] = scf.ID
|
||||||
|
}
|
||||||
|
for _, gotSuite := range definedCipherSuites {
|
||||||
|
id, ok := supportedCipherSuitesMap[strings.ToLower(gotSuite)]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("got unsupported cipher suite name: %s", gotSuite)
|
||||||
|
}
|
||||||
|
cipherSuites = append(cipherSuites, id)
|
||||||
|
}
|
||||||
|
return cipherSuites, nil
|
||||||
|
}
|
||||||
|
|
78
lib/httpserver/httpserver_test.go
Normal file
78
lib/httpserver/httpserver_test.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package httpserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_validateCipherSuites(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
definedCipherSuites []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want []uint16
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty cipher suites",
|
||||||
|
args: args{definedCipherSuites: []string{}},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got wrong string",
|
||||||
|
args: args{definedCipherSuites: []string{"word"}},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got wrong number",
|
||||||
|
args: args{definedCipherSuites: []string{"123"}},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got correct string cipher suite",
|
||||||
|
args: args{definedCipherSuites: []string{"TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"}},
|
||||||
|
want: []uint16{0x2f, 0x35},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got correct string with different cases (upper and lower) cipher suite",
|
||||||
|
args: args{definedCipherSuites: []string{"tls_rsa_with_aes_128_cbc_sha", "TLS_RSA_WITH_AES_256_CBC_SHA"}},
|
||||||
|
want: []uint16{0x2f, 0x35},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got correct number cipher suite",
|
||||||
|
args: args{definedCipherSuites: []string{"0x2f", "0x35"}},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got insecure number cipher suite",
|
||||||
|
args: args{definedCipherSuites: []string{"0x0005", "0x000a"}},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "got insecure string cipher suite",
|
||||||
|
args: args{definedCipherSuites: []string{"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA"}},
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := collectCipherSuites(tt.args.definedCipherSuites)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("collectCipherSuites() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("validateCipherSuites() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue