From b5faa4c09e36bfdc55a0f69ce10b0e113b0b41f9 Mon Sep 17 00:00:00 2001 From: Joachim Lusiardi Date: Fri, 29 May 2020 19:38:50 +0200 Subject: [PATCH] implement feature to add basic auth to containers via proxy variable --- README.md | 2 +- nginx_proxy.py | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b3ef98e..264eea1 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The following options are possible: * **ip**(optional, defaults to listen on all IPs) the IP on which the proxy should listen. * **location**(optional) if the proxied web application is not running on the /-path * **body_size**(optional, defaults to 1MB) the allowed maximal body size as defined in http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size - +* **auth_data**(optional, defaults to none) If set, the value must be constructed like `Realm;Username;Password` e.g. `SecretWebsite;admin;$apr1$RR/RTfI.$s7mRx/yKay7g3Jxmg/eMT/`. The crypted password can be created with `htpasswd`: ` htpasswd -n -b admin supersecret` ## Starting the container Since the container uses Docker's internal event reporting, it needs access to the daemon. At the diff --git a/nginx_proxy.py b/nginx_proxy.py index 69c2f17..4a4346c 100755 --- a/nginx_proxy.py +++ b/nginx_proxy.py @@ -10,12 +10,14 @@ import os import logging target_path = "/tmp/nginx/" +auth_path = target_path + "auth/" config_path = target_path + "conf/" pid_file = "/var/run/nginx.pid" non_location_template = """# proxy for container '$containername' server { listen $listen; server_name $names; + $auth_config location / { client_max_body_size $body_size; client_body_timeout 300s; @@ -32,6 +34,7 @@ location_template = """# proxy for container '$containername' server { listen $listen; server_name $names; + $auth_config location / { return 301 $$scheme://$name/$location; } @@ -119,6 +122,21 @@ def handle_container(id): logging.info('container "%s"(%s) does not listen on %s.', extract_name(inspect_data), container_listen_ip, str(listen_ips)) return logging.info('container "%s"(%s) is allowed to listen on %s.', extract_name(inspect_data), container_listen_ip, str(listen_ips)) + auth_data = get_if_available(proxy_data, 'auth_data', None) + logging.info('auth data: %s', auth_data) + auth_config = '' + if auth_data: + realm, htpasswd = auth_data.split(';', 1) + htpasswd = htpasswd.replace(';', ':') + auth_file_name = auth_path + 'proxy_{id}_{code}'.format(id=id, code=env_key) + with open(auth_file_name, 'w') as file: + file.write(htpasswd) + # write auth data to file + # add to config + auth_config = """ + auth_basic "{realm}"; + auth_basic_user_file {file}; + """.format(realm=realm,file=auth_file_name) substitutes = { 'containername': '{c} {d}'.format(c=extract_name(inspect_data), d=env_data), 'ip': extract_ip(inspect_data), @@ -126,7 +144,8 @@ def handle_container(id): 'names': get_if_available(proxy_data, 'server_names', '').replace(';', ' '), 'port': get_if_available(proxy_data, 'port', 80), 'body_size': get_if_available(proxy_data, 'body_size', '1m'), - 'listen': '*:80' + 'listen': '*:80', + 'auth_config': auth_config } logging.info('writing to %sproxy_%s', config_path, id) with open(config_path + '/proxy_{id}_{code}'.format(id=id,code=env_key), 'w') as file: @@ -196,6 +215,8 @@ if __name__ == '__main__': if not os.path.exists(config_path): logging.info('creating target path: %s', target_path) os.mkdir(target_path) + logging.info('creating target path: %s', auth_path) + os.mkdir(auth_path) logging.info('creating target path: %s', config_path) os.mkdir(config_path)