Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3d78630

Browse files
support HTTPS/TLS. (prometheus#946)
* support HTTPS/TLS. * Handling Andy's review comments 1.A better description of what's new. 2.Modify the parameter order of the start_wsgi_server method to maintain forward compatibility. 3.Enable authentication mode when safe. * revert tls_auth_handler func. * use "None" indicate "not provided". * TLS: Improved error handling; Documented capath * Update parameter names to make clear they are used to verify client certificates. * - Rename the `insecure_skip_verify` parameter to `client_auth_required`. - Update `_get_ssl_ctx` func, default not to set `ssl_ctx.verify_mode=ssl.CERT_REQUIRED`. - Update the description of default in README.md. Signed-off-by: kareza <[email protected]> --------- Signed-off-by: kareza <[email protected]> Co-authored-by: Andreas Maier <[email protected]>
1 parent a000193 commit 3d78630

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ ProcessCollector(namespace='mydaemon', pid=lambda: open('/var/run/daemon.pid').r
288288
### Platform Collector
289289

290290
The client also automatically exports some metadata about Python. If using Jython,
291-
metadata about the JVM in use is also included. This information is available as
292-
labels on the `python_info` metric. The value of the metric is 1, since it is the
291+
metadata about the JVM in use is also included. This information is available as
292+
labels on the `python_info` metric. The value of the metric is 1, since it is the
293293
labels that carry information.
294294

295295
### Disabling Default Collector metrics
@@ -327,6 +327,27 @@ To add Prometheus exposition to an existing HTTP server, see the `MetricsHandler
327327
which provides a `BaseHTTPRequestHandler`. It also serves as a simple example of how
328328
to write a custom endpoint.
329329

330+
By default, the prometheus client will accept only HTTP requests from Prometheus.
331+
To enable HTTPS, `certfile` and `keyfile` need to be provided. The certificate is
332+
presented to Prometheus as a server certificate during the TLS handshake, and
333+
the private key in the key file must belong to the public key in the certificate.
334+
335+
When HTTPS is enabled, you can enable mutual TLS (mTLS) by setting `client_auth_required=True`
336+
(i.e. Prometheus is required to present a client certificate during TLS handshake) and the
337+
client certificate including its hostname is validated against the CA certificate chain.
338+
339+
`client_cafile` can be used to specify a certificate file containing a CA certificate
340+
chain that is used to validate the client certificate. `client_capath` can be used to
341+
specify a certificate directory containing a CA certificate chain that is used to
342+
validate the client certificate. If neither of them is provided, a default CA certificate
343+
chain is used (see Python [ssl.SSLContext.load_default_certs()](https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_default_certs))
344+
345+
```python
346+
from prometheus_client import start_http_server
347+
348+
start_http_server(8000, certfile="server.crt", keyfile="server.key")
349+
```
350+
330351
#### Twisted
331352

332353
To use prometheus with [twisted](https://twistedmatrix.com/), there is `MetricsResource` which exposes metrics as a twisted resource.
@@ -393,7 +414,7 @@ Such an application can be useful when integrating Prometheus metrics with ASGI
393414
apps.
394415

395416
By default, the WSGI application will respect `Accept-Encoding:gzip` headers used by Prometheus
396-
and compress the response if such a header is present. This behaviour can be disabled by passing
417+
and compress the response if such a header is present. This behaviour can be disabled by passing
397418
`disable_compression=True` when creating the app, like this:
398419

399420
```python

prometheus_client/exposition.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,58 @@ def _get_best_family(address, port):
159159
return family, sockaddr[0]
160160

161161

162-
def start_wsgi_server(port: int, addr: str = '0.0.0.0', registry: CollectorRegistry = REGISTRY) -> None:
162+
def _get_ssl_ctx(
163+
certfile: str,
164+
keyfile: str,
165+
protocol: int,
166+
cafile: Optional[str] = None,
167+
capath: Optional[str] = None,
168+
client_auth_required: bool = False,
169+
) -> ssl.SSLContext:
170+
"""Load context supports SSL."""
171+
ssl_cxt = ssl.SSLContext(protocol=protocol)
172+
173+
if cafile is not None or capath is not None:
174+
try:
175+
ssl_cxt.load_verify_locations(cafile, capath)
176+
except IOError as exc:
177+
exc_type = type(exc)
178+
msg = str(exc)
179+
raise exc_type(f"Cannot load CA certificate chain from file "
180+
f"{cafile!r} or directory {capath!r}: {msg}")
181+
else:
182+
try:
183+
ssl_cxt.load_default_certs(purpose=ssl.Purpose.CLIENT_AUTH)
184+
except IOError as exc:
185+
exc_type = type(exc)
186+
msg = str(exc)
187+
raise exc_type(f"Cannot load default CA certificate chain: {msg}")
188+
189+
if client_auth_required:
190+
ssl_cxt.verify_mode = ssl.CERT_REQUIRED
191+
192+
try:
193+
ssl_cxt.load_cert_chain(certfile=certfile, keyfile=keyfile)
194+
except IOError as exc:
195+
exc_type = type(exc)
196+
msg = str(exc)
197+
raise exc_type(f"Cannot load server certificate file {certfile!r} or "
198+
f"its private key file {keyfile!r}: {msg}")
199+
200+
return ssl_cxt
201+
202+
203+
def start_wsgi_server(
204+
port: int,
205+
addr: str = '0.0.0.0',
206+
registry: CollectorRegistry = REGISTRY,
207+
certfile: Optional[str] = None,
208+
keyfile: Optional[str] = None,
209+
client_cafile: Optional[str] = None,
210+
client_capath: Optional[str] = None,
211+
protocol: int = ssl.PROTOCOL_TLS_SERVER,
212+
client_auth_required: bool = False,
213+
) -> None:
163214
"""Starts a WSGI server for prometheus metrics as a daemon thread."""
164215

165216
class TmpServer(ThreadingWSGIServer):
@@ -168,6 +219,9 @@ class TmpServer(ThreadingWSGIServer):
168219
TmpServer.address_family, addr = _get_best_family(addr, port)
169220
app = make_wsgi_app(registry)
170221
httpd = make_server(addr, port, app, TmpServer, handler_class=_SilentHandler)
222+
if certfile and keyfile:
223+
context = _get_ssl_ctx(certfile, keyfile, protocol, client_cafile, client_capath, client_auth_required)
224+
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
171225
t = threading.Thread(target=httpd.serve_forever)
172226
t.daemon = True
173227
t.start()
@@ -407,7 +461,7 @@ def tls_auth_handler(
407461
The default protocol (ssl.PROTOCOL_TLS_CLIENT) will also enable
408462
ssl.CERT_REQUIRED and SSLContext.check_hostname by default. This can be
409463
disabled by setting insecure_skip_verify to True.
410-
464+
411465
Both this handler and the TLS feature on pushgateay are experimental."""
412466
context = ssl.SSLContext(protocol=protocol)
413467
if cafile is not None:

0 commit comments

Comments
 (0)