diff --git a/README.md b/README.md index af97688..e571129 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,6 @@ - [alertmanager](roles/alertmanager/README.md) - [dnsmasq](roles/dnsmasq/README.md) - [mount_device](roles/mount_device/README.md) +- [prometheus](roles/prometheus/README.md) - [ufw](roles/ufw/README.md) - [wg_hub](roles/wg_hub/README.md) \ No newline at end of file diff --git a/galaxy.yml b/galaxy.yml index 6f50d1d..adcc287 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: genlab name: common -version: 0.5.0 +version: 0.6.0 readme: README.md authors: - Alexander Gorelyshev (corvus-migratorius@proton.me) diff --git a/roles/prometheus/README.md b/roles/prometheus/README.md new file mode 100644 index 0000000..971b023 --- /dev/null +++ b/roles/prometheus/README.md @@ -0,0 +1,50 @@ +genlab.prometheus +========= + +This ansible role installs [Prometheus](https://github.com/prometheus/prometheus) from binary distribution. Prometheus is a systems and service monitoring system. It collects metrics from configured targets at given intervals, evaluates rule expressions, displays the results, and can trigger alerts when specified conditions are observed. + +Prometheus configuration files and rules should be placed in separate directories in the source. They must have a `*.yml` suffix. You'll need to manually specify the paths to your rule files in the main Prometheus configuration file (prometheus.yml) on the target machine + +Requirements +------------ + +None + +Role Variables +-------------- +``` +prometheus_version: 3.2.1 # prometheus version +prometheus_dir: "/etc/prometheus" # where to install prometheus +prometheus_user: prometheus # user name +prometheus_group: prometheus # groups name +prometheus_config_dir: "/etc/prometheus/conf" # where to place prometheus config +prometheus_db_dir: "/var/lib/prometheus" # where to store prometheus db +prometheus_config_source_dir: prometheus # path to config files on source +prometheus_alertrules_source_dir: prometheus/rules # path to rule files on source +``` + +Dependencies +------------ + +None + +Example Playbook +---------------- + +```yaml +roles: + - role: genlab.prometheus + prometheus_config_source_dir: mydir/configs + prometheus_alertrules_source_dir: mydir/configs/rules + prometheus_version: 3.2.1 +``` + +License +------- + +BSD + +Author Information +------------------ + +corvus-migratorius@proton.me diff --git a/roles/prometheus/defaults/main.yml b/roles/prometheus/defaults/main.yml new file mode 100644 index 0000000..5ecc61c --- /dev/null +++ b/roles/prometheus/defaults/main.yml @@ -0,0 +1,7 @@ +--- +prometheus_version: 3.2.1 +prometheus_dir: "/etc/prometheus" +prometheus_user: prometheus +prometheus_group: prometheus +prometheus_config_dir: "/etc/prometheus/conf" +prometheus_db_dir: "/var/lib/prometheus" diff --git a/roles/prometheus/handlers/main.yml b/roles/prometheus/handlers/main.yml new file mode 100644 index 0000000..29ac016 --- /dev/null +++ b/roles/prometheus/handlers/main.yml @@ -0,0 +1,8 @@ +--- +- name: "(Re)start Prometheus service" + become: true + ansible.builtin.systemd: + name: prometheus.service + state: restarted + enabled: true + daemon_reload: true diff --git a/roles/prometheus/meta/main.yml b/roles/prometheus/meta/main.yml new file mode 100644 index 0000000..b4335ec --- /dev/null +++ b/roles/prometheus/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: "prometheus" + namespace: genlab + author: "Alexander Gorelyshev" + company: "Genlab, LLC" + description: "" + license: "MIT" + min_ansible_version: "2.1" + + platforms: + - name: "Ubuntu" + versions: ["focal", "jammy", "noble"] + + galaxy_tags: [] + +dependencies: [] diff --git a/roles/prometheus/molecule/default/converge.yml b/roles/prometheus/molecule/default/converge.yml new file mode 100644 index 0000000..a9b0439 --- /dev/null +++ b/roles/prometheus/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + + roles: + - role: genlab.common.prometheus + prometheus_config_source_dir: prometheus + alertrules_source_dir: prometheus/rules diff --git a/roles/prometheus/molecule/default/molecule.yml b/roles/prometheus/molecule/default/molecule.yml new file mode 100644 index 0000000..d82158e --- /dev/null +++ b/roles/prometheus/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy + +driver: + name: docker + +platforms: + - name: ubuntu + image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest + pre_build_image: true + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + +provisioner: + name: ansible + +verifier: + name: ansible + +lint: | + set -e + yamllint . + ansible-lint . diff --git a/roles/prometheus/molecule/default/prometheus/prometheus.yml b/roles/prometheus/molecule/default/prometheus/prometheus.yml new file mode 100644 index 0000000..31854f4 --- /dev/null +++ b/roles/prometheus/molecule/default/prometheus/prometheus.yml @@ -0,0 +1,14 @@ +--- +global: + scrape_interval: 15s + evaluation_interval: 15s + +rule_files: + - /etc/prometheus/conf/alertules.yml + # - "first.rules" + # - "second.rules" + +scrape_configs: + - job_name: prometheus + static_configs: + - targets: ['localhost:9090'] diff --git a/roles/prometheus/molecule/default/prometheus/rules/alertrules.yml b/roles/prometheus/molecule/default/prometheus/rules/alertrules.yml new file mode 100644 index 0000000..dc3c47f --- /dev/null +++ b/roles/prometheus/molecule/default/prometheus/rules/alertrules.yml @@ -0,0 +1,13 @@ +groups: + - name: example + labels: + team: myteam + rules: + - alert: HighRequestLatency + expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5 + for: 10m + keep_firing_for: 5m + labels: + severity: page + annotations: + summary: High request latency diff --git a/roles/prometheus/molecule/default/verify.yml b/roles/prometheus/molecule/default/verify.yml new file mode 100644 index 0000000..c085dd1 --- /dev/null +++ b/roles/prometheus/molecule/default/verify.yml @@ -0,0 +1,55 @@ +--- +- name: Verify + hosts: all + gather_facts: false + any_errors_fatal: true + + tasks: + + - name: "Include default vars" + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" + extensions: ['yml'] + + - name: "Check if Prometheus is installed" + changed_when: false + ansible.builtin.command: "prometheus --version" + register: prometheus_installed_version + + - name: "Check Prometheus version" + ansible.builtin.assert: + that: "prometheus_installed_version.stdout is regex('{{ prometheus_version }}')" + success_msg: "Prometheus version {{ prometheus_version }} is installed and working" + fail_msg: "Prometheus version {{ prometheus_version }} is not installed or not working correctly" + + # kics-scan ignore-block + - name: "Check if Prometheus is reachable" + ansible.builtin.uri: + url: "http://localhost:9090/-/healthy" + return_content: true + status_code: 200 + method: GET + body_format: json + register: prometheus_health + + - name: "Debug Prometheus health status" + ansible.builtin.assert: + that: "prometheus_health.content | trim == 'Prometheus Server is Healthy.'" + success_msg: "Prometheus is healthy" + fail_msg: "Prometheus is not healthy" + + # kics-scan ignore-block + - name: "Check if Prometheus is ready" + ansible.builtin.uri: + url: "http://localhost:9090/-/ready" + return_content: true + status_code: 200 + method: GET + body_format: json + register: prometheus_ready + + - name: "Debug Prometheus readiness status" + ansible.builtin.assert: + that: "prometheus_ready.content | trim == 'Prometheus Server is Ready.'" + success_msg: "Prometheus is ready" + fail_msg: "Prometheus is not ready" diff --git a/roles/prometheus/tasks/configure.yml b/roles/prometheus/tasks/configure.yml new file mode 100644 index 0000000..cbad1ad --- /dev/null +++ b/roles/prometheus/tasks/configure.yml @@ -0,0 +1,23 @@ +--- +- name: "Copy config file" + notify: "(Re)start Prometheus service" + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ prometheus_config_dir }}/{{ item | basename }}" + owner: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + mode: "0660" + with_fileglob: + - "{{ prometheus_config_source_dir }}/*.yml" + +- name: "Copy alert rules" + notify: "(Re)start Prometheus service" + when: alertrules_source_dir is defined + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ prometheus_config_dir }}/{{ item | basename }}" + owner: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + mode: "0660" + with_fileglob: + - "{{ alertrules_source_dir }}/*.yml" diff --git a/roles/prometheus/tasks/install.yml b/roles/prometheus/tasks/install.yml new file mode 100644 index 0000000..3118047 --- /dev/null +++ b/roles/prometheus/tasks/install.yml @@ -0,0 +1,84 @@ +--- +- name: "Create Prometheus system group" + ansible.builtin.group: + name: "{{ prometheus_group }}" + system: true + state: present + +- name: "Create Prometheus system user" + ansible.builtin.user: + name: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + system: true + shell: "/sbin/nologin" + create_home: false + state: present + +- name: "Install prometheus from binary" + block: + - name: "Check Prometheus version" + changed_when: false + ansible.builtin.command: + cmd: "prometheus --version" + register: prometheus_ver + + - name: "Assert version correctness" + ansible.builtin.assert: + that: "prometheus_ver.stdout is regex('{{ prometheus_version }}')" + success_msg: "prometheus version {{ prometheus_version }} is installed and working" + fail_msg: "prometheus version {{ prometheus_version }} is not installed or not working correctly" + + rescue: + - name: "Create prometheus directories {{ item }}" + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + mode: "0755" + with_items: + - "{{ prometheus_config_dir }}" + - "{{ prometheus_dir }}" + - "{{ prometheus_db_dir }}" + + - name: "Download Prometheus binary" + ansible.builtin.get_url: + url: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}/prometheus-{{ prometheus_version }}.linux-amd64.tar.gz" + dest: "/tmp/prometheus-{{ prometheus_version }}.linux-amd64.tar.gz" + owner: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + mode: "0644" + + - name: "Unpack Prometheus binaries" + notify: "(Re)start Prometheus service" + ansible.builtin.unarchive: + src: "/tmp/prometheus-{{ prometheus_version }}.linux-amd64.tar.gz" + dest: "{{ prometheus_dir }}" + creates: "{{ prometheus_dir }}/prometheus-{{ prometheus_version }}.linux-amd64" + remote_src: true + + - name: "Cleanup downloaded file" + ansible.builtin.file: + path: "/tmp/prometheus-{{ prometheus_version }}.linux-amd64.tar.gz" + state: absent + + - name: "Move official prometheus and promtool binaries" + ansible.builtin.copy: + src: "{{ prometheus_dir }}/prometheus-{{ prometheus_version }}.linux-amd64/{{ item }}" + dest: "/usr/local/bin/{{ item }}" + mode: "0755" + owner: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + remote_src: true + with_items: + - prometheus + - promtool + +- name: "Create systemd service unit" + notify: "(Re)start Prometheus service" + ansible.builtin.template: + src: prometheus.service.j2 + dest: /etc/systemd/system/prometheus.service + owner: "{{ prometheus_user }}" + group: "{{ prometheus_group }}" + mode: "0660" diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml new file mode 100644 index 0000000..43bcfba --- /dev/null +++ b/roles/prometheus/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: "Install Prometheus from binary" + ansible.builtin.include_tasks: install.yml + +- name: "Configure and add alert rules" + ansible.builtin.include_tasks: configure.yml + +- name: "Flush handlers" + ansible.builtin.meta: "flush_handlers" diff --git a/roles/prometheus/templates/prometheus.service.j2 b/roles/prometheus/templates/prometheus.service.j2 new file mode 100644 index 0000000..2f17191 --- /dev/null +++ b/roles/prometheus/templates/prometheus.service.j2 @@ -0,0 +1,28 @@ +[Unit] +Description=Prometheus +Wants=network-online.target +After=network-online.target +Documentation="https://prometheus.io/" + +[Service] +User=prometheus +Group=prometheus +Type=simple +ExecStart=/usr/local/bin/prometheus \ + --config.file {{ prometheus_config_dir }}/prometheus.yml \ + --storage.tsdb.path {{ prometheus_db_dir }} \ + --storage.tsdb.retention.time=30d + +# Security hardening +ReadWritePaths={{ prometheus_db_dir }} +ProtectSystem=strict +NoNewPrivileges=true +PrivateTmp=true +ProtectKernelModules=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectClock=yes +RestrictSUIDSGID=true + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/prometheus/vars/main.yml b/roles/prometheus/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/prometheus/vars/main.yml @@ -0,0 +1 @@ +---