diff --git a/README.md b/README.md index 899e450c59867705635993d088fcca968a09b256..848b338f12d46eddcfc0b7487baf048d640b10af 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ All variables which can be overridden are stored in [defaults/main.yml](defaults | `node_exporter_enabled_collectors` | [ systemd, textfile ] | List of additionally enabled collectors. It adds collectors to [those enabled by default](https://github.com/prometheus/node_exporter#enabled-by-default) | | `node_exporter_disabled_collectors` | [] | List of disabled collectors. By default node_exporter disables collectors listed [here](https://github.com/prometheus/node_exporter#disabled-by-default). | | `node_exporter_textfile_dir` | "/var/lib/node_exporter" | Directory used by the [Textfile Collector](https://github.com/prometheus/node_exporter#textfile-collector). To get permissions to write metrics in this directory, users must be in `node-exp` system group. +| `node_exporter_tls_server_config` | {} | Configuration for TLS authentication. Keys and values are the same as in [node_exporter docs](https://github.com/prometheus/node_exporter/blob/master/https/README.md#sample-config). | +| `node_exporter_http_server_config` | {} | Config for HTTP/2 support. Keys and values are the same as in [node_exporter docs](https://github.com/prometheus/node_exporter/blob/master/https/README.md#sample-config). | +| `node_exporter_basic_auth_users` | {} | Dictionary of users and password for basic authentication. Passwords are automatically hashed with bcrypt. | ## Example @@ -40,6 +43,36 @@ Use it in a playbook as follows: - cloudalchemy.node-exporter ``` +### TLS config + +Before running node_exporter role, user needs to provision their own certificate and key. +```yaml +- hosts: all + pre_tasks: + - name: Create node_exporter cert dir + file: + path: "/etc/node_exporter" + state: directory + owner: root + group: root + + - name: Create cert and key + openssl_certificate: + path: /etc/node_exporter/tls.cert + csr_path: /etc/node_exporter/tls.csr + privatekey_path: /etc/node_exporter/tls.key + provider: selfsigned + roles: + - cloudalchemy.node-exporter + vars: + node_exporter_tls_server_config: + cert_file: /etc/node_exporter/tls.cert + key_file: /etc/node_exporter/tls.key + node_exporter_basic_auth_users: + randomuser: examplepassword +``` + + ### Demo site We provide demo site for full monitoring solution based on prometheus and grafana. Repository with code and links to running instances is [available on github](https://github.com/cloudalchemy/demo-site) and site is hosted on [DigitalOcean](https://digitalocean.com). diff --git a/defaults/main.yml b/defaults/main.yml index d52091261e70e5d00c66eb3744ea2d35e5a9849e..52172348f96ec9c1727b3bb8dcbe662b8c200c9c 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -5,6 +5,12 @@ node_exporter_web_listen_address: "0.0.0.0:9100" node_exporter_textfile_dir: "/var/lib/node_exporter" +node_exporter_tls_server_config: {} + +node_exporter_http_server_config: {} + +node_exporter_basic_auth_users: {} + node_exporter_enabled_collectors: - systemd - textfile: diff --git a/molecule/alternative/playbook.yml b/molecule/alternative/playbook.yml index ce51111dba0ff735e4ce3f03f834c55c625a8647..991a4b8030e36c6d27d362c1ff945e9008b70296 100644 --- a/molecule/alternative/playbook.yml +++ b/molecule/alternative/playbook.yml @@ -4,6 +4,22 @@ any_errors_fatal: true roles: - ansible-node-exporter + pre_tasks: + - name: Create node_exporter cert dir + file: + path: "{{ node_exporter_tls_server_config.cert_file | dirname }}" + state: directory + owner: root + group: root + - name: Copy cert and key + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - src: "/tmp/tls.cert" + dest: "{{ node_exporter_tls_server_config.cert_file }}" + - src: "/tmp/tls.key" + dest: "{{ node_exporter_tls_server_config.key_file }}" vars: node_exporter_binary_local_dir: "/tmp/node_exporter-linux-amd64" node_exporter_textfile_dir: "" @@ -11,3 +27,11 @@ - entropy node_exporter_disabled_collectors: - diskstats + + node_exporter_tls_server_config: + cert_file: /etc/node_exporter/tls.cert + key_file: /etc/node_exporter/tls.key + node_exporter_http_server_config: + http2: true + node_exporter_basic_auth_users: + randomuser: examplepassword diff --git a/molecule/alternative/prepare.yml b/molecule/alternative/prepare.yml index 2f75da1308b8821da9f6477f90c0f87e9e961b68..665c8a381de5ef2f0e0c734c33362dce6c460f45 100644 --- a/molecule/alternative/prepare.yml +++ b/molecule/alternative/prepare.yml @@ -4,7 +4,7 @@ gather_facts: false vars: go_arch: amd64 - node_exporter_version: 0.18.1 + node_exporter_version: 1.0.0 tasks: - name: Download node_exporter binary to local folder become: false @@ -35,3 +35,23 @@ state: link run_once: true check_mode: false + + - name: install pyOpenSSL for certificate generation + pip: + name: "pyOpenSSL" + + - name: Create private key + openssl_privatekey: + path: "/tmp/tls.key" + + - name: Create CSR + openssl_csr: + path: "/tmp/tls.csr" + privatekey_path: "/tmp/tls.key" + + - name: Create certificate + openssl_certificate: + path: "/tmp/tls.cert" + csr_path: "/tmp/tls.csr" + privatekey_path: "/tmp/tls.key" + provider: selfsigned diff --git a/tasks/configure.yml b/tasks/configure.yml index 9e9f9bce9b50bebe29cce88b34295ffdc4a7d65f..0a269032770d065468ca819ff2f5b23625d0c82f 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -1,5 +1,5 @@ --- -- name: Copy the Node Exporter systemd service file +- name: Copy the node_exporter systemd service file template: src: node_exporter.service.j2 dest: /etc/systemd/system/node_exporter.service @@ -8,6 +8,28 @@ mode: 0644 notify: restart node_exporter +- block: + - name: Create node_exporter config directory + file: + path: "/etc/node_exporter" + state: directory + owner: root + group: root + mode: u+rwX,g+rwX,o=rX + + - name: Copy the node_exporter config file + template: + src: config.yaml.j2 + dest: /etc/node_exporter/config.yaml + owner: root + group: root + mode: 0644 + notify: restart node_exporter + when: + ( node_exporter_tls_server_config | length > 0 ) or + ( node_exporter_http_server_config | length > 0 ) or + ( node_exporter_basic_auth_users | length > 0 ) + - name: Create textfile collector dir file: path: "{{ node_exporter_textfile_dir }}" @@ -18,7 +40,7 @@ mode: u+rwX,g+rwX,o=rX when: node_exporter_textfile_dir | length > 0 -- name: Allow Node Exporter port in SELinux on RedHat OS family +- name: Allow node_exporter port in SELinux on RedHat OS family seport: ports: "{{ node_exporter_web_listen_address.split(':')[-1] }}" proto: tcp diff --git a/tasks/preflight.yml b/tasks/preflight.yml index 79fff42d3eb6fa8ea4d319a73076d3baf2b4dec4..3d9e770bf6b25f47dba812ee958ba1d4198d3fdd 100644 --- a/tasks/preflight.yml +++ b/tasks/preflight.yml @@ -27,6 +27,30 @@ - "item not in node_exporter_enabled_collectors" with_items: "{{ node_exporter_disabled_collectors }}" +- block: + - name: Assert that TLS key and cert path are set + assert: + that: + - "node_exporter_tls_server_config.cert_file is defined" + - "node_exporter_tls_server_config.key_file is defined" + + - name: Check existence of TLS cert file + stat: + path: "{{ node_exporter_tls_server_config.cert_file }}" + register: __node_exporter_cert_file + + - name: Check existence of TLS key file + stat: + path: "{{ node_exporter_tls_server_config.key_file }}" + register: __node_exporter_key_file + + - name: Assert that TLS key and cert are present + assert: + that: + - "{{ __node_exporter_cert_file.stat.exists }}" + - "{{ __node_exporter_key_file.stat.exists }}" + when: node_exporter_tls_server_config | length > 0 + - name: Check if node_exporter is installed stat: path: "{{ _node_exporter_binary_install_dir }}/node_exporter" diff --git a/templates/config.yaml.j2 b/templates/config.yaml.j2 new file mode 100644 index 0000000000000000000000000000000000000000..9013722c67b567bad81da83e887c5b3c2f22b604 --- /dev/null +++ b/templates/config.yaml.j2 @@ -0,0 +1,18 @@ +--- +{{ ansible_managed | comment }} +{% if node_exporter_tls_server_config | length > 0 %} +tls_server_config: +{{ node_exporter_tls_server_config | to_nice_yaml | indent(2, true) }} +{% endif %} + +{% if node_exporter_http_server_config | length > 0 %} +http_server_config: +{{ node_exporter_http_server_config | to_nice_yaml | indent(2, true) }} +{% endif %} + +{% if node_exporter_basic_auth_users | length > 0 %} +basic_auth_users: +{% for k, v in node_exporter_basic_auth_users.items() %} + {{ k }}: {{ v | password_hash('bcrypt', ('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' | shuffle(seed=inventory_hostname) | join)[:22], rounds=9) }} +{% endfor %} +{% endif %} diff --git a/templates/node_exporter.service.j2 b/templates/node_exporter.service.j2 index 0e1b53add2443f64fa56655c7db5b231d5d3d2a5..ad60a4febd9021b1bce70ae600c4880a371636b7 100644 --- a/templates/node_exporter.service.j2 +++ b/templates/node_exporter.service.j2 @@ -24,6 +24,9 @@ ExecStart={{ _node_exporter_binary_install_dir }}/node_exporter \ {% for collector in node_exporter_disabled_collectors %} --no-collector.{{ collector }} \ {% endfor %} +{% if node_exporter_tls_server_config | length > 0 or node_exporter_http_server_config | length > 0 or node_exporter_basic_auth_users | length > 0 %} + --web.config=/etc/node_exporter/config.yaml +{% endif %} --web.listen-address={{ node_exporter_web_listen_address }} SyslogIdentifier=node_exporter diff --git a/test-requirements.txt b/test-requirements.txt index 7f3b34f8bbaf5136b2431cb6bd658b7c37d7d968..efa5a5c0086013fd63bfb1533c7112bed3e83a47 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,3 +4,4 @@ ansible-lint>=3.4.0 testinfra>=1.7.0 jmespath selinux +passlib