-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow config of TLS cipher suites and min version (#256)
* Server: allow config of TLS cipher suites and min version Add a single parameter for each, not split across HTTP and gRPC. Required change upstream - prometheus/exporter-toolkit#110. Downstream projects rely on CLI parameters to generate docstrings, so we add `--server.tls-cipher-suites` and `--server.tls-min-version`. Both CLI and yaml require comma-separated lists of cipher suites, which is different to the yaml array format supported by prometheus/exporter-toolkit. The names accepted are from Go, listed here: https://pkg.go.dev/crypto/tls#pkg-constants Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
- Loading branch information
Showing
3 changed files
with
139 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package server | ||
|
||
import ( | ||
"crypto/tls" | ||
fmt "fmt" | ||
"strings" | ||
|
||
"github.com/prometheus/exporter-toolkit/web" | ||
) | ||
|
||
// Collect all cipher suite names and IDs recognized by Go, including insecure ones. | ||
func allCiphers() map[string]web.Cipher { | ||
acceptedCiphers := make(map[string]web.Cipher) | ||
for _, suite := range tls.CipherSuites() { | ||
acceptedCiphers[suite.Name] = web.Cipher(suite.ID) | ||
} | ||
for _, suite := range tls.InsecureCipherSuites() { | ||
acceptedCiphers[suite.Name] = web.Cipher(suite.ID) | ||
} | ||
return acceptedCiphers | ||
} | ||
|
||
func stringToCipherSuites(s string) ([]web.Cipher, error) { | ||
if s == "" { | ||
return nil, nil | ||
} | ||
ciphersSlice := []web.Cipher{} | ||
possibleCiphers := allCiphers() | ||
for _, cipher := range strings.Split(s, ",") { | ||
intValue, ok := possibleCiphers[cipher] | ||
if !ok { | ||
return nil, fmt.Errorf("cipher suite %q not recognized", cipher) | ||
} | ||
ciphersSlice = append(ciphersSlice, intValue) | ||
} | ||
return ciphersSlice, nil | ||
} | ||
|
||
// Using the same names that Kubernetes does | ||
var tlsVersions = map[string]uint16{ | ||
"VersionTLS10": tls.VersionTLS10, | ||
"VersionTLS11": tls.VersionTLS11, | ||
"VersionTLS12": tls.VersionTLS12, | ||
"VersionTLS13": tls.VersionTLS13, | ||
} | ||
|
||
func stringToTLSVersion(s string) (web.TLSVersion, error) { | ||
if s == "" { | ||
return 0, nil | ||
} | ||
if version, ok := tlsVersions[s]; ok { | ||
return web.TLSVersion(version), nil | ||
} | ||
return 0, fmt.Errorf("TLS version %q not recognized", s) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package server | ||
|
||
import ( | ||
"crypto/tls" | ||
"testing" | ||
|
||
"github.com/prometheus/exporter-toolkit/web" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func Test_stringToCipherSuites(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
arg string | ||
want []web.Cipher | ||
wantErr bool | ||
}{ | ||
{name: "blank", arg: "", want: nil}, | ||
{name: "bad", arg: "not-a-cipher", wantErr: true}, | ||
{name: "one", arg: "TLS_AES_256_GCM_SHA384", want: []web.Cipher{web.Cipher(tls.TLS_AES_256_GCM_SHA384)}}, | ||
{name: "two", arg: "TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256", | ||
want: []web.Cipher{web.Cipher(tls.TLS_AES_256_GCM_SHA384), web.Cipher(tls.TLS_CHACHA20_POLY1305_SHA256)}}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := stringToCipherSuites(tt.arg) | ||
if tt.wantErr { | ||
require.Error(t, err) | ||
} else { | ||
require.NoError(t, err) | ||
} | ||
require.Equal(t, tt.want, got) | ||
}) | ||
} | ||
} | ||
|
||
func Test_stringToTLSVersion(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
arg string | ||
want web.TLSVersion | ||
wantErr bool | ||
}{ | ||
{name: "blank", arg: "", want: 0}, | ||
{name: "bad", arg: "not-a-version", wantErr: true}, | ||
{name: "VersionTLS12", arg: "VersionTLS12", want: tls.VersionTLS12}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := stringToTLSVersion(tt.arg) | ||
if tt.wantErr { | ||
require.Error(t, err) | ||
} else { | ||
require.NoError(t, err) | ||
} | ||
require.Equal(t, tt.want, got) | ||
}) | ||
} | ||
} |