diff --git a/check_docker/check_docker.py b/check_docker/check_docker.py index f8a51aa..8a4a00e 100755 --- a/check_docker/check_docker.py +++ b/check_docker/check_docker.py @@ -9,6 +9,7 @@ import socket import stat import traceback +import ssl from collections import deque, namedtuple, UserDict, defaultdict from concurrent import futures from datetime import datetime, timezone @@ -20,6 +21,7 @@ from urllib.request import AbstractHTTPHandler, HTTPHandler, HTTPSHandler, OpenerDirector, HTTPRedirectHandler, \ Request, HTTPBasicAuthHandler + logger = logging.getLogger() __author__ = 'Tim Laurence' __copyright__ = "Copyright 2018" @@ -43,6 +45,7 @@ DEFAULT_HEADERS = [('Accept', 'application/vnd.docker.distribution.manifest.v2+json')] DEFAULT_PUBLIC_REGISTRY = 'registry-1.docker.io' + # The second value is the power to raise the base to. UNIT_ADJUSTMENTS_TEMPLATE = { '%': 0, @@ -162,11 +165,10 @@ class HeadRequest(Request): def get_method(self): return "HEAD" - better_urllib_get = OpenerDirector() better_urllib_get.addheaders = DEFAULT_HEADERS.copy() better_urllib_get.add_handler(HTTPHandler()) -better_urllib_get.add_handler(HTTPSHandler()) + better_urllib_get.add_handler(HTTPRedirectHandler()) better_urllib_get.add_handler(SocketFileHandler()) better_urllib_get.add_handler(Oauth2TokenAuthHandler()) @@ -250,9 +252,11 @@ def evaluate_numeric_thresholds(container, value, thresholds, name, short_name, ok(results_str) + @lru_cache(maxsize=None) def get_url(url): logger.debug("get_url: {}".format(url)) + response = better_urllib_get.open(url, timeout=timeout) logger.debug("get_url: {} {}".format(url, response.status)) return process_urllib_response(response), response.status @@ -691,6 +695,28 @@ def process_args(args): help='Use a base of 1000 when doing calculations of KB, MB, GB, & TB') parser.set_defaults(units_base=1024) + # TLS CA File + parser.add_argument('--cafile', + dest='cafile', + action='store', + type=str, + help='TLS CA File (ex: RootCA.pem)') + + # TLS Cert File + parser.add_argument('--certfile', + dest='certfile', + action='store', + type=str, + help='TLS Cert File (ex: TLS-server.pem)') + + # TLS Key File + parser.add_argument('--keyfile', + dest='keyfile', + action='store', + type=str, + help='TLS Key File (ex: Key-server.pem)') + + # Connection timeout parser.add_argument('--timeout', dest='timeout', @@ -789,15 +815,17 @@ def process_args(args): parser.print_help() parsed_args = parser.parse_args(args=args) - + global timeout timeout = parsed_args.timeout + global daemon global connection_type if parsed_args.secure_connection: daemon = 'https://' + parsed_args.secure_connection connection_type = 'https' + elif parsed_args.connection: if parsed_args.connection[0] == '/': daemon = 'socket://' + parsed_args.connection + ':' @@ -836,6 +864,19 @@ def print_results(): def perform_checks(raw_args): args = process_args(raw_args) + + # Add Certificate files for secure connection: + if args.secure_connection: + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + if args.cafile and args.certfile and args.keyfile: + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.check_hostname = True + ctx.load_verify_locations(args.cafile) + ctx.load_cert_chain(certfile=args.certfile, keyfile=args.keyfile) + better_urllib_get.add_handler(HTTPSHandler(context=ctx)) + elif args.connection: + better_urllib_get.add_handler(HTTPSHandler()) + global parallel_executor parallel_executor = futures.ThreadPoolExecutor(max_workers=args.threads) diff --git a/check_docker/check_swarm.py b/check_docker/check_swarm.py index 667a1f8..ca69488 100755 --- a/check_docker/check_swarm.py +++ b/check_docker/check_swarm.py @@ -6,6 +6,7 @@ import re import socket import stat +import ssl from functools import lru_cache from http.client import HTTPConnection from sys import argv @@ -73,7 +74,7 @@ def socket_open(self, req): better_urllib_get = OpenerDirector() better_urllib_get.addheaders = DEFAULT_HEADERS.copy() better_urllib_get.add_handler(HTTPHandler()) -better_urllib_get.add_handler(HTTPSHandler()) +#better_urllib_get.add_handler(HTTPSHandler()) better_urllib_get.add_handler(SocketFileHandler()) @@ -205,6 +206,28 @@ def process_args(args): type=float, default=DEFAULT_TIMEOUT, help='Connection timeout in seconds. (default: %(default)s)') + + # TLS CA File + parser.add_argument('--cafile', + dest='cafile', + action='store', + type=str, + help='TLS CA File (ex: RootCA.pem)') + + # TLS Cert File + parser.add_argument('--certfile', + dest='certfile', + action='store', + type=str, + help='TLS Cert File (ex: TLS-server.pem)') + + # TLS Key File + parser.add_argument('--keyfile', + dest='keyfile', + action='store', + type=str, + help='TLS Key File (ex: Key-server.pem)') + swarm_group = parser.add_mutually_exclusive_group(required=True) @@ -264,6 +287,19 @@ def print_results(): def perform_checks(raw_args): args = process_args(raw_args) + + # Add Certificate files for secure connection: + if args.secure_connection: + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + if args.cafile and args.certfile and args.keyfile: + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.check_hostname = True + ctx.load_verify_locations(args.cafile) + ctx.load_cert_chain(certfile=args.certfile, keyfile=args.keyfile) + better_urllib_get.add_handler(HTTPSHandler(context=ctx)) + elif args.connection: + better_urllib_get.add_handler(HTTPSHandler()) + if socketfile_permissions_failure(args): unknown("Cannot access docker socket file. User ID={}, socket file={}".format(os.getuid(), args.connection)) else: @@ -292,3 +328,4 @@ def main(): if __name__ == '__main__': main() +