diff options
author | Julien Pivotto <roidelapluie@inuits.eu> | 2020-05-13 20:26:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-13 20:26:01 +0200 |
commit | f87e566df9c790938be2c6e5a64f7b58ea0cefb9 (patch) | |
tree | 810eaba738dbc4062470f269babad1cc4663137d | |
parent | 0c532984b7a6a00d67de07a9794aacfeec2c11d3 (diff) | |
download | prometheus_node_collector-f87e566df9c790938be2c6e5a64f7b58ea0cefb9.tar.bz2 prometheus_node_collector-f87e566df9c790938be2c6e5a64f7b58ea0cefb9.tar.xz prometheus_node_collector-f87e566df9c790938be2c6e5a64f7b58ea0cefb9.zip |
tls: enable the selection of more TLS settings (#1695)
tls: enable the selection of more TLS settings
* Rename `tls_config` to `tls_server_config`.
* Add new http server config with HTTP/2 enabled by default.
Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
27 files changed, 433 insertions, 40 deletions
diff --git a/https/README.md b/https/README.md index 70b321e..dd0fa40 100644 --- a/https/README.md +++ b/https/README.md | |||
@@ -14,18 +14,48 @@ The config file should be written in YAML format, and is reloaded on each connec | |||
14 | ## Sample Config | 14 | ## Sample Config |
15 | 15 | ||
16 | ``` | 16 | ``` |
17 | tls_config: | 17 | tls_server_config: |
18 | # Certificate and key files for server to use to authenticate to client | 18 | # Certificate and key files for server to use to authenticate to client. |
19 | cert_file: <filename> | 19 | cert_file: <filename> |
20 | key_file: <filename> | 20 | key_file: <filename> |
21 | 21 | ||
22 | # Server policy for client authentication. Maps to ClientAuth Policies | 22 | # Server policy for client authentication. Maps to ClientAuth Policies. |
23 | # For more detail on clientAuth options: [ClientAuthType](https://golang.org/pkg/crypto/tls/#ClientAuthType) | 23 | # For more detail on clientAuth options: [ClientAuthType](https://golang.org/pkg/crypto/tls/#ClientAuthType) |
24 | [ client_auth_type: <string> | default = "NoClientCert" ] | 24 | [ client_auth_type: <string> | default = "NoClientCert" ] |
25 | 25 | ||
26 | # CA certificate for client certificate authentication to the server | 26 | # CA certificate for client certificate authentication to the server. |
27 | [ client_ca_file: <filename> ] | 27 | [ client_ca_file: <filename> ] |
28 | 28 | ||
29 | # Minimum TLS version that is acceptable. | ||
30 | [ min_version: <string> | default = "TLS12" ] | ||
31 | |||
32 | # Maximum TLS version that is acceptable. | ||
33 | [ max_version: <string> | default = "TLS13" ] | ||
34 | |||
35 | # List of supported cipher suites for TLS versions up to TLS 1.2. If empty, | ||
36 | # Go default cipher suites are used. Available cipher suites are documented | ||
37 | # in the go documentation: | ||
38 | # https://golang.org/pkg/crypto/tls/#pkg-constants | ||
39 | [ cipher_suites: | ||
40 | [ - <string> ] ] | ||
41 | |||
42 | # prefer_server_cipher_suites controls whether the server selects the | ||
43 | # client's most preferred ciphersuite, or the server's most preferred | ||
44 | # ciphersuite. If true then the server's preference, as expressed in | ||
45 | # the order of elements in cipher_suites, is used. | ||
46 | [ prefer_server_cipher_suites: <bool> | default = true ] | ||
47 | |||
48 | # Elliptic curves that will be used in an ECDHE handshake, in preference | ||
49 | # order. Available curves are documented in the go documentation: | ||
50 | # https://golang.org/pkg/crypto/tls/#CurveID | ||
51 | [ curve_preferences: | ||
52 | [ - <string> ] ] | ||
53 | |||
54 | http_server_config: | ||
55 | # Enable HTTP/2 support. Note that HTTP/2 is only supported with TLS. | ||
56 | # This can not be changed on the fly. | ||
57 | [ http2: <bool> | default = true ] | ||
58 | |||
29 | # List of usernames and hashed passwords that have full access to the web | 59 | # List of usernames and hashed passwords that have full access to the web |
30 | # server via basic authentication. If empty, no basic authentication is | 60 | # server via basic authentication. If empty, no basic authentication is |
31 | # required. Passwords are hashed with bcrypt. | 61 | # required. Passwords are hashed with bcrypt. |
diff --git a/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml b/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml index 742889f..91ec706 100644 --- a/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml +++ b/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | client_ca_file : "somefile" \ No newline at end of file | 4 | client_ca_file : "somefile" \ No newline at end of file |
diff --git a/https/testdata/tls_config_auth_clientCAs_missing.bad.yml b/https/testdata/tls_config_auth_clientCAs_missing.bad.yml index 5f172a9..fea2a67 100644 --- a/https/testdata/tls_config_auth_clientCAs_missing.bad.yml +++ b/https/testdata/tls_config_auth_clientCAs_missing.bad.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | client_auth_type : "RequireAndVerifyClientCert" \ No newline at end of file | 4 | client_auth_type : "RequireAndVerifyClientCert" \ No newline at end of file |
diff --git a/https/testdata/tls_config_auth_user_list_invalid.bad.yml b/https/testdata/tls_config_auth_user_list_invalid.bad.yml index 90c1d95..7324573 100644 --- a/https/testdata/tls_config_auth_user_list_invalid.bad.yml +++ b/https/testdata/tls_config_auth_user_list_invalid.bad.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | basic_auth_users: | 4 | basic_auth_users: |
diff --git a/https/testdata/tls_config_junk_key.yml b/https/testdata/tls_config_junk_key.yml index acb2cc3..77f5534 100644 --- a/https/testdata/tls_config_junk_key.yml +++ b/https/testdata/tls_config_junk_key.yml | |||
@@ -1,2 +1,2 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_filse: "testdata/server.crt" | 2 | cert_filse: "testdata/server.crt" |
diff --git a/https/testdata/tls_config_noAuth.bad.yml b/https/testdata/tls_config_noAuth.bad.yml index afba277..f309180 100644 --- a/https/testdata/tls_config_noAuth.bad.yml +++ b/https/testdata/tls_config_noAuth.bad.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | client_ca_file : "testdata/tls-ca-chain.pem" | 4 | client_ca_file : "testdata/tls-ca-chain.pem" |
diff --git a/https/testdata/tls_config_noAuth.good.blocking.yml b/https/testdata/tls_config_noAuth.good.blocking.yml index 3a21424..43e47ca 100644 --- a/https/testdata/tls_config_noAuth.good.blocking.yml +++ b/https/testdata/tls_config_noAuth.good.blocking.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | client_auth_type : "RequireAndVerifyClientCert" | 4 | client_auth_type : "RequireAndVerifyClientCert" |
diff --git a/https/testdata/tls_config_noAuth.good.yml b/https/testdata/tls_config_noAuth.good.yml index d762d8e..33b6a68 100644 --- a/https/testdata/tls_config_noAuth.good.yml +++ b/https/testdata/tls_config_noAuth.good.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | client_auth_type : "VerifyClientCertIfGiven" | 4 | client_auth_type : "VerifyClientCertIfGiven" |
diff --git a/https/testdata/tls_config_noAuth_allCiphers.good.yml b/https/testdata/tls_config_noAuth_allCiphers.good.yml new file mode 100644 index 0000000..e16aec1 --- /dev/null +++ b/https/testdata/tls_config_noAuth_allCiphers.good.yml | |||
@@ -0,0 +1,26 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | cipher_suites: | ||
7 | - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 | ||
8 | - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 | ||
9 | - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | ||
10 | - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | ||
11 | - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 | ||
12 | - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 | ||
13 | - TLS_AES_128_GCM_SHA256 | ||
14 | - TLS_AES_256_GCM_SHA384 | ||
15 | - TLS_CHACHA20_POLY1305_SHA256 | ||
16 | - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA | ||
17 | - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA | ||
18 | - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA | ||
19 | - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA | ||
20 | - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA | ||
21 | - TLS_RSA_WITH_3DES_EDE_CBC_SHA | ||
22 | - TLS_RSA_WITH_AES_128_CBC_SHA | ||
23 | - TLS_RSA_WITH_AES_256_CBC_SHA | ||
24 | - TLS_RSA_WITH_AES_128_GCM_SHA256 | ||
25 | - TLS_RSA_WITH_AES_256_GCM_SHA384 | ||
26 | |||
diff --git a/https/testdata/tls_config_noAuth_allCurves.good.yml b/https/testdata/tls_config_noAuth_allCurves.good.yml new file mode 100644 index 0000000..e727402 --- /dev/null +++ b/https/testdata/tls_config_noAuth_allCurves.good.yml | |||
@@ -0,0 +1,10 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | curve_preferences: | ||
7 | - CurveP256 | ||
8 | - CurveP384 | ||
9 | - CurveP521 | ||
10 | - X25519 | ||
diff --git a/https/testdata/tls_config_noAuth_certPath_empty.bad.yml b/https/testdata/tls_config_noAuth_certPath_empty.bad.yml index f7aaa94..b9739c0 100644 --- a/https/testdata/tls_config_noAuth_certPath_empty.bad.yml +++ b/https/testdata/tls_config_noAuth_certPath_empty.bad.yml | |||
@@ -1,3 +1,3 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "" | 2 | cert_file : "" |
3 | key_file : "testdata/server.key" \ No newline at end of file | 3 | key_file : "testdata/server.key" \ No newline at end of file |
diff --git a/https/testdata/tls_config_noAuth_certPath_invalid.bad.yml b/https/testdata/tls_config_noAuth_certPath_invalid.bad.yml index 09344f9..b2f46d9 100644 --- a/https/testdata/tls_config_noAuth_certPath_invalid.bad.yml +++ b/https/testdata/tls_config_noAuth_certPath_invalid.bad.yml | |||
@@ -1,3 +1,3 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "somefile" | 2 | cert_file : "somefile" |
3 | key_file : "testdata/server.key" \ No newline at end of file | 3 | key_file : "testdata/server.key" \ No newline at end of file |
diff --git a/https/testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml b/https/testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml index 1511b5a..4e366ad 100644 --- a/https/testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml +++ b/https/testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "" | 2 | cert_file : "" |
3 | key_file : "" | 3 | key_file : "" |
4 | client_auth_type: "x" | 4 | client_auth_type: "x" |
diff --git a/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml b/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml index 972e457..ab0a262 100644 --- a/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml +++ b/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml | |||
@@ -1,3 +1,3 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "somefile" | 2 | cert_file : "somefile" |
3 | key_file : "somefile" \ No newline at end of file | 3 | key_file : "somefile" \ No newline at end of file |
diff --git a/https/testdata/tls_config_noAuth_inventedCiphers.bad.yml b/https/testdata/tls_config_noAuth_inventedCiphers.bad.yml new file mode 100644 index 0000000..1c5b28e --- /dev/null +++ b/https/testdata/tls_config_noAuth_inventedCiphers.bad.yml | |||
@@ -0,0 +1,8 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | cipher_suites: | ||
7 | - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA2048 | ||
8 | |||
diff --git a/https/testdata/tls_config_noAuth_inventedCurves.bad.yml b/https/testdata/tls_config_noAuth_inventedCurves.bad.yml new file mode 100644 index 0000000..16de738 --- /dev/null +++ b/https/testdata/tls_config_noAuth_inventedCurves.bad.yml | |||
@@ -0,0 +1,7 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | curve_preferences: | ||
7 | - CurveP257 | ||
diff --git a/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml b/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml index 87a5265..d997029 100644 --- a/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml +++ b/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml | |||
@@ -1,3 +1,3 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "" \ No newline at end of file | 3 | key_file : "" \ No newline at end of file |
diff --git a/https/testdata/tls_config_noAuth_keyPath_invalid.bad.yml b/https/testdata/tls_config_noAuth_keyPath_invalid.bad.yml index b3985f3..2b9d37f 100644 --- a/https/testdata/tls_config_noAuth_keyPath_invalid.bad.yml +++ b/https/testdata/tls_config_noAuth_keyPath_invalid.bad.yml | |||
@@ -1,3 +1,3 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.cert" | 2 | cert_file : "testdata/server.cert" |
3 | key_file : "somefile" \ No newline at end of file | 3 | key_file : "somefile" \ No newline at end of file |
diff --git a/https/testdata/tls_config_noAuth_noHTTP2.good.yml b/https/testdata/tls_config_noAuth_noHTTP2.good.yml new file mode 100644 index 0000000..d962c3d --- /dev/null +++ b/https/testdata/tls_config_noAuth_noHTTP2.good.yml | |||
@@ -0,0 +1,10 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | cipher_suites: | ||
7 | - TLS_RSA_WITH_AES_128_CBC_SHA | ||
8 | max_version: TLS12 | ||
9 | http_server_config: | ||
10 | http2: false | ||
diff --git a/https/testdata/tls_config_noAuth_noHTTP2Cipher.bad.yml b/https/testdata/tls_config_noAuth_noHTTP2Cipher.bad.yml new file mode 100644 index 0000000..2d6723a --- /dev/null +++ b/https/testdata/tls_config_noAuth_noHTTP2Cipher.bad.yml | |||
@@ -0,0 +1,8 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | cipher_suites: | ||
7 | - TLS_RSA_WITH_AES_128_CBC_SHA | ||
8 | max_version: TLS12 | ||
diff --git a/https/testdata/tls_config_noAuth_someCiphers.good.yml b/https/testdata/tls_config_noAuth_someCiphers.good.yml new file mode 100644 index 0000000..aae1e65 --- /dev/null +++ b/https/testdata/tls_config_noAuth_someCiphers.good.yml | |||
@@ -0,0 +1,10 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | cipher_suites: | ||
7 | - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | ||
8 | - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | ||
9 | min_version: TLS12 | ||
10 | max_version: TLS12 | ||
diff --git a/https/testdata/tls_config_noAuth_someCiphers_noOrder.good.yml b/https/testdata/tls_config_noAuth_someCiphers_noOrder.good.yml new file mode 100644 index 0000000..d21c6be --- /dev/null +++ b/https/testdata/tls_config_noAuth_someCiphers_noOrder.good.yml | |||
@@ -0,0 +1,11 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | cipher_suites: | ||
7 | - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | ||
8 | - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | ||
9 | prefer_server_cipher_suites: false | ||
10 | min_version: TLS12 | ||
11 | max_version: TLS12 | ||
diff --git a/https/testdata/tls_config_noAuth_someCurves.good.yml b/https/testdata/tls_config_noAuth_someCurves.good.yml new file mode 100644 index 0000000..2e860fc --- /dev/null +++ b/https/testdata/tls_config_noAuth_someCurves.good.yml | |||
@@ -0,0 +1,8 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | min_version: TLS13 | ||
7 | curve_preferences: | ||
8 | - CurveP521 | ||
diff --git a/https/testdata/tls_config_noAuth_wrongTLSVersion.bad.yml b/https/testdata/tls_config_noAuth_wrongTLSVersion.bad.yml new file mode 100644 index 0000000..51a0d6a --- /dev/null +++ b/https/testdata/tls_config_noAuth_wrongTLSVersion.bad.yml | |||
@@ -0,0 +1,6 @@ | |||
1 | tls_server_config : | ||
2 | cert_file : "testdata/server.crt" | ||
3 | key_file : "testdata/server.key" | ||
4 | client_auth_type : "VerifyClientCertIfGiven" | ||
5 | client_ca_file : "testdata/tls-ca-chain.pem" | ||
6 | min_version: TLS111 | ||
diff --git a/https/testdata/tls_config_users.good.yml b/https/testdata/tls_config_users.good.yml index 278177d..8c686fc 100644 --- a/https/testdata/tls_config_users.good.yml +++ b/https/testdata/tls_config_users.good.yml | |||
@@ -1,4 +1,4 @@ | |||
1 | tls_config : | 1 | tls_server_config : |
2 | cert_file : "testdata/server.crt" | 2 | cert_file : "testdata/server.crt" |
3 | key_file : "testdata/server.key" | 3 | key_file : "testdata/server.key" |
4 | basic_auth_users: | 4 | basic_auth_users: |
diff --git a/https/tls_config.go b/https/tls_config.go index 44e57e9..e7cc632 100644 --- a/https/tls_config.go +++ b/https/tls_config.go | |||
@@ -17,6 +17,7 @@ package https | |||
17 | import ( | 17 | import ( |
18 | "crypto/tls" | 18 | "crypto/tls" |
19 | "crypto/x509" | 19 | "crypto/x509" |
20 | "fmt" | ||
20 | "io/ioutil" | 21 | "io/ioutil" |
21 | "net/http" | 22 | "net/http" |
22 | 23 | ||
@@ -32,15 +33,25 @@ var ( | |||
32 | ) | 33 | ) |
33 | 34 | ||
34 | type Config struct { | 35 | type Config struct { |
35 | TLSConfig TLSStruct `yaml:"tls_config"` | 36 | TLSConfig TLSStruct `yaml:"tls_server_config"` |
36 | Users map[string]config_util.Secret `yaml:"basic_auth_users"` | 37 | HTTPConfig HTTPStruct `yaml:"http_server_config"` |
38 | Users map[string]config_util.Secret `yaml:"basic_auth_users"` | ||
37 | } | 39 | } |
38 | 40 | ||
39 | type TLSStruct struct { | 41 | type TLSStruct struct { |
40 | TLSCertPath string `yaml:"cert_file"` | 42 | TLSCertPath string `yaml:"cert_file"` |
41 | TLSKeyPath string `yaml:"key_file"` | 43 | TLSKeyPath string `yaml:"key_file"` |
42 | ClientAuth string `yaml:"client_auth_type"` | 44 | ClientAuth string `yaml:"client_auth_type"` |
43 | ClientCAs string `yaml:"client_ca_file"` | 45 | ClientCAs string `yaml:"client_ca_file"` |
46 | CipherSuites []cipher `yaml:"cipher_suites"` | ||
47 | CurvePreferences []curve `yaml:"curve_preferences"` | ||
48 | MinVersion tlsVersion `yaml:"min_version"` | ||
49 | MaxVersion tlsVersion `yaml:"max_version"` | ||
50 | PreferServerCipherSuites bool `yaml:"prefer_server_cipher_suites"` | ||
51 | } | ||
52 | |||
53 | type HTTPStruct struct { | ||
54 | HTTP2 bool `yaml:"http2"` | ||
44 | } | 55 | } |
45 | 56 | ||
46 | func getConfig(configPath string) (*Config, error) { | 57 | func getConfig(configPath string) (*Config, error) { |
@@ -48,7 +59,14 @@ func getConfig(configPath string) (*Config, error) { | |||
48 | if err != nil { | 59 | if err != nil { |
49 | return nil, err | 60 | return nil, err |
50 | } | 61 | } |
51 | c := &Config{} | 62 | c := &Config{ |
63 | TLSConfig: TLSStruct{ | ||
64 | MinVersion: tls.VersionTLS12, | ||
65 | MaxVersion: tls.VersionTLS13, | ||
66 | PreferServerCipherSuites: true, | ||
67 | }, | ||
68 | HTTPConfig: HTTPStruct{HTTP2: true}, | ||
69 | } | ||
52 | err = yaml.UnmarshalStrict(content, c) | 70 | err = yaml.UnmarshalStrict(content, c) |
53 | return c, err | 71 | return c, err |
54 | } | 72 | } |
@@ -70,12 +88,11 @@ func ConfigToTLSConfig(c *TLSStruct) (*tls.Config, error) { | |||
70 | if c.TLSCertPath == "" { | 88 | if c.TLSCertPath == "" { |
71 | return nil, errors.New("missing cert_file") | 89 | return nil, errors.New("missing cert_file") |
72 | } | 90 | } |
91 | |||
73 | if c.TLSKeyPath == "" { | 92 | if c.TLSKeyPath == "" { |
74 | return nil, errors.New("missing key_file") | 93 | return nil, errors.New("missing key_file") |
75 | } | 94 | } |
76 | cfg := &tls.Config{ | 95 | |
77 | MinVersion: tls.VersionTLS12, | ||
78 | } | ||
79 | loadCert := func() (*tls.Certificate, error) { | 96 | loadCert := func() (*tls.Certificate, error) { |
80 | cert, err := tls.LoadX509KeyPair(c.TLSCertPath, c.TLSKeyPath) | 97 | cert, err := tls.LoadX509KeyPair(c.TLSCertPath, c.TLSKeyPath) |
81 | if err != nil { | 98 | if err != nil { |
@@ -83,14 +100,38 @@ func ConfigToTLSConfig(c *TLSStruct) (*tls.Config, error) { | |||
83 | } | 100 | } |
84 | return &cert, nil | 101 | return &cert, nil |
85 | } | 102 | } |
103 | |||
86 | // Confirm that certificate and key paths are valid. | 104 | // Confirm that certificate and key paths are valid. |
87 | if _, err := loadCert(); err != nil { | 105 | if _, err := loadCert(); err != nil { |
88 | return nil, err | 106 | return nil, err |
89 | } | 107 | } |
108 | |||
109 | cfg := &tls.Config{ | ||
110 | MinVersion: (uint16)(c.MinVersion), | ||
111 | MaxVersion: (uint16)(c.MaxVersion), | ||
112 | PreferServerCipherSuites: c.PreferServerCipherSuites, | ||
113 | } | ||
114 | |||
90 | cfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { | 115 | cfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { |
91 | return loadCert() | 116 | return loadCert() |
92 | } | 117 | } |
93 | 118 | ||
119 | var cf []uint16 | ||
120 | for _, c := range c.CipherSuites { | ||
121 | cf = append(cf, (uint16)(c)) | ||
122 | } | ||
123 | if len(cf) > 0 { | ||
124 | cfg.CipherSuites = cf | ||
125 | } | ||
126 | |||
127 | var cp []tls.CurveID | ||
128 | for _, c := range c.CurvePreferences { | ||
129 | cp = append(cp, (tls.CurveID)(c)) | ||
130 | } | ||
131 | if len(cp) > 0 { | ||
132 | cfg.CurvePreferences = cp | ||
133 | } | ||
134 | |||
94 | if c.ClientCAs != "" { | 135 | if c.ClientCAs != "" { |
95 | clientCAPool := x509.NewCertPool() | 136 | clientCAPool := x509.NewCertPool() |
96 | clientCAFile, err := ioutil.ReadFile(c.ClientCAs) | 137 | clientCAFile, err := ioutil.ReadFile(c.ClientCAs) |
@@ -126,7 +167,7 @@ func ConfigToTLSConfig(c *TLSStruct) (*tls.Config, error) { | |||
126 | // Listen starts the server on the given address. If tlsConfigPath isn't empty the server connection will be started using TLS. | 167 | // Listen starts the server on the given address. If tlsConfigPath isn't empty the server connection will be started using TLS. |
127 | func Listen(server *http.Server, tlsConfigPath string, logger log.Logger) error { | 168 | func Listen(server *http.Server, tlsConfigPath string, logger log.Logger) error { |
128 | if tlsConfigPath == "" { | 169 | if tlsConfigPath == "" { |
129 | level.Info(logger).Log("msg", "TLS is disabled and it cannot be enabled on the fly.") | 170 | level.Info(logger).Log("msg", "TLS is disabled and it cannot be enabled on the fly.", "http2", false) |
130 | return server.ListenAndServe() | 171 | return server.ListenAndServe() |
131 | } | 172 | } |
132 | 173 | ||
@@ -145,14 +186,21 @@ func Listen(server *http.Server, tlsConfigPath string, logger log.Logger) error | |||
145 | handler: handler, | 186 | handler: handler, |
146 | } | 187 | } |
147 | 188 | ||
148 | config, err := getTLSConfig(tlsConfigPath) | 189 | c, err := getConfig(tlsConfigPath) |
190 | if err != nil { | ||
191 | return err | ||
192 | } | ||
193 | config, err := ConfigToTLSConfig(&c.TLSConfig) | ||
149 | switch err { | 194 | switch err { |
150 | case nil: | 195 | case nil: |
196 | if !c.HTTPConfig.HTTP2 { | ||
197 | server.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) | ||
198 | } | ||
151 | // Valid TLS config. | 199 | // Valid TLS config. |
152 | level.Info(logger).Log("msg", "TLS is enabled and it cannot be disabled on the fly.") | 200 | level.Info(logger).Log("msg", "TLS is enabled and it cannot be disabled on the fly.", "http2", c.HTTPConfig.HTTP2) |
153 | case errNoTLSConfig: | 201 | case errNoTLSConfig: |
154 | // No TLS config, back to plain HTTP. | 202 | // No TLS config, back to plain HTTP. |
155 | level.Info(logger).Log("msg", "TLS is disabled and it cannot be enabled on the fly.") | 203 | level.Info(logger).Log("msg", "TLS is disabled and it cannot be enabled on the fly.", "http2", false) |
156 | return server.ListenAndServe() | 204 | return server.ListenAndServe() |
157 | default: | 205 | default: |
158 | // Invalid TLS config. | 206 | // Invalid TLS config. |
@@ -168,3 +216,86 @@ func Listen(server *http.Server, tlsConfigPath string, logger log.Logger) error | |||
168 | } | 216 | } |
169 | return server.ListenAndServeTLS("", "") | 217 | return server.ListenAndServeTLS("", "") |
170 | } | 218 | } |
219 | |||
220 | type cipher uint16 | ||
221 | |||
222 | func (c *cipher) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||
223 | var s string | ||
224 | err := unmarshal((*string)(&s)) | ||
225 | if err != nil { | ||
226 | return err | ||
227 | } | ||
228 | for _, cs := range tls.CipherSuites() { | ||
229 | if cs.Name == s { | ||
230 | *c = (cipher)(cs.ID) | ||
231 | return nil | ||
232 | } | ||
233 | } | ||
234 | return errors.New("unknown cipher: " + s) | ||
235 | } | ||
236 | |||
237 | func (c cipher) MarshalYAML() (interface{}, error) { | ||
238 | return tls.CipherSuiteName((uint16)(c)), nil | ||
239 | } | ||
240 | |||
241 | type curve tls.CurveID | ||
242 | |||
243 | var curves = map[string]curve{ | ||
244 | "CurveP256": (curve)(tls.CurveP256), | ||
245 | "CurveP384": (curve)(tls.CurveP384), | ||
246 | "CurveP521": (curve)(tls.CurveP521), | ||
247 | "X25519": (curve)(tls.X25519), | ||
248 | } | ||
249 | |||
250 | func (c *curve) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||
251 | var s string | ||
252 | err := unmarshal((*string)(&s)) | ||
253 | if err != nil { | ||
254 | return err | ||
255 | } | ||
256 | if curveid, ok := curves[s]; ok { | ||
257 | *c = curveid | ||
258 | return nil | ||
259 | } | ||
260 | return errors.New("unknown curve: " + s) | ||
261 | } | ||
262 | |||
263 | func (c *curve) MarshalYAML() (interface{}, error) { | ||
264 | for s, curveid := range curves { | ||
265 | if *c == curveid { | ||
266 | return s, nil | ||
267 | } | ||
268 | } | ||
269 | return fmt.Sprintf("%v", c), nil | ||
270 | } | ||
271 | |||
272 | type tlsVersion uint16 | ||
273 | |||
274 | var tlsVersions = map[string]tlsVersion{ | ||
275 | "TLS13": (tlsVersion)(tls.VersionTLS13), | ||
276 | "TLS12": (tlsVersion)(tls.VersionTLS12), | ||
277 | "TLS11": (tlsVersion)(tls.VersionTLS11), | ||
278 | "TLS10": (tlsVersion)(tls.VersionTLS10), | ||
279 | } | ||
280 | |||
281 | func (tv *tlsVersion) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||
282 | var s string | ||
283 | err := unmarshal((*string)(&s)) | ||
284 | if err != nil { | ||
285 | return err | ||
286 | } | ||
287 | if v, ok := tlsVersions[s]; ok { | ||
288 | *tv = v | ||
289 | return nil | ||
290 | } | ||
291 | return errors.New("unknown TLS version: " + s) | ||
292 | } | ||
293 | |||
294 | func (tv *tlsVersion) MarshalYAML() (interface{}, error) { | ||
295 | for s, v := range tlsVersions { | ||
296 | if *tv == v { | ||
297 | return s, nil | ||
298 | } | ||
299 | } | ||
300 | return fmt.Sprintf("%v", tv), nil | ||
301 | } | ||
diff --git a/https/tls_config_test.go b/https/tls_config_test.go index 07f412a..ccc7a99 100644 --- a/https/tls_config_test.go +++ b/https/tls_config_test.go | |||
@@ -11,6 +11,8 @@ | |||
11 | // See the License for the specific language governing permissions and | 11 | // See the License for the specific language governing permissions and |
12 | // limitations under the License. | 12 | // limitations under the License. |
13 | 13 | ||
14 | // +build go1.14 | ||
15 | |||
14 | package https | 16 | package https |
15 | 17 | ||
16 | import ( | 18 | import ( |
@@ -45,6 +47,12 @@ var ( | |||
45 | "Bad password": regexp.MustCompile(`hashedSecret too short to be a bcrypted password`), | 47 | "Bad password": regexp.MustCompile(`hashedSecret too short to be a bcrypted password`), |
46 | "Unauthorized": regexp.MustCompile(`Unauthorized`), | 48 | "Unauthorized": regexp.MustCompile(`Unauthorized`), |
47 | "Forbidden": regexp.MustCompile(`Forbidden`), | 49 | "Forbidden": regexp.MustCompile(`Forbidden`), |
50 | "Handshake failure": regexp.MustCompile(`handshake failure`), | ||
51 | "Unknown cipher": regexp.MustCompile(`unknown cipher`), | ||
52 | "Unknown curve": regexp.MustCompile(`unknown curve`), | ||
53 | "Unknown TLS version": regexp.MustCompile(`unknown TLS version`), | ||
54 | "No HTTP2 cipher": regexp.MustCompile(`TLSConfig.CipherSuites is missing an HTTP/2-required`), | ||
55 | "Incompatible TLS version": regexp.MustCompile(`protocol version not supported`), | ||
48 | } | 56 | } |
49 | ) | 57 | ) |
50 | 58 | ||
@@ -65,14 +73,18 @@ func getPort() string { | |||
65 | } | 73 | } |
66 | 74 | ||
67 | type TestInputs struct { | 75 | type TestInputs struct { |
68 | Name string | 76 | Name string |
69 | Server func() *http.Server | 77 | Server func() *http.Server |
70 | UseNilServer bool | 78 | UseNilServer bool |
71 | YAMLConfigPath string | 79 | YAMLConfigPath string |
72 | ExpectedError *regexp.Regexp | 80 | ExpectedError *regexp.Regexp |
73 | UseTLSClient bool | 81 | UseTLSClient bool |
74 | Username string | 82 | ClientMaxTLSVersion uint16 |
75 | Password string | 83 | CipherSuites []uint16 |
84 | ActualCipher uint16 | ||
85 | CurvePreferences []tls.CurveID | ||
86 | Username string | ||
87 | Password string | ||
76 | } | 88 | } |
77 | 89 | ||
78 | func TestYAMLFiles(t *testing.T) { | 90 | func TestYAMLFiles(t *testing.T) { |
@@ -142,6 +154,21 @@ func TestYAMLFiles(t *testing.T) { | |||
142 | YAMLConfigPath: "testdata/tls_config_auth_user_list_invalid.bad.yml", | 154 | YAMLConfigPath: "testdata/tls_config_auth_user_list_invalid.bad.yml", |
143 | ExpectedError: ErrorMap["Bad password"], | 155 | ExpectedError: ErrorMap["Bad password"], |
144 | }, | 156 | }, |
157 | { | ||
158 | Name: `invalid config yml (bad cipher)`, | ||
159 | YAMLConfigPath: "testdata/tls_config_noAuth_inventedCiphers.bad.yml", | ||
160 | ExpectedError: ErrorMap["Unknown cipher"], | ||
161 | }, | ||
162 | { | ||
163 | Name: `invalid config yml (bad curves)`, | ||
164 | YAMLConfigPath: "testdata/tls_config_noAuth_inventedCurves.bad.yml", | ||
165 | ExpectedError: ErrorMap["Unknown curve"], | ||
166 | }, | ||
167 | { | ||
168 | Name: `invalid config yml (bad TLS version)`, | ||
169 | YAMLConfigPath: "testdata/tls_config_noAuth_wrongTLSVersion.bad.yml", | ||
170 | ExpectedError: ErrorMap["Unknown TLS version"], | ||
171 | }, | ||
145 | } | 172 | } |
146 | for _, testInputs := range testTables { | 173 | for _, testInputs := range testTables { |
147 | t.Run(testInputs.Name, testInputs.Test) | 174 | t.Run(testInputs.Name, testInputs.Test) |
@@ -172,6 +199,87 @@ func TestServerBehaviour(t *testing.T) { | |||
172 | UseTLSClient: true, | 199 | UseTLSClient: true, |
173 | ExpectedError: nil, | 200 | ExpectedError: nil, |
174 | }, | 201 | }, |
202 | { | ||
203 | Name: `valid tls config yml with TLS 1.1 client`, | ||
204 | YAMLConfigPath: "testdata/tls_config_noAuth.good.yml", | ||
205 | UseTLSClient: true, | ||
206 | ClientMaxTLSVersion: tls.VersionTLS11, | ||
207 | ExpectedError: ErrorMap["Incompatible TLS version"], | ||
208 | }, | ||
209 | { | ||
210 | Name: `valid tls config yml with all ciphers`, | ||
211 | YAMLConfigPath: "testdata/tls_config_noAuth_allCiphers.good.yml", | ||
212 | UseTLSClient: true, | ||
213 | ExpectedError: nil, | ||
214 | }, | ||
215 | { | ||
216 | Name: `valid tls config yml with some ciphers`, | ||
217 | YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers.good.yml", | ||
218 | UseTLSClient: true, | ||
219 | CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | ||
220 | ExpectedError: nil, | ||
221 | }, | ||
222 | { | ||
223 | Name: `valid tls config yml with no common cipher`, | ||
224 | YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers.good.yml", | ||
225 | UseTLSClient: true, | ||
226 | CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, | ||
227 | ExpectedError: ErrorMap["Handshake failure"], | ||
228 | }, | ||
229 | { | ||
230 | Name: `valid tls config yml with multiple client ciphers`, | ||
231 | YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers.good.yml", | ||
232 | UseTLSClient: true, | ||
233 | CipherSuites: []uint16{ | ||
234 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
235 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
236 | }, | ||
237 | ActualCipher: tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
238 | ExpectedError: nil, | ||
239 | }, | ||
240 | { | ||
241 | Name: `valid tls config yml with multiple client ciphers, client chooses cipher`, | ||
242 | YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers_noOrder.good.yml", | ||
243 | UseTLSClient: true, | ||
244 | CipherSuites: []uint16{ | ||
245 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
246 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | ||
247 | }, | ||
248 | ActualCipher: tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
249 | ExpectedError: nil, | ||
250 | }, | ||
251 | { | ||
252 | Name: `valid tls config yml with all curves`, | ||
253 | YAMLConfigPath: "testdata/tls_config_noAuth_allCurves.good.yml", | ||
254 | UseTLSClient: true, | ||
255 | ExpectedError: nil, | ||
256 | }, | ||
257 | { | ||
258 | Name: `valid tls config yml with some curves`, | ||
259 | YAMLConfigPath: "testdata/tls_config_noAuth_someCurves.good.yml", | ||
260 | UseTLSClient: true, | ||
261 | CurvePreferences: []tls.CurveID{tls.CurveP521}, | ||
262 | ExpectedError: nil, | ||
263 | }, | ||
264 | { | ||
265 | Name: `valid tls config yml with no common curves`, | ||
266 | YAMLConfigPath: "testdata/tls_config_noAuth_someCurves.good.yml", | ||
267 | UseTLSClient: true, | ||
268 | CurvePreferences: []tls.CurveID{tls.CurveP384}, | ||
269 | ExpectedError: ErrorMap["Handshake failure"], | ||
270 | }, | ||
271 | { | ||
272 | Name: `valid tls config yml with non-http2 ciphers`, | ||
273 | YAMLConfigPath: "testdata/tls_config_noAuth_noHTTP2.good.yml", | ||
274 | UseTLSClient: true, | ||
275 | ExpectedError: nil, | ||
276 | }, | ||
277 | { | ||
278 | Name: `valid tls config yml with non-http2 ciphers but http2 enabled`, | ||
279 | YAMLConfigPath: "testdata/tls_config_noAuth_noHTTP2Cipher.bad.yml", | ||
280 | UseTLSClient: true, | ||
281 | ExpectedError: ErrorMap["No HTTP2 cipher"], | ||
282 | }, | ||
175 | } | 283 | } |
176 | for _, testInputs := range testTables { | 284 | for _, testInputs := range testTables { |
177 | t.Run(testInputs.Name, testInputs.Test) | 285 | t.Run(testInputs.Name, testInputs.Test) |
@@ -297,6 +405,14 @@ func (test *TestInputs) Test(t *testing.T) { | |||
297 | var proto string | 405 | var proto string |
298 | if test.UseTLSClient { | 406 | if test.UseTLSClient { |
299 | client = getTLSClient() | 407 | client = getTLSClient() |
408 | t := client.Transport.(*http.Transport) | ||
409 | t.TLSClientConfig.MaxVersion = test.ClientMaxTLSVersion | ||
410 | if len(test.CipherSuites) > 0 { | ||
411 | t.TLSClientConfig.CipherSuites = test.CipherSuites | ||
412 | } | ||
413 | if len(test.CurvePreferences) > 0 { | ||
414 | t.TLSClientConfig.CurvePreferences = test.CurvePreferences | ||
415 | } | ||
300 | proto = "https" | 416 | proto = "https" |
301 | } else { | 417 | } else { |
302 | client = http.DefaultClient | 418 | client = http.DefaultClient |
@@ -318,6 +434,18 @@ func (test *TestInputs) Test(t *testing.T) { | |||
318 | recordConnectionError(err) | 434 | recordConnectionError(err) |
319 | return | 435 | return |
320 | } | 436 | } |
437 | |||
438 | if test.ActualCipher != 0 { | ||
439 | if r.TLS.CipherSuite != test.ActualCipher { | ||
440 | recordConnectionError( | ||
441 | fmt.Errorf("bad cipher suite selected. Expected: %s, got: %s", | ||
442 | tls.CipherSuiteName(r.TLS.CipherSuite), | ||
443 | tls.CipherSuiteName(test.ActualCipher), | ||
444 | ), | ||
445 | ) | ||
446 | } | ||
447 | } | ||
448 | |||
321 | body, err := ioutil.ReadAll(r.Body) | 449 | body, err := ioutil.ReadAll(r.Body) |
322 | if err != nil { | 450 | if err != nil { |
323 | recordConnectionError(err) | 451 | recordConnectionError(err) |