From 9457306a881cfe476ee0abbdba4f6f1eaa80db9d Mon Sep 17 00:00:00 2001 From: heqnx Date: Sat, 5 Jul 2025 12:21:29 +0300 Subject: initial commit on a working icecast2 setup --- tasks/apt_packages.yaml | 11 ++++ tasks/harden.yaml | 161 ++++++++++++++++++++++++++++++++++++++++++++++ tasks/hugo_setup.yaml | 24 +++++++ tasks/icecast2_setup.yaml | 38 +++++++++++ tasks/nginx_setup.yaml | 47 ++++++++++++++ tasks/preflight.yaml | 16 +++++ 6 files changed, 297 insertions(+) create mode 100644 tasks/apt_packages.yaml create mode 100644 tasks/harden.yaml create mode 100644 tasks/hugo_setup.yaml create mode 100644 tasks/icecast2_setup.yaml create mode 100644 tasks/nginx_setup.yaml create mode 100644 tasks/preflight.yaml (limited to 'tasks') diff --git a/tasks/apt_packages.yaml b/tasks/apt_packages.yaml new file mode 100644 index 0000000..c67f043 --- /dev/null +++ b/tasks/apt_packages.yaml @@ -0,0 +1,11 @@ +- name: upgrade apt packages + apt: + upgrade: dist + +- name: install apt packages + apt: + name: "{{ apt_packages }}" + state: present + update_cache: true + environment: + DEBIAN_FRONTEND: noninteractive diff --git a/tasks/harden.yaml b/tasks/harden.yaml new file mode 100644 index 0000000..3fad047 --- /dev/null +++ b/tasks/harden.yaml @@ -0,0 +1,161 @@ +- name: clear /etc/issue and /etc/motd + copy: + content: "" + dest: "{{ item }}" + loop: + - /etc/issue + - /etc/motd + +- name: check if /etc/update-motd.d directory exists + stat: + path: /etc/update-motd.d + register: motd_dir + +- name: find files in /etc/update-motd.d + find: + paths: /etc/update-motd.d + file_type: file + register: motd_files + when: motd_dir.stat.exists + +- name: remove execute permissions from all files in /etc/update-motd.d + file: + path: "{{ item.path }}" + mode: u-x,g-x,o-x + loop: "{{ motd_files.files }}" + when: motd_dir.stat.exists + +- name: enforce root-only cron/at + file: + path: "{{ item }}" + state: touch + owner: root + group: root + mode: '0600' + loop: + - /etc/cron.allow + - /etc/at.allow + +- name: remove deny files for cron and at + file: + path: "{{ item }}" + state: absent + loop: + - /etc/cron.deny + - /etc/at.deny + +- name: backup sshd_config + copy: + src: /etc/ssh/sshd_config + dest: "/etc/ssh/sshd_config.bak_{{ ansible_date_time.iso8601_basic }}" + remote_src: true + +- name: harden sshd_config + copy: + dest: /etc/ssh/sshd_config + content: | + Port 22 + Banner /etc/issue + UsePAM yes + Protocol 2 + Subsystem sftp /usr/lib/openssh/sftp-server + LogLevel verbose + PrintMotd no + #AcceptEnv LANG LC_* + MaxSessions 5 + StrictModes yes + Compression no + MaxAuthTries 3 + IgnoreRhosts yes + PrintLastLog yes + AddressFamily inet + X11Forwarding no + PermitRootLogin yes + AllowTcpForwarding yes + ClientAliveInterval 1200 + AllowAgentForwarding no + PermitEmptyPasswords no + ClientAliveCountMax 0 + GSSAPIAuthentication no + KerberosAuthentication no + IgnoreUserKnownHosts yes + PermitUserEnvironment no + ChallengeResponseAuthentication no + MACs hmac-sha2-512,hmac-sha2-256 + Ciphers aes128-ctr,aes192-ctr,aes256-ctr + +- name: regenerate SSH host keys + shell: | + rm -f /etc/ssh/ssh_host_*key* + ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N "" + args: + creates: /etc/ssh/ssh_host_ed25519_key + +- name: restart ssh + systemd: + name: ssh + state: restarted + enabled: true + when: ansible_service_mgr == 'systemd' + +- name: enable unattended-upgrades + shell: dpkg-reconfigure --priority=low unattended-upgrades + args: + creates: /etc/apt/apt.conf.d/50unattended-upgrades + +- name: restart unattended-upgrades + systemd: + name: unattended-upgrades + state: restarted + enabled: true + when: ansible_service_mgr == 'systemd' + +- name: disable ipv6 in grub + lineinfile: + path: /etc/default/grub + regexp: '^GRUB_CMDLINE_LINUX=' + line: 'GRUB_CMDLINE_LINUX="ipv6.disable=1"' + +- name: update grub + command: update-grub + +- name: create sshd fail2ban jail + copy: + src: fail2ban/jail.d/sshd.local + dest: "{{ fail2ban_jail_dir }}/sshd.local" + owner: root + group: root + mode: '0644' + +- name: copy fail2ban jail configuration + copy: + src: /etc/fail2ban/jail.conf + dest: /etc/fail2ban/jail.local + remote_src: true + mode: '0644' + +- name: allow ssh port and enable ufw + ufw: + rule: allow + port: 22 + proto: tcp + +- name: restart fail2ban + systemd: + name: fail2ban + state: restarted + enabled: true + when: ansible_service_mgr == 'systemd' + +- name: enable ufw + ufw: + state: enabled + policy: deny + +- name: restart ufw + systemd: + name: ufw + state: restarted + enabled: true + when: ansible_service_mgr == 'systemd' diff --git a/tasks/hugo_setup.yaml b/tasks/hugo_setup.yaml new file mode 100644 index 0000000..475dc8c --- /dev/null +++ b/tasks/hugo_setup.yaml @@ -0,0 +1,24 @@ +- name: download latest hugo .deb + shell: | + curl -sSL https://api.github.com/repos/gohugoio/hugo/releases | + awk -F '"' '/browser_download_url/ {print $4}' | + grep -i 'extended' | + grep -i 'linux-amd64' | + head -1 + register: latest_hugo_url + +- name: download hugo .deb package + get_url: + url: "{{ latest_hugo_url.stdout }}" + dest: /tmp/hugo.deb + mode: '0644' + +- name: install hugo package + apt: + deb: /tmp/hugo.deb + state: present + +- name: remove hugo .deb package + file: + path: /tmp/hugo.deb + state: absent diff --git a/tasks/icecast2_setup.yaml b/tasks/icecast2_setup.yaml new file mode 100644 index 0000000..ee8342d --- /dev/null +++ b/tasks/icecast2_setup.yaml @@ -0,0 +1,38 @@ +- name: ensure {{ radio_music_dir }} directory exists + file: + path: "{{ radio_music_dir }}" + state: directory + owner: icecast2 + group: icecast + mode: '0700' + +- name: deploy icecast.xml from template + template: + src: icecast2/icecast.xml.j2 + dest: /etc/icecast2/icecast.xml + owner: root + group: root + mode: '0644' + +- name: deploy ices-playlist.xml.j2 from template + template: + src: icecast2/ices-playlist.xml.j2 + dest: /etc/icecast2/ices-playlist.xml + owner: root + group: root + mode: '0644' + +- name: deploy mp3-to-ogg.sh from template + template: + src: icecast2/mp3-to-ogg.sh.j2 + dest: /etc/icecast2/mp3-to-ogg.sh + owner: root + group: root + mode: '0744' + +- name: restart icecast2 + systemd: + name: icecast2 + state: restarted + enabled: true + when: ansible_service_mgr == 'systemd' diff --git a/tasks/nginx_setup.yaml b/tasks/nginx_setup.yaml new file mode 100644 index 0000000..604db6d --- /dev/null +++ b/tasks/nginx_setup.yaml @@ -0,0 +1,47 @@ +- name: remove /etc/nginx/sites-enabled directory + file: + path: /etc/nginx/sites-enabled + state: absent + +- name: remove /etc/nginx/sites-available directory + file: + path: /etc/nginx/sites-available + state: absent + +- name: ensure /var/www/html directory exists and is empty + file: + path: /var/www/html + state: directory + mode: '0755' + owner: www-data + group: www-data + +- name: clean /var/www/html contents + file: + path: /var/www/html + state: absent + become: true + ignore_errors: true + +- name: recreate /var/www/html directory + file: + path: /var/www/html + state: directory + mode: '0755' + owner: www-data + group: www-data + +- name: deploy nginx.conf from template + template: + src: nginx/nginx.conf.j2 + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: '0644' + +- name: restart nginx + systemd: + name: nginx + state: restarted + enabled: true + when: ansible_service_mgr == 'systemd' diff --git a/tasks/preflight.yaml b/tasks/preflight.yaml new file mode 100644 index 0000000..3358d46 --- /dev/null +++ b/tasks/preflight.yaml @@ -0,0 +1,16 @@ +- name: ensure script is run as root + assert: + that: + - ansible_effective_user_id == 0 + fail_msg: "this playbook must be run as root" + +- name: check if system is debian-based + command: dpkg -l + register: dpkg_check + changed_when: false + failed_when: false + +- name: fail if not debian-based + fail: + msg: "distribution not Debian-based" + when: dpkg_check.rc != 0 -- cgit v1.2.3