From aedfdbddb7479afd87bd1884ed1b08d941008e28 Mon Sep 17 00:00:00 2001 From: rezayaghobi-dev Date: Sun, 23 Aug 2026 22:11:09 +0330 Subject: [PATCH] added the a preparing ansible playbooks for automating new servers --- .gitignore | 2 + README.md | 57 +- ansible/README.md | 145 +++ .../reza-ansible/ansible.cfg | 8 + .../inventory/group_vars/all/backup.yaml | 6 + .../inventory/group_vars/all/docker.yaml | 10 + .../inventory/group_vars/all/preparing.yaml | 107 +++ .../inventory/group_vars/all/proxy.yaml | 4 + .../inventory/group_vars/all/repo-server.yaml | 27 + .../inventory/group_vars/all/vault.yaml | 14 + .../reza-ansible/inventory/host.yaml | 10 + .../inventory/host_vars/vagrant-test.yaml | 32 + .../reza-ansible/preparing.yaml | 10 + .../reza-ansible/repo-server.yaml | 8 + .../roles/docker/handlers/main.yaml | 4 + .../roles/docker/tasks/configure_docker.yaml | 20 + .../roles/docker/tasks/install_compose.yaml | 13 + .../roles/docker/tasks/install_docker.yaml | 41 + .../reza-ansible/roles/docker/tasks/main.yaml | 15 + .../roles/docker/templates/docker-service.j2 | 15 + .../roles/preparing_server/files/limits.conf | 8 + .../roles/preparing_server/files/ssh_banner | 10 + .../roles/preparing_server/handlers/main.yaml | 39 + .../roles/preparing_server/tasks/auditd.yml | 116 +++ .../roles/preparing_server/tasks/fstab.yml | 18 + .../preparing_server/tasks/hardening.yaml | 55 ++ .../roles/preparing_server/tasks/hosts.yml | 21 + .../preparing_server/tasks/journalconf.yml | 68 ++ .../roles/preparing_server/tasks/limits.yml | 21 + .../roles/preparing_server/tasks/lynis.yaml | 7 + .../roles/preparing_server/tasks/main.yaml | 40 + .../preparing_server/tasks/packages.yaml | 33 + .../preparing_server/tasks/resolvedconf.yml | 22 + .../roles/preparing_server/tasks/tuning.yaml | 15 + .../templates/coredump.conf.j2 | 5 + .../preparing_server/templates/fial2ban.j2 | 882 ++++++++++++++++++ .../templates/hardening.rules.j2 | 354 +++++++ .../preparing_server/templates/hosts.allow.j2 | 4 + .../preparing_server/templates/hosts.deny.j2 | 3 + .../roles/preparing_server/templates/hosts.j2 | 7 + .../preparing_server/templates/iptables.j2 | 64 ++ .../templates/journald.conf.j2 | 6 + .../preparing_server/templates/limits.conf.j2 | 6 + .../templates/logrotate.conf.j2 | 17 + .../preparing_server/templates/resolv.conf.j2 | 2 + .../templates/resolved.conf.j2 | 7 + .../preparing_server/templates/sshd_config.j2 | 115 +++ .../preparing_server/templates/timout.j2 | 5 + .../roles/repo-server/tasks/get-backup.yaml | 20 + .../roles/repo-server/tasks/image-pull.yaml | 20 + .../roles/repo-server/tasks/main.yaml | 10 + .../roles/repo-server/tasks/repo-setup.yaml | 45 + .../templates/docker-compose.yaml.j2 | 97 ++ .../templates/nexus-setup-with-api.sh.j2 | 216 +++++ .../repo-server/templates/traefik.yaml.j2 | 24 + .../{playbooks => update-playbooks}/ping.yml | 0 .../docker_compose_update/tasks/main.yml | 0 .../update-agent-canvas.yml | 0 .../update-filebrowser.yml | 0 .../update-grafana.yml | 0 .../update-n8n.yml | 0 .../update-npm.yml | 0 .../update-pihole.yml | 0 .../update-plex.yml | 0 .../update-portainer.yml | 0 .../update-prowlarr.yml | 0 .../update-radarr.yml | 0 .../update-samba.yml | 0 .../update-sentinel.yml | 0 .../update-smartctl.yml | 0 .../update-sonarr.yml | 0 .../update-whisparr.yml | 0 docs/AnsiblePlaybooks.md | 85 +- 73 files changed, 2971 insertions(+), 44 deletions(-) create mode 100644 ansible/README.md create mode 100644 ansible/preparing-playbook/reza-ansible/ansible.cfg create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/backup.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/docker.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/preparing.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/proxy.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/repo-server.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/vault.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/host.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/inventory/host_vars/vagrant-test.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/preparing.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/repo-server.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/docker/handlers/main.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/docker/tasks/configure_docker.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_compose.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_docker.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/docker/tasks/main.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/docker/templates/docker-service.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/limits.conf create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/ssh_banner create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/handlers/main.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/auditd.yml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/fstab.yml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hardening.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hosts.yml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/journalconf.yml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/limits.yml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/lynis.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/main.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/packages.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/resolvedconf.yml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/tuning.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/coredump.conf.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/fial2ban.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hardening.rules.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.allow.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.deny.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/iptables.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/journald.conf.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/limits.conf.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/logrotate.conf.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolv.conf.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolved.conf.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/sshd_config.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/timout.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/get-backup.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/image-pull.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/main.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/repo-setup.yaml create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/docker-compose.yaml.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/nexus-setup-with-api.sh.j2 create mode 100644 ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/traefik.yaml.j2 rename ansible/{playbooks => update-playbooks}/ping.yml (100%) rename ansible/{playbooks => update-playbooks}/roles/docker_compose_update/tasks/main.yml (100%) rename ansible/{playbooks => update-playbooks}/update-agent-canvas.yml (100%) rename ansible/{playbooks => update-playbooks}/update-filebrowser.yml (100%) rename ansible/{playbooks => update-playbooks}/update-grafana.yml (100%) rename ansible/{playbooks => update-playbooks}/update-n8n.yml (100%) rename ansible/{playbooks => update-playbooks}/update-npm.yml (100%) rename ansible/{playbooks => update-playbooks}/update-pihole.yml (100%) rename ansible/{playbooks => update-playbooks}/update-plex.yml (100%) rename ansible/{playbooks => update-playbooks}/update-portainer.yml (100%) rename ansible/{playbooks => update-playbooks}/update-prowlarr.yml (100%) rename ansible/{playbooks => update-playbooks}/update-radarr.yml (100%) rename ansible/{playbooks => update-playbooks}/update-samba.yml (100%) rename ansible/{playbooks => update-playbooks}/update-sentinel.yml (100%) rename ansible/{playbooks => update-playbooks}/update-smartctl.yml (100%) rename ansible/{playbooks => update-playbooks}/update-sonarr.yml (100%) rename ansible/{playbooks => update-playbooks}/update-whisparr.yml (100%) diff --git a/.gitignore b/.gitignore index 35d34c8..493eb45 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ **/data/ *.db *.sqlite* +vault.pass +.vault.pass diff --git a/README.md b/README.md index a9ca4e6..4f50c9b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,8 @@ This is a real, running homelab — not a demo. It's deployed on a home Ubuntu s | **OpenHands** | `docker-compose/openhands/` | Self-hosted AI coding agent (OpenHands/agent-canvas) backed by Ollama — see [AI Coding Agent](docs/AI-Agent.md) | | **Nginx Proxy Manager** | `docker-compose/nginx-proxy-manager/` | Reverse proxy giving every service a friendly `.home` hostname with locally-trusted HTTPS — see [Reverse Proxy](docs/Reverse-Proxy.md) | | **Semaphore** | `docker-compose/semaphore/` | Self-hosted Ansible UI (alternative to AWX) — see [Semaphore Guide](docs/Semaphore.md) | -| **Ansible playbooks** | `ansible/` | Shared update role (pull → recreate → health-check → prune) reused across every stack, run via Semaphore — see [Ansible Playbooks](docs/AnsiblePlaybooks.md) | +| **Ansible playbooks** | `ansible/update-playbooks/` | Shared update role (pull → recreate → health-check → prune) reused across every stack, run via Semaphore — see [Ansible Playbooks](docs/AnsiblePlaybooks.md) | +| **Server provisioning** | `ansible/preparing-playbook/` | Full server preparation playbook (packages, hardening, Docker, Nexus/Traefik) tested against Vagrant first — see [Ansible README](ansible/README.md) | | **GitLab CI/CD** | `docker-compose/gitlab/` | Self-hosted GitLab Omnibus + Docker-executor Runner, tuned for this hardware and integrated with the monitoring stack — see [GitLab CI/CD](docs/GitLab-CICD.md) | | **Custom CI images** | `docker-compose/gitlab/ci-images-reference/` | Self-built, minimal Docker images for CI pipelines, stored in a self-hosted Container Registry, rebuilt biweekly — see [Custom CI Runner Images](docs/CI-Custom-Images.md) | | **Voting app CI/CD** | `voting-app-monorepo` (self-hosted GitLab, referenced here) | Full pipeline: build, test, vulnerability scan, 3-environment deploy with rollback, load test, DB backup to MinIO — see [Voting App — Mono-Repo](docs/Voting-App-Monorepo.md) | @@ -119,26 +120,40 @@ homelab/ │ ├── docker-compose.yml │ └── .env.example ├── ansible/ -│ └── playbooks/ -│ ├── roles/ -│ │ └── docker_compose_update/ -│ │ └── tasks/main.yml -│ ├── update-filebrowser.yml -│ ├── update-n8n.yml -│ ├── update-npm.yml -│ ├── update-pihole.yml -│ ├── update-plex.yml -│ ├── update-portainer.yml -│ ├── update-prowlarr.yml -│ ├── update-radarr.yml -│ ├── update-samba.yml -│ ├── update-sentinel.yml -│ ├── update-smartctl.yml -│ ├── update-sonarr.yml -│ ├── update-whisparr.yml -│ ├── update-agent-canvas.yml -│ ├── update-grafana.yml -│ └── ping.yml +│ ├── README.md +│ ├── update-playbooks/ +│ │ ├── roles/ +│ │ │ └── docker_compose_update/ +│ │ │ └── tasks/main.yml +│ │ ├── update-filebrowser.yml +│ │ ├── update-n8n.yml +│ │ ├── update-npm.yml +│ │ ├── update-pihole.yml +│ │ ├── update-plex.yml +│ │ ├── update-portainer.yml +│ │ ├── update-prowlarr.yml +│ │ ├── update-radarr.yml +│ │ ├── update-samba.yml +│ │ ├── update-sentinel.yml +│ │ ├── update-smartctl.yml +│ │ ├── update-sonarr.yml +│ │ ├── update-whisparr.yml +│ │ ├── update-agent-canvas.yml +│ │ ├── update-grafana.yml +│ │ └── ping.yml +│ └── preparing-playbook/ +│ └── reza-ansible/ +│ ├── ansible.cfg +│ ├── preparing.yaml +│ ├── repo-server.yaml +│ ├── inventory/ +│ │ ├── host.yaml +│ │ ├── group_vars/all/ +│ │ └── host_vars/vagrant-test.yaml +│ └── roles/ +│ ├── preparing_server/ +│ ├── docker/ +│ └── repo-server/ ├── docs/ │ ├── Home.md │ ├── Architecture-and-Hardware.md diff --git a/ansible/README.md b/ansible/README.md new file mode 100644 index 0000000..d9a809e --- /dev/null +++ b/ansible/README.md @@ -0,0 +1,145 @@ +# Ansible + +Two playbooks families live here: one for **updating** Docker Compose stacks day-to-day, and one for **provisioning** a fresh server from scratch. Both are designed to run through [Semaphore](../docs/Semaphore.md). + +## Directory structure + +``` +ansible/ +├── update-playbooks/ # day-to-day Docker Compose stack updates +│ ├── roles/ +│ │ └── docker_compose_update/ +│ │ ├── defaults/ # role defaults (currently empty — vars come from playbooks) +│ │ └── tasks/ +│ │ └── main.yml # shared pull → recreate → health-check → prune logic +│ ├── ping.yml # connectivity check +│ ├── update-agent-canvas.yml +│ ├── update-filebrowser.yml +│ ├── update-grafana.yml +│ ├── update-n8n.yml +│ ├── update-npm.yml +│ ├── update-pihole.yml +│ ├── update-plex.yml +│ ├── update-portainer.yml +│ ├── update-prowlarr.yml +│ ├── update-radarr.yml +│ ├── update-samba.yml +│ ├── update-sentinel.yml +│ ├── update-smartctl.yml +│ ├── update-sonarr.yml +│ └── update-whisparr.yml +│ +└── preparing-playbook/ # one-time server provisioning (learning lab / Vagrant testing) + └── reza-ansible/ + ├── ansible.cfg + ├── preparing.yaml # playbook: harden + Docker install + ├── repo-server.yaml # playbook: Nexus + Traefik repo server + ├── .vault.pass # ⚠️ gitignored — must be created locally + ├── inventory/ + │ ├── host.yaml # inventory — hosts and connection details + │ ├── group_vars/ + │ │ └── all/ + │ │ ├── preparing.yaml # packages, sshd, iptables, sysctl, auditd + │ │ ├── docker.yaml # Docker daemon config (proxy, registry mirror) + │ │ ├── proxy.yaml # HTTP proxy credentials + │ │ ├── repo-server.yaml # Nexus/Traefik/domain config + │ │ ├── backup.yaml # backup volume/path config + │ │ └── vault.yaml # 🔒 Ansible Vault encrypted secrets + │ └── host_vars/ + │ └── vagrant-test.yaml # Vagrant-specific overrides + └── roles/ + ├── preparing_server/ # packages, sshd, iptables, fail2ban, auditd, lynis, sysctl + ├── docker/ # Docker CE + Compose plugin install + daemon config + └── repo-server/ # Nexus3 + Traefik + Docker registry setup +``` + +## update-playbooks — how it works + +Every always-on Docker Compose stack has a thin playbook that delegates to the shared `docker_compose_update` role. Each playbook is intentionally minimal: + +```yaml +--- +- hosts: all + become: true + vars: + compose_dir: "/home/rezayaghobi/docker/" + service_name: "" + roles: + - docker_compose_update +``` + +The shared role runs the same sequence for every stack: + +1. **Records start time** for a duration summary +2. **Snapshots `docker system df`** before the pull +3. **Runs `docker compose pull`** in the stack's directory +4. **Snapshots `docker system df`** again — before/after comparison catches unexpectedly large pulls +5. **Runs `docker compose up -d`** to recreate containers with new images +6. **Waits 5 seconds**, then checks `docker compose ps` +7. **Asserts every container is up** — fails the run (and skips cleanup) if anything shows `Exit`, `Created`, or `Restarting` +8. **Runs `docker image prune -f`** to reclaim space — only if the health check passed +9. **Prints a summary** — duration, cleanup result, pass/fail + +If any step fails, Ansible stops immediately rather than continuing to prune images out from under a broken deployment. + +### Adding a new stack + +Copy any existing playbook, change `compose_dir` and `service_name`. No changes to the role itself. + +## preparing-playbook — server provisioning + +A full server preparation pipeline for fresh Ubuntu/Debian installs, designed for testing against the Vagrant VM before running on real hardware. + +### `preparing.yaml` + +Runs two roles in sequence: + +1. **`preparing_server`** — installs base packages, configures sshd, sets up iptables rules, enables fail2ban, configures auditd, tunes sysctl, installs lynis for security auditing +2. **`docker`** — installs Docker CE + Compose plugin from Docker's official repo, configures daemon with proxy/mirror settings + +### `repo-server.yaml` + +Runs the **`repo-server`** role — pulls Nexus3, Traefik, and supporting images, then configures and starts them as a self-hosted artifact repository with TLS via Traefik. + +### Inventory + +- `inventory/host.yaml` — defines the `repo-servers` group (currently just `vagrant-test` on `127.0.0.1:2222`) +- `inventory/group_vars/all/` — shared variables for all hosts +- `inventory/host_vars/vagrant-test.yaml` — Vagrant-specific overrides (sshd port, iptables trusted ranges) + +### Running locally against Vagrant + +```bash +cd ansible/preparing-playbook/reza-ansible + +# provision the server (packages + hardening + Docker) +ansible-playbook preparing.yaml -i inventory/host.yaml + +# set up the repo server (Nexus + Traefik) +ansible-playbook repo-server.yaml -i inventory/host.yaml + +# connectivity check only +ansible all -m ping -i inventory/host.yaml +``` + +## ⚠️ Before pushing to GitHub + +The `preparing-playbook/` contains hardcoded credentials and personal infrastructure details that must be sanitized before making this repo public: + +| File | Contains | What to do | +|---|---|---| +| `.vault.pass` | Plaintext vault password | Already in `.gitignore` — must be recreated locally | +| `group_vars/all/vault.yaml` | Encrypted secrets | Safe to commit (Ansible Vault encrypted) | +| `group_vars/all/proxy.yaml` | Proxy username + password in plaintext | Move credentials to `vault.yaml`, reference as `{{ vault_proxy_user }}:{{ vault_proxy_pass }}` | +| `group_vars/all/docker.yaml` | Proxy IP, registry mirror URL | Replace with `{{ vault_docker_proxy }}` / `{{ vault_registry_mirror }}` | +| `group_vars/all/preparing.yaml` | Trusted IP addresses | Replace with `{{ vault_trusted_ips }}` | +| `group_vars/all/repo-server.yaml` | Domain name, emails, usernames | Replace with vault variables | +| `inventory/host.yaml` | SSH key file path | Replace with `{{ vault_ssh_key_path }}` or a generic path | + +The **update-playbooks/** are safe as-is — they only contain `compose_dir` paths with the local username and `service_name` labels. + +## Running via Semaphore + +Both playbook families are executed through [Semaphore](../docs/Semaphore.md) — no manual `ansible-playbook` on the server. Each playbook is set up as a Task Template pointed at this repo. See [Ansible Playbooks](../docs/AnsiblePlaybooks.md) for the full workflow and the [Semaphore Guide](../docs/Semaphore.md) for setup details. + +[← Back to Home](../docs/Home.md) diff --git a/ansible/preparing-playbook/reza-ansible/ansible.cfg b/ansible/preparing-playbook/reza-ansible/ansible.cfg new file mode 100644 index 0000000..e146088 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/ansible.cfg @@ -0,0 +1,8 @@ +[defaults] +vault_password_file = .vault.pass +connection = smart +timeout = 60 +deprecation_warnings = False +host_key_checking = False +pipelining=True +forks=100 diff --git a/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/backup.yaml b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/backup.yaml new file mode 100644 index 0000000..c964c1b --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/backup.yaml @@ -0,0 +1,6 @@ +--- +docker_root_directory: /var/lib/docker +traefik_backup_volume_name: traefik-acme +traefik_destination_backup_dir: /mnt/backups/traefik +nexus_backup_volume_name: nexus-data +nexus_destination_backup_dir: /mnt/backups/nexus diff --git a/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/docker.yaml b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/docker.yaml new file mode 100644 index 0000000..c4faf44 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/docker.yaml @@ -0,0 +1,10 @@ +# http proxy +http_proxy: http://37.59.93.12:8520 + +# docker variables +docker: + http_proxy: "{{ http_proxy }}" + no_proxy: localhost,127.0.0.1,hub.hamdocker.ir + log_max_file: "5" + log_max_size: 100m + registry_mirror: https://hub.hamdocker.ir \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/preparing.yaml b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/preparing.yaml new file mode 100644 index 0000000..bf96100 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/preparing.yaml @@ -0,0 +1,107 @@ +# basic package list for installation +packages: +- sysstat +- wget +- git +- vim +- nano +- bash-completion +- curl +- htop +- iftop +- jq +- ncdu +- unzip +- net-tools +- dnsutils +- atop +- sudo +- ntp +- fail2ban +- software-properties-common +- apache2-utils +- tcpdump +- telnet +- axel +- iptables-persistent +- auditd +- libpwquality-common +- cracklib-runtime + +# sshd configuration +sshd_config: + Port: "{{ ansible_port }}" + ListenAddress: 0.0.0.0 + PermitRootLogin: without-password + PasswordAuthentication: "yes" + AllowUsers: root + AllowGroups: root + +# iptables configuration +iptables: + network_adapter_access: + - lo + tcp_port_access: + - 80 + - 443 + #udp_port_access: + trusted_IP: + - 87.247.187.145 + trusted_Range: + - 10.60.10.0/24 + +# fail2ban configuration +fail2ban: + bantime: 10m + findtime: 10m + maxretry: 5 + +# setion timeout setting (seconds) +timeout_time: 600 + +# auditd vars +auditd_apply_audit_rules: 'yes' +auditd_action_mail_acct: root +auditd_admin_space_left_action: suspend +auditd_disk_error_action: suspend +auditd_disk_full_action: suspend +auditd_max_log_file: 8 +auditd_max_log_file_action: keep_logs +auditd_mode: 1 +auditd_num_logs: 5 +auditd_space_left: 75 +auditd_space_left_action: email +grub_audit_backlog_cmdline: audit_backlog_limit=8192 +grub_audit_cmdline: audit=1 + +# lynis variables +lynis_version: '3.1.7' +lynis_name: 'lynis-{{ lynis_version }}' +lynis_tarball_url: 'https://downloads.cisofy.com/lynis/{{ lynis_name }}.tar.gz' +lynis_tarball_unpackdest: '/opt' +lynis_tarball_unpackdest_dir: '{{ lynis_tarball_unpackdest }}/lynis' +lynis_tarball_dest: '{{ lynis_tarball_unpackdest_dir }}/{{ lynis_name }}.tar.gz' + +# dns variables +dns: 8.8.8.8 1.1.1.1 +fallback_dns: 9.9.9.9 4.2.2.4 +dnssec: allow-downgrade +dns_over_tls: opportunistic + +# Limit.conf variables +limit_nofile_hard: 1024 +limit_nofile_soft: 512 +limit_nproc_hard: 1024 +limit_nproc_soft: 512 + +# sysctll configuration variables +sysctl_config: + net.ipv4.ip_forward: 1 + net.ipv4.conf.all.forwarding: 1 + net.ipv6.conf.all.forwarding: 1 + vm.max_map_count: 262144 + fs.file-max: 1500000 + net.ipv4.tcp_tw_reuse: 1 + net.netfilter.nf_conntrack_tcp_timeout_established: 900 + net.netfilter.nf_conntrack_tcp_timeout_close_wait: 10 + net.netfilter.nf_conntrack_tcp_timeout_syn_recv: 30 diff --git a/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/proxy.yaml b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/proxy.yaml new file mode 100644 index 0000000..f00ba5c --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/proxy.yaml @@ -0,0 +1,4 @@ +# setup http proxy configuration +proxy_env: + http_proxy: http://salam:salam@130.185.121.18:6789 + https_proxy: "{{ http_proxy }}" diff --git a/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/repo-server.yaml b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/repo-server.yaml new file mode 100644 index 0000000..eba4235 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/repo-server.yaml @@ -0,0 +1,27 @@ +--- +# project directory +REPO_DIRE_NAME: /var/services + +# nexus3, gitlab, and traefik docker image address and version +NEXUS_IMAGE: sonatype/nexus3 +NEXUS_VERSION: 3.38.0 +TRAEFIK_IMAGE: traefik +TRAEFIK_VERSION: v2.6.1 + +# Domain and subdomain definition +DOMAIN_NAME: ansible.mecan.ir +TRAEFIK_SUB_DOMAIN: web +NEXUS_SUB_DOMAIN: repo +HUB_SUB_DOMAIN: hub + +# pass generate with this commands +# htpasswd -nbs user pass +WEB_AUTH_USER: DockerMe +TRAEFIK_ACME_EMAIL: ahmad@DockerMe.ir + +# Nexus configuration +NEXUS_ADMIN_USERNAME: admin +NEXUS_SERVICE_URL: "https://{{ NEXUS_SUB_DOMAIN }}.{{ DOMAIN_NAME }}" +NEXUS_REPO_USERNAME: repo +NEXUS_REPO_EMAIL: ahmad@DockerMe.ir +DOCKER_REPO_BLOBSTORE: docker \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/vault.yaml b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/vault.yaml new file mode 100644 index 0000000..9dcf195 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/group_vars/all/vault.yaml @@ -0,0 +1,14 @@ +$ANSIBLE_VAULT;1.1;AES256 +30386364343138303961623730613735393530646262323238396166333039613436303638653837 +6131363331313663346136383166383334316435373766630a653761633663353634363030643763 +37663434346633396263396166663139323331306237396665633635636463633364623863316537 +3933336437303834610a396136633330373439333064663835623435393338636436623566353932 +38643936343862643430333035356535636561363235366138616336326136623834633462626434 +31396131386231343631383161353531633030343932396439326632383730346162336238353130 +30313538386331323165323333663232306332643163653634653962613763663961313034343062 +61393639376239613632646162396433653933306136303739333033333431343239306664333334 +31333866393635393537653036346562653635633331353263333463656638616463336366653162 +66326634303733613730376635663732316331623466623765353265393464333435663034666638 +37666232656636643739386438656136633438386239323036366130336236353530356366393439 +37626235353334303335323931393332313935613233353762356565653939393831343662363762 +61343232613939623635353265303439373563303530333039626235663531646465 diff --git a/ansible/preparing-playbook/reza-ansible/inventory/host.yaml b/ansible/preparing-playbook/reza-ansible/inventory/host.yaml new file mode 100644 index 0000000..62efe83 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/host.yaml @@ -0,0 +1,10 @@ +all: + children: + repo-servers: + hosts: + vagrant-test: + ansible_host: 127.0.0.1 + ansible_port: 2222 + ansible_user: vagrant + ansible_ssh_private_key_file: /home/rezayaghobi/vagrant/.vagrant/machines/default/virtualbox/private_key + ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PubkeyAcceptedKeyTypes=+ssh-rsa -o HostKeyAlgorithms=+ssh-rsa' diff --git a/ansible/preparing-playbook/reza-ansible/inventory/host_vars/vagrant-test.yaml b/ansible/preparing-playbook/reza-ansible/inventory/host_vars/vagrant-test.yaml new file mode 100644 index 0000000..54b4be3 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/inventory/host_vars/vagrant-test.yaml @@ -0,0 +1,32 @@ +--- +# --- Overrides for local Vagrant testing --- +# Ansible dict vars are REPLACED wholesale by more specific scopes (this +# file beats group_vars/all/preparing.yaml), so each dict below is +# restated in full, not merged. + +# sshd must keep listening on the REAL guest port (22). Vagrant forwards +# host:2222 -> guest:22, not guest:2222, so reusing ansible_port (2222) +# here — like group_vars/all/preparing.yaml does — would configure sshd +# to listen where nothing forwards to, locking you out on the next +# connection. +sshd_config: + Port: 22 + ListenAddress: 0.0.0.0 + PermitRootLogin: without-password + PasswordAuthentication: "yes" + # root-only AllowUsers would lock out the 'vagrant' user Ansible/vagrant + # ssh connect as. Keep both. + AllowUsers: "root vagrant" + AllowGroups: "root vagrant" + +# Teacher's prod trusted IPs (87.247.187.145, 10.60.10.0/24) don't apply +# to a local box. 10.0.2.0/24 is VirtualBox's default NAT subnet. +iptables: + network_adapter_access: + - lo + tcp_port_access: + - 80 + - 443 + trusted_IP: [] + trusted_Range: + - 10.0.2.0/24 diff --git a/ansible/preparing-playbook/reza-ansible/preparing.yaml b/ansible/preparing-playbook/reza-ansible/preparing.yaml new file mode 100644 index 0000000..3e3a880 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/preparing.yaml @@ -0,0 +1,10 @@ +--- +- hosts: repo-servers + become: true + gather_facts: yes + name: install and configure repo server + roles: + # preparing server and hardening + - { role: preparing_server, become: True, tags: preparing_server } + # install and configure docker service + - { role: docker, become: True, tags: docker_setup } \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/repo-server.yaml b/ansible/preparing-playbook/reza-ansible/repo-server.yaml new file mode 100644 index 0000000..990deaa --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/repo-server.yaml @@ -0,0 +1,8 @@ +--- +- hosts: repo-servers + become: true + gather_facts: yes + name: install and configure repo server + roles: + # install and configure repo server + - { role: repo-server, become: True, tags: repo_setup } \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/docker/handlers/main.yaml b/ansible/preparing-playbook/reza-ansible/roles/docker/handlers/main.yaml new file mode 100644 index 0000000..f5700a7 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/docker/handlers/main.yaml @@ -0,0 +1,4 @@ +- name: restart docker + service: + name: docker + state: restarted \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/configure_docker.yaml b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/configure_docker.yaml new file mode 100644 index 0000000..6b97710 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/configure_docker.yaml @@ -0,0 +1,20 @@ +--- +- name: docker | Manual - create directories + file: + dest=/etc/systemd/system/docker.service.d/ + recurse=yes + state=directory + owner=root + group=root + +- name: Make docker configuration file. + template: + src: docker-service.j2 + dest: /etc/systemd/system/docker.service.d/override.conf + notify: restart docker + +- name: Restart service docker and daemon-reload to pick up config changes + ansible.builtin.systemd: + state: restarted + daemon_reload: yes + name: docker diff --git a/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_compose.yaml b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_compose.yaml new file mode 100644 index 0000000..752586c --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_compose.yaml @@ -0,0 +1,13 @@ +--- +- name: "apt-get update" + apt: + update_cache: yes + cache_valid_time: 3600 + +- name: ensure nginx is at the latest version + apt: + name: docker-compose-plugin + state: latest + update_cache: yes + environment: "{{ proxy_env }}" + tags: inatall_compose \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_docker.yaml b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_docker.yaml new file mode 100644 index 0000000..39571d0 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/install_docker.yaml @@ -0,0 +1,41 @@ +--- +- name: install dependency + apt: + name: "{{item}}" + state: present + update_cache: yes + loop: + - apt-transport-https + - ca-certificates + - curl + - gnupg-agent + - software-properties-common + +- name: give GPG key + apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present + environment: "{{ proxy_env }}" + +- name: add docker repo + apt_repository: + repo: deb https://download.docker.com/linux/ubuntu bionic stable + state: present + environment: "{{ proxy_env }}" + +- name: install docker + apt: + name: "{{item}}" + state: latest + update_cache: yes + loop: + - docker-ce + - docker-ce-cli + - containerd.io + environment: "{{ proxy_env }}" + +- name: start and enable docker + service: + name: docker + state: started + enabled: yes diff --git a/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/main.yaml b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/main.yaml new file mode 100644 index 0000000..30740eb --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/docker/tasks/main.yaml @@ -0,0 +1,15 @@ +--- +- name: install docker + import_tasks: install_docker.yaml + tags: install_docker + when: ansible_os_family == "Debian" + +- name: config docker + import_tasks: configure_docker.yaml + tags: config_docker + when: ansible_os_family == "Debian" + +- name: install compose + import_tasks: install_compose.yaml + tags: install_compose + when: ansible_os_family == "Debian" \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/docker/templates/docker-service.j2 b/ansible/preparing-playbook/reza-ansible/roles/docker/templates/docker-service.j2 new file mode 100644 index 0000000..b63fd3f --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/docker/templates/docker-service.j2 @@ -0,0 +1,15 @@ +[Service] +{% if docker.http_proxy is defined %} +Environment="HTTP_PROXY={{ docker.http_proxy }}" +Environment="HTTPS_PROXY={{ docker.http_proxy }}" +Environment="NO_PROXY={{ docker.no_proxy}}" +{% endif %} + +ExecStart= +ExecStart=/usr/bin/dockerd \ +{% if docker.log_max_size is defined %} + --log-opt max-size={{ docker.log_max_size }} --log-opt max-file={{ docker.log_max_file }} \ +{% endif %} +{% if docker.registry_mirror is defined %} + --registry-mirror={{ docker.registry_mirror }} +{% endif %} \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/limits.conf b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/limits.conf new file mode 100644 index 0000000..395c02e --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/limits.conf @@ -0,0 +1,8 @@ +root soft nofile 65535 +root hard nofile 65535 +root soft nproc 65535 +root hard nproc 65535 +* soft nofile 2048 +* hard nofile 2048 +* soft nproc 2048 +* hard nproc 2048 diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/ssh_banner b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/ssh_banner new file mode 100644 index 0000000..47a6237 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/files/ssh_banner @@ -0,0 +1,10 @@ +################################################################# +# ALERT # +# You are entering into a secured area! Your IP, Login Time, # +# Username has been noted and has been sent to the server # +# administrator! # +# This service is restricted to authorized users only. All # +# activities on this system are logged. # +# Unauthorized access will be fully investigated and reported # +# to the appropriate law enforcement agencies. # +################################################################# \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/handlers/main.yaml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/handlers/main.yaml new file mode 100644 index 0000000..a8c704f --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/handlers/main.yaml @@ -0,0 +1,39 @@ +- name: Restart ssh + systemd: + name: ssh + state: restarted + +- name: Restart iptables + systemd: + name: iptables + state: restarted + +- name: Restart fail2ban + systemd: + name: fail2ban + state: restarted + +- name: Restart ntp + systemd: + name: ntp + state: restarted + +# https://github.com/ansible/ansible/issues/22171 +- name: restart auditd + become: 'yes' + ansible.builtin.command: service auditd restart + args: + warn: false + +- name: generate auditd + become: 'yes' + ansible.builtin.command: augenrules --load + +- name: reload systemd + become: 'yes' + ansible.builtin.systemd: + daemon_reload: 'yes' + +- name: update cracklib debian + become: 'yes' + ansible.builtin.command: update-cracklib diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/auditd.yml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/auditd.yml new file mode 100644 index 0000000..d187e99 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/auditd.yml @@ -0,0 +1,116 @@ +--- +- name: set Debian audit grub cmdline + become: 'yes' + ansible.builtin.lineinfile: + line: 'GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX {{ grub_audit_cmdline }} {{ grub_audit_backlog_cmdline }}"' + dest: /etc/default/grub.d/99-hardening-audit.cfg + state: present + create: 'yes' + mode: 0755 + owner: root + group: root + +- name: set audit action_mail_acct + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^action_mail_acct =" + line: "action_mail_acct = {{ auditd_action_mail_acct }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit admin_space_left_action + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^admin_space_left_action = " + line: "admin_space_left_action = {{ auditd_admin_space_left_action }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit disk_error_action + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^disk_error_action =" + line: "disk_error_action = {{ auditd_disk_error_action }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit disk_full_action + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^disk_full_action =" + line: "disk_full_action = {{ auditd_disk_full_action }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit max_log_file + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^max_log_file =" + line: "max_log_file = {{ auditd_max_log_file }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit max_log_file_action + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^max_log_file_action =" + line: "max_log_file_action = {{ auditd_max_log_file_action }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit num_logs + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^num_logs =" + line: "num_logs = {{ auditd_num_logs }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit space_left + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^space_left =" + line: "space_left = {{ auditd_space_left }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: set audit space_left_action + become: 'yes' + ansible.builtin.lineinfile: + regexp: "^space_left_action =" + line: "space_left_action = {{ auditd_space_left_action }}" + dest: /etc/audit/auditd.conf + mode: 0640 + state: present + create: 'no' + +- name: audit.rules + become: 'yes' + ansible.builtin.template: + src: hardening.rules.j2 + dest: /etc/audit/rules.d/hardening.rules + backup: 'yes' + mode: 0600 + owner: root + group: root + when: auditd_apply_audit_rules|bool + notify: + - generate auditd + - restart auditd +... diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/fstab.yml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/fstab.yml new file mode 100644 index 0000000..57fedbf --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/fstab.yml @@ -0,0 +1,18 @@ +--- +- name: remove /tmp from fstab + become: 'yes' + mount: + path: /tmp + state: absent + tags: + - fstab + +- name: remove floppy from fstab + become: 'yes' + ansible.builtin.lineinfile: + path: /etc/fstab + state: absent + regexp: '^(.*)floppy(.*)$' + tags: + - fstab +... diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hardening.yaml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hardening.yaml new file mode 100644 index 0000000..42bc1e0 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hardening.yaml @@ -0,0 +1,55 @@ +--- +- name: Stop and Disable ufw service if started + ansible.builtin.service: + name: ufw + state: stopped + enabled: no + ignore_errors: yes # not installed on this box (confirmed: ufw: command not found) + +- name: Stop and Disable postfix service if started + ansible.builtin.service: + name: postfix + state: stopped + enabled: no + ignore_errors: yes + +- name: Make timout configuration file. + template: + src: timout.j2 + dest: /etc/profile.d/timout-settings.sh + +- name: Set timezone to Asia/Tehran + community.general.timezone: + name: Asia/Tehran + notify: Restart ntp + +- name: Copy ssh banner file. + copy: + src: ssh_banner + dest: /etc/issue + +- name: Make sshd configuration file. + template: + src: sshd_config.j2 + dest: /etc/ssh/sshd_config + notify: Restart ssh + + + +- name: Make iptables configuration file. + template: + src: iptables.j2 + dest: /etc/iptables/rules.v4 + +- name: restore iptables state from a file + community.general.iptables_state: + state: restored + path: /etc/iptables/rules.v4 + noflush: true + notify: Restart iptables + +- name: Make fail2ban configuration file. + template: + src: fial2ban.j2 + dest: /etc/fail2ban/jail.local + notify: Restart fail2ban diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hosts.yml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hosts.yml new file mode 100644 index 0000000..39981bc --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/hosts.yml @@ -0,0 +1,21 @@ +--- +- name: hosts.allow + become: 'yes' + ansible.builtin.template: + src: hosts.allow.j2 + dest: /etc/hosts.allow + backup: 'yes' + mode: 0644 + owner: root + group: root + +- name: hosts.deny + become: 'yes' + ansible.builtin.template: + src: hosts.deny.j2 + dest: /etc/hosts.deny + backup: 'yes' + mode: 0644 + owner: root + group: root +... diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/journalconf.yml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/journalconf.yml new file mode 100644 index 0000000..b21b033 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/journalconf.yml @@ -0,0 +1,68 @@ +--- +- name: systemd journald.conf + become: 'yes' + ansible.builtin.template: + src: journald.conf.j2 + dest: /etc/systemd/journald.conf + backup: 'yes' + mode: 0644 + owner: root + group: root + notify: + - reload systemd + +- name: logrotate.conf + become: 'yes' + ansible.builtin.template: + src: logrotate.conf.j2 + dest: /etc/logrotate.conf + backup: 'yes' + mode: 0644 + owner: root + group: root + +- name: cron.daily logrotate + become: 'yes' + ansible.builtin.lineinfile: + line: "/usr/sbin/logrotate /etc/logrotate.conf" + dest: /etc/cron.daily/logrotate + mode: 0750 + state: present + create: 'yes' + +- name: stat rsyslog.conf + become: 'yes' + ansible.builtin.stat: + path: /etc/rsyslog.conf + register: rsyslogconf + +- name: get rsyslog.conf FileCreateMode + become: 'yes' + environment: + PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + ansible.builtin.shell: grep "^$FileCreateMode" /etc/rsyslog.conf + register: rsyslog_filecreatemode + changed_when: false + when: rsyslogconf.stat.exists + +- name: set rsyslog.conf FileCreateMode + become: 'yes' + ansible.builtin.lineinfile: + regexp: '^\$FileCreateMode' + line: '$FileCreateMode 0600' + dest: /etc/rsyslog.conf + mode: 0640 + state: present + create: 'no' + when: rsyslogconf.stat.exists and rsyslog_filecreatemode.stdout.find('FileCreateMode') != -1 + +- name: set rsyslog.d FileCreateMode + become: 'yes' + ansible.builtin.lineinfile: + regexp: '^\$FileCreateMode' + line: '$FileCreateMode 0600' + dest: /etc/rsyslog.d/99-filecreatemode.conf + mode: 0644 + state: present + create: 'yes' +... diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/limits.yml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/limits.yml new file mode 100644 index 0000000..285eb3a --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/limits.yml @@ -0,0 +1,21 @@ +--- +- name: limits.conf + become: 'yes' + ansible.builtin.template: + src: limits.conf.j2 + dest: /etc/security/limits.conf + backup: 'yes' + mode: 0644 + owner: root + group: root + +- name: coredump.conf + become: 'yes' + ansible.builtin.template: + src: coredump.conf.j2 + dest: /etc/systemd/coredump.conf + backup: 'yes' + mode: 0644 + owner: root + group: root +... diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/lynis.yaml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/lynis.yaml new file mode 100644 index 0000000..bcb7180 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/lynis.yaml @@ -0,0 +1,7 @@ +--- +- name: Install lynis from Debian repo + apt: + name: lynis + state: present + update_cache: yes + tags: lynis diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/main.yaml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/main.yaml new file mode 100644 index 0000000..7fff680 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/main.yaml @@ -0,0 +1,40 @@ +--- +- name: install package + import_tasks: packages.yaml + tags: install_packages + +- name: change limit.conf + import_tasks: limits.yml + tags: tuning + +- name: configure sshd, iptabels and ... + import_tasks: hardening.yaml + tags: hardening, firewall + +- name: host file configure + import_tasks: hosts.yml + tags: hardening + +- name: audit log configure + import_tasks: auditd.yml + tags: hardening + +- name: fstab config + import_tasks: fstab.yml + tags: hardening + +- name: change resolved.conf + import_tasks: resolvedconf.yml + tags: hardening + +- name: change journal.conf + import_tasks: journalconf.yml + tags: hardening + +- name: change sysctl.conf + import_tasks: tuning.yaml + tags: tuning + +- name: download and config lynis scripts + import_tasks: lynis.yaml + tags: audit \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/packages.yaml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/packages.yaml new file mode 100644 index 0000000..dd8458e --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/packages.yaml @@ -0,0 +1,33 @@ +--- +- name: Update apt cache (no full-system/kernel upgrade — avoids grub-pc + shared-folder breakage) + apt: + update_cache: yes + cache_valid_time: 86400 +- name: Stop systemd-timesyncd (conflicts with the ntp package below) + ansible.builtin.systemd: + name: systemd-timesyncd + state: stopped + enabled: no + ignore_errors: yes + +- name: Remove systemd-timesyncd so ntp can install cleanly + apt: + name: systemd-timesyncd + state: absent + ignore_errors: yes + +- name: Install basic tools + apt: + name: "{{ packages }}" + state: present + force_apt_get: yes + update_cache: yes + +- name: Set hostname + hostname: + name: '{{ inventory_hostname }}' + +- name: Fix /etc/hosts + template: + src: "hosts.j2" + dest: "/etc/hosts" diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/resolvedconf.yml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/resolvedconf.yml new file mode 100644 index 0000000..1b16189 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/resolvedconf.yml @@ -0,0 +1,22 @@ +--- +- name: resolved.conf + become: 'yes' + ansible.builtin.template: + src: resolved.conf.j2 + dest: /etc/systemd/resolved.conf + backup: 'yes' + mode: 0644 + owner: root + group: root + notify: + - reload systemd + +- name: resolv.conf + become: 'yes' + template: + src: resolv.conf.j2 + dest: /etc/resolv.conf + backup: 'yes' + mode: 0644 + owner: root + group: root diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/tuning.yaml b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/tuning.yaml new file mode 100644 index 0000000..7770892 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/tasks/tuning.yaml @@ -0,0 +1,15 @@ +--- +- name: Add the br_netfilter module + community.general.modprobe: + name: br_netfilter + state: present + +- name: Change various sysctl-settings + sysctl: + name: "{{ item.key }}" + state: present + value: "{{ item.value }}" + sysctl_file: /etc/sysctl.d/MeCan.conf + reload: yes + ignoreerrors: yes + with_dict: '{{ sysctl_config }}' \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/coredump.conf.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/coredump.conf.j2 new file mode 100644 index 0000000..bb0c1c2 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/coredump.conf.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +[Coredump] +Storage=none +ProcessSizeMax=0 diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/fial2ban.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/fial2ban.j2 new file mode 100644 index 0000000..fc69362 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/fial2ban.j2 @@ -0,0 +1,882 @@ +# WARNING: heavily refactored in 0.9.0 release. Please review and +# customize settings for your setup. +# +# Changes: in most of the cases you should not modify this +# file, but provide customizations in jail.local file, +# or separate .conf files under jail.d/ directory, e.g.: +# +# HOW TO ACTIVATE JAILS: +# +# YOU SHOULD NOT MODIFY THIS FILE. +# +# It will probably be overwritten or improved in a distribution update. +# +# Provide customizations in a jail.local file or a jail.d/customisation.local. +# For example to change the default bantime for all jails and to enable the +# ssh-iptables jail the following (uncommented) would appear in the .local file. +# See man 5 jail.conf for details. +# +# [DEFAULT] +# bantime = 1h +# +# [sshd] +# enabled = true +# +# See jail.conf(5) man page for more information + + + +# Comments: use '#' for comment lines and ';' (following a space) for inline comments + + +[INCLUDES] + +#before = paths-distro.conf +before = paths-debian.conf + +# The DEFAULT allows a global definition of the options. They can be overridden +# in each jail afterwards. + +[DEFAULT] + +# +# MISCELLANEOUS OPTIONS +# + +# "ignorself" specifies whether the local resp. own IP addresses should be ignored +# (default is true). Fail2ban will not ban a host which matches such addresses. +#ignorself = true + +# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban +# will not ban a host which matches an address in this list. Several addresses +# can be defined using space (and/or comma) separator. +ignoreip = 127.0.0.1/8 ::1 10.0.2.0/24 + +# External command that will take an tagged arguments to ignore, e.g. , +# and return true if the IP is to be ignored. False otherwise. +# +# ignorecommand = /path/to/command +ignorecommand = + +# "bantime" is the number of seconds that a host is banned. +bantime = {{ fail2ban.bantime|default('10m') }} + +# A host is banned if it has generated "maxretry" during the last "findtime" +# seconds. +findtime = {{ fail2ban.findtime|default('10m') }} + +# "maxretry" is the number of failures before a host get banned. +maxretry = {{ fail2ban.maxretry|default('5') }} + +# "backend" specifies the backend used to get files modification. +# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto". +# This option can be overridden in each jail as well. +# +# pyinotify: requires pyinotify (a file alteration monitor) to be installed. +# If pyinotify is not installed, Fail2ban will use auto. +# gamin: requires Gamin (a file alteration monitor) to be installed. +# If Gamin is not installed, Fail2ban will use auto. +# polling: uses a polling algorithm which does not require external libraries. +# systemd: uses systemd python library to access the systemd journal. +# Specifying "logpath" is not valid for this backend. +# See "journalmatch" in the jails associated filter config +# auto: will try to use the following backends, in order: +# pyinotify, gamin, polling. +# +# Note: if systemd backend is chosen as the default but you enable a jail +# for which logs are present only in its own log files, specify some other +# backend for that jail (e.g. polling) and provide empty value for +# journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200 +backend = auto + +# "usedns" specifies if jails should trust hostnames in logs, +# warn when DNS lookups are performed, or ignore all hostnames in logs +# +# yes: if a hostname is encountered, a DNS lookup will be performed. +# warn: if a hostname is encountered, a DNS lookup will be performed, +# but it will be logged as a warning. +# no: if a hostname is encountered, will not be used for banning, +# but it will be logged as info. +# raw: use raw value (no hostname), allow use it for no-host filters/actions (example user) +usedns = warn + +# "logencoding" specifies the encoding of the log files handled by the jail +# This is used to decode the lines from the log file. +# Typical examples: "ascii", "utf-8" +# +# auto: will use the system locale setting +logencoding = auto + +# "enabled" enables the jails. +# By default all jails are disabled, and it should stay this way. +# Enable only relevant to your setup jails in your .local or jail.d/*.conf +# +# true: jail will be enabled and log files will get monitored for changes +# false: jail is not enabled +enabled = false + + +# "mode" defines the mode of the filter (see corresponding filter implementation for more info). +mode = normal + +# "filter" defines the filter to use by the jail. +# By default jails have names matching their filter name +# +filter = %(__name__)s[mode=%(mode)s] + + +# +# ACTIONS +# + +# Some options used for actions + +# Destination email address used solely for the interpolations in +# jail.{conf,local,d/*} configuration files. +destemail = root@localhost + +# Sender email address used solely for some actions +sender = root@ + +# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the +# mailing. Change mta configuration parameter to mail if you want to +# revert to conventional 'mail'. +mta = sendmail + +# Default protocol +protocol = tcp + +# Specify chain where jumps would need to be added in ban-actions expecting parameter chain +chain = + +# Ports to be banned +# Usually should be overridden in a particular jail +port = 0:65535 + +# Format of user-agent https://tools.ietf.org/html/rfc7231#section-5.5.3 +fail2ban_agent = Fail2Ban/%(fail2ban_version)s + +# +# Action shortcuts. To be used to define action parameter + +# Default banning action (e.g. iptables, iptables-new, +# iptables-multiport, shorewall, etc) It is used to define +# action_* variables. Can be overridden globally or per +# section within jail.local file +banaction = iptables-multiport +banaction_allports = iptables-allports + +# The simplest action to take: ban only +action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + +# ban & send an e-mail with whois report to the destemail. +action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] + +# ban & send an e-mail with whois report and relevant log lines +# to the destemail. +action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] + +# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action +# +# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines +# to the destemail. +action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"] + +# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines +# to the destemail. +action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"] + %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] + +# Report block via blocklist.de fail2ban reporting service API +# +# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action. +# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation +# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey` +# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in +# corresponding jail.d/my-jail.local file). +# +action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"] + +# Report ban via badips.com, and use as blacklist +# +# See BadIPsAction docstring in config/action.d/badips.py for +# documentation for this action. +# +# NOTE: This action relies on banaction being present on start and therefore +# should be last action defined for a jail. +# +action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"] +# +# Report ban via badips.com (uses action.d/badips.conf for reporting only) +# +action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"] + +# Report ban via abuseipdb.com. +# +# See action.d/abuseipdb.conf for usage example and details. +# +action_abuseipdb = abuseipdb + +# Choose default action. To change, just override value of 'action' with the +# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local +# globally (section [DEFAULT]) or per specific section +action = %(action_)s + + +# +# JAILS +# + +# +# SSH servers +# + +[sshd] +enabled = true +port = {{ sshd_config.Port|default('22') }} +backend = systemd + +[dropbear] + +port = {{ sshd_config.Port|default('22') }} +logpath = %(dropbear_log)s +backend = %(dropbear_backend)s + + +[selinux-ssh] + +port = {{ sshd_config.Port|default('22') }} +logpath = %(auditd_log)s + + +# +# HTTP servers +# + +[apache-auth] + +port = http,https +logpath = %(apache_error_log)s + + +[apache-badbots] +# Ban hosts which agent identifies spammer robots crawling the web +# for email addresses. The mail outputs are buffered. +port = http,https +logpath = %(apache_access_log)s +bantime = 48h +maxretry = 1 + + +[apache-noscript] + +port = http,https +logpath = %(apache_error_log)s + + +[apache-overflows] + +port = http,https +logpath = %(apache_error_log)s +maxretry = 2 + + +[apache-nohome] + +port = http,https +logpath = %(apache_error_log)s +maxretry = 2 + + +[apache-botsearch] + +port = http,https +logpath = %(apache_error_log)s +maxretry = 2 + + +[apache-fakegooglebot] + +port = http,https +logpath = %(apache_access_log)s +maxretry = 1 +ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot + + +[apache-modsecurity] + +port = http,https +logpath = %(apache_error_log)s +maxretry = 2 + + +[apache-shellshock] + +port = http,https +logpath = %(apache_error_log)s +maxretry = 1 + + +[openhab-auth] + +filter = openhab +action = iptables-allports[name=NoAuthFailures] +logpath = /opt/openhab/logs/request.log + + +[nginx-http-auth] + +port = http,https +logpath = %(nginx_error_log)s + +# To use 'nginx-limit-req' jail you should have `ngx_http_limit_req_module` +# and define `limit_req` and `limit_req_zone` as described in nginx documentation +# http://nginx.org/en/docs/http/ngx_http_limit_req_module.html +# or for example see in 'config/filter.d/nginx-limit-req.conf' +[nginx-limit-req] +port = http,https +logpath = %(nginx_error_log)s + +[nginx-botsearch] + +port = http,https +logpath = %(nginx_error_log)s +maxretry = 2 + + +# Ban attackers that try to use PHP's URL-fopen() functionality +# through GET/POST variables. - Experimental, with more than a year +# of usage in production environments. + +[php-url-fopen] + +port = http,https +logpath = %(nginx_access_log)s + %(apache_access_log)s + + +[suhosin] + +port = http,https +logpath = %(suhosin_log)s + + +[lighttpd-auth] +# Same as above for Apache's mod_auth +# It catches wrong authentifications +port = http,https +logpath = %(lighttpd_error_log)s + + +# +# Webmail and groupware servers +# + +[roundcube-auth] + +port = http,https +logpath = %(roundcube_errors_log)s +# Use following line in your jail.local if roundcube logs to journal. +#backend = %(syslog_backend)s + + +[openwebmail] + +port = http,https +logpath = /var/log/openwebmail.log + + +[horde] + +port = http,https +logpath = /var/log/horde/horde.log + + +[groupoffice] + +port = http,https +logpath = /home/groupoffice/log/info.log + + +[sogo-auth] +# Monitor SOGo groupware server +# without proxy this would be: +# port = 20000 +port = http,https +logpath = /var/log/sogo/sogo.log + + +[tine20] + +logpath = /var/log/tine20/tine20.log +port = http,https + + +# +# Web Applications +# +# + +[drupal-auth] + +port = http,https +logpath = %(syslog_daemon)s +backend = %(syslog_backend)s + +[guacamole] + +port = http,https +logpath = /var/log/tomcat*/catalina.out + +[monit] +#Ban clients brute-forcing the monit gui login +port = 2812 +logpath = /var/log/monit + + +[webmin-auth] + +port = 10000 +logpath = %(syslog_authpriv)s +backend = %(syslog_backend)s + + +[froxlor-auth] + +port = http,https +logpath = %(syslog_authpriv)s +backend = %(syslog_backend)s + + +# +# HTTP Proxy servers +# +# + +[squid] + +port = 80,443,3128,8080 +logpath = /var/log/squid/access.log + + +[3proxy] + +port = 3128 +logpath = /var/log/3proxy.log + + +# +# FTP servers +# + + +[proftpd] + +port = ftp,ftp-data,ftps,ftps-data +logpath = %(proftpd_log)s +backend = %(proftpd_backend)s + + +[pure-ftpd] + +port = ftp,ftp-data,ftps,ftps-data +logpath = %(pureftpd_log)s +backend = %(pureftpd_backend)s + + +[gssftpd] + +port = ftp,ftp-data,ftps,ftps-data +logpath = %(syslog_daemon)s +backend = %(syslog_backend)s + + +[wuftpd] + +port = ftp,ftp-data,ftps,ftps-data +logpath = %(wuftpd_log)s +backend = %(wuftpd_backend)s + + +[vsftpd] +# or overwrite it in jails.local to be +# logpath = %(syslog_authpriv)s +# if you want to rely on PAM failed login attempts +# vsftpd's failregex should match both of those formats +port = ftp,ftp-data,ftps,ftps-data +logpath = %(vsftpd_log)s + + +# +# Mail servers +# + +# ASSP SMTP Proxy Jail +[assp] + +port = smtp,465,submission +logpath = /root/path/to/assp/logs/maillog.txt + + +[courier-smtp] + +port = smtp,465,submission +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +[postfix] +# To use another modes set filter parameter "mode" in jail.local: +mode = more +port = smtp,465,submission +logpath = %(postfix_log)s +backend = %(postfix_backend)s + + +[postfix-rbl] + +filter = postfix[mode=rbl] +port = smtp,465,submission +logpath = %(postfix_log)s +backend = %(postfix_backend)s +maxretry = 1 + + +[sendmail-auth] + +port = submission,465,smtp +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +[sendmail-reject] +# To use more aggressive modes set filter parameter "mode" in jail.local: +# normal (default), extra or aggressive +# See "tests/files/logs/sendmail-reject" or "filter.d/sendmail-reject.conf" for usage example and details. +#mode = normal +port = smtp,465,submission +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +[qmail-rbl] + +filter = qmail +port = smtp,465,submission +logpath = /service/qmail/log/main/current + + +# dovecot defaults to logging to the mail syslog facility +# but can be set by syslog_facility in the dovecot configuration. +[dovecot] + +port = pop3,pop3s,imap,imaps,submission,465,sieve +logpath = %(dovecot_log)s +backend = %(dovecot_backend)s + + +[sieve] + +port = smtp,465,submission +logpath = %(dovecot_log)s +backend = %(dovecot_backend)s + + +[solid-pop3d] + +port = pop3,pop3s +logpath = %(solidpop3d_log)s + + +[exim] +# see filter.d/exim.conf for further modes supported from filter: +#mode = normal +port = smtp,465,submission +logpath = %(exim_main_log)s + + +[exim-spam] + +port = smtp,465,submission +logpath = %(exim_main_log)s + + +[kerio] + +port = imap,smtp,imaps,465 +logpath = /opt/kerio/mailserver/store/logs/security.log + + +# +# Mail servers authenticators: might be used for smtp,ftp,imap servers, so +# all relevant ports get banned +# + +[courier-auth] + +port = smtp,465,submission,imap,imaps,pop3,pop3s +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +[postfix-sasl] + +filter = postfix[mode=auth] +port = smtp,465,submission,imap,imaps,pop3,pop3s +# You might consider monitoring /var/log/mail.warn instead if you are +# running postfix since it would provide the same log lines at the +# "warn" level but overall at the smaller filesize. +logpath = %(postfix_log)s +backend = %(postfix_backend)s + + +[perdition] + +port = imap,imaps,pop3,pop3s +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +[squirrelmail] + +port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks +logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log + + +[cyrus-imap] + +port = imap,imaps +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +[uwimap-auth] + +port = imap,imaps +logpath = %(syslog_mail)s +backend = %(syslog_backend)s + + +# +# +# DNS servers +# + + +# !!! WARNING !!! +# Since UDP is connection-less protocol, spoofing of IP and imitation +# of illegal actions is way too simple. Thus enabling of this filter +# might provide an easy way for implementing a DoS against a chosen +# victim. See +# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html +# Please DO NOT USE this jail unless you know what you are doing. +# +# IMPORTANT: see filter.d/named-refused for instructions to enable logging +# This jail blocks UDP traffic for DNS requests. +# [named-refused-udp] +# +# filter = named-refused +# port = domain,953 +# protocol = udp +# logpath = /var/log/named/security.log + +# IMPORTANT: see filter.d/named-refused for instructions to enable logging +# This jail blocks TCP traffic for DNS requests. + +[named-refused] + +port = domain,953 +logpath = /var/log/named/security.log + + +[nsd] + +port = 53 +action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] + %(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] +logpath = /var/log/nsd.log + + +# +# Miscellaneous +# + +[asterisk] + +port = 5060,5061 +action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] + %(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] + %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"] +logpath = /var/log/asterisk/messages +maxretry = 10 + + +[freeswitch] + +port = 5060,5061 +action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] + %(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] + %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"] +logpath = /var/log/freeswitch.log +maxretry = 10 + + +# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or +# equivalent section: +# log-warning = 2 +# +# for syslog (daemon facility) +# [mysqld_safe] +# syslog +# +# for own logfile +# [mysqld] +# log-error=/var/log/mysqld.log +[mysqld-auth] + +port = 3306 +logpath = %(mysql_log)s +backend = %(mysql_backend)s + + +# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf') +[mongodb-auth] +# change port when running with "--shardsvr" or "--configsvr" runtime operation +port = 27017 +logpath = /var/log/mongodb/mongodb.log + + +# Jail for more extended banning of persistent abusers +# !!! WARNINGS !!! +# 1. Make sure that your loglevel specified in fail2ban.conf/.local +# is not at DEBUG level -- which might then cause fail2ban to fall into +# an infinite loop constantly feeding itself with non-informative lines +# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days) +# to maintain entries for failed logins for sufficient amount of time +[recidive] + +logpath = /var/log/fail2ban.log +banaction = %(banaction_allports)s +bantime = 1w +findtime = 1d + + +# Generic filter for PAM. Has to be used with action which bans all +# ports such as iptables-allports, shorewall + +[pam-generic] +# pam-generic filter can be customized to monitor specific subset of 'tty's +banaction = %(banaction_allports)s +logpath = %(syslog_authpriv)s +backend = %(syslog_backend)s + + +[xinetd-fail] + +banaction = iptables-multiport-log +logpath = %(syslog_daemon)s +backend = %(syslog_backend)s +maxretry = 2 + + +# stunnel - need to set port for this +[stunnel] + +logpath = /var/log/stunnel4/stunnel.log + + +[ejabberd-auth] + +port = 5222 +logpath = /var/log/ejabberd/ejabberd.log + + +[counter-strike] + +logpath = /opt/cstrike/logs/L[0-9]*.log +# Firewall: http://www.cstrike-planet.com/faq/6 +tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039 +udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015 +action = %(banaction)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp] + %(banaction)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp] + +# consider low maxretry and a long bantime +# nobody except your own Nagios server should ever probe nrpe +[nagios] + +logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility +backend = %(syslog_backend)s +maxretry = 1 + + +[oracleims] +# see "oracleims" filter file for configuration requirement for Oracle IMS v6 and above +logpath = /opt/sun/comms/messaging64/log/mail.log_current +banaction = %(banaction_allports)s + +[directadmin] +logpath = /var/log/directadmin/login.log +port = 2222 + +[portsentry] +logpath = /var/lib/portsentry/portsentry.history +maxretry = 1 + +[pass2allow-ftp] +# this pass2allow example allows FTP traffic after successful HTTP authentication +port = ftp,ftp-data,ftps,ftps-data +# knocking_url variable must be overridden to some secret value in jail.local +knocking_url = /knocking/ +filter = apache-pass[knocking_url="%(knocking_url)s"] +# access log of the website with HTTP auth +logpath = %(apache_access_log)s +blocktype = RETURN +returntype = DROP +action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s] +bantime = 1h +maxretry = 1 +findtime = 1 + + +[murmur] +# AKA mumble-server +port = 64738 +action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol=tcp, chain="%(chain)s", actname=%(banaction)s-tcp] + %(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol=udp, chain="%(chain)s", actname=%(banaction)s-udp] +logpath = /var/log/mumble-server/mumble-server.log + + +[screensharingd] +# For Mac OS Screen Sharing Service (VNC) +logpath = /var/log/system.log +logencoding = utf-8 + +[haproxy-http-auth] +# HAProxy by default doesn't log to file you'll need to set it up to forward +# logs to a syslog server which would then write them to disk. +# See "haproxy-http-auth" filter for a brief cautionary note when setting +# maxretry and findtime. +logpath = /var/log/haproxy.log + +[slapd] +port = ldap,ldaps +logpath = /var/log/slapd.log + +[domino-smtp] +port = smtp,ssmtp +logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log + +[phpmyadmin-syslog] +port = http,https +logpath = %(syslog_authpriv)s +backend = %(syslog_backend)s + + +[zoneminder] +# Zoneminder HTTP/HTTPS web interface auth +# Logs auth failures to apache2 error log +port = http,https +logpath = %(apache_error_log)s diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hardening.rules.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hardening.rules.j2 new file mode 100644 index 0000000..80de742 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hardening.rules.j2 @@ -0,0 +1,354 @@ +# {{ ansible_managed }} +# https://github.com/konstruktoid/ansible-role-hardening/blob/master/templates/etc/audit/rules.d/hardening.rules.j2 +# https://github.com/konstruktoid/Ansible/blob/master/roles/docker/templates/audit.rules.j2 +# https://github.com/gds-operations/puppet-auditd/tree/master/templates + +# Remove any existing rules +-D + +# Buffer Size +-b 8192 + +# Ignore errors +-i + +# Failure Mode +-f {{ auditd_mode|int }} + +# File and directory access +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S open -F dir=/bin -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/etc -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/home -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/root -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/sbin -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/srv -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/tmp -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/usr/bin -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/usr/sbin -F success=0 -k access +-a always,exit -F arch=b32 -S open -F dir=/var -F success=0 -k access +-a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S open -F dir=/bin -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/etc -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/home -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/root -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/sbin -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/srv -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/tmp -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/usr/bin -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/usr/sbin -F success=0 -k access +-a always,exit -F arch=b64 -S open -F dir=/var -F success=0 -k access +-a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k access + +-a always,exit -F arch=b32 -C euid!=uid -F euid=0 -Fauid>=1000 -F auid!=-1 -S execve -k actions +-a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -C euid!=uid -F euid=0 -Fauid>=1000 -F auid!=-1 -S execve -k actions +-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=-1 -k actions +-a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=-1 -k actions + +# su and sudo +-w /bin/su -p x -k actions +-w /etc/sudoers -p wa -k actions +-w /etc/sudoers.d -p wa -k actions +-w /usr/bin/sudo -p x -k actions + +-a always,exit -S all -F dir=/home/ -F uid=0 -C auid!=obj_uid -k admin-user-home + +# Apparmor configuration and tools +-w /etc/apparmor -p wa -k apparmor +-w /etc/apparmor.d -p wa -k apparmor +-w /sbin/apparmor_parser -p x -k apparmor-tools +-w /usr/sbin/aa-complain -p x -k apparmor-tools +-w /usr/sbin/aa-disable -p x -k apparmor-tools +-w /usr/sbin/aa-enforce -p x -k apparmor-tools + +# Auditd configuration +-w /etc/audisp -p wa -k audispconfig +-w /etc/audit -p wa -k auditconfig +-w /etc/libaudit.conf -p wa -k auditconfig +-w /var/log/audit -p rwxa -k auditlog +-w /sbin/auditctl -p x -k audittools +-w /sbin/auditd -p x -k audittools + +# Cron +-w /etc/cron.allow -p wa -k cron +-w /etc/cron.d -p wa -k cron +-w /etc/cron.daily -p wa -k cron +-w /etc/cron.deny -p wa -k cron +-w /etc/cron.hourly -p wa -k cron +-w /etc/cron.monthly -p wa -k cron +-w /etc/cron.weekly -p wa -k cron +-w /etc/crontab -p wa -k cron +-w /var/spool/cron/crontabs -p rwxa -k cron + +-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=-1 -k delete +-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=-1 -k delete + +# Docker configuration and tools +-a exit,always -F path=/var/lib/docker -F perm=war -k docker +-w /etc/default/docker -p rwxa -k docker +-w /etc/docker -p rwxa -k docker +-w /etc/sysconfig/docker -p rwxa -k docker +-w /etc/sysconfig/docker-network -p rwxa -k docker +-w /etc/sysconfig/docker-registry -p rwxa -k docker +-w /etc/sysconfig/docker-storage -p rwxa -k docker +-w /etc/systemd/system/docker-registry.service -p rwxa -k docker +-w /etc/systemd/system/docker.service -p rwxa -k docker +-w /lib/systemd/system/docker-registry.service -p rwxa -k docker +-w /lib/systemd/system/docker.service -p rwxa -k docker +-w /lib/systemd/system/docker.socket -p rwxa -k docker +-w /usr/bin/containerd -p rwxa -k docker +-w /usr/bin/containerd-shim -p rwxa -k docker +-w /usr/bin/containerd-shim-runc-v1 -p rwxa -k docker +-w /usr/bin/containerd-shim-runc-v2 -p rwxa -k docker +-w /usr/bin/ctr -p rwxa -k docker +-w /usr/bin/docker -p rwxa -k docker +-w /usr/bin/docker-containerd -p rwxa -k docker +-w /usr/bin/docker-containerd-ctr -p rwxa -k docker +-w /usr/bin/docker-containerd-shim -p rwxa -k docker +-w /usr/bin/docker-init -p rwxa -k docker +-w /usr/bin/docker-proxy -p rwxa -k docker +-w /usr/bin/docker-runc -p rwxa -k docker +-w /usr/bin/dockerd -p rwxa -k docker +-w /usr/bin/dockerd-ce -p rwxa -k docker +-w /usr/bin/rootlesskit -p rwxa -k docker +-w /usr/bin/rootlesskit-docker-proxy -p rwxa -k docker +-w /usr/bin/runc -p rwxa -k docker +-w /usr/lib/systemd/system/docker-registry.service -p rwxa -k docker +-w /usr/lib/systemd/system/docker.service -p rwxa -k docker +-w /usr/sbin/runc -p rwxa -k docker +-w /var/run/docker.sock -p rwxa -k docker + +# Group modifications +-w /etc/group -p wa -k group-modification +-w /etc/gshadow -p wa -k group-modification +-w /etc/passwd -p wa -k group-modification +-w /etc/security/opasswd -p wa -k group-modification +-w /etc/shadow -p wa -k group-modification +-w /usr/sbin/addgroup -p x -k group-modification +-w /usr/sbin/groupadd -p x -k group-modification +-w /usr/sbin/groupmod -p x -k group-modification + +# Startup scripts +-w /etc/init -p wa -k init +-w /etc/init.d -p wa -k init +-w /etc/inittab -p wa -k init + +# Library lookup paths +-w /etc/ld.so.conf -p wa -k libpath +-w /etc/ld.so.conf.d/ -p wa -k libpath + +# Local time +-w /etc/localtime -p wa -k localtime + +# Login monitoring +-w /etc/login.defs -p wa -k login +-w /etc/securetty -p wa -k login +-w /var/log/faillog -p wa -k login +-w /var/log/lastlog -p wa -k login +-w /var/log/tallylog -p wa -k login +-w /var/run/faillock -p wa -k login + +# SELinux configuration +-w /etc/selinux -p wa -k mac-policy + +# Postfix configuration +-w /etc/aliases -p wa -k mail +-w /etc/postfix -p wa -k mail + +# Kernel module configuration and tools +-w /etc/modprobe.conf -p wa -k modprobe +-w /etc/modprobe.d -p wa -k modprobe +-w /etc/modules -p wa -k modprobe +-a always,exit -F arch=b32 -S finit_module -k modules +-a always,exit -F arch=b32 -S init_module -k modules +-a always,exit -F arch=b64 -S finit_module -k modules +-a always,exit -F arch=b64 -S init_module -S delete_module -k modules +-w /bin/kmod -p x -k modules +-w /sbin/insmod -p x -k modules +-w /sbin/modprobe -p x -k modules +-w /sbin/rmmod -p x -k modules +-w /usr/bin/kmod -p x -k modules +-w /usr/sbin/insmod -p x -k modules +-w /usr/sbin/modprobe -p x -k modules +-w /usr/sbin/rmmod -p x -k modules + +# +-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=-1 -k mounts +-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=-1 -k mounts + +# Network configuration +-w /etc/hosts -p wa -k network-config +-w /etc/issue -p wa -k network-config +-w /etc/issue.net -p wa -k network-config +-w /etc/netplan -p wa -k network-config +-w /etc/network -p wa -k network-config +-w /etc/sysconfig/network -p wa -k network-config + +# PAM configuration +-w /etc/pam.d -p wa -k pam +-w /etc/security/limits.conf -p wa -k pam +-w /etc/security/namespace.conf -p wa -k pam +-w /etc/security/namespace.init -p wa -k pam +-w /etc/security/pam_env.conf -p wa -k pam + +# Password modifications +-w /usr/bin/passwd -p x -k passwd-modification + +# Power state +-w /sbin/halt -p x -k power +-w /sbin/poweroff -p x -k power +-w /sbin/reboot -p x -k power +-w /sbin/shutdown -p x -k power + +# Use of privileged commands +-a always,exit -F path=/bin/fusermount -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/bin/mount -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/bin/ntfs-3g -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/bin/ping -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/bin/ping6 -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/bin/su -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/bin/umount -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/sbin/pam_extrausers_chkpwd -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/bsd-write -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/cgclassify -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/cgexec -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/dotlockfile -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/expiry -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/locate -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/mlocate -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/pkexec -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/screen -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/staprun -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/traceroute6.iputils -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/wall -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/bin/write -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/dbus-1.0/dbus-daemon-launch-helper -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/eject/dmcrypt-get-device -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/policykit-1/polkit-agent-helper-1 -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/polkit-1/polkit-agent-helper-1 -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/snapd/snap-confine -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/lib/x86_64-linux-gnu/utempter/utempter -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/libexec/abrt-action-install-debuginfo-to-abrt-cache -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/libexec/dbus-1/dbus-daemon-launch-helper -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/libexec/pt_chown -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/libexec/utempter/utempter -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/fping -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/fping6 -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/mount.cifs -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/netreport -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/pam_extrausers_chkpwd -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/pam-tmpdir-helper -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/usernetct -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=-1 -k privileged +-a always,exit -F path=/usr/sbin/vlock-main -F perm=x -F auid>=1000 -F auid!=-1 -k privileged + +# +-w /var/log/btmp -p wa -k session +-w /var/log/wtmp -p wa -k session +-w /var/run/utmp -p wa -k session + +# Special files +-a always,exit -F arch=b32 -S mknod,mknodat -k specialfiles +-a always,exit -F arch=b64 -S mknod,mknodat -k specialfiles + +# sshd configuration +-w /etc/ssh/sshd_config -p rwxa -k sshd +-w /etc/ssh/sshd_config.d/ -p rwxa -k sshd + +# Kernel modification +-w /etc/sysctl.conf -p wa -k sysctl + +# Hostname changes +-a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale +-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale + +# systemd configuration and tools +-w /etc/systemd -p wa -k systemd +-w /lib/systemd -p wa -k systemd +-w /bin/journalctl -p x -k systemd-tools +-w /bin/systemctl -p x -k systemd-tools + +# Time modification +-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change +-a always,exit -F arch=b32 -S clock_settime -k time-change +-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change +-a always,exit -F arch=b64 -S clock_settime -k time-change +-w /etc/localtime -p wa -k time-change +-w /etc/timezone -p wa -k time-changezone + +# /tmp directories +-w /tmp -p wxa -k tmp +-w /var/tmp -p wxa -k tmp + +# User modification +-w /usr/sbin/adduser -p x -k user-modification +-w /usr/sbin/useradd -p x -k user-modification +-w /usr/sbin/usermod -p x -k user-modification + +-e 2 diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.allow.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.allow.j2 new file mode 100644 index 0000000..ba0a36c --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.allow.j2 @@ -0,0 +1,4 @@ +# {{ ansible_managed }} + +sshd : ALL : ALLOW +ALL: LOCAL, 127.0.0.1 diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.deny.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.deny.j2 new file mode 100644 index 0000000..d313f5c --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.deny.j2 @@ -0,0 +1,3 @@ +# {{ ansible_managed }} + +ALL: ALL diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.j2 new file mode 100644 index 0000000..b49c377 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/hosts.j2 @@ -0,0 +1,7 @@ +127.0.0.1 localhost localhost.localdomain +127.0.1.1 {{ inventory_hostname }} + +# The following lines are desirable for IPv6 capable hosts +::1 localhost6 localhost6.localdomain +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/iptables.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/iptables.j2 new file mode 100644 index 0000000..05890af --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/iptables.j2 @@ -0,0 +1,64 @@ +*mangle +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,PSH,URG -j DROP +-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j DROP +COMMIT +*filter +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:CHECK_INPUT - [0:0] +:CHECK_OUTPUT - [0:0] +-A INPUT -j CHECK_INPUT +-A INPUT -j DROP +-A OUTPUT -j CHECK_OUTPUT +-A OUTPUT -j DROP +-A CHECK_INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +{% if iptables.network_adapter_access is defined %} +{% for net in iptables.network_adapter_access %} +-A CHECK_INPUT -i {{ net }} -j ACCEPT +{% endfor %} +{% endif %} +-A CHECK_INPUT -p tcp -m tcp --dport {{ sshd_config.Port|default('22') }} -j ACCEPT +{% if iptables.tcp_port_access is defined %} +{% for tcp in iptables.tcp_port_access %} +-A CHECK_INPUT -p tcp -m tcp --dport {{ tcp }} -j ACCEPT +{% endfor %} +{% endif %} +{% if iptables.udp_port_access is defined %} +{% for udp in iptables.udp_port_access %} +-A CHECK_INPUT -p udp -m udp --dport {{ udp }} -j ACCEPT +{% endfor %} +{% endif %} +{% if iptables.trusted_IP is defined %} +{% for ip in iptables.trusted_IP %} +-A CHECK_INPUT -s {{ ip }} -j ACCEPT -m comment --comment "The Trusted Server Ip" +{% endfor %} +{% endif %} +{% if iptables.trusted_Range is defined %} +{% for range in iptables.trusted_Range %} +-A CHECK_INPUT -s {{ range }} -j ACCEPT -m comment --comment "The Trusted Server Range" +{% endfor %} +{% endif %} +-A CHECK_OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +-A CHECK_OUTPUT -j ACCEPT +COMMIT + + + diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/journald.conf.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/journald.conf.j2 new file mode 100644 index 0000000..1105334 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/journald.conf.j2 @@ -0,0 +1,6 @@ +# {{ ansible_managed }} + +[Journal] +Storage=persistent +ForwardToSyslog=yes +Compress=yes diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/limits.conf.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/limits.conf.j2 new file mode 100644 index 0000000..c82e17c --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/limits.conf.j2 @@ -0,0 +1,6 @@ +# {{ ansible_managed }} + +* hard maxlogins 10 +* hard core 0 +* soft nproc {{ limit_nproc_soft }} +* hard nproc {{ limit_nproc_hard }} diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/logrotate.conf.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/logrotate.conf.j2 new file mode 100644 index 0000000..1088367 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/logrotate.conf.j2 @@ -0,0 +1,17 @@ +# {{ ansible_managed }} +# CCE-80195-1 + +daily +{% if ansible_distribution == 'Ubuntu' %} +su root syslog +{% endif %} +rotate 7 +create +dateext +compress + +compresscmd /usr/bin/xz +uncompresscmd /usr/bin/unxz +compressext .xz + +include /etc/logrotate.d diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolv.conf.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolv.conf.j2 new file mode 100644 index 0000000..df5e911 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolv.conf.j2 @@ -0,0 +1,2 @@ +nameserver 8.8.8.8 +nameserver 4.2.2.4 \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolved.conf.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolved.conf.j2 new file mode 100644 index 0000000..6d4aade --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/resolved.conf.j2 @@ -0,0 +1,7 @@ +# {{ ansible_managed }} + +[Resolve] +DNS={{ dns }} +FallbackDNS={{ fallback_dns }} +DNSSEC={{ dnssec }} +DNSOverTLS={{ dns_over_tls }} \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/sshd_config.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/sshd_config.j2 new file mode 100644 index 0000000..7f770cc --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/sshd_config.j2 @@ -0,0 +1,115 @@ +Include /etc/ssh/sshd_config.d/*.conf + +Port {{ sshd_config.Port|default('22') }} +#AddressFamily any +ListenAddress {{ sshd_config.ListenAddress|default('0.0.0.0') }} +#ListenAddress :: + +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key +#HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none + +# Logging +#SyslogFacility AUTH +LogLevel VERBOSE + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin {{ sshd_config.PermitRootLogin|default('without-password') }} +#StrictModes yes +MaxAuthTries 3 +MaxSessions 2 + +#PubkeyAuthentication yes + +# Expect .ssh/authorized_keys2 to be disregarded by default in future. +#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 + +#AuthorizedPrincipalsFile none + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +PasswordAuthentication {{ sshd_config.PasswordAuthentication|default('yes') }} +#PermitEmptyPasswords no + +# Change to yes to enable challenge-response passwords (beware issues with +# some PAM modules and threads) +ChallengeResponseAuthentication no + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes +#GSSAPIStrictAcceptorCheck yes +#GSSAPIKeyExchange no + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +UsePAM yes + +AllowAgentForwarding no +AllowTcpForwarding no +#GatewayPorts no +X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +PrintMotd no +#PrintLastLog yes +TCPKeepAlive no +#PermitUserEnvironment no +Compression no +#ClientAliveInterval 0 +ClientAliveCountMax 2 +#UseDNS no +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +Banner /etc/issue + +# Allow client to pass locale environment variables +AcceptEnv LANG LC_* + +# override default of no subsystems +Subsystem sftp /usr/lib/openssh/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server + +{% if sshd_config.AllowUsers is defined %} +AllowUsers {{ sshd_config.AllowUsers }} +{% endif %} +{% if sshd_config.AllowGroups is defined %} +AllowGroups {{ sshd_config.AllowGroups }} +{% endif %} \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/timout.j2 b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/timout.j2 new file mode 100644 index 0000000..1737e13 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/preparing_server/templates/timout.j2 @@ -0,0 +1,5 @@ +#!/bin/bash +### 300 seconds == 5 minutes ## +TMOUT={{ timeout_time }} +readonly TMOUT +export TMOUT diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/get-backup.yaml b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/get-backup.yaml new file mode 100644 index 0000000..9c795a5 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/get-backup.yaml @@ -0,0 +1,20 @@ +--- +#- synchronize: +# mode: pull +# #src: "rsync://{{ ansible_host }}{{ docker_root_directory }}/volumes/{{ traefik_backup_volume_name }}/_data/" +# src: rsync://{{ ansible_host }}/opt/ +# dest: "{{ traefik_destination_backup_dir }}" + +- name: Copy a "traefik certificate" file on the remote machine to controller host + copy: + src: "{{ docker_root_directory }}/volumes/{{ traefik_backup_volume_name }}/_data/" + remote_src: yes + dest: "{{ traefik_destination_backup_dir }}" + directory_mode: true + +- name: Copy a "nexus data" file on the remote machine to controller host + copy: + src: "{{ docker_root_directory }}/volumes/{{ nexus_backup_volume_name }}/_data/" + dest: "{{ nexus_destination_backup_dir }}" + directory_mode: true + remote_src: yes diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/image-pull.yaml b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/image-pull.yaml new file mode 100644 index 0000000..984e2c7 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/image-pull.yaml @@ -0,0 +1,20 @@ +--- +# download images +- name: Docker module dependency | Login and pull image + apt: + name: "{{ item }}" + force_apt_get: yes + with_items: + - python3-docker + - docker-compose + register: apt_action + retries: 100 + until: apt_action is success or ('Failed to lock apt for exclusive operation' not in apt_action.msg and '/var/lib/dpkg/lock' not in apt_action.msg) + +- name: docker images pull + docker_image: + name: "{{ item }}" + source: pull + with_items: + - "{{ TRAEFIK_IMAGE }}:{{ TRAEFIK_VERSION }}" + - "{{ NEXUS_IMAGE }}:{{ NEXUS_VERSION }}" \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/main.yaml b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/main.yaml new file mode 100644 index 0000000..98b6bf7 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/main.yaml @@ -0,0 +1,10 @@ +--- +- name: pull all image + include: image-pull.yaml + +- name: config and setup all service + include: repo-setup.yaml + +#- name: get volumes backup +# include: get-backup.yaml +# tags: repo_get_backup diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/repo-setup.yaml b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/repo-setup.yaml new file mode 100644 index 0000000..09ce56c --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/tasks/repo-setup.yaml @@ -0,0 +1,45 @@ +--- +- name: Creates directory + file: + path: "{{ item }}" + state: directory + loop: + - "{{ REPO_DIRE_NAME }}" + - "{{ REPO_DIRE_NAME }}/traefik" + - "{{ REPO_DIRE_NAME }}/traefik/certs" + +- name: copy bash script + template: + src: nexus-setup-with-api.sh.j2 + dest: "{{ REPO_DIRE_NAME }}/nexus-setup-with-api.sh" + +- name: Copy trafik config file. + template: + src: traefik.yaml.j2 + dest: "{{ REPO_DIRE_NAME }}/traefik/config.yml" + +- name: copy Docker Compose files + template: + src: docker-compose.yaml.j2 + dest: "{{ REPO_DIRE_NAME }}/docker-compose.yaml" + +#- name: Build the docker-compose stack +# shell: docker compose -f "{{ REPO_DIRE_NAME }}"/docker-compose.yaml up -d + +- name: Run `docker-compose up` again + docker_compose: + project_src: "{{ REPO_DIRE_NAME }}" + build: no + files: + - docker-compose.yaml + register: output + +- debug: + var: output + +- name: Pause for 2 minutes to run nexus service + pause: + minutes: 2 + +- name: Execute the script + command: bash "{{ REPO_DIRE_NAME }}/nexus-setup-with-api.sh" \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/docker-compose.yaml.j2 b/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/docker-compose.yaml.j2 new file mode 100644 index 0000000..661d802 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/docker-compose.yaml.j2 @@ -0,0 +1,97 @@ +version: '3.4' + +networks: + web_net: + external: false + name: web_net + +volumes: + traefik-acme: + name: traefik-acme + nexus-data: + name: nexus-data + +services: + traefik: + image: "{{TRAEFIK_IMAGE }}:{{TRAEFIK_VERSION}}" + restart: always + container_name: traefik + command: + - "--log.level=INFO" + - "--log.filepath=/log-file.log" + - "--log.format=json" + - "--api=true" + - "--ping=true" + - "--accesslog=true" + - "--accesslog.bufferingsize=100" + - "--api.insecure=true" + - "--providers.docker.endpoint=unix:///var/run/docker.sock" + - "--providers.docker.exposedbydefault=false" + - "--providers.docker.network=web_net" + - "--entrypoints.http.address=:80" + - "--entrypoints.https.address=:443" + - "--metrics.prometheus=true" + - "--entryPoints.metrics.address=:8082" + - "--metrics.prometheus.entryPoint=metrics" + - "--certificatesresolvers.mycert.acme.email={{ TRAEFIK_ACME_EMAIL }}" + - "--certificatesresolvers.mycert.acme.storage=/acme/acme.json" + - "--certificatesresolvers.mycert.acme.tlschallenge=true" + - "--providers.file.filename=/traefik/config.yml" + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./traefik:/traefik + - traefik-acme:/acme + networks: + - web_net + labels: + - "traefik.enable=true" + - "traefik.docker.network=web_net" + - "traefik.http.routers.traefik.entrypoints=http" + - "traefik.http.routers.traefik.rule=Host(`{{ TRAEFIK_SUB_DOMAIN }}.{{ DOMAIN_NAME }}`)" + - "traefik.http.routers.traefik.middlewares=https-redirect" + - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" + - "traefik.http.middlewares.web-auth.basicauth.users={{ WEB_AUTH_USER }}:{{ WEB_AUTH_PASS }}" + - "traefik.http.routers.traefik-secure.middlewares=web-auth,security@file,hsts@file" + - "traefik.http.routers.traefik-secure.entrypoints=https" + - "traefik.http.routers.traefik-secure.rule=Host(`{{ TRAEFIK_SUB_DOMAIN }}.{{ DOMAIN_NAME }}`)" + - "traefik.http.routers.traefik-secure.tls=true" + - "traefik.http.routers.traefik-secure.tls.options=default" + - "traefik.http.routers.traefik-secure.tls.certresolver=mycert" + - "traefik.http.services.traefik.loadbalancer.server.port=8080" + + nexus: + image: "{{ NEXUS_IMAGE }}:{{ NEXUS_VERSION }}" + container_name: nexus + restart: always + volumes: + - "nexus-data:/nexus-data" + networks: + - web_net + labels: + - "traefik.enable=true" + - "traefik.docker.network=web_net" + - "traefik.http.routers.repo.entrypoints=http" + - "traefik.http.routers.repo.rule=Host(`{{NEXUS_SUB_DOMAIN}}.{{ DOMAIN_NAME }}`)" + - "traefik.http.routers.repo.service=repo-secure" + - "traefik.http.routers.repo.middlewares=https-redirect" + - "traefik.http.routers.repo-secure.entrypoints=https" + - "traefik.http.routers.repo-secure.rule=Host(`{{NEXUS_SUB_DOMAIN}}.{{ DOMAIN_NAME }}`)" + - "traefik.http.routers.repo-secure.tls=true" + - "traefik.http.routers.repo-secure.tls.options=default" + - "traefik.http.routers.repo-secure.service=repo-secure" + - "traefik.http.routers.repo-secure.tls.certresolver=mycert" + - "traefik.http.services.repo-secure.loadbalancer.server.port=8081" + - "traefik.http.routers.hubdocker.entrypoints=http" + - "traefik.http.routers.hubdocker.rule=Host(`{{HUB_SUB_DOMAIN}}.{{ DOMAIN_NAME }}`)" + - "traefik.http.routers.hubdocker.middlewares=https-redirect" + - "traefik.http.routers.hubdocker-secure.entrypoints=https" + - "traefik.http.routers.hubdocker.service=hubdocker-secure" + - "traefik.http.routers.hubdocker-secure.rule=Host(`{{HUB_SUB_DOMAIN}}.{{ DOMAIN_NAME }}`)" + - "traefik.http.routers.hubdocker-secure.tls=true" + - "traefik.http.routers.hubdocker-secure.tls.options=default" + - "traefik.http.routers.hubdocker-secure.service=hubdocker-secure" + - "traefik.http.routers.hubdocker-secure.tls.certresolver=mycert" + - "traefik.http.services.hubdocker-secure.loadbalancer.server.port=8090" \ No newline at end of file diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/nexus-setup-with-api.sh.j2 b/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/nexus-setup-with-api.sh.j2 new file mode 100644 index 0000000..f0c6757 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/nexus-setup-with-api.sh.j2 @@ -0,0 +1,216 @@ +#!/bin/bash + +# variable section +ADMIN_USERNAME={{ NEXUS_ADMIN_USERNAME }} +ADMIN_PASSWORD={{ NEXUS_ADMIN_PASSWORD }} +NEXUS_URL={{ NEXUS_SERVICE_URL }} + +REPO_USERNAME={{ NEXUS_REPO_USERNAME }} +REPO_PASSWORD={{ NEXUS_REPO_PASSWORD }} +REPO_EMAIL={{ NEXUS_REPO_EMAIL }} + +DOCKER_REPO_BLOBSTORE={{ DOCKER_REPO_BLOBSTORE }} +# ----------------------------------------------------- +# writable state +curl -k -X 'GET' \ + ''${NEXUS_URL}'/service/rest/v1/status/writable' \ + -H 'accept: application/json' + + +Nexus_Health=$(curl -k -X 'GET' ''${NEXUS_URL}'/service/rest/v1/status/writable' -H 'accept: application/json' 2>/dev/null) +echo ${Nexus_Health} + +until [ -z "$Nexus_Health" ] +do + Nexus_Health=$(curl -k -X 'GET' ''${NEXUS_URL}'/service/rest/v1/status/writable' -H 'accept: application/json' 2>/dev/null) + echo ${Nexus_Health} + echo "Waiting for nexus starting..." + echo ${TIME} + TIME=$((TIME+1)) + echo + sleep 1 +done +echo "nexus writable state is ok" + +# get bootstrap password +BOOTSTRAP_ADMIN_PASSWORD=$(docker exec -i nexus cat /nexus-data/admin.password) +echo ${BOOTSTRAP_ADMIN_PASSWORD} + +# change password +curl -k -X 'PUT' \ + ''${NEXUS_URL}'/service/rest/v1/security/users/admin/change-password' \ + -u "admin:${BOOTSTRAP_ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: text/plain' \ + -d ''${ADMIN_PASSWORD}'' + +# delete default repository +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/maven-releases' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/maven-snapshots' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/maven-central' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/maven-public' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/nuget.org-proxy' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/nuget-group' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'DELETE' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/nuget-hosted' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +# disable anonymous access +curl -k -X 'PUT' \ + ''${NEXUS_URL}'/service/rest/v1/security/anonymous' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "enabled": false +}' + +# activate realms +curl -k -X 'PUT' \ + ''${NEXUS_URL}'/service/rest/v1/security/realms/active' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '[ + "DockerToken", + "NexusAuthenticatingRealm", + "NexusAuthorizingRealm" +]' + +# create role +curl -k -X 'POST' \ + ''${NEXUS_URL}'/service/rest/v1/security/roles' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "id": "repo-admin", + "name": "repo-admin", + "description": "all repository admin", + "privileges": [ + "nx-repository-admin-*-*-*" + ] +}' + +# create user +curl -k -X 'POST' \ + ''${NEXUS_URL}'/service/rest/v1/security/users' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "userId": "'${REPO_USERNAME}'", + "firstName": "'${REPO_USERNAME}'", + "lastName": "afranet", + "emailAddress": "'${REPO_EMAIL}'", + "password": "'${REPO_PASSWORD}'", + "status": "active", + "roles": [ + "repo-admin", + "nx-anonymous" + ] +}' + +curl -k -X 'POST' \ + ''${NEXUS_URL}'/service/rest/v1/blobstores/file' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "softQuota": { + "type": "spaceRemainingQuota", + "limit": 102400 + }, + "path": "'${DOCKER_REPO_BLOBSTORE}'", + "name": "'${DOCKER_REPO_BLOBSTORE}'" +}' + +# create docker proxy repository +curl -k -X 'POST' \ + ''${NEXUS_URL}'/service/rest/v1/repositories/docker/proxy' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "name": "hub", + "online": true, + "storage": { + "blobStoreName": "'${DOCKER_REPO_BLOBSTORE}'", + "strictContentTypeValidation": true + }, + "cleanup": { + "policyNames": [ + "string" + ] + }, + "proxy": { + "remoteUrl": "https://mirror.gcr.io", + "contentMaxAge": 1440, + "metadataMaxAge": 1440 + }, + "negativeCache": { + "enabled": true, + "timeToLive": 1440 + }, + "httpClient": { + "blocked": false, + "autoBlock": true + }, + "routingRule": "string", + "docker": { + "v1Enabled": true, + "forceBasicAuth": false, + "httpPort": 8090 + }, + "dockerProxy": { + "indexType": "HUB" + } +}' + +# check all repositories +curl -k -X 'GET' \ + ''${NEXUS_URL}'/service/rest/v1/repositories' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +# check all blobstore +curl -k -X 'GET' \ + ''${NEXUS_URL}'/service/rest/v1/blobstores' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +# check all users and roles +curl -k -X 'GET' \ + ''${NEXUS_URL}'/service/rest/v1/security/users' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' + +curl -k -X 'GET' \ + ''${NEXUS_URL}'/service/rest/v1/security/roles' \ + -u "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" \ + -H 'accept: application/json' diff --git a/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/traefik.yaml.j2 b/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/traefik.yaml.j2 new file mode 100644 index 0000000..7df3930 --- /dev/null +++ b/ansible/preparing-playbook/reza-ansible/roles/repo-server/templates/traefik.yaml.j2 @@ -0,0 +1,24 @@ +http: + middlewares: + security: + headers: + frameDeny: true + contentTypeNosniff: true + browserXssFilter: true + hsts: + headers: + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + forceSTSHeader: true +tls: + options: + default: + minVersion: VersionTLS12 + maxVersion: VersionTLS13 + cipherSuites: + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 + - TLS_AES_256_GCM_SHA384 + - TLS_CHACHA20_POLY1305_SHA256 \ No newline at end of file diff --git a/ansible/playbooks/ping.yml b/ansible/update-playbooks/ping.yml similarity index 100% rename from ansible/playbooks/ping.yml rename to ansible/update-playbooks/ping.yml diff --git a/ansible/playbooks/roles/docker_compose_update/tasks/main.yml b/ansible/update-playbooks/roles/docker_compose_update/tasks/main.yml similarity index 100% rename from ansible/playbooks/roles/docker_compose_update/tasks/main.yml rename to ansible/update-playbooks/roles/docker_compose_update/tasks/main.yml diff --git a/ansible/playbooks/update-agent-canvas.yml b/ansible/update-playbooks/update-agent-canvas.yml similarity index 100% rename from ansible/playbooks/update-agent-canvas.yml rename to ansible/update-playbooks/update-agent-canvas.yml diff --git a/ansible/playbooks/update-filebrowser.yml b/ansible/update-playbooks/update-filebrowser.yml similarity index 100% rename from ansible/playbooks/update-filebrowser.yml rename to ansible/update-playbooks/update-filebrowser.yml diff --git a/ansible/playbooks/update-grafana.yml b/ansible/update-playbooks/update-grafana.yml similarity index 100% rename from ansible/playbooks/update-grafana.yml rename to ansible/update-playbooks/update-grafana.yml diff --git a/ansible/playbooks/update-n8n.yml b/ansible/update-playbooks/update-n8n.yml similarity index 100% rename from ansible/playbooks/update-n8n.yml rename to ansible/update-playbooks/update-n8n.yml diff --git a/ansible/playbooks/update-npm.yml b/ansible/update-playbooks/update-npm.yml similarity index 100% rename from ansible/playbooks/update-npm.yml rename to ansible/update-playbooks/update-npm.yml diff --git a/ansible/playbooks/update-pihole.yml b/ansible/update-playbooks/update-pihole.yml similarity index 100% rename from ansible/playbooks/update-pihole.yml rename to ansible/update-playbooks/update-pihole.yml diff --git a/ansible/playbooks/update-plex.yml b/ansible/update-playbooks/update-plex.yml similarity index 100% rename from ansible/playbooks/update-plex.yml rename to ansible/update-playbooks/update-plex.yml diff --git a/ansible/playbooks/update-portainer.yml b/ansible/update-playbooks/update-portainer.yml similarity index 100% rename from ansible/playbooks/update-portainer.yml rename to ansible/update-playbooks/update-portainer.yml diff --git a/ansible/playbooks/update-prowlarr.yml b/ansible/update-playbooks/update-prowlarr.yml similarity index 100% rename from ansible/playbooks/update-prowlarr.yml rename to ansible/update-playbooks/update-prowlarr.yml diff --git a/ansible/playbooks/update-radarr.yml b/ansible/update-playbooks/update-radarr.yml similarity index 100% rename from ansible/playbooks/update-radarr.yml rename to ansible/update-playbooks/update-radarr.yml diff --git a/ansible/playbooks/update-samba.yml b/ansible/update-playbooks/update-samba.yml similarity index 100% rename from ansible/playbooks/update-samba.yml rename to ansible/update-playbooks/update-samba.yml diff --git a/ansible/playbooks/update-sentinel.yml b/ansible/update-playbooks/update-sentinel.yml similarity index 100% rename from ansible/playbooks/update-sentinel.yml rename to ansible/update-playbooks/update-sentinel.yml diff --git a/ansible/playbooks/update-smartctl.yml b/ansible/update-playbooks/update-smartctl.yml similarity index 100% rename from ansible/playbooks/update-smartctl.yml rename to ansible/update-playbooks/update-smartctl.yml diff --git a/ansible/playbooks/update-sonarr.yml b/ansible/update-playbooks/update-sonarr.yml similarity index 100% rename from ansible/playbooks/update-sonarr.yml rename to ansible/update-playbooks/update-sonarr.yml diff --git a/ansible/playbooks/update-whisparr.yml b/ansible/update-playbooks/update-whisparr.yml similarity index 100% rename from ansible/playbooks/update-whisparr.yml rename to ansible/update-playbooks/update-whisparr.yml diff --git a/docs/AnsiblePlaybooks.md b/docs/AnsiblePlaybooks.md index 8716a1c..4de1bb8 100644 --- a/docs/AnsiblePlaybooks.md +++ b/docs/AnsiblePlaybooks.md @@ -1,6 +1,6 @@ # Ansible Playbooks -How updates get applied across the homelab: one shared role, one thin playbook per stack, triggered through Semaphore. +How updates get applied across the homelab: one shared role, one thin playbook per stack, triggered through Semaphore. A separate provisioning playbook handles fresh server setup. ## Why @@ -10,29 +10,47 @@ Updating each Docker Compose stack by hand — SSH in, `cd` into the folder, `do ``` ansible/ -└── playbooks/ - ├── roles/ - │ └── docker_compose_update/ - │ └── tasks/ - │ └── main.yml # the shared update logic - ├── update-filebrowser.yml - ├── update-n8n.yml - ├── update-npm.yml - ├── update-pihole.yml - ├── update-plex.yml - ├── update-portainer.yml - ├── update-prowlarr.yml - ├── update-radarr.yml - ├── update-samba.yml - ├── update-sentinel.yml - ├── update-smartctl.yml - ├── update-sonarr.yml - ├── update-whisparr.yml - ├── update-agent-canvas.yml - ├── update-grafana.yml - └── ping.yml +├── README.md # full directory documentation +├── update-playbooks/ # day-to-day stack updates +│ ├── roles/ +│ │ └── docker_compose_update/ +│ │ └── tasks/main.yml # the shared update logic +│ ├── update-filebrowser.yml +│ ├── update-n8n.yml +│ ├── update-npm.yml +│ ├── update-pihole.yml +│ ├── update-plex.yml +│ ├── update-portainer.yml +│ ├── update-prowlarr.yml +│ ├── update-radarr.yml +│ ├── update-samba.yml +│ ├── update-sentinel.yml +│ ├── update-smartctl.yml +│ ├── update-sonarr.yml +│ ├── update-whisparr.yml +│ ├── update-agent-canvas.yml +│ ├── update-grafana.yml +│ └── ping.yml +│ +└── preparing-playbook/ # one-time server provisioning + └── reza-ansible/ + ├── ansible.cfg + ├── preparing.yaml # harden + Docker install + ├── repo-server.yaml # Nexus + Traefik setup + ├── inventory/ + │ ├── host.yaml + │ ├── group_vars/all/ # shared variables + │ └── host_vars/vagrant-test.yaml # Vagrant overrides + └── roles/ + ├── preparing_server/ # packages, sshd, iptables, auditd, lynis + ├── docker/ # Docker CE + Compose plugin + └── repo-server/ # Nexus3 + Traefik + registry ``` +See the [ansible/ README](../ansible/README.md) for the full breakdown of every file and role. + +## update-playbooks — how it works + One role, reused by every playbook. Each playbook is intentionally tiny: ```yaml @@ -64,7 +82,27 @@ Adding a new stack means adding a new playbook like the one above — no changes If any step fails (a bad pull, a container that won't start), Ansible stops the play immediately rather than continuing on to prune images out from under a broken deployment. -## Running it via Semaphore +## preparing-playbook — server provisioning + +A full server preparation pipeline for fresh Ubuntu/Debian installs, designed for testing against the Vagrant VM before running on real hardware. See the [ansible/ README](../ansible/README.md) for details on each role. + +### `preparing.yaml` + +Runs two roles: **preparing_server** (packages, sshd, iptables, fail2ban, auditd, sysctl, lynis) then **docker** (Docker CE + Compose plugin install + daemon config). + +### `repo-server.yaml` + +Runs the **repo-server** role — pulls and configures Nexus3, Traefik, and a Docker registry as a self-hosted artifact repository. + +### Running locally + +```bash +cd ansible/preparing-playbook/reza-ansible +ansible-playbook preparing.yaml -i inventory/host.yaml +ansible-playbook repo-server.yaml -i inventory/host.yaml +``` + +## Running via Semaphore Semaphore ([see Semaphore Guide](Semaphore.md)) is what actually executes these — no manual `ansible-playbook` on the server. Each playbook is set up as a Task Template pointed at this repo, so updating a stack is a matter of picking its template and hitting run. @@ -77,5 +115,6 @@ The Semaphore dashboard gives a quick visual of run history — successes in gre - Keeping the update logic in a single role instead of copy-pasting it into every playbook means a fix or improvement (like the disk-usage snapshots) only has to happen once — see the role's own history for an example of that in practice. - The `docker system df` before/after comparison earns its place: it's what made an unexpectedly large image pull for OpenHands/Ollama visible immediately, instead of just being a mystery bandwidth spike after the fact. - The health-check assert before pruning matters — pruning images out from under a stack that failed to come back up would make debugging (and rolling back) harder, not easier. +- Testing provisioning playbooks against a disposable Vagrant VM first catches issues like sshd port mismatches and iptables misconfigurations before they lock you out of real hardware. [← Back to Home](Home.md)