diff options
author | ksherryBAE <44226893+ksherryBAE@users.noreply.github.com> | 2019-11-15 23:12:57 +0000 |
---|---|---|
committer | Ben Kochie <superq@gmail.com> | 2019-11-16 00:12:57 +0100 |
commit | aede04172cbcd072629e0a5f43cd0435e26a28d4 (patch) | |
tree | b8752e10fa80cc2b2ad0aa655529fb67223ad3f2 /https | |
parent | 20fe5bfb5be4caf3c8c11533b7fb35cb97d810f5 (diff) | |
download | prometheus_node_collector-aede04172cbcd072629e0a5f43cd0435e26a28d4.tar.bz2 prometheus_node_collector-aede04172cbcd072629e0a5f43cd0435e26a28d4.tar.xz prometheus_node_collector-aede04172cbcd072629e0a5f43cd0435e26a28d4.zip |
Adding TLS to node exporter - cleaner version (#1277)
Add support for https connections.
Signed-off-by: ksherryBAE <kieran.sherry@baesystems.com>
Signed-off-by: James Ritchie <james.g.ritchie@baesystems.com>
Signed-off-by: Simon Pasquier <spasquie@redhat.com>
Signed-off-by: Ben RIdley <benridley29@gmail.com>
Diffstat (limited to 'https')
20 files changed, 876 insertions, 0 deletions
diff --git a/https/README.md b/https/README.md new file mode 100644 index 0000000..b8c7ac4 --- /dev/null +++ b/https/README.md | |||
@@ -0,0 +1,24 @@ | |||
1 | # HTTPS Package for Prometheus | ||
2 | |||
3 | The `https` directory contains a Go package and a sample configuration file for running `node_exporter` with HTTPS instead of HTTP. | ||
4 | When running a server with TLS use the flag `--web.config` | ||
5 | |||
6 | e.g. `./node_exporter --web.config="web-config.yml"` | ||
7 | If the config is kept within the https directory. | ||
8 | |||
9 | The config file should be written in YAML format, and is reloaded on each connection to check for new certificates and/or authentication policy. | ||
10 | |||
11 | ##Sample Config: | ||
12 | ``` | ||
13 | tlsConfig : | ||
14 | # Certificate and key files for server to use to authenticate to client | ||
15 | tlsCertPath : <filename> | ||
16 | tlsKeyPath : <filename> | ||
17 | |||
18 | # Server policy for client authentication. Maps to ClientAuth Policies | ||
19 | # For more detail on clientAuth options: [ClientAuthType](https://golang.org/pkg/crypto/tls/#ClientAuthType) | ||
20 | [ clientAuth : <string> | default = "NoClientCert" ] | ||
21 | |||
22 | # CA certificate for client certificate authentication to the server | ||
23 | [ clientCAs : <filename> ] | ||
24 | ``` | ||
diff --git a/https/testdata/server.crt b/https/testdata/server.crt new file mode 100644 index 0000000..2ead969 --- /dev/null +++ b/https/testdata/server.crt | |||
@@ -0,0 +1,96 @@ | |||
1 | Certificate: | ||
2 | Data: | ||
3 | Version: 3 (0x2) | ||
4 | Serial Number: 1 (0x1) | ||
5 | Signature Algorithm: sha1WithRSAEncryption | ||
6 | Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus TLS CA | ||
7 | Validity | ||
8 | Not Before: Apr 5 08:06:57 2019 GMT | ||
9 | Not After : Mar 26 08:06:57 2059 GMT | ||
10 | Subject: C=US, O=Prometheus, CN=prometheus.example.com | ||
11 | Subject Public Key Info: | ||
12 | Public Key Algorithm: rsaEncryption | ||
13 | RSA Public-Key: (2048 bit) | ||
14 | Modulus: | ||
15 | 00:bd:6c:b6:7f:d1:2f:be:e4:41:eb:5d:ff:50:78: | ||
16 | 03:2b:76:03:da:01:48:20:13:90:66:c9:ce:6e:06: | ||
17 | e5:fa:2d:0d:c0:b0:46:28:44:10:a0:61:79:87:a2: | ||
18 | 98:4c:29:fa:f9:bb:0f:44:c7:90:5c:5c:55:60:cd: | ||
19 | 45:da:b8:e4:dd:28:72:c8:8b:a1:3e:4b:00:09:82: | ||
20 | b0:2c:dc:d6:17:c9:02:f4:cd:26:c7:11:28:f3:77: | ||
21 | b5:97:c2:76:c2:e0:07:d7:34:5b:e0:ed:1a:59:a5: | ||
22 | b4:b7:16:09:3d:35:bd:d9:03:07:9d:7c:3b:f0:63: | ||
23 | bd:5e:02:99:cf:32:e1:ac:4c:7a:3e:4c:b2:8e:98: | ||
24 | 68:07:4f:59:dc:0d:bf:cc:83:04:5c:d8:90:f0:73: | ||
25 | da:2b:08:17:c4:36:a7:d8:94:3d:b6:c0:af:29:0a: | ||
26 | d3:19:5f:eb:7d:cc:4d:05:56:11:0a:ee:b1:f3:d7: | ||
27 | c9:5a:3c:8c:57:16:91:51:14:f8:20:4e:0f:29:9e: | ||
28 | 04:21:e6:f1:e4:e8:44:af:d7:25:92:08:64:fc:2c: | ||
29 | 1c:2e:4f:71:53:91:53:1d:e5:f9:7b:52:0f:21:da: | ||
30 | 5c:dd:19:68:96:ca:70:6a:f1:c4:0d:07:af:f8:65: | ||
31 | 13:92:e9:ef:65:b3:89:86:fd:c0:74:5c:a4:6b:49: | ||
32 | 62:c5 | ||
33 | Exponent: 65537 (0x10001) | ||
34 | X509v3 extensions: | ||
35 | X509v3 Key Usage: critical | ||
36 | Digital Signature, Key Encipherment | ||
37 | X509v3 Basic Constraints: | ||
38 | CA:FALSE | ||
39 | X509v3 Extended Key Usage: | ||
40 | TLS Web Server Authentication, TLS Web Client Authentication | ||
41 | X509v3 Subject Key Identifier: | ||
42 | 00:61:01:AD:25:44:8A:EF:E1:2C:EC:83:5A:3A:3B:EA:A0:BD:E1:45 | ||
43 | X509v3 Authority Key Identifier: | ||
44 | keyid:4D:02:BF:71:95:6A:AA:58:C5:9C:B8:83:67:5E:64:16:99:E1:2A:9E | ||
45 | |||
46 | Authority Information Access: | ||
47 | CA Issuers - URI:http://example.com/ca/tls-ca.cer | ||
48 | |||
49 | X509v3 CRL Distribution Points: | ||
50 | |||
51 | Full Name: | ||
52 | URI:http://example.com/ca/tls-ca.crl | ||
53 | |||
54 | X509v3 Subject Alternative Name: | ||
55 | IP Address:127.0.0.1, IP Address:127.0.0.0, DNS:localhost | ||
56 | Signature Algorithm: sha1WithRSAEncryption | ||
57 | 77:97:e4:ef:db:10:8e:62:50:96:4a:6e:f5:a4:f9:1f:19:3b: | ||
58 | c8:a4:dd:b3:f6:11:41:1a:fb:e3:f8:dd:0e:64:e5:2b:00:b9: | ||
59 | e6:25:9f:2e:e1:d2:9a:cd:b6:f2:41:4d:27:dd:2c:9a:af:97: | ||
60 | 79:e8:cf:61:fb:cf:be:25:c6:e1:19:a0:c8:90:44:a0:76:8a: | ||
61 | 45:d4:37:22:e5:d4:80:b4:b3:0f:a8:33:08:24:ad:21:0b:b7: | ||
62 | 98:46:93:90:8a:ae:77:0c:cb:b8:59:d3:3b:9b:fb:16:5a:22: | ||
63 | ca:c2:97:9d:78:1b:fc:23:fc:a0:42:54:40:de:88:4b:07:2b: | ||
64 | 19:4e:0e:79:bf:c9:9f:01:a6:46:c5:55:fa:9f:c0:0d:8a:a6: | ||
65 | e1:47:16:a6:0e:be:23:c9:e9:58:d6:31:71:8c:80:9c:16:64: | ||
66 | f0:14:08:22:a1:23:7c:98:b9:62:d1:4a:ce:e3:5c:59:fb:41: | ||
67 | 87:a5:3b:36:dd:3d:45:48:b0:b0:77:6f:de:58:2a:27:4d:56: | ||
68 | 20:54:08:20:c8:6d:79:b5:b9:e6:3a:03:24:0f:6d:67:39:20: | ||
69 | 78:10:2f:47:85:83:c1:4d:17:33:79:84:75:27:fa:47:67:59: | ||
70 | 56:cc:33:7b:a5:77:aa:59:9a:98:30:10:1a:78:43:34:8f:ed: | ||
71 | c2:a1:a3:ea | ||
72 | -----BEGIN CERTIFICATE----- | ||
73 | MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET | ||
74 | MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp | ||
75 | Y2F0ZSBBdXRob3JpdHkxGjAYBgNVBAMMEVByb21ldGhldXMgVExTIENBMCAXDTE5 | ||
76 | MDQwNTA4MDY1N1oYDzIwNTkwMzI2MDgwNjU3WjBDMQswCQYDVQQGEwJVUzETMBEG | ||
77 | A1UECgwKUHJvbWV0aGV1czEfMB0GA1UEAwwWcHJvbWV0aGV1cy5leGFtcGxlLmNv | ||
78 | bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1stn/RL77kQetd/1B4 | ||
79 | Ayt2A9oBSCATkGbJzm4G5fotDcCwRihEEKBheYeimEwp+vm7D0THkFxcVWDNRdq4 | ||
80 | 5N0ocsiLoT5LAAmCsCzc1hfJAvTNJscRKPN3tZfCdsLgB9c0W+DtGlmltLcWCT01 | ||
81 | vdkDB518O/BjvV4Cmc8y4axMej5Mso6YaAdPWdwNv8yDBFzYkPBz2isIF8Q2p9iU | ||
82 | PbbArykK0xlf633MTQVWEQrusfPXyVo8jFcWkVEU+CBODymeBCHm8eToRK/XJZII | ||
83 | ZPwsHC5PcVORUx3l+XtSDyHaXN0ZaJbKcGrxxA0Hr/hlE5Lp72WziYb9wHRcpGtJ | ||
84 | YsUCAwEAAaOCAREwggENMA4GA1UdDwEB/wQEAwIFoDAJBgNVHRMEAjAAMB0GA1Ud | ||
85 | JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUAGEBrSVEiu/hLOyD | ||
86 | Wjo76qC94UUwHwYDVR0jBBgwFoAUTQK/cZVqqljFnLiDZ15kFpnhKp4wPAYIKwYB | ||
87 | BQUHAQEEMDAuMCwGCCsGAQUFBzAChiBodHRwOi8vZXhhbXBsZS5jb20vY2EvdGxz | ||
88 | LWNhLmNlcjAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vZXhhbXBsZS5jb20vY2Ev | ||
89 | dGxzLWNhLmNybDAgBgNVHREEGTAXhwR/AAABhwR/AAAAgglsb2NhbGhvc3QwDQYJ | ||
90 | KoZIhvcNAQEFBQADggEBAHeX5O/bEI5iUJZKbvWk+R8ZO8ik3bP2EUEa++P43Q5k | ||
91 | 5SsAueYlny7h0prNtvJBTSfdLJqvl3noz2H7z74lxuEZoMiQRKB2ikXUNyLl1IC0 | ||
92 | sw+oMwgkrSELt5hGk5CKrncMy7hZ0zub+xZaIsrCl514G/wj/KBCVEDeiEsHKxlO | ||
93 | Dnm/yZ8BpkbFVfqfwA2KpuFHFqYOviPJ6VjWMXGMgJwWZPAUCCKhI3yYuWLRSs7j | ||
94 | XFn7QYelOzbdPUVIsLB3b95YKidNViBUCCDIbXm1ueY6AyQPbWc5IHgQL0eFg8FN | ||
95 | FzN5hHUn+kdnWVbMM3uld6pZmpgwEBp4QzSP7cKho+o= | ||
96 | -----END CERTIFICATE----- | ||
diff --git a/https/testdata/server.key b/https/testdata/server.key new file mode 100644 index 0000000..e1226c0 --- /dev/null +++ b/https/testdata/server.key | |||
@@ -0,0 +1,28 @@ | |||
1 | -----BEGIN PRIVATE KEY----- | ||
2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9bLZ/0S++5EHr | ||
3 | Xf9QeAMrdgPaAUggE5Bmyc5uBuX6LQ3AsEYoRBCgYXmHophMKfr5uw9Ex5BcXFVg | ||
4 | zUXauOTdKHLIi6E+SwAJgrAs3NYXyQL0zSbHESjzd7WXwnbC4AfXNFvg7RpZpbS3 | ||
5 | Fgk9Nb3ZAwedfDvwY71eApnPMuGsTHo+TLKOmGgHT1ncDb/MgwRc2JDwc9orCBfE | ||
6 | NqfYlD22wK8pCtMZX+t9zE0FVhEK7rHz18laPIxXFpFRFPggTg8pngQh5vHk6ESv | ||
7 | 1yWSCGT8LBwuT3FTkVMd5fl7Ug8h2lzdGWiWynBq8cQNB6/4ZROS6e9ls4mG/cB0 | ||
8 | XKRrSWLFAgMBAAECggEAezQ0V1o11dEc1vuiTjJgzWnLA4aF5OcUquZjb8jo2Blp | ||
9 | soR0fUgYEFiV9RRaPl+nr7ptKe0rBgfAOGALKUHNCdN/JNU8oQmjEoyADg3s6jeB | ||
10 | xruQlzWgDwszf2uqVwHj16Nkhx1wYBKZQeQBSmCkBHwl/daKHcahqn3CkLOleKx+ | ||
11 | Qlc3BzWNaGte6qpJMs0It3by1FuxRwVz5VkL8uhzj0WIOYMA84t0gTnFH9gfRO3F | ||
12 | licotxg/Nl5M36wWcfL8Jq++72AtaKcD1jUEwuQpogrVeqflmeHwn/TlL++Hv6Xe | ||
13 | Lq0jt3OCUKUV40eq9c5uEgTmyrVHMDkfFdXzutdMAQKBgQDsSMXk7P4SX6u6uTjV | ||
14 | In9eWw6ZyJ2aL6VB9co/NMsj49GrrFT8VX9d+JPe9P/n6tuGcFbymNep22njRksR | ||
15 | 0ItpW1NFRR/R3g0kYe1EhkRpNm6fhY9oIuR9xhcNnPNYkqAKT3T/dxrzbwsNhomi | ||
16 | X8aht/eCz4ZsK/KdOGTkPozxgQKBgQDNOvrclT1Wl4bxONp9pEV5XpRSD/qigfIp | ||
17 | i5wxy7ihX/QY9RToIWJDnzMVLnEYe64RB2WB8/4WwNPOQcuaxXbFUFct/2NdhTnS | ||
18 | ToJPgPe819zW9t1FLTf1fHtsRBpGFtbhdlUDOiOtJiMXYiwlRh2uyWFhjOo8TNUE | ||
19 | qMwai0vLRQKBgQCDH4t6lC4W4jK5x2oLlT5bjWqX2uXjF8e8x/q5gsGspBPKEjOD | ||
20 | aKrq6jSdSRbui73RaGxH6pvb7iBf+LVWKIYFLKIUUdzrqS9f3lw+Z8h1HrjbG9JO | ||
21 | dvaX+aL3cf71S0E3F4sU7fLt3tSiZ+PfUQk424+mbyXox6a2qwIKS9AJgQKBgHCu | ||
22 | dHROYJo9ojKpo5Ueb6K+4jLYYSV+sYZMCBtzHlFETNKzJaJ6SeiU7Ugw8pmdtqnU | ||
23 | 5M/gNl8pymFR0MeOqbKWdPdlZJpBfsjQoE2kouEFqFRCwKStui7IBUAheEeJXLv3 | ||
24 | 659U+aek69l35oMkp0GDgjs8UpN/H+pp/36Hgrr9AoGAftWU405rpStHEdRVrazP | ||
25 | FibQesT9HOdJgmm1gNIhj+PnFs7lKER9p0Wdl79QnIqjwyhjCXL94TFerzTKLY2c | ||
26 | IRj5dcRHiiT0iK8wq8bzGNYCqV73oQXaUFMiutNAArXwzwuvPFPWNBQsjLzeDLeC | ||
27 | mcOsCcPAk8cLYtVfZo2sP3g= | ||
28 | -----END PRIVATE KEY----- | ||
diff --git a/https/testdata/tls-ca-chain.pem b/https/testdata/tls-ca-chain.pem new file mode 100644 index 0000000..722264d --- /dev/null +++ b/https/testdata/tls-ca-chain.pem | |||
@@ -0,0 +1,173 @@ | |||
1 | Certificate: | ||
2 | Data: | ||
3 | Version: 3 (0x2) | ||
4 | Serial Number: 2 (0x2) | ||
5 | Signature Algorithm: sha1WithRSAEncryption | ||
6 | Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA | ||
7 | Validity | ||
8 | Not Before: Apr 5 08:00:37 2019 GMT | ||
9 | Not After : Mar 26 08:00:37 2059 GMT | ||
10 | Subject: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus TLS CA | ||
11 | Subject Public Key Info: | ||
12 | Public Key Algorithm: rsaEncryption | ||
13 | RSA Public-Key: (2048 bit) | ||
14 | Modulus: | ||
15 | 00:aa:d2:34:6b:ed:f1:f4:01:08:e5:00:9f:75:c8: | ||
16 | ba:fc:4b:72:c6:04:93:af:f1:f6:b5:ce:01:0d:c6: | ||
17 | bd:d3:16:98:9d:e5:51:56:12:58:16:ee:18:6e:f0: | ||
18 | 68:a9:42:16:65:cf:e3:31:f5:90:79:9d:13:32:87: | ||
19 | 3b:1f:65:fd:84:88:a4:56:3d:26:54:69:05:27:5a: | ||
20 | ea:89:02:e7:31:9b:7d:7f:76:93:54:70:bc:17:92: | ||
21 | 06:9f:9f:90:4a:8a:cf:82:a7:7b:7c:71:c4:fa:34: | ||
22 | 56:00:32:1a:85:c5:f8:e4:4a:63:43:37:9d:60:84: | ||
23 | 4d:78:6e:87:12:c4:2b:1f:93:a5:fe:cc:5e:f1:df: | ||
24 | c1:97:ff:b7:3e:20:38:1d:71:15:11:ec:6c:7a:cc: | ||
25 | 0e:87:52:31:b1:b9:74:c3:07:1c:42:4b:1e:c1:17: | ||
26 | bc:e4:13:b7:b0:20:2e:c4:07:93:bd:a8:11:f9:da: | ||
27 | a7:d0:df:4a:48:be:9b:6d:65:c3:ae:58:56:c0:9f: | ||
28 | 17:c5:d8:32:b1:04:22:fb:5b:18:f6:20:10:50:ec: | ||
29 | 2d:10:4f:cc:48:8f:f2:75:dd:33:a4:0e:f5:55:da: | ||
30 | 2c:89:a1:3a:52:bb:11:11:0b:97:27:17:73:35:da: | ||
31 | 10:71:b3:9f:a8:42:91:e6:3a:66:00:f9:e5:11:8f: | ||
32 | 5b:57 | ||
33 | Exponent: 65537 (0x10001) | ||
34 | X509v3 extensions: | ||
35 | X509v3 Key Usage: critical | ||
36 | Certificate Sign, CRL Sign | ||
37 | X509v3 Basic Constraints: critical | ||
38 | CA:TRUE, pathlen:0 | ||
39 | X509v3 Subject Key Identifier: | ||
40 | 4D:02:BF:71:95:6A:AA:58:C5:9C:B8:83:67:5E:64:16:99:E1:2A:9E | ||
41 | X509v3 Authority Key Identifier: | ||
42 | keyid:3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A | ||
43 | |||
44 | Authority Information Access: | ||
45 | CA Issuers - URI:https://example.com/ca/root-ca.cer | ||
46 | |||
47 | X509v3 CRL Distribution Points: | ||
48 | |||
49 | Full Name: | ||
50 | URI:https://example.com/ca/root-ca.crl | ||
51 | |||
52 | Signature Algorithm: sha1WithRSAEncryption | ||
53 | 63:fc:ba:30:a5:05:d6:76:14:f1:77:38:b1:41:6f:81:d9:b4: | ||
54 | 02:fd:bc:e5:f6:d9:e6:73:e0:71:cf:4c:fb:13:b5:6b:bd:b9: | ||
55 | c6:f6:28:18:36:e1:8c:d9:93:b3:78:4a:3d:39:1b:f4:fb:69: | ||
56 | 75:24:ae:e1:a0:2f:94:05:bf:10:3c:3e:d2:2b:a8:f3:31:25: | ||
57 | 2e:ed:13:ad:60:5d:22:9a:26:15:20:86:98:73:4c:f6:4b:48: | ||
58 | b8:1f:67:ba:4e:c9:47:ed:85:dc:38:dc:02:0c:fb:54:d5:2e: | ||
59 | 6c:b4:95:18:51:d1:ae:ea:e8:fb:b4:19:50:04:bc:31:7e:51: | ||
60 | 9e:85:29:4d:c8:f7:26:d6:d6:8d:35:2d:9e:e2:06:16:38:e2: | ||
61 | 56:80:ec:f3:a3:34:e3:28:c4:e8:10:d0:8a:a6:6f:20:9a:b9: | ||
62 | dc:b9:90:6b:ba:8a:27:2c:29:72:28:55:e7:59:a6:a7:90:ec: | ||
63 | 32:e8:d0:26:4a:c1:44:dd:20:bf:dc:4d:1e:7e:cc:e5:a2:5b: | ||
64 | e8:df:3d:4b:01:aa:48:56:17:e9:29:d8:71:83:05:36:8c:11: | ||
65 | 4f:77:b8:95:20:b7:c7:21:06:c2:87:97:b4:6b:d3:f7:23:ba: | ||
66 | 4d:5f:15:d1:0c:4d:6e:f1:6a:9d:57:5c:02:6a:d7:31:18:ef: | ||
67 | 5c:fc:f8:04 | ||
68 | -----BEGIN CERTIFICATE----- | ||
69 | MIIELTCCAxWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJVUzET | ||
70 | MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp | ||
71 | Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMElByb21ldGhldXMgUm9vdCBDQTAgFw0x | ||
72 | OTA0MDUwODAwMzdaGA8yMDU5MDMyNjA4MDAzN1owaTELMAkGA1UEBhMCVVMxEzAR | ||
73 | BgNVBAoMClByb21ldGhldXMxKTAnBgNVBAsMIFByb21ldGhldXMgQ2VydGlmaWNh | ||
74 | dGUgQXV0aG9yaXR5MRowGAYDVQQDDBFQcm9tZXRoZXVzIFRMUyBDQTCCASIwDQYJ | ||
75 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKrSNGvt8fQBCOUAn3XIuvxLcsYEk6/x | ||
76 | 9rXOAQ3GvdMWmJ3lUVYSWBbuGG7waKlCFmXP4zH1kHmdEzKHOx9l/YSIpFY9JlRp | ||
77 | BSda6okC5zGbfX92k1RwvBeSBp+fkEqKz4Kne3xxxPo0VgAyGoXF+ORKY0M3nWCE | ||
78 | TXhuhxLEKx+Tpf7MXvHfwZf/tz4gOB1xFRHsbHrMDodSMbG5dMMHHEJLHsEXvOQT | ||
79 | t7AgLsQHk72oEfnap9DfSki+m21lw65YVsCfF8XYMrEEIvtbGPYgEFDsLRBPzEiP | ||
80 | 8nXdM6QO9VXaLImhOlK7ERELlycXczXaEHGzn6hCkeY6ZgD55RGPW1cCAwEAAaOB | ||
81 | 3DCB2TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E | ||
82 | FgQUTQK/cZVqqljFnLiDZ15kFpnhKp4wHwYDVR0jBBgwFoAUPB6oxkwFTSDsiNsp | ||
83 | 1Hv5El3O6howPgYIKwYBBQUHAQEEMjAwMC4GCCsGAQUFBzAChiJodHRwczovL2V4 | ||
84 | YW1wbGUuY29tL2NhL3Jvb3QtY2EuY2VyMDMGA1UdHwQsMCowKKAmoCSGImh0dHBz | ||
85 | Oi8vZXhhbXBsZS5jb20vY2Evcm9vdC1jYS5jcmwwDQYJKoZIhvcNAQEFBQADggEB | ||
86 | AGP8ujClBdZ2FPF3OLFBb4HZtAL9vOX22eZz4HHPTPsTtWu9ucb2KBg24YzZk7N4 | ||
87 | Sj05G/T7aXUkruGgL5QFvxA8PtIrqPMxJS7tE61gXSKaJhUghphzTPZLSLgfZ7pO | ||
88 | yUfthdw43AIM+1TVLmy0lRhR0a7q6Pu0GVAEvDF+UZ6FKU3I9ybW1o01LZ7iBhY4 | ||
89 | 4laA7POjNOMoxOgQ0IqmbyCaudy5kGu6iicsKXIoVedZpqeQ7DLo0CZKwUTdIL/c | ||
90 | TR5+zOWiW+jfPUsBqkhWF+kp2HGDBTaMEU93uJUgt8chBsKHl7Rr0/cjuk1fFdEM | ||
91 | TW7xap1XXAJq1zEY71z8+AQ= | ||
92 | -----END CERTIFICATE----- | ||
93 | Certificate: | ||
94 | Data: | ||
95 | Version: 3 (0x2) | ||
96 | Serial Number: 1 (0x1) | ||
97 | Signature Algorithm: sha1WithRSAEncryption | ||
98 | Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA | ||
99 | Validity | ||
100 | Not Before: Apr 5 07:55:00 2019 GMT | ||
101 | Not After : Mar 26 07:55:00 2059 GMT | ||
102 | Subject: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA | ||
103 | Subject Public Key Info: | ||
104 | Public Key Algorithm: rsaEncryption | ||
105 | RSA Public-Key: (2048 bit) | ||
106 | Modulus: | ||
107 | 00:bf:b9:e2:ab:5f:61:22:e1:4e:cd:ee:da:b0:26: | ||
108 | 2e:bb:b0:7e:1c:ce:10:be:16:29:35:0c:0c:1d:93: | ||
109 | 01:29:2a:f6:f9:c2:6e:5c:10:44:ca:f8:dc:ad:7a: | ||
110 | 06:64:0f:8a:18:ad:b2:a2:94:49:c9:ba:8c:45:94: | ||
111 | 7c:d9:e0:11:45:d8:16:79:a2:20:9f:8c:63:60:72: | ||
112 | 2a:5b:f9:66:80:ac:85:67:01:5a:eb:91:c1:d2:88: | ||
113 | 87:9e:4c:18:c9:f2:f0:7a:18:c0:e6:ab:2c:78:de: | ||
114 | 5f:b2:22:4e:94:9c:f5:cd:e6:e2:33:30:e9:20:10: | ||
115 | a6:a1:75:eb:59:ab:45:a9:f7:3e:54:40:ae:05:25: | ||
116 | be:74:c5:3a:fd:af:73:16:60:45:7c:4a:e0:0e:0d: | ||
117 | a1:15:7f:9a:1f:c2:a7:04:ad:ef:b3:e4:f6:00:2c: | ||
118 | 4e:0b:04:90:49:ee:d3:db:a6:12:c4:91:0b:32:4f: | ||
119 | 11:84:c7:c4:8a:ef:51:66:7a:b0:20:2f:cb:95:8d: | ||
120 | 96:57:60:66:5e:f9:4f:5a:94:9c:71:ad:eb:ca:70: | ||
121 | 3e:62:06:c2:3a:29:f8:9e:86:af:da:07:78:f8:31: | ||
122 | af:42:48:49:9e:4a:df:1b:27:1f:44:35:81:6d:fa: | ||
123 | 7a:c5:6a:0a:35:23:c7:c4:d5:fe:c9:9e:61:c9:30: | ||
124 | cd:1f | ||
125 | Exponent: 65537 (0x10001) | ||
126 | X509v3 extensions: | ||
127 | X509v3 Key Usage: critical | ||
128 | Certificate Sign, CRL Sign | ||
129 | X509v3 Basic Constraints: critical | ||
130 | CA:TRUE | ||
131 | X509v3 Subject Key Identifier: | ||
132 | 3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A | ||
133 | X509v3 Authority Key Identifier: | ||
134 | keyid:3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A | ||
135 | |||
136 | Signature Algorithm: sha1WithRSAEncryption | ||
137 | 56:2f:79:e5:12:91:f5:19:a7:d1:32:28:fd:e3:9d:8f:e1:3c: | ||
138 | bb:a3:a5:f2:55:8a:03:ad:2c:1d:18:82:e1:7f:19:75:d9:47: | ||
139 | 5b:e7:7c:e4:a5:e0:eb:dc:7e:24:a3:7d:99:1a:cf:39:ba:a5: | ||
140 | b4:b8:45:68:83:cf:70:ad:56:f2:34:73:65:fc:6c:b0:53:9a: | ||
141 | 79:04:f7:3e:7e:4b:22:1b:e7:76:23:20:bc:9c:05:a2:5d:01: | ||
142 | d2:f0:09:49:17:b2:61:74:1a:5b:f4:e0:fd:ce:11:ba:13:4a: | ||
143 | e6:07:11:7d:30:e2:11:87:ee:33:1a:68:de:67:f4:ac:b5:58: | ||
144 | 1a:ac:cf:7a:2d:fd:c3:44:5b:4b:cd:6c:ff:f6:49:b4:55:4a: | ||
145 | 09:a0:92:2d:57:3b:69:85:54:3e:e9:ec:ef:b2:a5:7a:29:75: | ||
146 | 2b:f8:eb:4b:d4:cf:68:ee:3e:c8:63:7e:12:eb:e4:2f:63:a3: | ||
147 | a7:c8:0f:e9:39:ff:5c:29:65:7f:25:f0:42:bf:07:ba:06:b8: | ||
148 | 5e:d6:56:ba:f8:67:56:1b:42:aa:b3:04:d8:6e:88:10:a5:70: | ||
149 | b5:81:04:a4:90:a3:f0:83:4d:0c:6b:12:5d:a4:4c:83:5a:ff: | ||
150 | a8:7a:86:61:ff:0f:4c:e5:0f:17:d1:64:3c:bd:d9:22:7e:b7: | ||
151 | fa:9b:83:ba | ||
152 | -----BEGIN CERTIFICATE----- | ||
153 | MIIDtDCCApygAwIBAgIBATANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJVUzET | ||
154 | MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp | ||
155 | Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMElByb21ldGhldXMgUm9vdCBDQTAgFw0x | ||
156 | OTA0MDUwNzU1MDBaGA8yMDU5MDMyNjA3NTUwMFowajELMAkGA1UEBhMCVVMxEzAR | ||
157 | BgNVBAoMClByb21ldGhldXMxKTAnBgNVBAsMIFByb21ldGhldXMgQ2VydGlmaWNh | ||
158 | dGUgQXV0aG9yaXR5MRswGQYDVQQDDBJQcm9tZXRoZXVzIFJvb3QgQ0EwggEiMA0G | ||
159 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/ueKrX2Ei4U7N7tqwJi67sH4czhC+ | ||
160 | Fik1DAwdkwEpKvb5wm5cEETK+NytegZkD4oYrbKilEnJuoxFlHzZ4BFF2BZ5oiCf | ||
161 | jGNgcipb+WaArIVnAVrrkcHSiIeeTBjJ8vB6GMDmqyx43l+yIk6UnPXN5uIzMOkg | ||
162 | EKahdetZq0Wp9z5UQK4FJb50xTr9r3MWYEV8SuAODaEVf5ofwqcEre+z5PYALE4L | ||
163 | BJBJ7tPbphLEkQsyTxGEx8SK71FmerAgL8uVjZZXYGZe+U9alJxxrevKcD5iBsI6 | ||
164 | Kfiehq/aB3j4Ma9CSEmeSt8bJx9ENYFt+nrFago1I8fE1f7JnmHJMM0fAgMBAAGj | ||
165 | YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQ8 | ||
166 | HqjGTAVNIOyI2ynUe/kSXc7qGjAfBgNVHSMEGDAWgBQ8HqjGTAVNIOyI2ynUe/kS | ||
167 | Xc7qGjANBgkqhkiG9w0BAQUFAAOCAQEAVi955RKR9Rmn0TIo/eOdj+E8u6Ol8lWK | ||
168 | A60sHRiC4X8ZddlHW+d85KXg69x+JKN9mRrPObqltLhFaIPPcK1W8jRzZfxssFOa | ||
169 | eQT3Pn5LIhvndiMgvJwFol0B0vAJSReyYXQaW/Tg/c4RuhNK5gcRfTDiEYfuMxpo | ||
170 | 3mf0rLVYGqzPei39w0RbS81s//ZJtFVKCaCSLVc7aYVUPuns77Kleil1K/jrS9TP | ||
171 | aO4+yGN+EuvkL2Ojp8gP6Tn/XCllfyXwQr8Huga4XtZWuvhnVhtCqrME2G6IEKVw | ||
172 | tYEEpJCj8INNDGsSXaRMg1r/qHqGYf8PTOUPF9FkPL3ZIn63+puDug== | ||
173 | -----END CERTIFICATE----- | ||
diff --git a/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml b/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml new file mode 100644 index 0000000..c34cc4f --- /dev/null +++ b/https/testdata/tls_config_auth_clientCAs_invalid.bad.yml | |||
@@ -0,0 +1,4 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.crt" | ||
3 | tlsKeyPath : "testdata/server.key" | ||
4 | clientCAs : "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 new file mode 100644 index 0000000..fc92932 --- /dev/null +++ b/https/testdata/tls_config_auth_clientCAs_missing.bad.yml | |||
@@ -0,0 +1,4 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.crt" | ||
3 | tlsKeyPath : "testdata/server.key" | ||
4 | clientAuth : "RequireAndVerifyClientCert" \ No newline at end of file | ||
diff --git a/https/testdata/tls_config_empty.yml b/https/testdata/tls_config_empty.yml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/https/testdata/tls_config_empty.yml | |||
diff --git a/https/testdata/tls_config_junk.yml b/https/testdata/tls_config_junk.yml new file mode 100644 index 0000000..568a7c4 --- /dev/null +++ b/https/testdata/tls_config_junk.yml | |||
@@ -0,0 +1,20 @@ | |||
1 | hWkNKCp3fvIx3jKnsaBI | ||
2 | TuEjdwNS8A2vYdFbiKqr | ||
3 | ay3RiOtykgt4m6m3KOol | ||
4 | ZreGpJRGmpDSVV9cioiF | ||
5 | r7kDOHhHU2frvv0nLcY2 | ||
6 | uQMQM4XgqFkCG6gFAIJZ | ||
7 | g99tTkrZhN9b6pkJ6J2y | ||
8 | rzdt729HrA2RblDGYfjs | ||
9 | MW7GxrBdlCnliYJGPhfr | ||
10 | g9kaXxMXcDwsw0C0rv0u | ||
11 | 637ZmfRGElb6VBVOtgqn | ||
12 | RG0MRezjLYCJQBMUdRDE | ||
13 | RzO4VicAzj7asVZAT3oo | ||
14 | nPw267UONk7h7KBYRgch | ||
15 | Alj38foWqjV3heXXdahm | ||
16 | TrMzMgl6JIQ1x4OZB5i4 | ||
17 | qlrXFJoeV6Pr77nuiEh9 | ||
18 | 3yE5vMnnKHm2nImEfzMG | ||
19 | bI01UDObHRSaoJLC0vTD | ||
20 | G9tlcKU883NkQ6nsxJ8Y | ||
diff --git a/https/testdata/tls_config_noAuth.bad.yml b/https/testdata/tls_config_noAuth.bad.yml new file mode 100644 index 0000000..f0dd228 --- /dev/null +++ b/https/testdata/tls_config_noAuth.bad.yml | |||
@@ -0,0 +1,4 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.crt" | ||
3 | tlsKeyPath : "testdata/server.key" | ||
4 | clientCAs : "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 new file mode 100644 index 0000000..f567693 --- /dev/null +++ b/https/testdata/tls_config_noAuth.good.blocking.yml | |||
@@ -0,0 +1,5 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.crt" | ||
3 | tlsKeyPath : "testdata/server.key" | ||
4 | clientAuth : "RequireAndVerifyClientCert" | ||
5 | clientCAs: "testdata/tls-ca-chain.pem" \ No newline at end of file | ||
diff --git a/https/testdata/tls_config_noAuth.good.yml b/https/testdata/tls_config_noAuth.good.yml new file mode 100644 index 0000000..76e46cf --- /dev/null +++ b/https/testdata/tls_config_noAuth.good.yml | |||
@@ -0,0 +1,5 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.crt" | ||
3 | tlsKeyPath : "testdata/server.key" | ||
4 | clientAuth : "VerifyClientCertIfGiven" | ||
5 | clientCAs : "testdata/tls-ca-chain.pem" | ||
diff --git a/https/testdata/tls_config_noAuth_certPath_empty.bad.yml b/https/testdata/tls_config_noAuth_certPath_empty.bad.yml new file mode 100644 index 0000000..39c7abd --- /dev/null +++ b/https/testdata/tls_config_noAuth_certPath_empty.bad.yml | |||
@@ -0,0 +1,3 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "" | ||
3 | tlsKeyPath : "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 new file mode 100644 index 0000000..5bdbd1a --- /dev/null +++ b/https/testdata/tls_config_noAuth_certPath_invalid.bad.yml | |||
@@ -0,0 +1,3 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "somefile" | ||
3 | tlsKeyPath : "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 new file mode 100644 index 0000000..938e5d6 --- /dev/null +++ b/https/testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml | |||
@@ -0,0 +1,3 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "" | ||
3 | tlsKeyPath : "" \ No newline at end of file | ||
diff --git a/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml b/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml new file mode 100644 index 0000000..b93ffd6 --- /dev/null +++ b/https/testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml | |||
@@ -0,0 +1,3 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "somefile" | ||
3 | tlsKeyPath : "somefile" \ No newline at end of file | ||
diff --git a/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml b/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml new file mode 100644 index 0000000..424f92f --- /dev/null +++ b/https/testdata/tls_config_noAuth_keyPath_empty.bad.yml | |||
@@ -0,0 +1,3 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.crt" | ||
3 | tlsKeyPath : "" \ 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 new file mode 100644 index 0000000..2625074 --- /dev/null +++ b/https/testdata/tls_config_noAuth_keyPath_invalid.bad.yml | |||
@@ -0,0 +1,3 @@ | |||
1 | tlsConfig : | ||
2 | tlsCertPath : "testdata/server.cert" | ||
3 | tlsKeyPath : "somefile" \ No newline at end of file | ||
diff --git a/https/tls_config.go b/https/tls_config.go new file mode 100644 index 0000000..dd473d8 --- /dev/null +++ b/https/tls_config.go | |||
@@ -0,0 +1,123 @@ | |||
1 | // Copyright 2019 The Prometheus Authors | ||
2 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
3 | // you may not use this file except in compliance with the License. | ||
4 | // You may obtain a copy of the License at | ||
5 | // | ||
6 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
7 | // | ||
8 | // Unless required by applicable law or agreed to in writing, software | ||
9 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
11 | // See the License for the specific language governing permissions and | ||
12 | // limitations under the License. | ||
13 | |||
14 | // Package https allows the implementation of TLS. | ||
15 | package https | ||
16 | |||
17 | import ( | ||
18 | "crypto/tls" | ||
19 | "crypto/x509" | ||
20 | "io/ioutil" | ||
21 | "net/http" | ||
22 | |||
23 | "github.com/pkg/errors" | ||
24 | "gopkg.in/yaml.v2" | ||
25 | ) | ||
26 | |||
27 | type Config struct { | ||
28 | TLSConfig TLSStruct `yaml:"tlsConfig"` | ||
29 | } | ||
30 | |||
31 | type TLSStruct struct { | ||
32 | TLSCertPath string `yaml:"tlsCertPath"` | ||
33 | TLSKeyPath string `yaml:"tlsKeyPath"` | ||
34 | ClientAuth string `yaml:"clientAuth"` | ||
35 | ClientCAs string `yaml:"clientCAs"` | ||
36 | } | ||
37 | |||
38 | func getTLSConfig(configPath string) (*tls.Config, error) { | ||
39 | content, err := ioutil.ReadFile(configPath) | ||
40 | if err != nil { | ||
41 | return nil, err | ||
42 | } | ||
43 | c := &Config{} | ||
44 | err = yaml.Unmarshal(content, c) | ||
45 | if err != nil { | ||
46 | return nil, err | ||
47 | } | ||
48 | return configToTLSConfig(&c.TLSConfig) | ||
49 | } | ||
50 | |||
51 | func configToTLSConfig(c *TLSStruct) (*tls.Config, error) { | ||
52 | cfg := &tls.Config{} | ||
53 | if len(c.TLSCertPath) == 0 { | ||
54 | return nil, errors.New("missing TLSCertPath") | ||
55 | } | ||
56 | if len(c.TLSKeyPath) == 0 { | ||
57 | return nil, errors.New("missing TLSKeyPath") | ||
58 | } | ||
59 | loadCert := func() (*tls.Certificate, error) { | ||
60 | cert, err := tls.LoadX509KeyPair(c.TLSCertPath, c.TLSKeyPath) | ||
61 | if err != nil { | ||
62 | return nil, errors.Wrap(err, "failed to load X509KeyPair") | ||
63 | } | ||
64 | return &cert, nil | ||
65 | } | ||
66 | // Confirm that certificate and key paths are valid. | ||
67 | if _, err := loadCert(); err != nil { | ||
68 | return nil, err | ||
69 | } | ||
70 | cfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { | ||
71 | return loadCert() | ||
72 | } | ||
73 | |||
74 | if len(c.ClientCAs) > 0 { | ||
75 | clientCAPool := x509.NewCertPool() | ||
76 | clientCAFile, err := ioutil.ReadFile(c.ClientCAs) | ||
77 | if err != nil { | ||
78 | return nil, err | ||
79 | } | ||
80 | clientCAPool.AppendCertsFromPEM(clientCAFile) | ||
81 | cfg.ClientCAs = clientCAPool | ||
82 | } | ||
83 | if len(c.ClientAuth) > 0 { | ||
84 | switch s := (c.ClientAuth); s { | ||
85 | case "NoClientCert": | ||
86 | cfg.ClientAuth = tls.NoClientCert | ||
87 | case "RequestClientCert": | ||
88 | cfg.ClientAuth = tls.RequestClientCert | ||
89 | case "RequireClientCert": | ||
90 | cfg.ClientAuth = tls.RequireAnyClientCert | ||
91 | case "VerifyClientCertIfGiven": | ||
92 | cfg.ClientAuth = tls.VerifyClientCertIfGiven | ||
93 | case "RequireAndVerifyClientCert": | ||
94 | cfg.ClientAuth = tls.RequireAndVerifyClientCert | ||
95 | case "": | ||
96 | cfg.ClientAuth = tls.NoClientCert | ||
97 | default: | ||
98 | return nil, errors.New("Invalid ClientAuth: " + s) | ||
99 | } | ||
100 | } | ||
101 | if len(c.ClientCAs) > 0 && cfg.ClientAuth == tls.NoClientCert { | ||
102 | return nil, errors.New("Client CA's have been configured without a Client Auth Policy") | ||
103 | } | ||
104 | return cfg, nil | ||
105 | } | ||
106 | |||
107 | // Listen starts the server on the given address. If tlsConfigPath isn't empty the server connection will be started using TLS. | ||
108 | func Listen(server *http.Server, tlsConfigPath string) error { | ||
109 | if (tlsConfigPath) == "" { | ||
110 | return server.ListenAndServe() | ||
111 | } | ||
112 | var err error | ||
113 | server.TLSConfig, err = getTLSConfig(tlsConfigPath) | ||
114 | if err != nil { | ||
115 | return err | ||
116 | } | ||
117 | // Set the GetConfigForClient method of the HTTPS server so that the config | ||
118 | // and certs are reloaded on new connections. | ||
119 | server.TLSConfig.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) { | ||
120 | return getTLSConfig(tlsConfigPath) | ||
121 | } | ||
122 | return server.ListenAndServeTLS("", "") | ||
123 | } | ||
diff --git a/https/tls_config_test.go b/https/tls_config_test.go new file mode 100644 index 0000000..717f201 --- /dev/null +++ b/https/tls_config_test.go | |||
@@ -0,0 +1,362 @@ | |||
1 | // Copyright 2019 The Prometheus Authors | ||
2 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
3 | // you may not use this file except in compliance with the License. | ||
4 | // You may obtain a copy of the License at | ||
5 | // | ||
6 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
7 | // | ||
8 | // Unless required by applicable law or agreed to in writing, software | ||
9 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
11 | // See the License for the specific language governing permissions and | ||
12 | // limitations under the License. | ||
13 | |||
14 | package https | ||
15 | |||
16 | import ( | ||
17 | "crypto/tls" | ||
18 | "crypto/x509" | ||
19 | "errors" | ||
20 | "fmt" | ||
21 | "io/ioutil" | ||
22 | "net" | ||
23 | "net/http" | ||
24 | "regexp" | ||
25 | "sync" | ||
26 | "testing" | ||
27 | "time" | ||
28 | ) | ||
29 | |||
30 | var ( | ||
31 | port = getPort() | ||
32 | |||
33 | ErrorMap = map[string]*regexp.Regexp{ | ||
34 | "HTTP Response to HTTPS": regexp.MustCompile(`server gave HTTP response to HTTPS client`), | ||
35 | "No such file": regexp.MustCompile(`no such file`), | ||
36 | "Invalid argument": regexp.MustCompile(`invalid argument`), | ||
37 | "YAML error": regexp.MustCompile(`yaml`), | ||
38 | "Invalid ClientAuth": regexp.MustCompile(`invalid ClientAuth`), | ||
39 | "TLS handshake": regexp.MustCompile(`tls`), | ||
40 | "HTTP Request to HTTPS server": regexp.MustCompile(`HTTP`), | ||
41 | "Invalid CertPath": regexp.MustCompile(`missing TLSCertPath`), | ||
42 | "Invalid KeyPath": regexp.MustCompile(`missing TLSKeyPath`), | ||
43 | "ClientCA set without policy": regexp.MustCompile(`Client CA's have been configured without a Client Auth Policy`), | ||
44 | } | ||
45 | ) | ||
46 | |||
47 | func getPort() string { | ||
48 | listener, err := net.Listen("tcp", ":0") | ||
49 | if err != nil { | ||
50 | panic(err) | ||
51 | } | ||
52 | defer listener.Close() | ||
53 | p := listener.Addr().(*net.TCPAddr).Port | ||
54 | return fmt.Sprintf(":%v", p) | ||
55 | } | ||
56 | |||
57 | type TestInputs struct { | ||
58 | Name string | ||
59 | Server func() *http.Server | ||
60 | UseNilServer bool | ||
61 | YAMLConfigPath string | ||
62 | ExpectedError *regexp.Regexp | ||
63 | UseTLSClient bool | ||
64 | } | ||
65 | |||
66 | func TestYAMLFiles(t *testing.T) { | ||
67 | testTables := []*TestInputs{ | ||
68 | { | ||
69 | Name: `path to config yml invalid`, | ||
70 | YAMLConfigPath: "somefile", | ||
71 | ExpectedError: ErrorMap["No such file"], | ||
72 | }, | ||
73 | { | ||
74 | Name: `empty config yml`, | ||
75 | YAMLConfigPath: "testdata/tls_config_empty.yml", | ||
76 | ExpectedError: ErrorMap["Invalid CertPath"], | ||
77 | }, | ||
78 | { | ||
79 | Name: `invalid config yml (invalid structure)`, | ||
80 | YAMLConfigPath: "testdata/tls_config_junk.yml", | ||
81 | ExpectedError: ErrorMap["YAML error"], | ||
82 | }, | ||
83 | { | ||
84 | Name: `invalid config yml (cert path empty)`, | ||
85 | YAMLConfigPath: "testdata/tls_config_noAuth_certPath_empty.bad.yml", | ||
86 | ExpectedError: ErrorMap["Invalid CertPath"], | ||
87 | }, | ||
88 | { | ||
89 | Name: `invalid config yml (key path empty)`, | ||
90 | YAMLConfigPath: "testdata/tls_config_noAuth_keyPath_empty.bad.yml", | ||
91 | ExpectedError: ErrorMap["Invalid KeyPath"], | ||
92 | }, | ||
93 | { | ||
94 | Name: `invalid config yml (cert path and key path empty)`, | ||
95 | YAMLConfigPath: "testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml", | ||
96 | ExpectedError: ErrorMap["Invalid CertPath"], | ||
97 | }, | ||
98 | { | ||
99 | Name: `invalid config yml (cert path invalid)`, | ||
100 | YAMLConfigPath: "testdata/tls_config_noAuth_certPath_invalid.bad.yml", | ||
101 | ExpectedError: ErrorMap["No such file"], | ||
102 | }, | ||
103 | { | ||
104 | Name: `invalid config yml (key path invalid)`, | ||
105 | YAMLConfigPath: "testdata/tls_config_noAuth_keyPath_invalid.bad.yml", | ||
106 | ExpectedError: ErrorMap["No such file"], | ||
107 | }, | ||
108 | { | ||
109 | Name: `invalid config yml (cert path and key path invalid)`, | ||
110 | YAMLConfigPath: "testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml", | ||
111 | ExpectedError: ErrorMap["No such file"], | ||
112 | }, | ||
113 | { | ||
114 | Name: `invalid config yml (invalid ClientAuth)`, | ||
115 | YAMLConfigPath: "testdata/tls_config_noAuth.bad.yml", | ||
116 | ExpectedError: ErrorMap["ClientCA set without policy"], | ||
117 | }, | ||
118 | { | ||
119 | Name: `invalid config yml (invalid ClientCAs filepath)`, | ||
120 | YAMLConfigPath: "testdata/tls_config_auth_clientCAs_invalid.bad.yml", | ||
121 | ExpectedError: ErrorMap["No such file"], | ||
122 | }, | ||
123 | } | ||
124 | for _, testInputs := range testTables { | ||
125 | t.Run(testInputs.Name, testInputs.Test) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | func TestServerBehaviour(t *testing.T) { | ||
130 | testTables := []*TestInputs{ | ||
131 | { | ||
132 | Name: `empty string YAMLConfigPath and default client`, | ||
133 | YAMLConfigPath: "", | ||
134 | ExpectedError: nil, | ||
135 | }, | ||
136 | { | ||
137 | Name: `empty string YAMLConfigPath and TLS client`, | ||
138 | YAMLConfigPath: "", | ||
139 | UseTLSClient: true, | ||
140 | ExpectedError: ErrorMap["HTTP Response to HTTPS"], | ||
141 | }, | ||
142 | { | ||
143 | Name: `valid tls config yml and default client`, | ||
144 | YAMLConfigPath: "testdata/tls_config_noAuth.good.yml", | ||
145 | ExpectedError: ErrorMap["HTTP Request to HTTPS server"], | ||
146 | }, | ||
147 | { | ||
148 | Name: `valid tls config yml and tls client`, | ||
149 | YAMLConfigPath: "testdata/tls_config_noAuth.good.yml", | ||
150 | UseTLSClient: true, | ||
151 | ExpectedError: nil, | ||
152 | }, | ||
153 | } | ||
154 | for _, testInputs := range testTables { | ||
155 | t.Run(testInputs.Name, testInputs.Test) | ||
156 | } | ||
157 | } | ||
158 | |||
159 | func TestConfigReloading(t *testing.T) { | ||
160 | errorChannel := make(chan error, 1) | ||
161 | var once sync.Once | ||
162 | recordConnectionError := func(err error) { | ||
163 | once.Do(func() { | ||
164 | errorChannel <- err | ||
165 | }) | ||
166 | } | ||
167 | defer func() { | ||
168 | if recover() != nil { | ||
169 | recordConnectionError(errors.New("Panic in test function")) | ||
170 | } | ||
171 | }() | ||
172 | |||
173 | goodYAMLPath := "testdata/tls_config_noAuth.good.yml" | ||
174 | badYAMLPath := "testdata/tls_config_noAuth.good.blocking.yml" | ||
175 | |||
176 | server := &http.Server{ | ||
177 | Addr: port, | ||
178 | Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
179 | w.Write([]byte("Hello World!")) | ||
180 | }), | ||
181 | } | ||
182 | defer func() { | ||
183 | server.Close() | ||
184 | }() | ||
185 | |||
186 | go func() { | ||
187 | defer func() { | ||
188 | if recover() != nil { | ||
189 | recordConnectionError(errors.New("Panic starting server")) | ||
190 | } | ||
191 | }() | ||
192 | err := Listen(server, badYAMLPath) | ||
193 | recordConnectionError(err) | ||
194 | }() | ||
195 | |||
196 | client := getTLSClient() | ||
197 | |||
198 | TestClientConnection := func() error { | ||
199 | time.Sleep(250 * time.Millisecond) | ||
200 | r, err := client.Get("https://localhost" + port) | ||
201 | if err != nil { | ||
202 | return (err) | ||
203 | } | ||
204 | body, err := ioutil.ReadAll(r.Body) | ||
205 | if err != nil { | ||
206 | return (err) | ||
207 | } | ||
208 | if string(body) != "Hello World!" { | ||
209 | return (errors.New(string(body))) | ||
210 | } | ||
211 | return (nil) | ||
212 | } | ||
213 | |||
214 | err := TestClientConnection() | ||
215 | if err == nil { | ||
216 | recordConnectionError(errors.New("Connection accepted but should have failed.")) | ||
217 | } else { | ||
218 | swapFileContents(goodYAMLPath, badYAMLPath) | ||
219 | defer swapFileContents(goodYAMLPath, badYAMLPath) | ||
220 | err = TestClientConnection() | ||
221 | if err != nil { | ||
222 | recordConnectionError(errors.New("Connection failed but should have been accepted.")) | ||
223 | } else { | ||
224 | |||
225 | recordConnectionError(nil) | ||
226 | } | ||
227 | } | ||
228 | |||
229 | err = <-errorChannel | ||
230 | if err != nil { | ||
231 | t.Errorf(" *** Failed test: %s *** Returned error: %v", "TestConfigReloading", err) | ||
232 | } | ||
233 | } | ||
234 | |||
235 | func (test *TestInputs) Test(t *testing.T) { | ||
236 | errorChannel := make(chan error, 1) | ||
237 | var once sync.Once | ||
238 | recordConnectionError := func(err error) { | ||
239 | once.Do(func() { | ||
240 | errorChannel <- err | ||
241 | }) | ||
242 | } | ||
243 | defer func() { | ||
244 | if recover() != nil { | ||
245 | recordConnectionError(errors.New("Panic in test function")) | ||
246 | } | ||
247 | }() | ||
248 | |||
249 | var server *http.Server | ||
250 | if test.UseNilServer { | ||
251 | server = nil | ||
252 | } else { | ||
253 | server = &http.Server{ | ||
254 | Addr: port, | ||
255 | Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
256 | w.Write([]byte("Hello World!")) | ||
257 | }), | ||
258 | } | ||
259 | defer func() { | ||
260 | server.Close() | ||
261 | }() | ||
262 | } | ||
263 | go func() { | ||
264 | defer func() { | ||
265 | if recover() != nil { | ||
266 | recordConnectionError(errors.New("Panic starting server")) | ||
267 | } | ||
268 | }() | ||
269 | err := Listen(server, test.YAMLConfigPath) | ||
270 | recordConnectionError(err) | ||
271 | }() | ||
272 | |||
273 | var ClientConnection func() (*http.Response, error) | ||
274 | if test.UseTLSClient { | ||
275 | ClientConnection = func() (*http.Response, error) { | ||
276 | client := getTLSClient() | ||
277 | return client.Get("https://localhost" + port) | ||
278 | } | ||
279 | } else { | ||
280 | ClientConnection = func() (*http.Response, error) { | ||
281 | client := http.DefaultClient | ||
282 | return client.Get("http://localhost" + port) | ||
283 | } | ||
284 | } | ||
285 | go func() { | ||
286 | time.Sleep(250 * time.Millisecond) | ||
287 | r, err := ClientConnection() | ||
288 | if err != nil { | ||
289 | recordConnectionError(err) | ||
290 | return | ||
291 | } | ||
292 | body, err := ioutil.ReadAll(r.Body) | ||
293 | if err != nil { | ||
294 | recordConnectionError(err) | ||
295 | return | ||
296 | } | ||
297 | if string(body) != "Hello World!" { | ||
298 | recordConnectionError(errors.New(string(body))) | ||
299 | return | ||
300 | } | ||
301 | recordConnectionError(nil) | ||
302 | }() | ||
303 | err := <-errorChannel | ||
304 | if test.isCorrectError(err) == false { | ||
305 | if test.ExpectedError == nil { | ||
306 | t.Logf("Expected no error, got error: %v", err) | ||
307 | } else { | ||
308 | t.Logf("Expected error matching regular expression: %v", test.ExpectedError) | ||
309 | t.Logf("Got: %v", err) | ||
310 | } | ||
311 | t.Fail() | ||
312 | } | ||
313 | } | ||
314 | |||
315 | func (test *TestInputs) isCorrectError(returnedError error) bool { | ||
316 | switch { | ||
317 | case returnedError == nil && test.ExpectedError == nil: | ||
318 | case returnedError != nil && test.ExpectedError != nil && test.ExpectedError.MatchString(returnedError.Error()): | ||
319 | default: | ||
320 | return false | ||
321 | } | ||
322 | return true | ||
323 | } | ||
324 | |||
325 | func getTLSClient() *http.Client { | ||
326 | cert, err := ioutil.ReadFile("testdata/tls-ca-chain.pem") | ||
327 | if err != nil { | ||
328 | panic("Unable to start TLS client. Check cert path") | ||
329 | } | ||
330 | client := &http.Client{ | ||
331 | Transport: &http.Transport{ | ||
332 | TLSClientConfig: &tls.Config{ | ||
333 | RootCAs: func() *x509.CertPool { | ||
334 | caCertPool := x509.NewCertPool() | ||
335 | caCertPool.AppendCertsFromPEM(cert) | ||
336 | return caCertPool | ||
337 | }(), | ||
338 | }, | ||
339 | }, | ||
340 | } | ||
341 | return client | ||
342 | } | ||
343 | |||
344 | func swapFileContents(file1, file2 string) error { | ||
345 | content1, err := ioutil.ReadFile(file1) | ||
346 | if err != nil { | ||
347 | return err | ||
348 | } | ||
349 | content2, err := ioutil.ReadFile(file2) | ||
350 | if err != nil { | ||
351 | return err | ||
352 | } | ||
353 | err = ioutil.WriteFile(file1, content2, 0644) | ||
354 | if err != nil { | ||
355 | return err | ||
356 | } | ||
357 | err = ioutil.WriteFile(file2, content1, 0644) | ||
358 | if err != nil { | ||
359 | return err | ||
360 | } | ||
361 | return nil | ||
362 | } | ||
diff --git a/https/web-config.yml b/https/web-config.yml new file mode 100644 index 0000000..0f439da --- /dev/null +++ b/https/web-config.yml | |||
@@ -0,0 +1,10 @@ | |||
1 | tlsConfig : | ||
2 | # Certificate and key files for server to use to authenticate to client | ||
3 | tlsCertPath : <filename> | ||
4 | tlsKeyPath : <filename> | ||
5 | |||
6 | # Server policy for client authentication. Maps to ClientAuth Policies | ||
7 | [ clientAuth : <string> ] | ||
8 | |||
9 | # CA certificate for client certificate authentication to the server | ||
10 | [ clientCAs : <filename> ] | ||