diff --git a/roles/cadvisor/defaults/main.yml b/roles/cadvisor/defaults/main.yml index db0d00054..b8276e84c 100644 --- a/roles/cadvisor/defaults/main.yml +++ b/roles/cadvisor/defaults/main.yml @@ -14,6 +14,8 @@ cadvisor_whitelisted_container_labels: [] cadvisor_store_container_labels: true cadvisor_docker_only: false +cadvisor_basic_auth_users: {} + cadvisor_system_group: "root" cadvisor_system_user: "{{ cadvisor_system_group }}" @@ -27,3 +29,5 @@ cadvisor_binary_install_dir: "/usr/local/bin" # cadvisor_housekeeping_interval: 10s cadvisor_max_housekeeping_interval: 15s + +cadvisor_config_dir: "/etc/cadvisor" diff --git a/roles/cadvisor/meta/argument_specs.yml b/roles/cadvisor/meta/argument_specs.yml index 26f879d29..57c45689c 100644 --- a/roles/cadvisor/meta/argument_specs.yml +++ b/roles/cadvisor/meta/argument_specs.yml @@ -73,6 +73,13 @@ argument_specs: description: "do not report raw cgroup metrics, except the root cgroup" type: "bool" default: false + cadvisor_basic_auth_users: + description: + - "Dictionary of username / password for HTTP basic authentication" + - >- + Warning : The endpoints `/api/*` and `/metrics` are exposed without authentication. See https://github.com/google/cadvisor/blob/master/docs/web.md#web-ui-authentication and https://github.com/google/cadvisor/issues/3401 for more details. + type: "dict" + default: {} cadvisor_system_group: description: - "I(Advanced)" @@ -97,3 +104,6 @@ argument_specs: cadvisor_max_housekeeping_interval: description: 'Largest interval to allow between container housekeepings' default: '10s' + cadvisor_config_dir: + description: "Directory for cAdvisor configuration files" + default: "/etc/cadvisor" diff --git a/roles/cadvisor/molecule/alternative/molecule.yml b/roles/cadvisor/molecule/alternative/molecule.yml index d523c0ab5..4caac7e2c 100644 --- a/roles/cadvisor/molecule/alternative/molecule.yml +++ b/roles/cadvisor/molecule/alternative/molecule.yml @@ -17,3 +17,5 @@ provisioner: env_metadata_whitelist: [ "PATH" ] store_container_labels: false cadvisor_housekeeping_interval: 15s + cadvisor_basic_auth_users: + foo: bar diff --git a/roles/cadvisor/molecule/alternative/tests/test_alternative.py b/roles/cadvisor/molecule/alternative/tests/test_alternative.py index fdd117589..dfa88f87d 100644 --- a/roles/cadvisor/molecule/alternative/tests/test_alternative.py +++ b/roles/cadvisor/molecule/alternative/tests/test_alternative.py @@ -31,3 +31,13 @@ def test_protecthome_property(host): ]) def test_socket(host, sockets): assert host.socket(sockets).is_listening + + +def test_forbidden_access(host): + output = host.check_output('curl -s -o /dev/null -w "%{http_code}" -L http://127.0.0.1:8000/') + assert '401' in output + + +def test_granted_access(host): + output = host.check_output('curl -s -o /dev/null -w "%{http_code}" -L http://127.0.0.1:8000/ -u foo:bar') + assert '200' in output diff --git a/roles/cadvisor/tasks/configure.yml b/roles/cadvisor/tasks/configure.yml new file mode 100644 index 000000000..3861c91bd --- /dev/null +++ b/roles/cadvisor/tasks/configure.yml @@ -0,0 +1,30 @@ +--- + +- name: Configure + ansible.builtin.include_role: + name: prometheus.prometheus._common + tasks_from: configure.yml + vars: + _common_config_dir: "{{ cadvisor_config_dir if (cadvisor_basic_auth_users | length > 0) else None }}" + _common_system_group: "{{ cadvisor_system_group }}" + _common_system_user: "{{ cadvisor_system_user }}" + tags: + - cadvisor + - configure + - cadvisor_configure + +- name: Generate htpasswd file + ansible.builtin.template: + src: "htpasswd.j2" + dest: "{{ cadvisor_config_dir }}/htpasswd" + owner: "{{ cadvisor_system_user }}" + group: "{{ cadvisor_system_group }}" + mode: 0640 + become: true + when: cadvisor_basic_auth_users | length > 0 + notify: + - Restart cadvisor + tags: + - cadvisor + - configure + - cadvisor_configure diff --git a/roles/cadvisor/tasks/main.yml b/roles/cadvisor/tasks/main.yml index 3d544a555..d3d0a44a8 100644 --- a/roles/cadvisor/tasks/main.yml +++ b/roles/cadvisor/tasks/main.yml @@ -34,9 +34,8 @@ - cadvisor_configure - name: Configure - ansible.builtin.include_role: - name: prometheus.prometheus._common - tasks_from: configure.yml + ansible.builtin.include_tasks: + file: configure.yml tags: - cadvisor_configure diff --git a/roles/cadvisor/templates/cadvisor.service.j2 b/roles/cadvisor/templates/cadvisor.service.j2 index dd18d8f5a..c880d034c 100644 --- a/roles/cadvisor/templates/cadvisor.service.j2 +++ b/roles/cadvisor/templates/cadvisor.service.j2 @@ -24,6 +24,10 @@ ExecStart={{ cadvisor_binary_install_dir }}/cadvisor \ {% endif -%} {% if cadvisor_env_metadata_whitelist | length > 0 %} '--env_metadata_whitelist={{ cadvisor_env_metadata_whitelist | join(',') }}' \ +{% endif %} +{% if cadvisor_basic_auth_users | length > 0 %} + '--http_auth_file={{ cadvisor_config_dir }}/htpasswd' \ + '--http_auth_realm=cadvisor' \ {% endif %} '--store_container_labels={{ cadvisor_store_container_labels | lower }}' \ '--listen_ip={{ cadvisor_listen_ip }}' \ diff --git a/roles/cadvisor/templates/htpasswd.j2 b/roles/cadvisor/templates/htpasswd.j2 new file mode 100644 index 000000000..f14990007 --- /dev/null +++ b/roles/cadvisor/templates/htpasswd.j2 @@ -0,0 +1,4 @@ +{{ ansible_managed | comment }} +{% for user, password in cadvisor_basic_auth_users.items() %} +{{ user }}:{{ password | string | password_hash('bcrypt', ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' | shuffle(seed=inventory_hostname) | join)[:22], rounds=9) }} +{% endfor %}