From b233c43b5e5ffdebc93f7c8923f197a9b2576a62 Mon Sep 17 00:00:00 2001 From: seaspark Date: Thu, 22 Feb 2024 21:15:25 +0000 Subject: [PATCH] Init host ansible setup --- .gitignore | 11 + ansible.cfg | 6 + ansible_resources/hosts | 6 + ansible_resources/prox-server-setup.yml | 70 +++++ home_resources/.bashrc | 125 ++++++++ .../.local/bin/spark_ansible-editvault.sh | 57 ++++ .../.local/bin/spark_ansible-playbook.sh | 57 ++++ .../.local/bin/spark_ansible-viewvault.sh | 57 ++++ home_resources/.ssh/config | 14 + prox-server-ansible-playbooks-generate.yml | 17 ++ .../etc/nginx/sites-available/cockpit.domain | 59 ++++ root_resources/etc/cockpit.conf | 9 + root_resources/etc/cockpit.oath | 1 + root_resources/etc/doas.conf | 3 + root_resources/etc/network/interfaces | 38 +++ root_resources/etc/pam.d/cockpit | 30 ++ root_resources/etc/resolv.conf | 6 + root_resources/etc/samba/smb.conf | 238 +++++++++++++++ root_resources/etc/ssh/ssh_config | 53 ++++ root_resources/etc/ssh/sshd_config | 126 ++++++++ root_resources/etc/wireguard/wg0.conf | 11 + server-firewall-setup.yml | 281 ++++++++++++++++++ server-setup.yml | 238 +++++++++++++++ server-zfs-setup.yml | 62 ++++ serversecrets.example | 31 ++ vm_resources/bridged-network.xml | 5 + 26 files changed, 1611 insertions(+) create mode 100644 .gitignore create mode 100644 ansible.cfg create mode 100644 ansible_resources/hosts create mode 100644 ansible_resources/prox-server-setup.yml create mode 100644 home_resources/.bashrc create mode 100755 home_resources/.local/bin/spark_ansible-editvault.sh create mode 100755 home_resources/.local/bin/spark_ansible-playbook.sh create mode 100755 home_resources/.local/bin/spark_ansible-viewvault.sh create mode 100644 home_resources/.ssh/config create mode 100644 prox-server-ansible-playbooks-generate.yml create mode 100644 proxy_resources/etc/nginx/sites-available/cockpit.domain create mode 100644 root_resources/etc/cockpit.conf create mode 100644 root_resources/etc/cockpit.oath create mode 100644 root_resources/etc/doas.conf create mode 100644 root_resources/etc/network/interfaces create mode 100644 root_resources/etc/pam.d/cockpit create mode 100644 root_resources/etc/resolv.conf create mode 100644 root_resources/etc/samba/smb.conf create mode 100644 root_resources/etc/ssh/ssh_config create mode 100644 root_resources/etc/ssh/sshd_config create mode 100644 root_resources/etc/wireguard/wg0.conf create mode 100644 server-firewall-setup.yml create mode 100644 server-setup.yml create mode 100644 server-zfs-setup.yml create mode 100644 serversecrets.example create mode 100644 vm_resources/bridged-network.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..124a171 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +**/*.enc +newkey_out +hosts +prox-server-firewall-setup.yml +prox-server-setup.yml +prox-deploy-service.yml + +!**/ansible_resources/* + +!.gitkeep +**/certbot/certs/* diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..c36ea5d --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +inventory = hosts + +[privilege_escalation] +become_method=doas +become_ask_pass=True diff --git a/ansible_resources/hosts b/ansible_resources/hosts new file mode 100644 index 0000000..ddde437 --- /dev/null +++ b/ansible_resources/hosts @@ -0,0 +1,6 @@ +# {{ ansible_managed }} + +all: + hosts: + {{ proxy_server_hostname }}: + {{ proxy_server_hostname }}-defaultport: diff --git a/ansible_resources/prox-server-setup.yml b/ansible_resources/prox-server-setup.yml new file mode 100644 index 0000000..2f534f7 --- /dev/null +++ b/ansible_resources/prox-server-setup.yml @@ -0,0 +1,70 @@ +# {{ ansible_managed }} + +- hosts: + - {{ proxy_server_hostname }} + # - {{ proxy_server_hostname }}-defaultport + become: 'yes' + ignore_errors: true + vars: + + # Packages to install + packages: + # Reverse Proxy/Webserver + - nginx + + # VPN Server + - wireguard + + # TLS + - certbot + - python3-certbot-nginx + + tasks: + - name: Apply default doas configuration allowing wheel group users to elevate commands with prompt + become: yes + template: + src: root_resources/etc/doas.conf + dest: "/etc/doas.conf" + - name: Temporarily disable doas pass prompt as doas persist does not work within scripts + become: yes + replace: + path: /etc/doas.conf + regexp: 'persist' + replace: 'nopass' + + - name: Ensure list of packages is installed + apt: + name: '{{ "{{" }} packages {{ "}}" }}' + state: present + # NGinx Reverse Proxy/Webserver Setup + - name: Ensure NGinx sites config directory exists + ansible.builtin.file: + path: /etc/nginx/sites-available/ + state: directory + + - name: Ensure reverse proxy git domain config is updated + template: + src: proxy_resources/etc/nginx/sites-available/cockpit.domain + dest: "/etc/nginx/sites-available/cockpit.{{ domain_name }}" + - name: Enable the reverse proxy git domain config + ansible.builtin.file: + src: /etc/nginx/sites-available/cockpit.{{ domain_name }} + dest: /etc/nginx/sites-enabled/cockpit.{{ domain_name }} + state: link + + - name: Enable NGinx + ansible.builtin.systemd: + name: nginx + enabled: yes + state: started + + - name: Reset doas configuration back to default + become: yes + template: + src: root_resources/etc/doas.conf + dest: "/etc/doas.conf" + + # End + - name: Debug Finish message + debug: + msg: Ansible playbook has finished! diff --git a/home_resources/.bashrc b/home_resources/.bashrc new file mode 100644 index 0000000..e1000a0 --- /dev/null +++ b/home_resources/.bashrc @@ -0,0 +1,125 @@ +# {{ ansible_managed }} + +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) +# for examples + +# If not running interactively, don't do anything +case $- in + *i*) ;; + *) return;; +esac + +# don't put duplicate lines or lines starting with space in the history. +# See bash(1) for more options +HISTCONTROL=ignoreboth + +# append to the history file, don't overwrite it +shopt -s histappend + +# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) +HISTSIZE=1000 +HISTFILESIZE=2000 + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# If set, the pattern "**" used in a pathname expansion context will +# match all files and zero or more directories and subdirectories. +#shopt -s globstar + +# make less more friendly for non-text input files, see lesspipe(1) +#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# set a fancy prompt (non-color, unless we know we "want" color) +case "$TERM" in + xterm-color|*-256color) color_prompt=yes;; +esac + +# uncomment for a colored prompt, if the terminal has the capability; turned +# off by default to not distract the user: the focus in a terminal window +# should be on the output of commands, not on the prompt +force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes + else + color_prompt= + fi +fi + +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' +fi +unset color_prompt force_color_prompt + +# If this is an xterm set the title to user@host:dir +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac + +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + + #alias grep='grep --color=auto' + #alias fgrep='fgrep --color=auto' + #alias egrep='egrep --color=auto' +fi + +# colored GCC warnings and errors +export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# some more ls aliases +#alias ll='ls -l' +#alias la='ls -A' +#alias l='ls -CF' + +# Alias definitions. +# You may want to put all your additions into a separate file like +# ~/.bash_aliases, instead of adding them here directly. +# See /usr/share/doc/bash-doc/examples in the bash-doc package. + +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi + +# enable programmable completion features (you don't need to enable +# this, if it's already enabled in /etc/bash.bashrc and /etc/profile +# sources /etc/bash.bashrc). +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + +export PATH="/usr/sbin:${PATH}" + +export EDITOR=vim + +neofetch +# List all open ports and their associated programs +ss -tulpn +# List ZFS pools status +zpool status diff --git a/home_resources/.local/bin/spark_ansible-editvault.sh b/home_resources/.local/bin/spark_ansible-editvault.sh new file mode 100755 index 0000000..3415ee3 --- /dev/null +++ b/home_resources/.local/bin/spark_ansible-editvault.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# {{ ansible_managed }} + +if [ -z $1 ]; then + echo "No ansible vault provided." + exit 1 +fi + +USBKEYVAR=/dev/disk/by-uuid/{{ usbkey_uuid }} +USBKEYSLOCATION={{ usbkey_keysdir }} + +# Figure out if path given is relative or absolute, assign variables accordingly +if [[ "$(echo $1 | cut -c 1)" == "/" ]]; then + # Absolute + ABSOLUTELOCATION=$1 +else + # Relative + ABSOLUTELOCATION="$(pwd)/$1" +fi +# Probably cleaner to do this in awk or the like but good enough! +# FILEPARENTDIR="$(echo $ABSOLUTELOCATION | cut -d / --fields=$(echo $ABSOLUTELOCATION | grep -o / | wc -l))" +FILENAME="$(echo $ABSOLUTELOCATION | cut -d / --fields=$(($(echo $ABSOLUTELOCATION | grep -o / | wc -l) + 1))-)" + +if [ -e $USBKEYVAR ]; then + echo "USB Key detected, will mount if not already." + if doas mount $USBKEYVAR; then + echo "Mounted USB Key, proceeding..." + else + echo "Failed to mount USB Key, assuming its already mounted and proceeding..." + fi + if [[ "$FILENAME" == *"server"* ]]; then + echo "Detected as a server vault, decrypting accordingly..." + if ansible-vault edit --vault-password-file $USBKEYSLOCATION/serversecrets $ABSOLUTELOCATION; then + echo "Ansible Vault edit success!" + else + echo "Ansible Vault edit failure!" + fi + elif [[ "$FILENAME" == *"service"* ]]; then + echo "Detected as a service vault, decrypting accordingly..." + if ansible-vault edit --vault-password-file $USBKEYSLOCATION/servicesecrets $ABSOLUTELOCATION; then + echo "Ansible Vault edit success!" + else + echo "Ansible Vault edit failure!" + fi + else + echo "Does not appear to be a server or service vault, please make sure the vault file includes either 'server' or 'service' in the name to identify!" + fi + if doas umount $USBKEYVAR; then + echo "Unmounted USB Key." + else + echo "Failed to unmount USB Key!" + fi +else + echo "USB Key not detected, please check if plugged in!" + exit 1 +fi diff --git a/home_resources/.local/bin/spark_ansible-playbook.sh b/home_resources/.local/bin/spark_ansible-playbook.sh new file mode 100755 index 0000000..48df2ba --- /dev/null +++ b/home_resources/.local/bin/spark_ansible-playbook.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# {{ ansible_managed }} + +if [ -z $1 ]; then + echo "No ansible playbook provided." + exit 1 +fi + +USBKEYVAR=/dev/disk/by-uuid/{{ usbkey_uuid }} +USBKEYSLOCATION={{ usbkey_keysdir }} + +# Figure out if path given is relative or absolute, assign variables accordingly +if [[ "$(echo $1 | cut -c 1)" == "/" ]]; then + # Absolute + ABSOLUTELOCATION=$1 +else + # Relative + ABSOLUTELOCATION="$(pwd)/$1" +fi +# Probably cleaner to do this in awk or the like but good enough! +FILEPARENTDIR="$(echo $ABSOLUTELOCATION | cut -d / --fields=$(echo $ABSOLUTELOCATION | grep -o / | wc -l))" +FILENAME="$(echo $ABSOLUTELOCATION | cut -d / --fields=$(($(echo $ABSOLUTELOCATION | grep -o / | wc -l) + 1))-)" + +if [ -e $USBKEYVAR ]; then + echo "USB Key detected, will mount if not already." + if doas mount $USBKEYVAR; then + echo "Mounted USB Key, proceeding..." + else + echo "Failed to mount USB Key, assuming its already mounted and proceeding..." + fi + if [[ "$FILENAME" == *"server"* ]]; then + echo "Detected as a server playbook file, decrypting accordingly..." + if ansible-playbook -e @{{ ansibleconf_directory }}/serversecrets.enc --vault-password-file $USBKEYSLOCATION/serversecrets $ABSOLUTELOCATION; then + echo "Ansible Playbook success!" + else + echo "Ansible Playbook failure!" + fi + elif [[ "$FILENAME" == *"service"* ]]; then + echo "Detected as a service playbook file, decrypting accordingly..." + if ansible-playbook -e @{{ ansibleconf_directory }}/serversecrets.enc --vault-password-file $USBKEYSLOCATION/serversecrets -e @{{ ansibleconf_directory }}/services/$FILEPARENTDIR/servicesecrets.enc --vault-password-file $USBKEYSLOCATION/servicesecrets $ABSOLUTELOCATION; then + echo "Ansible Playbook success!" + else + echo "Ansible Playbook failure!" + fi + else + echo "Does not appear to be a server or service playbook file, please make sure the playbook file includes either 'server' or 'service' in the name to identify!" + fi + if doas umount $USBKEYVAR; then + echo "Unmounted USB Key." + else + echo "Failed to unmount USB Key!" + fi +else + echo "USB Key not detected, please check if plugged in!" + exit 1 +fi diff --git a/home_resources/.local/bin/spark_ansible-viewvault.sh b/home_resources/.local/bin/spark_ansible-viewvault.sh new file mode 100755 index 0000000..81c6be1 --- /dev/null +++ b/home_resources/.local/bin/spark_ansible-viewvault.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# {{ ansible_managed }} + +if [ -z $1 ]; then + echo "No ansible vault provided." + exit 1 +fi + +USBKEYVAR=/dev/disk/by-uuid/{{ usbkey_uuid }} +USBKEYSLOCATION={{ usbkey_keysdir }} + +# Figure out if path given is relative or absolute, assign variables accordingly +if [[ "$(echo $1 | cut -c 1)" == "/" ]]; then + # Absolute + ABSOLUTELOCATION=$1 +else + # Relative + ABSOLUTELOCATION="$(pwd)/$1" +fi +# Probably cleaner to do this in awk or the like but good enough! +# FILEPARENTDIR="$(echo $ABSOLUTELOCATION | cut -d / --fields=$(echo $ABSOLUTELOCATION | grep -o / | wc -l))" +FILENAME="$(echo $ABSOLUTELOCATION | cut -d / --fields=$(($(echo $ABSOLUTELOCATION | grep -o / | wc -l) + 1))-)" + +if [ -e $USBKEYVAR ]; then + echo "USB Key detected, will mount if not already." + if doas mount $USBKEYVAR; then + echo "Mounted USB Key, proceeding..." + else + echo "Failed to mount USB Key, assuming its already mounted and proceeding..." + fi + if [[ "$FILENAME" == *"server"* ]]; then + echo "Detected as a server vault, decrypting accordingly..." + if ansible-vault view --vault-password-file $USBKEYSLOCATION/serversecrets $ABSOLUTELOCATION; then + echo "Ansible Vault view success!" + else + echo "Ansible Vault view failure!" + fi + elif [[ "$FILENAME" == *"service"* ]]; then + echo "Detected as a service vault, decrypting accordingly..." + if ansible-vault view --vault-password-file $USBKEYSLOCATION/servicesecrets $ABSOLUTELOCATION; then + echo "Ansible Vault view success!" + else + echo "Ansible Vault view failure!" + fi + else + echo "Does not appear to be a server or service vault, please make sure the vault file includes either 'server' or 'service' in the name to identify!" + fi + if doas umount $USBKEYVAR; then + echo "Unmounted USB Key." + else + echo "Failed to unmount USB Key!" + fi +else + echo "USB Key not detected, please check if plugged in!" + exit 1 +fi diff --git a/home_resources/.ssh/config b/home_resources/.ssh/config new file mode 100644 index 0000000..4db4a82 --- /dev/null +++ b/home_resources/.ssh/config @@ -0,0 +1,14 @@ +# {{ ansible_managed }} + +Host {{ proxy_server_hostname }} +Hostname {{ proxy_server_ip }} +Port {{ proxy_server_ssh_port }} +User {{ proxy_server_username }} +PubKeyAuthentication yes +IdentityFile ~/.ssh/id_ed25519_{{ proxy_server_hostname }} +Host {{ proxy_server_hostname }}-defaultport +Hostname {{ proxy_server_ip }} +Port 22 +User {{ proxy_server_username }} +PubKeyAuthentication yes +IdentityFile ~/.ssh/id_ed25519_{{ proxy_server_hostname }} diff --git a/prox-server-ansible-playbooks-generate.yml b/prox-server-ansible-playbooks-generate.yml new file mode 100644 index 0000000..5f094ee --- /dev/null +++ b/prox-server-ansible-playbooks-generate.yml @@ -0,0 +1,17 @@ +- hosts: localhost + tasks: + - name: Generate hosts file + template: + src: "ansible_resources/hosts" + dest: "hosts" + mode: '0777' + - name: Generate proxy server playbooks + template: + src: "ansible_resources/{{ item }}" + dest: "{{ item }}" + mode: '0777' + loop: + - prox-server-setup.yml + - name: Debug Finish message + debug: + msg: Ansible playbook has finished! diff --git a/proxy_resources/etc/nginx/sites-available/cockpit.domain b/proxy_resources/etc/nginx/sites-available/cockpit.domain new file mode 100644 index 0000000..e107f3d --- /dev/null +++ b/proxy_resources/etc/nginx/sites-available/cockpit.domain @@ -0,0 +1,59 @@ +# {{ ansible_managed }} + +# Cockpit Instance Proxy +server { + + server_name cockpit.{{ domain_name }} www.cockpit.{{ domain_name }}; + + location / { + proxy_pass http://10.0.0.199:9090; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Required for web sockets to function + proxy_http_version 1.1; + proxy_buffering off; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Pass ETag header from Cockpit to clients. + # See: https://github.com/cockpit-project/cockpit/issues/5239 + gzip off; + + include proxy_params; + } + + listen [::]:443 ssl; + listen 443 ssl; + ssl_certificate /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ domain_name }}/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + +} + +server { + if ($host = www.cockpit.{{ domain_name }}) { + return 301 https://$host$request_uri; + } + + + if ($host = cockpit.{{ domain_name }}) { + return 301 https://$host$request_uri; + } + + + listen 80; + listen [::]:80; + + server_name cockpit.{{ domain_name }} www.cockpit.{{ domain_name }}; + return 404; + + + + +} + diff --git a/root_resources/etc/cockpit.conf b/root_resources/etc/cockpit.conf new file mode 100644 index 0000000..4ee6faa --- /dev/null +++ b/root_resources/etc/cockpit.conf @@ -0,0 +1,9 @@ +[WebService] +Origins = https://cockpit.{{ domain_name }} wss://cockpit.{{ domain_name }} +ProtocolHeader = X-Forwarded-Proto + +[Log] +Fatal = /var/log/cockpit.log + +[Session] +IdleTimeout=15 diff --git a/root_resources/etc/cockpit.oath b/root_resources/etc/cockpit.oath new file mode 100644 index 0000000..e39be4a --- /dev/null +++ b/root_resources/etc/cockpit.oath @@ -0,0 +1 @@ +HOTP/T30/6 {{ admin_user_name }} - {{ cockpit_2fa_key }} diff --git a/root_resources/etc/doas.conf b/root_resources/etc/doas.conf new file mode 100644 index 0000000..728b7ec --- /dev/null +++ b/root_resources/etc/doas.conf @@ -0,0 +1,3 @@ +# {{ ansible_managed }} + +permit persist :wheel diff --git a/root_resources/etc/network/interfaces b/root_resources/etc/network/interfaces new file mode 100644 index 0000000..b4f2681 --- /dev/null +++ b/root_resources/etc/network/interfaces @@ -0,0 +1,38 @@ +# {{ ansible_managed }} + +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +source /etc/network/interfaces.d/* + +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +#auto enp2s0 +#iface enp2s0 inet static +# address 192.168.1.61 +# netmask 255.255.255.0 +# gateway 192.168.1.254 +# # dns-* options are implemented by the resolvconf package, if installed +# dns-nameservers 192.168.1.254 1.1.1.1 8.8.8.8 +# dns-search {{ domain_name }} + +auto enp2s0 +iface enp2s0 inet manual + +# Bridge 0 for Virtual Machines +auto br0 +iface br0 inet static + address 192.168.1.61 + netmask 255.255.255.0 + network 192.168.1.1 + broadcast 192.168.1.255 + gateway 192.168.1.254 + bridge_ports enp2s0 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + dns-nameservers 192.168.1.254 1.1.1.1 8.8.8.8 + dns-search {{ domain_name }} diff --git a/root_resources/etc/pam.d/cockpit b/root_resources/etc/pam.d/cockpit new file mode 100644 index 0000000..709971c --- /dev/null +++ b/root_resources/etc/pam.d/cockpit @@ -0,0 +1,30 @@ +# {{ ansible_managed }} + +#%PAM-1.0 +# this MUST be first in the "auth" stack as it sets PAM_USER +# user_unknown is definitive, so die instead of ignore to avoid subsequent modules mess up the error code +-auth [success=done new_authtok_reqd=done user_unknown=die default=ignore] pam_cockpit_cert.so +auth required pam_sepermit.so +auth substack common-auth +auth optional pam_ssh_add.so +account required pam_nologin.so +account include common-account +password include common-password +# pam_selinux.so close should be the first session rule +session required pam_selinux.so close +session required pam_loginuid.so +# pam_selinux.so open should only be followed by sessions to be executed in the user context +session required pam_selinux.so open env_params +session optional pam_keyinit.so force revoke +session optional pam_ssh_add.so +session include common-session + +# Read environment variables from /etc/environment and +# /etc/security/pam_env.conf. +session required pam_env.so # [1] +# In Debian 4.0 (etch), locale-related environment variables were moved to +# /etc/default/locale, so read that as well. +session required pam_env.so user_readenv=1 envfile=/etc/default/locale + +# Oath Two Factor Authentication for cockpit +auth required pam_oath.so usersfile=/etc/cockpit.oath diff --git a/root_resources/etc/resolv.conf b/root_resources/etc/resolv.conf new file mode 100644 index 0000000..3ea17f2 --- /dev/null +++ b/root_resources/etc/resolv.conf @@ -0,0 +1,6 @@ +# {{ ansible_managed }} + +nameserver 192.168.1.254 + +# Google Public DNS +nameserver 8.8.8.8 diff --git a/root_resources/etc/samba/smb.conf b/root_resources/etc/samba/smb.conf new file mode 100644 index 0000000..a44aade --- /dev/null +++ b/root_resources/etc/samba/smb.conf @@ -0,0 +1,238 @@ +# {{ ansible_managed }} + +# +# Sample configuration file for the Samba suite for Debian GNU/Linux. +# +# +# This is the main Samba configuration file. You should read the +# smb.conf(5) manual page in order to understand the options listed +# here. Samba has a huge number of configurable options most of which +# are not shown in this example +# +# Some options that are often worth tuning have been included as +# commented-out examples in this file. +# - When such options are commented with ";", the proposed setting +# differs from the default Samba behaviour +# - When commented with "#", the proposed setting is the default +# behaviour of Samba but the option is considered important +# enough to be mentioned here +# +# NOTE: Whenever you modify this file you should run the command +# "testparm" to check that you have not made any basic syntactic +# errors. + +#======================= Global Settings ======================= + +[global] + +## Browsing/Identification ### + +# Change this to the workgroup/NT-domain name your Samba server will part of + workgroup = WORKGROUP + +#### Networking #### + +# The specific set of interfaces / networks to bind to +# This can be either the interface name or an IP address/netmask; +# interface names are normally preferred +; interfaces = 127.0.0.0/8 eth0 + +# Only bind to the named interfaces and/or networks; you must use the +# 'interfaces' option above to use this. +# It is recommended that you enable this feature if your Samba machine is +# not protected by a firewall or is a firewall itself. However, this +# option cannot handle dynamic or non-broadcast interfaces correctly. +; bind interfaces only = yes + + + +#### Debugging/Accounting #### + +# This tells Samba to use a separate log file for each machine +# that connects + log file = /var/log/samba/log.%m + +# Cap the size of the individual log files (in KiB). + max log size = 1000 + +# We want Samba to only log to /var/log/samba/log.{smbd,nmbd}. +# Append syslog@1 if you want important messages to be sent to syslog too. + logging = file + +# Do something sensible when Samba crashes: mail the admin a backtrace + panic action = /usr/share/samba/panic-action %d + + +####### Authentication ####### + +# Server role. Defines in which mode Samba will operate. Possible +# values are "standalone server", "member server", "classic primary +# domain controller", "classic backup domain controller", "active +# directory domain controller". +# +# Most people will want "standalone server" or "member server". +# Running as "active directory domain controller" will require first +# running "samba-tool domain provision" to wipe databases and create a +# new domain. + server role = standalone server + + obey pam restrictions = yes + +# This boolean parameter controls whether Samba attempts to sync the Unix +# password with the SMB password when the encrypted SMB password in the +# passdb is changed. + unix password sync = yes + +# For Unix password sync to work on a Debian GNU/Linux system, the following +# parameters must be set (thanks to Ian Kahan < for +# sending the correct chat script for the passwd program in Debian Sarge). + passwd program = /usr/bin/passwd %u + passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* . + +# This boolean controls whether PAM will be used for password changes +# when requested by an SMB client instead of the program listed in +# 'passwd program'. The default is 'no'. + pam password change = yes + +# This option controls how unsuccessful authentication attempts are mapped +# to anonymous connections + map to guest = bad user + +########## Domains ########### + +# +# The following settings only takes effect if 'server role = classic +# primary domain controller', 'server role = classic backup domain controller' +# or 'domain logons' is set +# + +# It specifies the location of the user's +# profile directory from the client point of view) The following +# required a [profiles] share to be setup on the samba server (see +# below) +; logon path = \\%N\profiles\%U +# Another common choice is storing the profile in the user's home directory +# (this is Samba's default) +# logon path = \\%N\%U\profile + +# The following setting only takes effect if 'domain logons' is set +# It specifies the location of a user's home directory (from the client +# point of view) +; logon drive = H: +# logon home = \\%N\%U + +# The following setting only takes effect if 'domain logons' is set +# It specifies the script to run during logon. The script must be stored +# in the [netlogon] share +# NOTE: Must be store in 'DOS' file format convention +; logon script = logon.cmd + +# This allows Unix users to be created on the domain controller via the SAMR +# RPC pipe. The example command creates a user account with a disabled Unix +# password; please adapt to your needs +; add user script = /usr/sbin/adduser --quiet --disabled-password --gecos "" %u + +# This allows machine accounts to be created on the domain controller via the +# SAMR RPC pipe. +# The following assumes a "machines" group exists on the system +; add machine script = /usr/sbin/useradd -g machines -c "%u machine account" -d /var/lib/samba -s /bin/false %u + +# This allows Unix groups to be created on the domain controller via the SAMR +# RPC pipe. +; add group script = /usr/sbin/addgroup --force-badname %g + +############ Misc ############ + +# Using the following line enables you to customise your configuration +# on a per machine basis. The %m gets replaced with the netbios name +# of the machine that is connecting +; include = /home/samba/etc/smb.conf.%m + +# Some defaults for winbind (make sure you're not using the ranges +# for something else.) +; idmap config * : backend = tdb +; idmap config * : range = 3000-7999 +; idmap config YOURDOMAINHERE : backend = tdb +; idmap config YOURDOMAINHERE : range = 100000-999999 +; template shell = /bin/bash + +# Setup usershare options to enable non-root users to share folders +# with the net usershare command. + +# Maximum number of usershare. 0 means that usershare is disabled. +# usershare max shares = 100 + +# Allow users who've been granted usershare privileges to create +# public shares, not just authenticated ones + usershare allow guests = yes + +#======================= Share Definitions ======================= + +#[homes] +# comment = Home Directories +# browseable = no + +# By default, the home directories are exported read-only. Change the +# next parameter to 'no' if you want to be able to write to them. +# read only = yes + +# File creation mask is set to 0700 for security reasons. If you want to +# create files with group=rw permissions, set next parameter to 0775. +# create mask = 0700 + +# Directory creation mask is set to 0700 for security reasons. If you want to +# create dirs. with group=rw permissions, set next parameter to 0775. +# directory mask = 0700 + +# By default, \\server\username shares can be connected to by anyone +# with access to the samba server. +# The following parameter makes sure that only "username" can connect +# to \\server\username +# This might need tweaking when using external authentication schemes +# valid users = %S + +# Un-comment the following and create the netlogon directory for Domain Logons +# (you need to configure Samba to act as a domain controller too.) +;[netlogon] +; comment = Network Logon Service +; path = /home/samba/netlogon +; guest ok = yes +; read only = yes + +# Un-comment the following and create the profiles directory to store +# users profiles (see the "logon path" option above) +# (you need to configure Samba to act as a domain controller too.) +# The path below should be writable by all users so that their +# profile directory may be created the first time they log on +;[profiles] +; comment = Users profiles +; path = /home/samba/profiles +; guest ok = no +; browseable = no +; create mask = 0600 +; directory mask = 0700 + +#[printers] +# comment = All Printers +# browseable = no +# path = /var/spool/samba +# printable = yes +# guest ok = no +# read only = yes +# create mask = 0700 + +# Windows clients look for this share name as a source of downloadable +# printer drivers +#[print$] +# comment = Printer Drivers +# path = /var/lib/samba/printers +# browseable = yes +# read only = yes +# guest ok = no +# Uncomment to allow remote administration of Windows print drivers. +# You may need to replace 'lpadmin' with the name of the group your +# admin users are members of. +# Please note that you also need to set appropriate Unix permissions +# to the drivers directory for these users to have write rights in it +; write list = root, @lpadmin + diff --git a/root_resources/etc/ssh/ssh_config b/root_resources/etc/ssh/ssh_config new file mode 100644 index 0000000..485eaf5 --- /dev/null +++ b/root_resources/etc/ssh/ssh_config @@ -0,0 +1,53 @@ +# {{ ansible_managed }} + +# This is the ssh client system-wide configuration file. See +# ssh_config(5) for more information. This file provides defaults for +# users, and the values can be changed in per-user configuration files +# or on the command line. + +# Configuration data is parsed as follows: +# 1. command line options +# 2. user-specific file +# 3. system-wide file +# Any configuration value is only changed the first time it is set. +# Thus, host-specific definitions should be at the beginning of the +# configuration file, and defaults at the end. + +# Site-wide defaults for some commonly used options. For a comprehensive +# list of available options, their meanings and defaults, please see the +# ssh_config(5) man page. + +Include /etc/ssh/ssh_config.d/*.conf + +Host * +# ForwardAgent no +# ForwardX11 no +# ForwardX11Trusted yes +# HostbasedAuthentication no +# GSSAPIAuthentication no +# GSSAPIDelegateCredentials no +# GSSAPIKeyExchange no +# GSSAPITrustDNS no +# BatchMode no +# CheckHostIP yes +# AddressFamily any +# ConnectTimeout 0 +# StrictHostKeyChecking ask +# IdentityFile ~/.ssh/id_rsa +# IdentityFile ~/.ssh/id_dsa +# IdentityFile ~/.ssh/id_ecdsa +# IdentityFile ~/.ssh/id_ed25519 +# Port 22 +# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc +# MACs hmac-md5,hmac-sha1,umac-64@openssh.com +# EscapeChar ~ +# Tunnel no +# TunnelDevice any:any +# PermitLocalCommand no +# VisualHostKey no +# ProxyCommand ssh -q -W %h:%p gateway.example.com +# RekeyLimit 1G 1h +# UserKnownHostsFile ~/.ssh/known_hosts.d/%k + SendEnv LANG LC_* + HashKnownHosts yes + GSSAPIAuthentication yes diff --git a/root_resources/etc/ssh/sshd_config b/root_resources/etc/ssh/sshd_config new file mode 100644 index 0000000..9f0c4d3 --- /dev/null +++ b/root_resources/etc/ssh/sshd_config @@ -0,0 +1,126 @@ +# {{ ansible_managed }} + +# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +Include /etc/ssh/sshd_config.d/*.conf + +#Port 22 +#AddressFamily any +#ListenAddress 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 INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin no +#PermitRootLogin prohibit-password +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# Expect .ssh/authorized_keys2 to be disregarded by default in future. +#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# 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 no +#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 no + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +PrintMotd no +#PrintLastLog yes +#TCPKeepAlive yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS no +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# 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 diff --git a/root_resources/etc/wireguard/wg0.conf b/root_resources/etc/wireguard/wg0.conf new file mode 100644 index 0000000..d2fc2eb --- /dev/null +++ b/root_resources/etc/wireguard/wg0.conf @@ -0,0 +1,11 @@ +# {{ ansible_managed }} + +[Interface] +Address = 10.0.0.199/32 +PrivateKey = {{ cockpit_backend_privkey }} +DNS = 1.1.1.1 + +[Peer] +PublicKey = {{ vpn_server_pubkey }} +Endpoint = {{ domain_name }}:51820 +AllowedIPs = 10.0.0.1/32 # Only any packets to/from our Proxy server will be tunneled by the VPN diff --git a/server-firewall-setup.yml b/server-firewall-setup.yml new file mode 100644 index 0000000..4e461a8 --- /dev/null +++ b/server-firewall-setup.yml @@ -0,0 +1,281 @@ +- hosts: localhost + become: 'yes' + tasks: + # Telnet/SSH Configuration + - name: Accept inbound SSH only on internal network + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: 192.168.1.0/24 + destination_port: 22 + jump: ACCEPT + - name: Allow all outbound telnet, SSH on default port and SSH proxy server port + ansible.builtin.iptables: + chain: OUTPUT + protocol: tcp + destination_port: "{{ item }}" + jump: ACCEPT + loop: + - 23 + - 22 + - "{{ proxy_server_ssh_port }}" + + # Policy Configuration + - name: Drop incoming/outgoing/forward traffic by default + ansible.builtin.iptables: + chain: "{{ item }}" + policy: DROP + loop: + - INPUT + - OUTPUT + - FORWARD + - name: Allow inbound/outbound already established/related connections to bypass firewall rules + ansible.builtin.iptables: + chain: "{{ item }}" + ctstate: ESTABLISHED,RELATED + jump: ACCEPT + loop: + - INPUT + - OUTPUT + + # Loopback Configuration + - name: Allow inbound loopback traffic + ansible.builtin.iptables: + chain: INPUT + in_interface: lo + jump: ACCEPT + - name: Allow outbound loopback traffic + ansible.builtin.iptables: + chain: OUTPUT + out_interface: lo + jump: ACCEPT + + # DNS Configuration + - name: Accept inbound TCP/UDP DNS/TCP WHOIS lookup requests only from gateway or Google Public DNS + ansible.builtin.iptables: + chain: INPUT + protocol: "{{ item.protocol }}" + source: "{{ item.source }}" + destination_port: "{{ item.port }}" + jump: ACCEPT + loop: + - { source: 192.168.1.254, protocol: tcp, port: 53 } + - { source: 192.168.1.254, protocol: udp, port: 53 } + - { source: 8.8.8.8, protocol: tcp, port: 53 } + - { source: 8.8.8.8, protocol: udp, port: 53 } + - { source: 192.168.1.254, protocol: tcp, port: 43 } + - { source: 8.8.8.8, protocol: tcp, port: 43 } + - name: Accept outbound TCP/UDP DNS/TCP WHOIS lookup requests only from gateway or Google Public DNS + ansible.builtin.iptables: + chain: OUTPUT + protocol: "{{ item.protocol }}" + destination: "{{ item.destination }}" + destination_port: "{{ item.port }}" + jump: ACCEPT + loop: + - { destination: 192.168.1.254, protocol: tcp, port: 53 } + - { destination: 192.168.1.254, protocol: udp, port: 53 } + - { destination: 8.8.8.8, protocol: tcp, port: 53 } + - { destination: 8.8.8.8, protocol: udp, port: 53 } + - { destination: 192.168.1.254, protocol: tcp, port: 43 } + - { destination: 8.8.8.8, protocol: tcp, port: 43 } + + # ICMP Configuration + - name: Allow all outbound pinging + ansible.builtin.iptables: + chain: OUTPUT + protocol: icmp + jump: ACCEPT + + # SMB/SAMBA Service + - name: Accept inbound SMB/NETBIOS SSN/NETBIOS DGM/NETBIOS NS only from internal network + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: 192.168.1.0/24 + destination_port: "{{ item }}" + jump: ACCEPT + loop: + - 445 + - 139 + - 138 + - 137 + - name: Allow outbound SMB/NETBIOS SSN/NETBIOS DGM/NETBIOS NS only to internal network + ansible.builtin.iptables: + chain: OUTPUT + protocol: tcp + destination: 192.168.1.0/24 + destination_port: "{{ item }}" + jump: ACCEPT + loop: + - 445 + - 139 + - 138 + - 137 + + # VPN to Proxy Server Configuration + - name: Accept inbound Wireguard connections only from proxy server + ansible.builtin.iptables: + chain: INPUT + protocol: udp + source: "{{ proxy_server_ip }}" + destination_port: "{{ proxy_server_vpn_port }}" + jump: ACCEPT + - name: Allow all outbound Wireguard connections + ansible.builtin.iptables: + chain: OUTPUT + protocol: udp + destination_port: "{{ proxy_server_vpn_port }}" + jump: ACCEPT + + # Docker + - name: Accept inbound HTTPS only from Github Container Registry + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + source: 140.82.121.34 + destination_port: 443 + jump: ACCEPT + - name: Allow outbound HTTPS only to Github Container Registry + ansible.builtin.iptables: + chain: OUTPUT + protocol: tcp + destination: 140.82.121.34 + destination_port: 443 + jump: ACCEPT + + # SERVICES FIREWALL CONFIGURATION NOW HANDLED ON A PER CONTAINER BASIS VIA GLUTUN VPN CLIENT (as now using VPNs within in the containers) + # # Mail Service + # - name: Allow source (Inbound) local network traffic to the Mail service ports + # ansible.builtin.iptables: + # chain: DOCKER-USER + # source: 192.168.1.0/24 + # protocol: tcp + # destination_port: "{{ item }}" + # jump: ACCEPT + # loop: + # - 25 # SMTP Cleartext 25 + # - 465 # ESMTP Implicit TLS 465 + # - 587 # SMTP+STARTTLS Explicit TLS 587 + # - 993 # IMAPS Implicit TLS 993 + # - 143 # IMAPS IMAP+STARTTLS Explicit TLS 143 + # + # - name: Allow source (Inbound) proxy server traffic to the Mail service ports + # ansible.builtin.iptables: + # chain: DOCKER-USER + # source: "{{ proxy_server_ip }}" + # protocol: tcp + # destination_port: "{{ item }}" + # jump: ACCEPT + # loop: + # - 25 # SMTP Cleartext 25 + # - 465 # ESMTP Implicit TLS 465 + # - 587 # SMTP+STARTTLS Explicit TLS 587 + # - 993 # IMAPS Implicit TLS 993 + # - 143 # IMAPS IMAP+STARTTLS Explicit TLS 143 + # - name: Allow destination (Outbound) proxy server Mail container traffic to the Mail service ports + # ansible.builtin.iptables: + # chain: DOCKER-USER + # destination: "{{ proxy_server_ip }}" + # protocol: tcp + # destination_port: "{{ item }}" + # jump: ACCEPT + # loop: + # - 25 # SMTP Cleartext 25 + # - 465 # ESMTP Implicit TLS 465 + # - 587 # SMTP+STARTTLS Explicit TLS 587 + # - 993 # IMAPS Implicit TLS 993 + # - 143 # IMAPS IMAP+STARTTLS Explicit TLS 143 + # + # - name: Deny any other traffic on Mail service ports + # ansible.builtin.iptables: + # chain: DOCKER-USER + # protocol: tcp + # destination_port: "{{ item }}" + # jump: DROP + # loop: + # - 25 # SMTP Cleartext 25 + # - 465 # ESMTP Implicit TLS 465 + # - 587 # SMTP+STARTTLS Explicit TLS 587 + # - 993 # IMAPS Implicit TLS 993 + # - 143 # IMAPS IMAP+STARTTLS Explicit TLS 143 + # + # # Invidious Service + # - name: Allow source (Inbound) local network traffic to the Invidious service only on service port 3000 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # source: 192.168.1.0/24 + # protocol: tcp + # destination_port: 3000 + # jump: ACCEPT + # - name: Allow destination (Outbound) local network traffic to the Invidious service only on service port 3000 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # destination: 192.168.1.0/24 + # protocol: tcp + # destination_port: 3000 + # jump: ACCEPT + # + # - name: Allow source (Inbound) proxy server traffic to the Invidious service only on service port 3000 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # source: "{{ proxy_server_ip }}" + # protocol: tcp + # destination_port: 3000 + # jump: ACCEPT + # - name: Allow destination (Outbound) proxy server traffic to the Invidious service only on service port 3000 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # destination: "{{ proxy_server_ip }}" + # protocol: tcp + # destination_port: 3000 + # jump: ACCEPT + # + # - name: Deny any other traffic on Invidious port 3000 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # protocol: tcp + # destination_port: 3000 + # jump: DROP + # + # # Minecraft Service + # - name: Allow source (Inbound) local network traffic to the Invidious service only on service port 25565 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # source: 192.168.1.0/24 + # protocol: tcp + # destination_port: 25565 + # jump: ACCEPT + # - name: Allow destination (Outbound) local network traffic to the Invidious service only on service port 25565 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # destination: 192.168.1.0/24 + # protocol: tcp + # destination_port: 25565 + # jump: ACCEPT + # + # - name: Allow source (Inbound) proxy server traffic to the Invidious service only on service port 25565 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # source: "{{ proxy_server_ip }}" + # protocol: tcp + # destination_port: 25565 + # jump: ACCEPT + # - name: Allow destination (Outbound) proxy server traffic to the Invidious service only on service port 25565 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # destination: "{{ proxy_server_ip }}" + # protocol: tcp + # destination_port: 25565 + # jump: ACCEPT + # + # - name: Deny any other traffic on Minecraft port 25565 + # ansible.builtin.iptables: + # chain: DOCKER-USER + # protocol: tcp + # destination_port: 25565 + # jump: DROP + + - name: Debug Finish message + debug: + msg: Ansible playbook has finished! diff --git a/server-setup.yml b/server-setup.yml new file mode 100644 index 0000000..6638356 --- /dev/null +++ b/server-setup.yml @@ -0,0 +1,238 @@ +- hosts: localhost + vars: + # Packages to install + packages: + # System + - linux-headers-amd64 + - build-essential + - ssh + - mount + - vim + - neofetch + - htop + - doas + + # Headless KVM Setup + - qemu-kvm + - libvirt-clients + - libvirt-daemon-system + - bridge-utils + - virtinst + - libvirt-daemon + - cpu-checker + - libguestfs-tools + - libosinfo-bin + + # File Server + - zfsutils-linux + - samba + + # USB Key + # - exfat-fuse + # - exfat-utils + - exfatprogs + + # VPN Client to access Proxy Server (Primarily for cockpit) + - wireguard + + # Firewall + - iptables-persistent + + # Cockpit web interface for web management of server + - cockpit + - cockpit-machines + + # Two Factor Authentication for Cockpit + - libpam-oath + - oathtool + available_servicedirs: [] + tasks: + # System Setup + - name: Ensure .bashrc is updated + template: + src: home_resources/.bashrc + dest: "~/.bashrc" + - name: Add contrib + replace: + dest: /etc/apt/sources.list + regexp: '^(deb(?!.* contrib).*)' + replace: '\1 contrib' + + # Custom Helper Scripts + - name: Create the local bin dir if it does not exist + ansible.builtin.file: + path: "~/.local/bin" + state: directory + mode: '0755' + - name: Ensure custom scripts are added to local bin dir + template: + src: "home_resources/.local/bin/{{ item }}" + dest: "~/.local/bin/{{ item }}" + mode: '0777' + loop: + - spark_ansible-playbook.sh + - spark_ansible-editvault.sh + - spark_ansible-viewvault.sh + + # Network Config + - name: Ensure Network configuration is updated + become: yes + template: + src: root_resources/etc/network/interfaces + dest: "/etc/network/interfaces" + + # DNS Config + - name: Ensure DNS configuration is updated + become: yes + template: + src: root_resources/etc/resolv.conf + dest: "/etc/resolv.conf" + - name: Enable Systemd Resolved for DNS queries + become: yes + ansible.builtin.systemd: + name: systemd-resolved + enabled: yes + state: started + + # Package Config + - name: Ensure list of packages is installed + become: yes + apt: + name: '{{ packages }}' + state: present + + # FStab Config + - name: Mount up USB key by UUID + become: yes + ansible.posix.mount: + path: '{{ usbkey_mountdir }}' + src: UUID={{ usbkey_uuid }} + fstype: exfat + opts: nofail,dmask=0000,fmask=0111,gid=1000,uid=1000 + state: present + + # SSH Server Setup + - name: Enable SSH + become: yes + ansible.builtin.systemd: + name: ssh + enabled: yes + state: started + - name: Ensure local ssh configuration is updated + template: + src: home_resources/.ssh/config + dest: "~/.ssh/config" + - name: Ensure sshd configuration is updated + become: yes + template: + src: root_resources/etc/ssh/sshd_config + dest: "/etc/ssh/sshd_config" + + # Cockpit Configuration + - name: Ensure cockpit configuration is updated + become: yes + template: + src: root_resources/etc/cockpit/cockpit.conf + dest: "/etc/cockpit/cockpit.conf" + # Cockpit 2FA Setup + - name: Add cockpit two factor authentication key to system + become: yes + template: + src: root_resources/etc/cockpit.oath + dest: "/etc/cockpit.oath" + - name: Configure cockpit to use oath two factor authentication + become: yes + template: + src: root_resources/etc/pam.d/cockpit + dest: "/etc/pam.d/cockpit" + + # Wireguard VPN Client Setup to establish connection to reverse proxy frontend (Primarily for cockpit) + - name: Ensure wireguard client configuration is updated + become: yes + template: + src: root_resources/etc/wireguard/wg0.conf + dest: "/etc/wireguard/wg0.conf" + - name: Ensure wireguard can find resolvconf on SystemD init systems # (This is for SystemD init systems, on systemd systems resolvectl is used instead) + become: yes + ansible.builtin.file: + src: /usr/bin/resolvectl + dest: "/usr/local/bin/resolvconf" + state: link + - name: Enable wireguard client + become: yes + ansible.builtin.systemd: + name: wg-quick@wg0 + enabled: yes + state: started + + # Each respective service will have a user associated to it to ensure it'll be able to only edit the files in their folder in the service directory + # Services Configuration - Groups + - name: "Create admin user {{ admin_user_name }}" + become: yes + ansible.builtin.user: + name: "{{ admin_user_name }}" + state: present + groups: wheel,libvirt + append: yes + + - name: "Ensure doas is configured correctly" + become: yes + template: + src: root_resources/etc/doas.conf + dest: "/etc/doas.conf" + + # Services directory - where VM's etc are stored + - name: Directory permissions for Service folder # (Directory should already exist via ZFS!) + become: yes + ansible.builtin.file: + path: /spool1/services + state: directory + owner: "{{ admin_user_name }}" + group: root + mode: '0755' + + # Nextcloud has its own dedicated zfs directory to be able to set its own quota + - name: Directory permissions for dedicated Nextcloud service folder # (Directory should already exist via ZFS!) + become: yes + ansible.builtin.file: + path: /spool1/nextcloud + state: directory + owner: "{{ admin_user_name }}" + group: root + mode: '1700' + + # File Server Setup + - name: Enable SAMBA + become: yes + ansible.builtin.systemd: + name: smbd + enabled: yes + state: started + - name: Ensure samba configuration is updated + become: yes + template: + src: root_resources/etc/samba/smb.conf + dest: "/etc/samba/smb.conf" + + # SMB Fileserver Permissions + - name: Directory permissions for spool1 secret SMB fileserver directory # (Directory should already exist via ZFS!) + become: yes + ansible.builtin.file: + path: /spool1/secret + state: directory + owner: "{{ admin_user_name }}" + group: root + mode: '1700' + - name: Directory permissions for spool2 secret SMB fileserver directory # (Directory should already exist via ZFS!) + become: yes + ansible.builtin.file: + path: /spool2/secret + state: directory + owner: "{{ admin_user_name }}" + group: root + mode: '1700' + + # End + - name: Debug Finish message + debug: + msg: Ansible playbook has finished! diff --git a/server-zfs-setup.yml b/server-zfs-setup.yml new file mode 100644 index 0000000..01bd584 --- /dev/null +++ b/server-zfs-setup.yml @@ -0,0 +1,62 @@ +- hosts: localhost + become: 'yes' + tasks: + - name: Create spool1 if it does not exist + command: zpool create spool1 -O compression=lz4 -o ashift=12 creates=/spool1 mirror /dev/disk/by-id/ata-ST2000VX008-2E3164_Z52BETNW /dev/disk/by-id/ata-ST2000VX008-2E3164_Z52BF5FD + - name: Create spool2 if it does not exist + command: zpool create spool2 -O compression=lz4 -o ashift=12 creates=/spool2 /dev/disk/by-id/ata-ST4000VX013-2XG104_WFN5V6JE + - name: Create new encrypted filesystem on spool1 - secret + community.general.zfs: + name: spool1/secret + state: present + extra_zfs_properties: + casesensitivity: 'mixed' + xattr: 'sa' + encryption: 'on' + keyformat: 'raw' + keylocation: 'file://{{usbkey_keysdir}}/spool1_secret' + sharesmb: 'on' + quota: '250Gb' + - name: Create new encrypted filesystem on spool1 - services + community.general.zfs: + name: spool1/services + state: present + extra_zfs_properties: + casesensitivity: 'mixed' + xattr: 'sa' + encryption: 'on' + keyformat: 'raw' + keylocation: 'file://{{usbkey_keysdir}}/spool1_services' + quota: '500Gb' + - name: Create new encrypted filesystem on spool1 - nextcloud + community.general.zfs: + name: spool1/nextcloud + state: present + extra_zfs_properties: + casesensitivity: 'mixed' + xattr: 'sa' + encryption: 'on' + keyformat: 'raw' + keylocation: 'file://{{usbkey_keysdir}}/spool1_nextcloud' + quota: '1Tb' + - name: Create new encrypted filesystem encompassing all of spool2 + ignore_errors: true + community.general.zfs: + name: spool2/secret + state: present + extra_zfs_properties: + casesensitivity: 'mixed' + xattr: 'sa' + encryption: 'on' + keyformat: 'raw' + keylocation: 'file://{{usbkey_keysdir}}/spool2_secret' + sharesmb: 'on' + - name: Debug Finish message + debug: + msg: Ansible playbook has finished! + +# Left to Right Configuration +# lrwxrwxrwx 1 root root 9 Apr 29 05:01 /dev/disk/by-id/ata-ST4000VX013-2XG104_WFN5V6JE -> ../../sdb +# lrwxrwxrwx 1 root root 9 Apr 29 05:01 /dev/disk/by-id/ata-ST2000VX008-2E3164_Z52BETNW -> ../../sdc +# lrwxrwxrwx 1 root root 9 Apr 29 05:01 /dev/disk/by-id/ata-ST2000VX008-2E3164_Z52BF5FD -> ../../sdd +# lrwxrwxrwx 1 root root 9 Apr 29 05:01 ata-WDC_WD5000AAKX-08U6AA0_WD-WCC2EE4D3K01 -> ../../sda diff --git a/serversecrets.example b/serversecrets.example new file mode 100644 index 0000000..f6cc8dc --- /dev/null +++ b/serversecrets.example @@ -0,0 +1,31 @@ +# Server secrets example, to be encrypted with ansible vault and called serversecrets.enc +admin_user_name: admin + +# Ansible Configuration Directory - Where all the ansible playbooks are stored +ansibleconf_directory: ~/host-ansible-setup + +# Services Directory - Where all service data and virtual machine configuration will be deployed +services_directory: /services + +domain_name: ***.com + +# Primarily used in resources +proxy_server_hostname: *** +proxy_server_username: *** +proxy_server_ip: 127.0.0.1 +proxy_server_ssh_port: 22 +proxy_server_vpn_port: 51820 + +# USB Encryption Key +usbkey_uuid: *** +usbkey_mountdir: /mnt +usbkey_keysdir: /mnt/keys + +# Frontend reverse proxy VPN key +vpn_server_pubkey: *** + +# VPN Key to link reverse proxy and cockpit backend +cockpit_backend_privkey: *** + +# Cockpit 2FA Key +cockpit_2fa_key: *** diff --git a/vm_resources/bridged-network.xml b/vm_resources/bridged-network.xml new file mode 100644 index 0000000..c4ffd83 --- /dev/null +++ b/vm_resources/bridged-network.xml @@ -0,0 +1,5 @@ + + bridged-network + + +