Initial CV-aligned infrastructure portfolio
ci / validate (push) Failing after 1m8s

Rework portfolio around Linux operations, Zabbix monitoring, migration validation, and ELK/Grafana log observability.

Add AAP-style LVM resize workflow, Zabbix server/proxy/agent automation assets, Linux/AIX monitoring templates, and updated validation CI.
This commit is contained in:
Mateusz Suski
2026-05-04 17:37:24 +00:00
commit 35e6b139fc
114 changed files with 6422 additions and 0 deletions
@@ -0,0 +1,48 @@
# Base Provision Role
Provision basic infrastructure on enterprise nodes with security hardening.
## Features
- **Idempotent**: All tasks use proper idempotency markers (`changed_when`, `failed_when`)
- **Handlers**: SSH and fail2ban restarts use handlers instead of direct service calls
- **Variables**: All configuration in `defaults/main.yml` - no hardcoding
- **Validation**: Pre-flight checks for system requirements
- **Firewall**: UFW firewall configuration with configurable rules
- **SSH Security**: Root login disabled, password auth disabled, key-based auth only
## Role Variables
See `defaults/main.yml` for all available variables.
### Key Variables
- `node_timezone`: System timezone (default: UTC)
- `admin_user`: Admin username for infrastructure access
- `ssh_port`: SSH service port (default: 22)
- `base_packages`: List of base packages to install
- `firewall_enabled`: Enable UFW firewall (default: true)
- `firewall_allowed_tcp_ports`: Allowed TCP ports for firewall
## Secret Variables
This portfolio demo does not require secrets for offline validation. If you extend it with real passwords or keys, copy `group_vars/vault.example.yml` into an encrypted Ansible Vault file and keep real values out of normal git history.
## Usage
```yaml
- role: base_provision
vars:
node_timezone: "Europe/Warsaw"
firewall_enabled: true
```
## Handlers
- `restart sshd`: Restarts SSH service (triggered by config changes)
- `restart fail2ban`: Restarts fail2ban service (triggered by config changes)
## Tags
- `provision`: All provisioning tasks
- `base`: Base provision role tasks
@@ -0,0 +1,44 @@
---
# Base provisioning configuration
node_timezone: "UTC"
admin_user: "infra-admin"
ssh_port: 22
ssh_disabled_root_login: true
ssh_disable_password_auth: true
# Packages to install
base_packages:
- curl
- wget
- vim
- htop
- net-tools
- iptables
- fail2ban
- unattended-upgrades
# Firewall rules
firewall_enabled: true
firewall_default_policy: deny
firewall_allowed_tcp_ports:
- 22
- 80
- 443
# Application directories
app_directories:
- path: /opt/application
owner: "{{ admin_user }}"
group: "{{ admin_user }}"
mode: '0755'
- path: /var/log/application
owner: "{{ admin_user }}"
group: "{{ admin_user }}"
mode: '0755'
- path: /etc/application
owner: root
group: root
mode: '0755'
# Service verification
services_to_verify: []
@@ -0,0 +1,11 @@
---
- name: restart sshd
ansible.builtin.service:
name: sshd
state: restarted
- name: restart fail2ban
ansible.builtin.service:
name: fail2ban
state: restarted
enabled: true
@@ -0,0 +1,138 @@
---
- name: Validate system requirements
ansible.builtin.assert:
that:
- ansible_os_family == "Debian"
- ansible_python_version is version('3.6', '>=')
fail_msg: "Unsupported system - requires Debian and Python 3.6+"
- name: Update package cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
changed_when: false
- name: Install base packages
ansible.builtin.apt:
name: "{{ base_packages }}"
state: present
update_cache: true
- name: Check if admin user exists
ansible.builtin.getent:
database: passwd
key: "{{ admin_user }}"
register: admin_check
failed_when: false
changed_when: false
- name: Create admin user
ansible.builtin.user:
name: "{{ admin_user }}"
groups: sudo
append: true
create_home: true
shell: /bin/bash
when: admin_check.failed
- name: Configure timezone
community.general.timezone:
name: "{{ node_timezone }}"
- name: Configure SSH security
block:
- name: Disable root SSH login
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
state: present
when: ssh_disabled_root_login
notify: restart sshd
- name: Set SSH port
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^Port'
line: "Port {{ ssh_port }}"
state: present
notify: restart sshd
- name: Disable password authentication
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
state: present
when: ssh_disable_password_auth
notify: restart sshd
- name: Configure firewall
block:
- name: Enable UFW firewall
community.general.ufw:
state: enabled
policy: "{{ firewall_default_policy }}"
when: firewall_enabled
- name: Allow SSH access
community.general.ufw:
rule: allow
port: "{{ ssh_port }}"
proto: tcp
when: firewall_enabled
- name: Allow HTTP/HTTPS
community.general.ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop: "{{ firewall_allowed_tcp_ports }}"
when: firewall_enabled and item not in [ssh_port]
- name: Configure fail2ban
ansible.builtin.template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
backup: true
mode: '0644'
notify: restart fail2ban
- name: Enable unattended upgrades
ansible.builtin.lineinfile:
path: /etc/apt/apt.conf.d/20auto-upgrades
regexp: '^APT::Periodic::Unattended-Upgrade'
line: 'APT::Periodic::Unattended-Upgrade "1";'
state: present
- name: Create application directories
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
loop: "{{ app_directories }}"
- name: Record role-specific service intent
ansible.builtin.debug:
msg: "Would configure {{ node_type | default('generic') }} service components in a full lab deployment"
- name: Verify services are running
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: true
loop: "{{ services_to_verify }}"
when: services_to_verify | length > 0
failed_when: false
- name: Run health checks
ansible.builtin.uri:
url: http://localhost/health
method: GET
status_code: 200
register: health_check
failed_when: false
ignore_errors: true
when: "'webservers' in group_names"
@@ -0,0 +1,14 @@
# fail2ban configuration
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
port = {{ ssh_port }}
logpath = /var/log/auth.log
maxretry = 3
[recidive]
enabled = true