Compare commits

...

74 Commits

Author SHA1 Message Date
Alex Tavarez
d149361e60 set up or initialized Python project 2025-12-21 16:58:39 -05:00
Alex Tavarez
1851b0bb04 added Python lock file to version control exclusion rules 2025-12-21 16:57:41 -05:00
Alex Tavarez
88aac6b598 created environment variables file 2025-12-21 16:56:35 -05:00
Alex Tavarez
ed06773cac changed a version control exclude rule due to change in Python environment dir change 2025-12-21 16:55:59 -05:00
Alex Tavarez
0dc3edc0bc added next few tasks 2025-12-21 16:54:39 -05:00
Alex Tavarez
ea7d9f7caf changed some fields/keys/attributes and changed references to reflect those changes 2025-12-21 16:53:52 -05:00
Alex Tavarez
ffa5408e9c further clarified STDOUT message guiding user 2025-12-21 14:44:47 -05:00
Alex Tavarez
2d7f783bb9 added some more guiding STDOUT statements for commands and removed useless function 2025-12-21 14:35:56 -05:00
Alex Tavarez
eb437ce2e9 refactor: script file no longer necessary after refactor 2025-12-21 13:58:11 -05:00
Alex Tavarez
07ff003870 refactor: changed name and location of file setting environment variables, made it take shell arguments with native functions as well 2025-12-21 13:57:09 -05:00
Alex Tavarez
d88a9d6176 fix: playbook task already has access to inventory-level variables 2025-12-16 13:48:33 -05:00
Alex Tavarez
c39463f4a7 feature: added a set of default path environment variables to be used as part of execution environment 2025-12-16 13:47:47 -05:00
Alex Tavarez
474574860a fix: changed from dot notation to bracket notation for attr/meth access 2025-12-16 13:44:10 -05:00
Alex Tavarez
645d815413 fix: removed some unnecessary escape characters, added title for installation section, added links to Gitea Wiki 2025-12-16 12:52:05 -05:00
Alex Tavarez
3c3f7cbf1d fix: edited typos and added more exposition for the role scope section 2025-12-15 10:22:58 -05:00
Alex Tavarez
e175e41810 Filled in role metadata and placed in dependencies 2025-12-15 10:12:08 -05:00
Alex Tavarez
3040a6203d Added task for adding essential documentation on Ansible inventory file naming conventions 2025-12-15 10:10:45 -05:00
Alex Tavarez
29bd8090be Rewrote README to reflect refactored and rewritten Ansible project, and essential information 2025-12-15 10:08:23 -05:00
Alex Tavarez
40bbe62203 removed Podman post-installation handlers as containers will no longer be managed via Ansible 2025-12-07 21:35:53 -05:00
Alex Tavarez
cb69a9b430 removed a list of container software due to separate repo handling this via Compose files 2025-12-07 21:34:43 -05:00
Alex Tavarez
19f1681473 Added containers to software dictionary list 2025-12-01 21:11:39 -05:00
Alex Tavarez
5e5dabff1a Added the creation of symbolic links to Nextcloud snap binaries for Nextcloud 2025-12-01 19:20:06 -05:00
Alex Tavarez
d4aa128e4c Added configuration value related to setting default phone region for Nextcloud 2025-12-01 18:59:31 -05:00
Alex Tavarez
512c7a82e5 Added default phone region for accepting phone numbers, and overwrote URLs for Nextcloud 2025-12-01 18:58:07 -05:00
Alex Tavarez
6c4c3d0794 Added ClamAV and ClamAV SystemD daemon package installations 2025-11-30 14:54:25 -05:00
Alex Tavarez
5a75942336 Created handler for podman installation that installs containers 2025-11-30 14:53:27 -05:00
Alex Tavarez
dd463297dd Added TODOs for this handler 2025-11-30 14:52:09 -05:00
Alex Tavarez
a1bc0ae727 Created systemd user unit service file for Aria2 2025-11-18 21:47:11 -05:00
Alex Tavarez
4dd524a5f2 Added RSyncD configuration file 2025-11-18 21:45:43 -05:00
Alex Tavarez
5901f69c29 Added handler for installing containers after podman installation 2025-11-18 21:45:14 -05:00
Alex Tavarez
73ef748c95 Added Jinja variables 2025-11-18 21:44:28 -05:00
Alex Tavarez
065e93d7c7 Added configuration fields for Aria2 2025-11-18 21:43:48 -05:00
Alex Tavarez
3f11b7c78d Added handler for RSyncD configuration 2025-11-18 21:38:39 -05:00
Alex Tavarez
64873bb846 Added a handler for Aria2 setting up daemon and configuration 2025-11-18 21:37:40 -05:00
Alex Tavarez
bdc6905491 Added Fail2Ban jails for ProFTPd and SSHD 2025-11-18 21:36:59 -05:00
Alex Tavarez
272c1342c1 Excluded Ansible Galaxy cache data and token file from version control tracking 2025-11-18 21:36:09 -05:00
Alex Tavarez
db18e6ddf6 Commented LDAP and NodeJS packages, uncommented aria and rsync packages, from software list--added container, misc and snap software 2025-11-18 21:34:30 -05:00
Alex Tavarez
ee3cf37d2f Imported new additional tasks 2025-11-18 21:31:56 -05:00
Alex Tavarez
7d2d9081e2 Created set of additional tasks for custom filters for new Fail2Ban ProFTPd jail 2025-11-18 21:30:47 -05:00
Alex Tavarez
870b16582c Added set of tasks configuring Nextcloud after installation 2025-11-18 21:29:25 -05:00
Alex Tavarez
de70d3bdd3 Added task to modify default branch name 2025-11-18 21:28:33 -05:00
Alex Tavarez
72395382d3 Changed order of preferred paths for Ansible 2025-11-18 21:27:01 -05:00
Alex Tavarez
fd5cdca0e9 Excluded collections from version control tracking 2025-11-18 21:25:57 -05:00
Alex Tavarez
0a072b4c90 Added handler for nextcloud, to configure it after it has been installed by snapd 2025-11-17 09:39:49 -05:00
Alex Tavarez
736277c377 Added handler for snapd that installs listed snap packages after snapd itself is installed 2025-11-17 09:37:43 -05:00
Alex Tavarez
b386f5e363 Added snap software packages and an LDAP library package for PHP 2025-11-17 09:37:04 -05:00
Alex Tavarez
da694910c6 Added snap software packages and an LDAP library package for PHP 2025-11-17 09:36:19 -05:00
Alex Tavarez
93bc285f3d Started creation of play after VPS has been made and initial configuration of main services has been done 2025-11-16 14:02:09 -05:00
Alex Tavarez
c0a798837d Added a new major task for later 2025-11-16 14:01:14 -05:00
Alex Tavarez
856704f9d7 Added some configuration information for ProFTPd to be used by its configuration file templates ireferred to by its handler 2025-11-16 14:00:43 -05:00
Alex Tavarez
f74482c400 Re-added a line specifying a default root for default server and moved MaxInstances line into here due to it being more appropriate context 2025-11-16 13:59:49 -05:00
Alex Tavarez
a6218cbaef fix: changed join function sytnax to correct Python method syntax 2025-11-16 13:58:37 -05:00
Alex Tavarez
8c88322621 Renamed file and edited to render it exemplar 2025-11-16 13:57:30 -05:00
Alex Tavarez
960f54efca Added more directives to file to increase security of and friendliness of ProFTPd FTP server 2025-11-16 13:55:15 -05:00
Alex Tavarez
a6039e2c13 Added an import of task transfering over SSL/TLS certificates 2025-11-16 13:53:51 -05:00
Alex Tavarez
c3eed3e396 Added a task to transfer over and register FQDN certificates from Ansible to remote machine 2025-11-16 13:53:02 -05:00
Alex Tavarez
4fad50c9dc Created a task for creating public FTP directory, created MOTD script transfer tasks 2025-11-16 13:51:47 -05:00
Alex Tavarez
ea2346c41b Added importing of ProFTPd handler task to main bootstraps role handler 2025-11-16 13:49:15 -05:00
Alex Tavarez
8b2390a1b7 Added a handler for configuring ProFTPd after it has been installed 2025-11-16 13:47:56 -05:00
Alex Tavarez
ee8a391d0e Added list of basenames for SSH MOTD scripts for ease of selection, and added a service to a user 2025-11-16 13:47:06 -05:00
Alex Tavarez
460e3f42ce Added exclusions of files with variable values specific to my use case, rather than being generic 2025-11-16 13:45:27 -05:00
Alex Tavarez
e06807ed37 fix: removed line that will be added via task instead 2025-11-12 19:38:35 -05:00
Alex Tavarez
08df87b0bf fix: changed to more appropriate uppercasing of domain name 2025-11-12 19:07:12 -05:00
Alex Tavarez
d52f7e02a8 fix: wrong variable name for ServerName directive in template 2025-11-12 19:06:30 -05:00
Alex Tavarez
a387326cca feature: created preliminary ProFTPd installation task handler that configures ProFTPd 2025-11-12 18:54:40 -05:00
Alex Tavarez
a0413c7ebc fix: changed Ansible user module system attribute value to boolean type 2025-11-12 18:52:43 -05:00
Alex Tavarez
b4f6afa628 feature: added a configuration section for ProFTPd to fill in template file variables 2025-11-12 18:51:45 -05:00
Alex Tavarez
4d3d060ec2 feature: added ProFTPd configuration template files to be used by handlers at installation 2025-11-12 18:50:26 -05:00
Alex Tavarez
f97a93ee05 feature: added an id attribute for users that must be specified for their account creation 2025-11-12 18:48:25 -05:00
Alex Tavarez
bbdcba0b72 feature: added and uncommented more software 2025-11-12 08:33:53 -05:00
Alex Tavarez
4fc691d1db feature: explicitly set PrintMotd SSH option to always be true to allow non-script MOTD capabilities regardless of PAM usage in SSH 2025-11-12 08:33:13 -05:00
Alex Tavarez
8bf893ee1f feature: changed to have PAM allowed by default for SSH for MOTD capabilities 2025-11-12 08:31:47 -05:00
Alex Tavarez
3ed2791d13 feature: renamed and changed contents of file to provide a handler configuring proftpd 2025-11-12 08:30:02 -05:00
Alex Tavarez
f139afe429 Added some exclusion rules for sensitive data 2025-11-12 08:28:15 -05:00
38 changed files with 1401 additions and 100 deletions

6
.bin/ansible_aliases Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
set -euo pipefail
alias ansible-galaxy="/usr/bin/ansible-galaxy"
alias ansible-vault="/usr/bin/ansible-vault"
alias ansible-playbook="/usr/bin/ansible-playbook"

187
.bin/skansible.sh Executable file
View File

@@ -0,0 +1,187 @@
#!/bin/bash
set -euo pipefail
SKATO_ANSIBLE_ROOT=$(dirname "$0")
SKATO_ANSIBLE_ROOT=$(dirname "$SKATO_ANSIBLE_ROOT")
export SKATO_ANSIBLE_ROOT
printf "root=%s\n" "$SKATO_ANSIBLE_ROOT" > "./config" # INI format
export SKATO_BOOTSTRAP_ROLE="${SKATO_ANSIBLE_ROOT}/roles/bootstrap"
export SKANSIBLE_SECRETS="${SKATO_ANSIBLE_ROOT}/.secrets"
if [[ -f "./ansible_aliases" ]]; then
source ./ansible_aliases
fi
# Relative directory paths for role templates/files
export SKANSIBLE_ARIA="aria2"
export SKANSIBLE_PROFTPD="proftpd"
export SKANSIBLE_PROFTPD_CONFS="${SKANSIBLE_PROFTPD}/conf.d"
# @NOTE below 4 filepaths have filenames that must correspond to
# the filenames in role ProFTPd templates'/files' Display settings
export SKANSIBLE_PROFTPD_CONFS_WELCOME="${SKANSIBLE_PROFTPD}/conf.d/WELCOME.txt"
export SKANSIBLE_PROFTPD_CONFS_BANNER="${SKANSIBLE_PROFTPD}/conf.d/BANNER.txt"
export SKANSIBLE_PROFTPD_CONFS_SUCCESS="${SKANSIBLE_PROFTPD}/conf.d/SUCCESS.txt"
export SKANSIBLE_PROFTPD_CONFS_EXIT="${SKANSIBLE_PROFTPD}/conf.d/BYE.txt"
export SKANSIBLE_SSHD_CONFS="sshd_config.d"
export SKANSIBLE_SYSTEMD="systemd"
export SKANSIBLE_SYSTEMD_USER_UNITS="${SKANSIBLE_SYSTEMD}/user"
export SKANSIBLE_FAIL2BAN="fail2ban"
export SKANSIBLE_FAIL2BAN_JAILS="${SKANSIBLE_FAIL2BAN}/jail.d"
export SKANSIBLE_FAIL2BAN_FILTERS="${SKANSIBLE_FAIL2BAN}/filter.d"
export SKANSIBLE_GITCONFIG_CONFS="gitconfig.d"
# @NOTE files in here must have extension "key" with IDs in
# "gpg_keys" inventory variable list as basenames.
export SKANSIBLE_GPG="gnupg"
# @NOTE files in path below must have extensions "key" (private),
# "crt" (signed), or "pem" (public) with inventory host FQDN as basename
export SKANSIBLE_SSL="ca-certificates"
set-root () {
if [[ $# -eq 0 ]]; then
SKATO_ANSIBLE_ROOT=$(awk -F "=" '/root/ {print $2}' "./config")
export SKATO_ANSIBLE_ROOT
elif [[ -z "$1" ]]; then
SKATO_ANSIBLE_ROOT="$1"
export SKATO_ANSIBLE_ROOT
sed -i 's|^(root=).*||g' "./config"
sed -i "1 i\root=${SKATO_ANSIBLE_ROOT}" "./config"
fi
}
gxy () {
ansible-galaxy "$@"
}
vult () {
ansible-vault "$@"
}
play () {
ansible-playbook "$@"
}
import-gpg () {
for id in "$@";
do
gpg --export-secret-keys "$id" > "${SKATO_BOOTSTRAP_ROLE}/files/${SKANSIBLE_GPG}/${id}.key"
printf "Please manually add GPG key with 'id' of '%s' in 'users.\$username.gpg_keys' list of inventory file." "$id"
done
printf "Please manually change ID attribute of GPG keys in 'users.\$username.gpg_keys' list of inventory file."
}
import-ssl () {
for domain in "$@";
do
cp "/usr/local/share/ca-certificates/${domain}.key" "${SKATO_BOOTSTRAP_ROLE}/files/${SKANSIBLE_SSL}/${domain}.key"
cp "/usr/local/share/ca-certificates/${domain}.pem" "${SKATO_BOOTSTRAP_ROLE}/files/${SKANSIBLE_SSL}/${domain}.pem"
cp "/usr/local/share/ca-certificates/${domain}.crt" "${SKATO_BOOTSTRAP_ROLE}/files/${SKANSIBLE_SSL}/${domain}.crt"
printf "Please manually change 'fqdn' attribute in inventory group or host variable file to '%s'." "$domain"
done
}
import () {
case "$1" in
ssl) shift; import-ssl "$@";;
gpg) shift; import-gpg "$@";;
*) exit 1;;
esac
}
decrypt () {
while getopts "mv:i:d:" flag; do
case "$flag" in
m) METHOD=$OPTARG;;
v) VAULT_ID=$OPTARG;;
i) INPUT_FILE=$OPTARG;;
d) OUTPUT_PATH=$OPTARG;;
*) exit 1;;
esac
done
if ! [[ "$VAULT_ID" == *"@"* ]]; then
ID_TAG="$VAULT_ID"
if [[ "$METHOD" == "prompt" ]]; then
VAULT_ID="${VAULT_ID}@prompt"
elif [[ "$METHOD" == "file" ]]; then
if [[ -z "$INPUT_FILE" ]]; then
exit 1
else
VAULT_ID="${VAULT_ID}@${INPUT_FILE}"
fi
else
exit 1
fi
fi
if [[ -z "$OUTPUT_PATH" ]]; then
OUTPUT_FILE="${SKANSIBLE_SECRETS}/${ID_TAG}.txt"
else
mkdir -p "${SKANSIBLE_SECRETS}/${OUTPUT_PATH}"
OUTPUT_FILE="${SKANSIBLE_SECRETS}/${OUTPUT_PATH}/${ID_TAG}.txt"
fi
ansible-vault decrypt --vault-id "$VAULT_ID" --output "$OUTPUT_FILE" "$INPUT_FILE"
}
encrypt () {
while getopts "mv:d:pn:" flag; do
case "$flag" in
m) METHOD="$OPTARG";;
v) VAULT_ID="$OPTARG";;
d) PASS_PATH="$OPTARG";;
p) read -rp "Provide intended password: " PASSWORD;;
n) VAR_NAME="$OPTARG";;
*) exit 1;;
esac
done
while [[ -z "$PASSWORD" ]]; do
printf "Password missing. \nPlease specify a password. \n"
read -rp "Provide intended password: " PASSWORD
done
if ! [[ "$VAULT_ID" == *"@"* ]]; then
ID_TAG="${VAULT_ID}"
if [[ "$METHOD" == "prompt" ]]; then
VAULT_ID="${VAULT_ID}@prompt"
elif [[ "$METHOD" == "file" ]]; then
if [[ -z "$PASS_PATH" ]]; then
PASS_FILE="${SKANSIBLE_SECRETS}/${VAULT_ID}.txt"
else
mkdir -p "${SKANSIBLE_SECRETS}/${PASS_PATH}"
PASS_FILE="${SKANSIBLE_SECRETS}/${PASS_PATH}/${VAULT_ID}.txt"
fi
printf "%s\n" "$PASSWORD" > "$PASS_FILE"
VAULT_ID="${VAULT_ID}@${PASS_FILE}"
fi
fi
printf "Make sure to copy following to appropriate location in appropriate YAML file under %s: \n" "$SKATO_ANSIBLE_ROOT"
if [[ -z "$VAR_NAME" ]]; then
ansible-vault encrypt_string --name "$VAR_NAME" --stdin-name "$VAR_NAME" --vault-id "$VAULT_ID" --output - "$PASSWORD"
else
ansible-vault encrypt_string --stdin-name "$ID_TAG" --vault-id "$VAULT_ID" --output - "$PASSWORD"
fi
YAMLS_WITH_PASSWORDS=("${SKATO_BOOTSTRAP_ROLE}/vars/main/software.yml" "${SKATO_BOOTSTRAP_ROLE}/defaults/main/software.yml")
printf "Examples of common YAML files passwords may be in: \n"
printf " 1. any YAML file in %s \n" "${SKATO_ANSIBLE_ROOT}/hostvars"
printf " 2. any YAML file in %s \n" "${SKATO_ANSIBLE_ROOT}/groupvars"
for i in "${!YAMLS_WITH_PASSWORDS[@]}"; do
printf " %u. %s \n" "$(( i + 3 ))" "${YAMLS_WITH_PASSWORDS[$i]}"
done
}
# source ./extensions.d/edit.sh
case "$1" in
set-root) shift; set-root "$1";;
gxy) shift; gxy "$@";;
vult) shift; vult "$@";;
play) shift; play "$@";;
import) shift; import "$@";;
decrypt) shift; decrypt "$@";;
encrypt) shift; encrypt "$@";;
*) exit 1;;
esac

28
.env Normal file
View File

@@ -0,0 +1,28 @@
SKATO_ANSIBLE_ROOT=$(dirname "$0")
SKATO_ANSIBLE_ROOT=$(dirname "$SKATO_ANSIBLE_ROOT")
SKATO_BOOTSTRAP_ROLE="${SKATO_ANSIBLE_ROOT}/roles/bootstrap"
SKANSIBLE_SECRETS="${SKATO_ANSIBLE_ROOT}/.secrets"
# Relative directory paths for role templates/files
SKANSIBLE_ARIA="aria2"
SKANSIBLE_PROFTPD="proftpd"
SKANSIBLE_PROFTPD_CONFS="${SKANSIBLE_PROFTPD}/conf.d"
# @NOTE below 4 filepaths have filenames that must correspond to
# the filenames in role ProFTPd templates'/files' Display settings
SKANSIBLE_PROFTPD_CONFS_WELCOME="${SKANSIBLE_PROFTPD}/conf.d/WELCOME.txt"
SKANSIBLE_PROFTPD_CONFS_BANNER="${SKANSIBLE_PROFTPD}/conf.d/BANNER.txt"
SKANSIBLE_PROFTPD_CONFS_SUCCESS="${SKANSIBLE_PROFTPD}/conf.d/SUCCESS.txt"
SKANSIBLE_PROFTPD_CONFS_EXIT="${SKANSIBLE_PROFTPD}/conf.d/BYE.txt"
SKANSIBLE_SSHD_CONFS="sshd_config.d"
SKANSIBLE_SYSTEMD="systemd"
SKANSIBLE_SYSTEMD_USER_UNITS="${SKANSIBLE_SYSTEMD}/user"
SKANSIBLE_FAIL2BAN="fail2ban"
SKANSIBLE_FAIL2BAN_JAILS="${SKANSIBLE_FAIL2BAN}/jail.d"
SKANSIBLE_FAIL2BAN_FILTERS="${SKANSIBLE_FAIL2BAN}/filter.d"
SKANSIBLE_GITCONFIG_CONFS="gitconfig.d"
# @NOTE files in here must have extension "key" with IDs in
# "gpg_keys" inventory variable list as basenames.
SKANSIBLE_GPG="gnupg"
# @NOTE files in path below must have extensions "key" (private),
# "crt" (signed), or "pem" (public) with inventory host FQDN as basename
SKANSIBLE_SSL="ca-certificates"

14
.gitignore vendored
View File

@@ -1,4 +1,4 @@
.env/
.venv/
*.bak
hosts.yml
.secrets/*
@@ -7,4 +7,14 @@ hosts.yml
**/*.asc
**/*.pem
**/*.ppk
log.txt
**/*.crt
**/*.cert
log.txt
**/update-motd.d/*.sh
**/vhost@vps1-sukaato.moe.conf.j2
collections/
motd
banner
.galaxy_cache/
galaxy_token
uv.lock

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

View File

@@ -1,25 +1,39 @@
# SUKAATO Ansible
This repository is for automating the management of the configuration of, and the provisioning of software for, my virtual private servers using [Ansible](https://www.redhat.com/en/ansible-collaborative?intcmp=7015Y000003t7aWQAQ). This repository is especially useful for setting up the virtual private server(s) that is(/are) to host and serve my website(s). It is also meant to be useful for provisioning of software and the configuration of that software for personal or household LAN computers.
This repository is for automating the management of the configuration of, and the provisioning of software for, my virtual private servers using [Ansible](https://www.redhat.com/en/ansible-collaborative?intcmp=7015Y000003t7aWQAQ). It's main purpose is to spin up the VPSs, create initial users and groups, import SSH or GPG keys, lock down SSH access or harden SSH, and then install and configure packages available to the given package manager of the operating system. The `bootstrap` role in here serves to abstract some of these tasks for our main playbook files.
## Installation and Use
## Variable Names and Their Scopes
All files with file extension `.example` must be converted to [YAML](https://yaml.org/) files that follow their semantics and naming (or follow the minimum bare "namespace" nesting for dictionaries or lists thereof) *prior* to executing any given [play or task](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html). For more on semantics and naming conventions see the [mini-documentation](#mini-documentation).
To be able to make use of the Ansible playbooks, it is necessary to specify some variables in or at relevant scopes, though some may have some defaults. The relevant scopes variables are defined in, for our purposes, are:
> [!IMPORTANT]
> Keep in mind files with the `.example` extension may also be present recursively under given [role](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html) directories (i.e., under path `${SUKAATO_ANSIBLE_PROJECT}/.ansible/roles/**/**/`).
- Ansible **inventory scope**: corresponds to variables inside per-hostname files in `group_vars` or `host_vars` directories, or the inventory file itself, i.e. `hosts.ini` or `hosts.yml`. The inventory file has some enforced naming conventions to be covered later or elsewhere.
- Ansible **role scope**: corresponds to variables found in files inside the `defaults` / `vars` directory in a role directory, or variables found in files inside subdirectory `main` in either `defaults` or `vars` directory of that role directory. There are favored conventional directory structures within which these variables are specified in the aforementioned directories, to be covered later or elsewhere.
## Mini-Documentation
Other variables that tend to have default definitions as is but that may be of interest are those found in Jinja templates of roles, in this case of the role `bootstrap`. Look through the `bootstrap` role's `templates` directory and you will discover them--most of them defined in role tasks or handlers that make reference to them. However, more information may be found elsewhere.
### Available Roles
### Inventory Scope
To surmise, the available or planned [roles](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html) are as follows (and are all found under `${SUKAATO_ANSIBLE_PROJECT}/.ansible/roles`):
Herein are listed the relevant variables at or in the *inventory* scope. These must be specified for a specific inventory host or group, typically in their corresponding files under `group_vars` or `host_vars`. Some variables must take in a dictionary type to be valid. To save space, there will be more detail on what keys are required or optional for such dictionaries [elsewhere](https://git.sukaato.moe/admin/skato-ansible/wiki/Inventory-Scope) and not here.
role name | purpose
---|---
lockdown | creating initial `sudo`-capable user, disabling system/SSH root login, setting up key-based SSH authentication, transferring GPG keys, configuring environment, hardening system
bootstrap | installing programming language and server/container packages, installing extra system managers and essential utilities, configuring and running servers/services/containers
postinstall | installing and configuring custom sets of packages, largely non-server related and not essential
name | type | value validity rule
---|---|---
`fqdn` | `<str>` | fully qualified domain name
`vps_service` | `<dict{<str>:<str\|bool\|list>}>` | valid fields providing data for spinning up new VPS
`groups` | `<dict{$group_name:<dict>}>` | fields/keys that are group names with data configuring that group
`users` | `<dict{$user_name:<dict>}>` | fields/keys that are user names with data configuring that user
`keywords` | `<list[<str>]>` | strings that describe the VPS, useful for applying tags if allowed by API
`custom_vars` | `<dict{<str>:<any>}>` | your own custom variables, though there are some reserved variable names for this namespace
### Role Scope
Herein are listed the relevant variables at or in the *role* scope. These must be specified for a set of role tasks expected to run in a playbook for the host specified for its play. Some variables must take in a dictionary type to be valid. To save space, there will be more detail on what keys are required or optional for such dictionaries [elsewhere](https://git.sukaato.moe/admin/skato-ansible/wiki/Role-Scope) and not here.
name | type | value validity rule
---|---|---
`software` | `<dict{<str>:<dict>}>` | valid fields providing data for software installations
`config` | `<dict{$software_name:<dict>}>` | software name fields providing data for configuring that software
## Installation
> **TBC**
> This README is yet unfinished. Check back later.
> This README is yet unfinished and unverified. Check back later.

View File

@@ -16,7 +16,7 @@
;force_color=False
# (path) The default root path for Ansible config files on the controller.
home=.ansible
home=.
# (boolean) This setting allows suppressing colorizing output, which is used to give a better indication of failure and status information.
;nocolor=False
@@ -38,7 +38,7 @@ become_plugins=plugins/become:.ansible/plugins/become:/usr/share/ansible/plugins
fact_caching=jsonfile
# (string) Defines connection or path information for the cache plugin
fact_caching_connection=.ansible/facts
fact_caching_connection=.facts
# (string) Prefix to use for cache plugin files/tables
;fact_caching_prefix=ansible_facts
@@ -54,7 +54,7 @@ fact_caching_connection=.ansible/facts
# (pathspec) Colon separated paths in which Ansible will search for collections content. Collections must be in nested *subdirectories*, not directly in these directories. For example, if ``COLLECTIONS_PATHS`` includes ``'{{ ANSIBLE_HOME ~ "/collections" }}'``, and you want to add ``my.collection`` to that directory, it must be saved as ``'{{ ANSIBLE_HOME} ~ "/collections/ansible_collections/my/collection" }}'``.
collections_path=.ansible/collections:collections:/usr/share/collections:/etc/ansible/collections
collections_path=collections:.ansible/collections:/usr/share/collections:/etc/ansible/collections
# (boolean) A boolean to enable or disable scanning the sys.path for installed collections
;collections_scan_sys_path=True
@@ -169,7 +169,7 @@ local_tmp=.tmp
;log_filter=
# (path) File to which Ansible will log on the controller. When empty logging is disabled.
log_path=.ansible/log.txt
log_path=log.txt
# (pathspec) Colon separated paths in which Ansible will search for Lookup Plugins.
lookup_plugins=plugins/lookup:.ansible/lookup:/usr/share/ansible/plugins/lookup
@@ -223,7 +223,7 @@ netconf_plugins=plugins/netconf:.ansible/netconf:/usr/share/ansible/plugins/netc
;remote_user=
# (pathspec) Colon separated paths in which Ansible will search for Roles.
roles_path=.ansible/roles:roles:/usr/share/ansible/roles:/etc/ansible/roles
roles_path=roles:.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
# (string) Set the main callback used to display Ansible output. You can only have one at a time.
# You can have many other callbacks, but just one can be in charge of stdout.

View File

@@ -2,7 +2,7 @@
---
# vars file
custom_vars:
generality:
shared:
ssh_authorized_keys:
- sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIO0sbFLwfgSWpWwn4cy4cddKvV74efUMZVYTTjX2vnjAAAABHNzaDo= rika@hikiki
- sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHJqHHMplgqm8yiq4Qwisk67p9+f9sLM8tIAzuw2qkwpAAAABHNzaDo= rika@hikiki
@@ -39,6 +39,10 @@ vps_service:
- ~/.ssh/id_ecdsa-sha2_sukaato_yubikey.ppk
- ~/.ssh/id_ecdsa-sha2_sukaato_miniyubikey.ppk
ssh_private_key_path_pref: 0
ssh_motd_script_basenames:
- 00-logo.sh
- 01-server.sh
- 02-info.sh
keywords:
- social media
- internet
@@ -51,11 +55,13 @@ groups:
# @NOTE key/field names SHOULD match value of 'group_name' key or field of its object
remote:
group_name: remote
type: system
type: system
id: ~
users:
# @NOTE key/field names MUST match value of 'username' key or field of its object
senpai:
username: senpai
id: 1000
password: !vault |
$ANSIBLE_VAULT;1.2;AES256;vps1-senpai
62626662666239376237616464626630393562373130623934653764333139346337313539613863
@@ -75,9 +81,9 @@ users:
groups:
- sudo
- "{{ groups.remote.group_name }}"
services: []
ssh_authorized_keys: "{{ custom_vars.generality.ssh_authorized_keys }}"
ssh_private_key_paths: "{{ custom_vars.generality.ssh_private_key_paths }}"
services: [sshd]
ssh_authorized_keys: "{{ custom_vars['shared']['ssh_authorized_keys'] }}"
ssh_private_key_paths: "{{ custom_vars['shared']['ssh_private_key_paths'] }}"
ssh_private_key_path_pref: 0
gpg_keys:
- id: 558041D5CF2AB23B # @NOTE professional
@@ -113,6 +119,7 @@ users:
email: ajt95@prole.biz
ftp:
username: ftp
id: 999
password: ~
shell: /sbin/nologin
home: /srv/ftp
@@ -121,9 +128,9 @@ users:
group: ~
groups:
- "{{ groups.remote.group_name }}"
services: [proftpd,sftp]
ssh_authorized_keys: "{{ custom_vars.generality.ssh_authorized_keys }}"
ssh_private_key_paths: "{{ custom_vars.generality.ssh_private_key_paths }}"
services: [proftpd,sftp,ftps]
ssh_authorized_keys: "{{ custom_vars['shared']['ssh_authorized_keys'] }}"
ssh_private_key_paths: "{{ custom_vars['shared']['ssh_private_key_paths'] }}"
ssh_private_key_path_pref: 0
gpg_keys: []
gpg_keyid_pref: 0

View File

@@ -13,7 +13,7 @@
private_ip: true
region: "{{ vps_service.region }}"
root_pass: "{{ vps_service.password }}"
tags: "{{ hostvars[inventory_hostname].keywords }}"
tags: "{{ keywords }}"
state: "{{ 'present' if vps_service.exists else 'absent' }}"
tags:
- vps_step

9
playbooks/soft-init.yml Normal file
View File

@@ -0,0 +1,9 @@
---
- name: Configure the rest of the system for the administrative user(s)
hosts: vps1
# remote_user: # @NOTE can be uncommented to insert known administrative user
# @NOTE below can be uncommented to insert known administrative user
# vars:
# ansible_user: root
tasks:

12
pyproject.toml Normal file
View File

@@ -0,0 +1,12 @@
[project]
name = "skansible"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"ansible>=13.1.0",
"ansible-lint>=25.12.1",
"ansible-navigator>=25.12.0",
"click>=8.3.1",
]

View File

@@ -0,0 +1,16 @@
# fail2ban filter for the ProFTPD FTP daemon
[INCLUDES]
before = common.conf
[Definition]
_daemon = proftpd
failregex = \(\S+\[<HOST>\]\)[: -]+ USER \S+: no such user found from \S+ \[[0-9.]+\] to \S+:\S+\s*$
\(\S+\[<HOST>\]\)[: -]+ USER \S+ \(Login failed\):.*\s+$
\(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \([0-9]+\) exceeded, connection refused.*\s+$
\(\S+\[<HOST>\]\)[: -]+ SECURITY VIOLATION: \S+ login attempted\.\s+$
\(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \(\d+\) exceeded\s+$
ignoreregex =

View File

@@ -0,0 +1,7 @@
[proftpd]
enabled = true
port = 990
filter = custom_proftpd
logpath = /var/log/proftpd.log
maxretry = 6

View File

@@ -0,0 +1,35 @@
[sshd]
# ==========================
# SSH Jail Configuration
# ==========================
# Enable the SSH jail to monitor and protect against brute-force attacks.
enabled = true
# Port Fail2Ban should monitor for SSH connections.
# If you run SSH on a custom port, replace 'ssh' with the actual port number (e.g., 2222).
port = ssh
# Filter definition to use.
# 'sshd' refers to the default filter that matches common SSH authentication failures.
filter = sshd
# Log file location.
# '%(sshd_log)s' uses the default value set by the system, typically /var/log/auth.log or journalctl.
logpath = %(sshd_log)s
# Backend for reading logs.
# 'systemd' is recommended if your system uses journalctl for logging.
backend = systemd
# ==========================
# SSH-Specific Overrides
# ==========================
# Time window to evaluate failed login attempts.
# If 'maxretry' failures occur within this time, the IP will be banned.
findtime = 5m
# Number of failed attempts allowed before triggering a ban.
maxretry = 4

View File

@@ -0,0 +1,49 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
- name: Configure Aria2
listen: aria
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users.keys()
block:
- name: Create Aria2 user configuration directory
block:
- name: Create configuration directory
ansible.builtin.file:
force: false
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
owner: "{{ ansible_facts['user_id'] }}"
path: "{{ ansible_facts['user_dir'] }}/.config"
state: directory
- name: Create configuration directory
when: ansible_facts['user_id'] in hostvars[inventory_hostname].users.keys()
ansible.builtin.file:
force: false
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
owner: "{{ ansible_facts['user_id'] }}"
path: "{{ ansible_facts['user_dir'] }}/.config/aria2"
state: directory
- name: Create Aria2 configuration
ansible.builtin.template:
backup: true
dest: "{{ ansible_facts['user_dir'] }}/.config/aria2/aria2.conf"
force: true
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
owner: "{{ ansible_facts['user_id'] }}"
src: aria2/aria2.conf.j2
# validate: string
- name: Create Aria2 SystemD user unit service
ansible.builtin.copy:
backup: true
dest: "{{ ansible_facts['user_dir'] }}/.config/systemd/user/aria2cd.service"
force: true
group: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].group | default(ansible_facts['user_id']) }}"
owner: "{{ ansible_facts['user_id'] }}"
src: systemd/user/aria2cd.service.j2
# validate: string
- name: Start Aria2 SystemD user unit service
ansible.builtin.systemd_service:
daemon_reload: true
enabled: true
name: aria2cd
scope: user
state: started

View File

@@ -1,3 +0,0 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap

View File

@@ -304,3 +304,11 @@
scope: global
state: present
value: "{{ hostvars[inventory_hostname].users[ansible_facts['user_id']].git_profile.email }}"
- name: Set default initial branch name
become: true
community.general.git_config:
add_mode: replace-all
name: init.defaultBranch
scope: system
state: present
value: main

View File

@@ -1,6 +1,20 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
# @NOTE below for packages
- name: Postinstall set-up of git
ansible.builtin.import_tasks:
file: git.yml
- name: Postinstall set-up of ProFTPd
ansible.builtin.import_tasks:
file: proftpd.yml
- name: Postinstall set-up of ProFTPd
ansible.builtin.import_tasks:
file: proftpd.yml
# @NOTE below for snaps
- name: Postinstall set-up of snapd
ansible.builtin.import_tasks:
file: snapd.yml
- name: Postinstall set-up of Nextcloud snap
ansible.builtin.import_tasks:
file: nextcloud.yml

View File

@@ -0,0 +1,105 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
- name: Configure Nextcloud snap
become: true
listen: nextcloud
block:
- name: Enable monitoring of network hardware
ansible.builtin.command:
cmd: "snap connect nextcloud:network-observe"
- name: Begin manual installation
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.manual-install
- "{{ config.nextcloud.users.admin.username }}"
- "{{ config.nextcloud.users.admin.password }}"
# @TODO see if setting below is necessary given use of reverse proxy
- name: Set trusted domains
block:
- name: Set FQDN as trusted domain
ansible.builtin.command:
cmd: "/snap/bin//snap/bin/nextcloud.occ config:system:set trusted_domains 1 --value='cloud.{{ hostvars[inventory_hostname].fqdn }}'"
# @TODO configure perhaps for trusted (reverse) proxy instead of above
- name: Set trusted reverse proxy addresses
block:
- name: Set trusted reverse proxy IPv4 address based on hostname
# @TODO create config.trusted_revproxy_ips data structure in bootstrap role's vars dir--may include loopback addresses
when: config.trusted_revproxy_ips.ipv4 is None or len(config.trusted_revproxy_ips.ipv4) < 1
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- trusted_proxies 0
- "--value=$(hostname -I | awk -F ' ' '{ print $1 }')"
- name: Set trusted reverse proxy IPv4 address
when: config.trusted_revproxy_ips.ipv4 is not None and len(config.trusted_revproxy_ips.ipv4) > 0
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- "trusted_proxies {{ idx }}"
- "--value={{ item }}"
loop: "{{ config.trusted_revproxy_ips.ipv4 }}"
loop_control:
index_var: idx
- name: Set trusted reverse proxy IPv6 address based on hostname
when: config.trusted_revproxy_ips.ipv6 is None or len(config.trusted_revproxy_ips.ipv6) < 1
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- trusted_proxies 1
- --value=$(hostname -I | awk -F ' ' '{ print $2 }')
- name: Set trusted reverse proxy IPv6 address
when: config.trusted_revproxy_ips.ipv6 is not None and len(config.trusted_revproxy_ips.ipv6) > 0
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- "trusted_proxies {{ idx }}"
- "--value={{ item }}"
loop: "{{ config.trusted_revproxy_ips.ipv6 }}"
loop_control:
index_var: idx
# @TODO create task based on shell command `sudo /snap/bin/nextcloud.occ config:system:set default_phone_region --value="US"`
- name: Set default phone region
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- default_phone_region
- "--value={{ config.nextcloud.phone_region }}"
# @TODO create task based on shell command:
# `sudo /snap/bin/nextcloud.occ config:system:set overwrite.cli.url --value="https://cloud.{{ fqdn }}"` for Caddy task
- name: Set overwrite CLI URL
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- overwrite.cli.url
- "--value=cloud.{{ hostvars[inventory_hostname].fqdn }}"
# @TODO create task based on shell command `sudo /snap/bin/nextcloud.occ config:system:set overwriteprotocol --value="https"` for Caddy task
- name: Overwrite protocol
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- overwriteprotocol
- --value="https"
# @TODO create system-level bash alias for `/snap/bin/nextcloud.occ` command
- name: Get Nextcloud snap binaries
ansible.builtin.find:
paths:
- /snap/bin
patterns:
- nextcloud\..*
recurse: false
use_regex: true
register: nextcloud_snap_binaries
- name: Create symbolic links for Nextcloud snap binaries
ansible.builtin.file:
dest: "/usr/sbin/{{ item.path | basename }}"
src: "{{ item.path }}"
state: link
loop: "{{ nextcloud_snap_binaries.files }}"

View File

@@ -0,0 +1,157 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
- name: Configure ProFTPd server
listen: proftpd
become: true
block:
- name: Create ProFTPd non-web user subdirectories
when: "'ftps' in item[0]['services'] and not 'caddy' in item[1]['services'] and not 'httpd' in item[1]['services'] and not 'www-data' in item[1]['services'] and not 'http' in item[1]['services'] and not 'https' in item[1]['services']"
ansible.builtin.file:
# follow: true
force: true
owner: "{{ item[0]['username'] }}"
group: "{{ item[0]['group'] | default(item[0]['username']) }}"
path: "{{ item[0]['home'] | default('/home/' ~ item[0]['username']) }}/{{ item[1]['username'] }}"
state: directory
loop: "{{ hostvars[inventory_hostname]['users'].values() | product(config['proftpd']['users'].values()) }}"
- name: Create ProFTPd FTP public directory for anonymous logins
when: "'ftps' in item.value['services']"
ansible.builtin.file:
# follow: true
force: true
owner: "{{ item.value['username'] }}"
group: "{{ item.value['group'] | default(item.value['username']) }}"
path: "{{ item.value['home'] | default('/home/' ~ item.value['username']) }}/public"
state: directory
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname]['users']) }}"
- name: Configure ProFTPd main control server
ansible.builtin.template:
backup: true
comment_end_string: "#}"
comment_start_string: "{#"
dest: /etc/proftpd/proftpd.conf
follow: true
force: true
group: root
owner: root
src: proftpd/proftpd.conf.j2
validate: proftpd --configtest
vars:
ftp_server_name: init
max_conns: 30
- name: Configure ProFTPd global settings
ansible.builtin.template:
backup: true
comment_end_string: "#}"
comment_start_string: "{#"
dest: /etc/proftpd/conf.d/global.conf
follow: true
force: true
group: root
owner: root
src: proftpd/conf.d/global.conf.j2
validate: proftpd --configtest
vars:
pasv_ports: "49152 65534"
allow_symlinks: false
- name: Add virtual users to ProFTPd
block:
- name: Create virtual user authentication files
ansible.builtin.file:
force: true
group: root
mode: "0640"
owner: root
path: "{{ item.value }}"
state: touch
loop: "{{ lookup('ansible.builtin.dict', config['proftpd']['auth_paths']) }}"
- name: Create the virtual users
when: "not 'caddy' in item.value['services'] and not 'httpd' in item.value['services'] and not 'www-data' in item.value['services'] and not 'http' in item.value['services'] and not 'https' in item.value['services']"
ansible.builtin.command:
argv:
- ftpasswd
- --passwd
- "--name={{ item.value['username'] }}"
- "--uid=$(id -u {{ item.value['id'] }})"
- "--gid=$(id -g {{ item.value['gid'] }})"
- "--home={{ hostvars[inventory_hostname]['users']['ftp']['home'] | default('/srv/ftp') }}/{{ item.value['username'] }}"
- --shell=/sbin/nologin
- --file={{ config['proftpd']['auth_paths']['users'] }}
- --stdin
stdin: "{{ item.value['password'] }}"
loop: "{{ lookup('ansible.builtin.dict', config['proftpd']['users']) }}"
- name: Create the virtual groups of virtual users
when: "not 'caddy' in item.value['services'] and not 'httpd' in item.value['services'] and not 'www-data' in item.value['services'] and not 'http' in item.value['services'] and not 'https' in item.value['services']"
ansible.builtin.command:
argv:
- ftpasswd
- --group
- "--name={{ item.value['username'] }}"
- "--gid=$(id -g {{ item.value['gid'] }})"
- "--member={{ item.value['username'] }}"
- --file={{ config['proftpd']['auth_paths']['groups'] }}
loop: "{{ lookup('ansible.builtin.dict', config['proftpd']['users']) }}"
# @TODO create tasks in block integrating LDAP users to ProFTPd
# - name: Integrate LDAP users into ProFTPd
- name: Create ProFTPd FTPS virtual host
ansible.builtin.template:
backup: true
comment_end_string: "#}"
comment_start_string: "{#"
dest: "/etc/proftpd/conf.d/{{ config['proftpd']['name'].lowercase() }}.conf"
follow: true
force: true
group: root
owner: root
src: "proftpd/conf.d/vhost@vps1-{{ hostvars[inventory_hostname].fqdn }}.conf.j2"
validate: proftpd --configtest
vars:
ftp_server_name: "{{ config['proftpd']['name'].uppercase() }}'s Archive'"
allowed_users: "{{ ','.join(list(map(lambda u: u['username'], filter(lambda u: not 'http' in u['services'] and not 'https' in u['services'] and not 'httpd' in u['services'] and not 'caddy' in u['services'] and not 'www-data' in u['services'], config['proftpd']['users'].values())))) }}"
anon_root: "{{ map(lambda u: u['home'], filter(lambda u: 'ftps' in u['services'] or 'proftpd' in u['services'], hostvars[inventory_hostname]['users'].values())) | list | random }}/public"
anon_user: "{{ config['proftpd']['users']['smuggler']['username'] }}"
- name: Set ProFTPd jail in fail2ban
block:
- name: Create fail2ban system configuration directory
ansible.builtin.file:
force: false
group: root
mode: "0755"
owner: root
path: /etc/fail2ban
state: directory
- name: Create fail2ban filters system configuration directory
ansible.builtin.file:
force: false
group: root
mode: "0755"
owner: root
path: /etc/fail2ban/filter.d
state: directory
- name: Create fail2ban filter system configuration
ansible.builtin.copy:
backup: true
dest: /etc/fail2ban/filter.d/custom_proftpd.conf
force: true
group: root
owner: root
src: fail2ban/filter.d/custom_proftpd.conf
# validate: string
- name: Create fail2ban jails system configuration directory
ansible.builtin.file:
force: false
group: root
mode: "0755"
owner: root
path: /etc/fail2ban/jail.d
state: directory
- name: Create fail2ban jail system configuration
ansible.builtin.copy:
backup: true
dest: /etc/fail2ban/jail.d/proftpd.local
force: true
group: root
owner: root
src: fail2ban/jail.d/proftpd.local
# validate: string

View File

@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
- name: Configure RSyncD
listen: rsync
become: true
block:
# @TODO further construct the following commented task
# - name: Add directories to be published by RSyncD
- name: Create RSyncD configuration
ansible.builtin.template:
backup: true
dest: /etc/rsyncd.conf
force: true
group: root
owner: root
src: rsyncd.conf.j2
# validate: string
- name: Start and enable RSyncD SystemD system unit service
ansible.builtin.systemd_service:
enabled: true
name: rsync
scope: system
state: started

View File

@@ -0,0 +1,17 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
- name: Install all snapd applications
become: true
listen: snapd
block:
- name: Install snaps
community.general.snap:
channel: "{{ item.value['channel'] | default('latest/stable') }}"
name:
- "{{ item.value['name'] }}"
# @TODO test the below list extend method for list of lists
options: "{{ item.value['opts'] }}"
state: present
notify: "{{ item.key }}"
loop: "{{ lookup('ansible.builtin.dict', software.snaps) }}"

View File

@@ -1,12 +1,9 @@
#SPDX-License-Identifier: MIT-0
# SPDX-License-Identifier: MIT-0
galaxy_info:
author: your name
description: your role description
company: your company (optional)
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
author: Alex Tavarez
description: A role that aids in the deployment and bootstrapping of a new VPS.
company: SUKAATO
issue_tracker_url: https://git.sukaato.moe/admin/skato-ansible/issues
# Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default)
@@ -16,20 +13,13 @@ galaxy_info:
# - Apache-2.0
# - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: "2.1"
galaxy_tags:
- sukaato
- vps
- server
- web
min_ansible_version: 2.1
# If this a Container Enabled role, provide the minimum Ansible Container version.
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.
dependencies:
- community.general
# - containers.podman

View File

@@ -1,6 +1,24 @@
#SPDX-License-Identifier: MIT-0
---
# tasks file for bootstrap
- name: Create directory for MOTD update scripts
ansible.builtin.file:
force: true
group: root
owner: root
path: /etc/update-motd.d
state: directory
- name: Create MOTD update scripts
ansible.builtin.copy:
force: true
backup: true
group: root
mode: "0744"
owner: root
dest: "/etc/update-motd.d/{{ item }}"
src: "update-motd.d/{{ item }}"
state: present
loop: "{{ hostvars[inventory_hostname].vps_service.ssh_motd_script_basenames }}"
- name: Create hidden SSH directories under users' home directories
when: hostvars[inventory_hostname].groups.remote.group_name in item.value.groups
ansible.builtin.file:
@@ -17,7 +35,7 @@
when: hostvars[inventory_hostname].groups.remote.group_name in item.value.groups and item.value.ssh_authorized_keys is not None and len(item.value.ssh_authorized_keys) > 0
ansible.builtin.copy:
backup: true
content: "{{ item.value.ssh_authorized_keys.join('\n') }}"
content: "{{ '\n'.join(item.value.ssh_authorized_keys) }}"
dest: "{{ item.value.home | default('/home/' ~ item.value.username) }}/.ssh/authorized_keys"
# follow: true
force: true
@@ -29,21 +47,29 @@
- ensure_files
- name: Harden SSH security
block:
- name: Create public subdirectory for SSH's SFTP-exclusive user's chroot
when: "'sftp' in item.value.services"
ansible.builtin.file:
group: "{{ item.value.group | default(item.value.username) }}"
owner: "{{ item.value.username }}"
path: "{{ item.value.home | default('/home/' ~ item.value.username) }}/public"
state: directory
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
- name: Set users in group ftp to only be usable with SSH's SFTP service
when: "'sftp' in item.value.services"
ansible.builtin.blockinfile:
backup: true
block: |
block: |2
Match User {{ item.value.username }}
ForceCommand internal-sftp -d /public
AuthorizedKeysFile {{ item.value.home | default('/home/' ~ item.value.username) }}/.ssh/authorized_keys
Match Group {{ item.value.group | default(item.value.username) }}
ForceCommand internal-sftp -d /%u
ChrootDirectory {{ item.value.home | default('/home/' ~ item.value.username) }}
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
Match User {{ item.value.username }}
ForceCommand internal-sftp -d /public
AuthorizedKeysFile {{ item.value.home | default('/home/' ~ item.value.username) }}/.ssh/authorized_keys
create: true
group: root
insertafter: EOF
@@ -73,7 +99,7 @@
vars:
empty_auth_used: false
pass_auth_used: false
pam_auth_used: false
pam_auth_used: true
key_auth_used: true
tags:
- ssh_auth_step

View File

@@ -0,0 +1,39 @@
#SPDX-License-Identifier: MIT-0
---
# tasks file for bootstrap
- name: Provide requisite SSL signed certificate for FQDN
ansible.builtin.copy:
backup: true
checksum: string
dest: "/usr/local/share/ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.crt"
force: true
group: root
owner: root
src: "ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.crt"
# validate: string
- name: Provide requisite SSL private key for FQDN
ansible.builtin.copy:
backup: true
dest: "/usr/local/share/ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.key"
force: true
group: root
mode: "0600"
owner: root
src: "ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.key"
# validate: string
- name: Provide requisite SSL public key for FQDN
ansible.builtin.copy:
backup: true
checksum: string
dest: "/usr/local/share/ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.pem"
force: true
group: root
owner: root
src: "ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.pem"
# validate: string
- name: Update system registration of SSL certificates
ansible.builtin.command:
cmd: update-ca-certificates
creates: "/etc/ssl/certs/{{ hostvars[inventory_hostname].fqdn }}.pem"

View File

@@ -5,7 +5,7 @@
ansible.builtin.group:
name: "{{ item.value.group_name }}"
state: present
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
system: "{{ item.value.type == 'system' }}"
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].groups) }}"
- name: Create users
block:
@@ -20,10 +20,11 @@
ssh_key_type: "ed25519"
group: "{{ item.value.group | default(item.value.username) }}"
name: "{{ item.value.username }}"
uid: "{{ item.value.id }}"
shell: "{{ item.value.shell }}"
password: "{{ item.value.password }}"
state: present
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
system: "{{ item.value.type == 'system' }}"
update_password: always
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
- name: Create regular users
@@ -35,10 +36,11 @@
generate_ssh_key: true
group: "{{ item.value.group | default(item.value.username) }}"
name: "{{ item.value.username }}"
uid: "{{ item.value.id }}"
shell: "{{ item.value.shell }}"
password: "{{ item.value.password }}"
state: present
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
system: "{{ item.value.type == 'system' }}"
update_password: always
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
- name: Create users for managing data related to services
@@ -49,9 +51,10 @@
home: "{{ item.value.home | default('/home/' ~ item.value.username) }}"
group: "{{ item.value.group | default(item.value.username) }}"
name: "{{ item.value.username }}"
uid: "{{ item.value.id }}"
shell: "{{ item.value.shell }}"
state: present
system: "{{ 'true' if item.value.type == 'system' else 'false' }}"
system: "{{ item.value.type == 'system' }}"
loop: "{{ lookup('ansible.builtin.dict', hostvars[inventory_hostname].users) }}"
- name: Adjust users' groups
when: item.value.groups is not None and len(item.value.groups) > 0

View File

@@ -4,6 +4,9 @@
- name: Populate system with groups and user accounts
ansible.builtin.import_tasks:
file: "create_users@{{ ansible_facts['system'].lowercase() }}.yml"
- name: Provide SSL certificate files
ansible.builtin.import_tasks:
file: "configure_ssl@{{ ansible_facts['system'].lowercase() }}.yml"
- name: Configure SSH for root
ansible.builtin.import_tasks:
file: "configure_ssh@{{ ansible_facts['system'].lowercase() }}.yml"

View File

@@ -21,7 +21,7 @@
use: "{{ ansible_facts['pkg_mgr'] }}"
state: present
# @TODO create handler to notify to for configuring neovim
# notify: neovim
# notify: neovim
- name: Install kitty-terminfo for SSH client xterm-kitty compatibility
become: true
block:
@@ -42,6 +42,7 @@
name: snapd
use: "{{ ansible_facts['pkg_mgr'] }}"
state: present
notify: snapd
- name: Install flatpak
when: "ansible_facts['pkg_mgr'] == 'apt'"
block:
@@ -74,7 +75,7 @@
name: git
use: "{{ ansible_facts['pkg_mgr'] }}"
state: present
notify: git
notify: git
- name: Install packages
when: ansible_facts['pkg_mgr'] in item.value.name
ansible.builtin.package:

View File

@@ -0,0 +1,83 @@
# Global settings
continue=true
# check-integrity=true
daemon=true
human-readable=true
dir=~/downloads
file-allocation=falloc
log-level=warn
max-concurrent-downloads=3
max-overall-download-limit=0
# RPC settings
enable-rpc=true
rpc-allow-origin-all=true
rpc-max-request-size=10M
rpc-listen-all=true
rpc-listen-port=6800
rpc-secret={{ config['aria']['api_key'] }}
# rpc-certificate=
# rpc-private-key=
# rpc-secure=true
# HTTP/FTP/SFTP settings
connect-timeout=120
timeout=90
server-stat-of=~/.config/aria2/dl.log
server-stat-if=~/.config/aria2/dl.log
server-stat-timeout=86400
# checksum=sha-256={{ config.aria.checksum }}
max-connection-per-server=5
max-tries=10
max-file-not-found=7
min-split-size=100M
split=7
retry-wait=10
netrc-path=~/.netrc
reuse-uri=true
uri-selector=feedback
seed-ratio=1.5
seed-time=75
# HTTP settings
http-accept-gzip=true
http-auth-challenge=true
http-no-cache=true
enable-http-pipelining=true
enable-http-keep-alive=true
save-cookies=~/.config/aria2/cookie.txt
load-cookies=~/.config/aria2/cookie.txt
# user-agent=Mozilla/5.0
# FTP/SFTP settings
ftp-pasv=true
ftp-type=binary
ftp-reuse-connection=true
# ssh-host-key-md=sha-256=
# Bittorrent settings
listen-port=6881-6999
# bt-hash-check-seed=true
# bt-force-encryption=true
bt-save-metadata=true
bt-load-saved-metadata=true
bt-max-open-files=50
bt-max-peers=150
bt-stop-timeout=7200
bt-tracker=udp://93.158.213.92:1337/announce,udp://23.134.88.9:6969/announce,udp://23.134.88.9:1337/announce,udp://185.243.218.213:80/announce,udp://89.234.156.205:451/announce,udp://44.30.4.4:6969/announce,udp://23.175.184.30:23333/announce,udp://51.222.82.36:6969/announce,udp://211.75.205.189:80/announce,udp://77.91.85.95:6969/announce,udp://45.13.119.213:6969/announce,udp://43.154.112.29:17272/announce,udp://209.141.59.25:6969/announce,udp://5.255.124.190:6969/announce,udp://152.53.152.105:1984/announce,udp://109.201.134.183:80/announce,udp://111.90.151.241:6969/announce,udp://152.53.152.105:54123/announce,udp://189.69.171.209:6969/announce,udp://151.243.109.110:6969/announce
bt-tracker-connect-timeout=120
bt-tracker-timeout=333
bt-tracker-interval=0
enable-dht=true
dht-listen-port=6881-6999
dht-message-timeout=15
enable-peer-exchange=true
follow-torrent=mem
# Metalink settings
follow-metalink=mem
metalink-language=en,es,ja
metalink-location=jp,us,ch
# metalink-os=linux

View File

@@ -0,0 +1,31 @@
<Global>
# PassivePorts {{ pasv_ports }}
RequireValidShell off
{% if allow_symlinks %}
ShowSymlinks on
{% else %}
ShowSymlinks off
{% endif %}
AllowRetrieveRestart on
HiddenStores .%P- .frag
DisplayLogin /etc/proftpd/WELCOME.txt
DisplayChdir .README.md true
DisplayConnect /etc/proftpd/BANNER.txt
DisplayFileTransfer /etc/proftpd/SUCCESS.txt
DisplayReadme /etc/proftpd/ANNOUNCE.md
DisplayQuit /etc/proftpd/BYE.txt
TimeoutNoTransfer 3600
TimeoutStalled 210
TimeoutIdle 1400
Umask 0022 0022
AllowOverwrite on
<Directory />
<Limit ALL>
DenyAll
</Limit>
</Directory>
</Global>

View File

@@ -0,0 +1,93 @@
<IfModule !mod_tls.c>
LoadModule mod_tls.c
</IfModule>
<IfModule mod_tls.c>
<VirtualHost 0.0.0.0>
ServerName "{{ ftp_server_name }}"
ServerIdent on "Our head librarians Furcas and Marbas welcome you!"
ServerAlias {{ hostvars[inventory_hostname].fqdn }} ftp.{{ hostvars[inventory_hostname].fqdn }} {{ hostvars[inventory_hostname].fqdn.split('.')[0] }}
ServerLog /var/log/proftpd/{{ hostvars[inventory_hostname].fqdn }}.log
Protocols ftps
Port 990
DefaultRoot ~
# AllowStoreRestart on
MaxStoreFileSize 10 Gb
MaxTransfersPerUser STOR,RETR 9
MaxTransfersPerHost STOR,RETR 36
DirFakeUser on ~
DirFakeGroup on ~
# AuthOrder mod_auth_pam.c mod_auth_unix.c*
AuthOrder mod_auth_file.c
AuthUserFile {{ config.proftpd.auth_paths.users }}
AuthGroupFile {{ config.proftpd.auth_paths.groups }}
AuthFileOptions SyntaxCheck
TLSEngine on
TLSLog /var/log/proftpd/tls.log
# @NOTE: "SSLv23" means all SSL versions
TLSProtocol SSLv23
TLSOptions AllowClientRenegotiations
TLSVerifyClient off
TLSRequired on
TLSRenegotiate required off
TLSECCertificateFile {{ config.proftpd.tls_paths.cert }}
TLSECCertificateKeyFile {{ config.proftpd.tls_paths.privkey }}
TLSCACertificateFile {{ config.proftpd.tls_paths.cert }}
<Limit LOGIN>
AllowUser OR {{ allowed_users}}
</Limit>
<Directory ~>
<Limit READ DIRS>
AllowAll
</Limit>
</Directory>
<Directory ~/*>
UserOwner ftp
GroupOwner ftp
HideUser !~
HideFiles ^\.(.+)?
HideNoAccess on
<Limit ALL>
AllowAll
</Limit>
</Directory>
<Anonymous {{ anon_root }}>
User ftp
Group ftp
RequireValidShell off
DirFakeUser on anon
DirFakeGroup on anon
DirFakeMode 0444
UserAlias anon {{ anon_user }}
AllowStoreRestart off
MaxStoreFileSize 4 Gb
MaxTransfersPerUser STOR,RETR 3
MaxTransfersPerHost STOR,RETR 10
HideUser !~
HideNoAccess on
<Directory {{ anon_root }}>
<Limit READ DIRS>
AllowAll
</Limit>
</Directory>
<Directory {{ anon_root }}/*>
# <Limit READ DIRS MKD RMD XMKD XRMD>
<Limit READ DIRS>
AllowAll
</Limit>
HideFiles ^\.(.+)?
</Directory>
</Anonymous>
</VirtualHost>
</IfModule>

View File

@@ -0,0 +1,185 @@
#
# /etc/proftpd/proftpd.conf -- This is a basic ProFTPD configuration file.
# To really apply changes, reload proftpd after modifications, if
# it runs in daemon mode. It is not required in inetd/xinetd mode.
#
# Includes DSO modules
Include /etc/proftpd/modules.conf
# Set off to disable IPv6 support which is annoying on IPv4 only boxes.
UseIPv6 on
# If set on you can experience a longer connection delay in many cases.
<IfModule mod_ident.c>
IdentLookups on
</IfModule>
ServerName "{{ ftp_server_name }}"
# Set to inetd only if you would run proftpd by inetd/xinetd/socket.
# Read README.Debian for more information on proper configuration.
ServerType standalone
DeferWelcome off
MaxInstances {{ max_conns }}
# Disable MultilineRFC2228 per https://github.com/proftpd/proftpd/issues/1085
# MultilineRFC2228on
DefaultServer on
DefaultRoot ~
DenyFilter \*.*/
# Users require a valid shell listed in /etc/shells to login.
# Use this directive to release that constrain.
# RequireValidShell off
# Port 21 is the standard FTP port.
Port 21
# If your host was NATted, this option is useful in order to
# allow passive tranfers to work. You have to use your public
# address and opening the passive ports used on your firewall as well.
# MasqueradeAddress 1.2.3.4
# This is useful for masquerading address with dynamic IPs:
# refresh any configured MasqueradeAddress directives every 8 hours
# <IfModule mod_dynmasq.c>
# DynMasqRefresh 28800
# </IfModule>
# Set the user and group that the server normally runs at.
User proftpd
Group nogroup
# Uncomment this if you are using NIS or LDAP via NSS to retrieve passwords:
# PersistentPasswd off
# This is required to use both PAM-based authentication and local passwords
# AuthOrder mod_auth_pam.c* mod_auth_unix.c
# Be warned: use of this directive impacts CPU average load!
# Uncomment this if you like to see progress and transfer rate with ftpwho
# in downloads. That is not needed for uploads rates.
#
# UseSendFile off
TransferLog /var/log/proftpd/transfer.log
SystemLog /var/log/proftpd/connection.log
# Logging onto /var/log/lastlog is enabled but set to off by default
#UseLastlog on
# In order to keep log file dates consistent after chroot, use timezone info
# from /etc/localtime. If this is not set, and proftpd is configured to
# chroot (e.g. DefaultRoot or <Anonymous>), it will use the non-daylight
# savings timezone regardless of whether DST is in effect.
#SetEnv TZ :/etc/localtime
<IfModule mod_quotatab.c>
QuotaEngine off
</IfModule>
<IfModule mod_ratio.c>
Ratios off
</IfModule>
# Delay engine reduces impact of the so-called Timing Attack described in
# http://www.securityfocus.com/bid/11430/discuss
# It is on by default.
<IfModule mod_delay.c>
DelayEngine on
</IfModule>
<IfModule mod_ctrls.c>
ControlsEngine off
ControlsMaxClients 2
ControlsLog /var/log/proftpd/controls.log
ControlsInterval 5
ControlsSocket /var/run/proftpd/proftpd.sock
</IfModule>
<IfModule mod_ctrls_admin.c>
AdminControlsEngine off
</IfModule>
#
# Alternative authentication frameworks
#
#Include /etc/proftpd/ldap.conf
#Include /etc/proftpd/sql.conf
#
# This is used for FTPS connections
#
#Include /etc/proftpd/tls.conf
#
# This is used for SFTP connections
#
#Include /etc/proftpd/sftp.conf
#
# This is used for other add-on modules
#
#Include /etc/proftpd/dnsbl.conf
#Include /etc/proftpd/geoip.conf
#Include /etc/proftpd/snmp.conf
#
# Useful to keep VirtualHost/VirtualRoot directives separated
#
#Include /etc/proftpd/virtuals.conf
# A basic anonymous configuration, no upload directories.
# <Anonymous ~ftp>
# User ftp
# Group nogroup
# # We want clients to be able to login with "anonymous" as well as "ftp"
# UserAlias anonymous ftp
# # Cosmetic changes, all files belongs to ftp user
# DirFakeUser on ftp
# DirFakeGroup on ftp
#
# RequireValidShell off
#
# # Limit the maximum number of anonymous logins
# MaxClients 10
#
# # We want 'welcome.msg' displayed at login, and '.message' displayed
# # in each newly chdired directory.
# DisplayLogin welcome.msg
# DisplayChdir .message
#
# # Limit WRITE everywhere in the anonymous chroot
# <Directory *>
# <Limit WRITE>
# DenyAll
# </Limit>
# </Directory>
#
# # Uncomment this if you're brave.
# # <Directory incoming>
# # # Umask 022 is a good standard umask to prevent new files and dirs
# # # (second parm) from being group and world writable.
# # Umask 022 022
# # <Limit READ WRITE>
# # DenyAll
# # </Limit>
# # <Limit STOR>
# # AllowAll
# # </Limit>
# # </Directory>
#
# </Anonymous>
<Limit LOGIN>
DenyAll
</Limit>
# Include other custom configuration files
# !! Please note, that this statement will read /all/ file from this subdir,
# i.e. backup files created by your editor, too !!!
# Eventually create file patterns like this: /etc/proftpd/conf.d/*.conf
#
Include /etc/proftpd/conf.d/

View File

@@ -0,0 +1,41 @@
port = 873
use chroot = true
max connections = 17
ignore nonreadable = true
pid file = /var/run/rsyncd.pid
[{{ ansible_facts['user_id'] }}-dl]
path = {{ ansible_facts['user_dir'] }}/downloads/public
uid = rika
gid = rika
timeout = 90
comment = Personal download inventory
read only = true
exclude = .nextcloudsync.log .calnotes .caltrash .stfolder .stignore .directory .ssh *.pub
[{{ ansible_facts['user_id'] }}-public]
path = {{ ansible_facts['user_dir'] }}/public/rsync
uid = rika
gid = rika
timeout = 90
comment = Public share point
read only = true
exclude = .nextcloudsync.log .calnotes .caltrash .stfolder .stignore .directory .ssh *.pub
[{{ ansible_facts['user_id'] }}-soulseek]
path = {{ ansible_facts['user_dir'] }}/public/soulseek
uid = rika
gid = rika
timeout = 90
comment = Personal SoulSeek inventory
read only = true
exclude = .nextcloudsync.log .calnotes .caltrash .stfolder .stignore .directory .ssh *.pub
[{{ ansible_facts['user_id'] }}-portfolio]
path = {{ ansible_facts['user_dir'] }}/portfolio
uid = rika
gid = rika
timeout = 90
comment = Personal portfolio
read only = true
exclude = .nextcloudsync.log .calnotes .caltrash .stfolder .stignore .directory .ssh *.pub

View File

@@ -1,15 +1,15 @@
{% if list_type == 'whitelist' %}
{% if policed_groups is not None and len(policed_groups) > 0 %}
AllowGroups {{ policed_groups.join(' ') }}
AllowGroups {{ ' '.join(policed_groups) }}
{% endif %}
{% if policed_users is not None and len(policed_users) > 0 %}
AllowUsers {{ policed_users.join(' ') }}
AllowUsers {{ ' '.join(policed_users) }}
{% endif %}
{% else %}
{% if policed_groups is not None and len(policed_groups) > 0 %}
DenyGroups {{ policed_groups.join(' ') }}
DenyGroups {{ ' '.join(policed_groups) }}
{% endif %}
{% if policed_users is not None and len(policed_users) > 0 %}
DenyGroups {{ policed_users.join(' ') }}
DenyGroups {{ ' '.join(policed_users) }}
{% endif %}
{% endif %}

View File

@@ -24,4 +24,5 @@ UsePAM no # enable if implementing TOTP 2FA
PubkeyAuthentication yes
{% else %}
PubkeyAuthentication no
{% endif %}
{% endif %}
PrintMotd yes

View File

@@ -0,0 +1,13 @@
[Unit]
Description=aria2 Daemon
After=network.target
[Service]
Type=forking
ExecStart=/usr/bin/aria2c --conf-path={{ ansible_facts['user_dir'] }}/.config/aria2/aria2.conf
ExecReload=/usr/bin/kill -HUP $MAINPID
RestartSec=1min
Restart=on-failure
[Install]
WantedBy=default.target

View File

@@ -5,6 +5,9 @@
software:
pkgs:
# @NOTE keep fields or keys constant; otherwise will have to edit handler notifiers and listeners elsewhere
failtwoban:
name:
apt: fail2ban
gocryptfs:
name:
apt: gocryptfs
@@ -80,18 +83,19 @@ software:
crystal-docs:
name:
apt: crystal-doc
javascript-lang:
name:
apt: nodejs
# @TODO replace below commented with an NVM-style installation (v22): https://nodejs.org/en/download
# javascript-lang:
# name:
# apt: nodejs
# javascript-pkg:
# name:
# apt: npm
# javascript-linter:
# name:
# apt: eslint
javascript-docs:
name:
apt: nodejs-doc
javascript-pkg:
name:
apt: npm
javascript-linter:
name:
apt: eslint
php-lang:
name:
apt: php
@@ -104,6 +108,9 @@ software:
php-pkg:
name:
apt: composer
# php-ldap:
# name:
# apt: php-ldap
html-linter:
name:
apt: tidy
@@ -119,6 +126,9 @@ software:
distrobox:
name:
apt: distrobox
fastfetch:
name:
apt: fastfetch
# @TODO manually install the commented below on current active new VPS, then uncomment
# duplicity:
# name:
@@ -180,18 +190,32 @@ software:
# slapd:
# name:
# apt: slapd
# proftpd:
# name:
# apt: proftpd
# rsync:
# name:
# apt: rsync
proftpd-mod-crypto:
name:
apt: proftpd-mod-crypto
# @TODO write configuration files and handler for below two package installations
# based on:
clamav:
name:
apt: clamav
clamd:
name:
apt: clamav-daemon
proftpd:
name:
apt: proftpd
proftpd-docs:
name:
apt: proftpd-doc
rsync:
name:
apt: rsync
# rclone:
# name:
# apt: rsync
# aria:
# name:
# apt: aria2
# apt: rclone
aria:
name:
apt: aria2
# mopidy:
# name:
# apt: mopidy
@@ -201,8 +225,73 @@ software:
# caddy:
# name:
# apt: caddy
snaps:
nextcloud:
name: nextcloud
channel: ~
opts:
- "nextcloud:php.memory-limit=512M"
- "nextcloud:nextcloud.cron-interval=10m"
- "nextcloud:http.compression=true"
- "nextcloud:ports.http=81"
# @TODO see how to set these options: https://help.nextcloud.com/t/how-to-configure-nextcloud-snap/216036#p-649442-trusted-domains-configuration-8
# @TODO see how to set these options: https://help.nextcloud.com/t/how-to-configure-nextcloud-snap/216036#p-649442-trusted-proxy-configuration-9
links:
quartz:
name: quartz
src: https://github.com/jackyzha0/quartz.git
branch: v4
version: ~
output: ~
config:
git:
sys:
editor: nvim
proftpd:
name: "{{ hostvars[inventory_hostname].fqdn.split('.')[0] }}"
auth_paths:
users: /etc/proftpd/ftpd.passwd
groups: /etc/proftpd/ftpd.group
msg:
welcome: "Our head librarians Furcas and Marbas welcome you!"
users:
webmaster:
username: webmaster
id: "{{ ['caddy', 'www-data'][0] }}"
gid: "{{ ['caddy', 'www-data'][0] }}"
# @TODO create vaulted password for this ProFTPd virtual user
password: !vault |
$ANSIBLE_VAULT;1.2;AES256;vps1-webmaster
63633938633139636663623166343836643839306538373762393834393230336334383334303163
3465323831366163386265353664313932383664373838660a363463303364373963353638396462
65356135623030653533333766623865643065303739386538636662303537376466333039613363
3932313334643163650a303336623031613964356433363536373236303266663735343939383930
3636
services: [http,https]
smuggler:
username: smuggler
id: "{{ hostvars[inventory_hostname].users.ftp.username }}"
gid: "{{ hostvars[inventory_hostname].users.ftp.group | default(hostvars[inventory_hostname].users.ftp.username) }}"
# @TODO create vaulted password for this ProFTPd virtual user
password: !vault |
$ANSIBLE_VAULT;1.2;AES256;vps1-smuggler
38396565313866383761303137343431613830643436666431316434393362623035623031656263
6537313630393433336133643166363564383163616232320a623034636664353864613862353366
38303663363665663366336131663431383936306131616262376162653837326163393561323465
3734333031323330300a353562353035323731303732323534613938353935393433646235356137
62336333666362383665623466353337303134623966663061366235303261653333
services: []
tls_paths:
cert: "/usr/local/share/ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.crt"
privkey: "/usr/local/share/ca-certificates/{{ hostvars[inventory_hostname].fqdn }}.key"
nextcloud:
users:
admin:
username: admin
# @TODO change this password to ansible-vaulted actual choice password later
password: password123 # @NOTE placeholder
phone_region: US
aria:
checksum: ~
api_key: ~

View File

@@ -3,12 +3,12 @@
#+language: en
* PLANNED
** TODO [#A] Add more sections to ~README.md~, as enlisted below
- Section about inventory conventional groups, with subsection on essential or avaialble host/group variables
- Section about available roles, with subsection on essential or available role variables
- Section about available playbooks, with subsection on essential or available playbook variables
- Section about conventional external variable files, their location(s) and the semantics of their filenames
- Section about conventions for handling sensitive information, and for directory tree structures under ~${SUKAATO_ANSIBLE_PROJECT}/playbooks/{files,templates}~ or ~${SUKAATO_ANSIBLE_PROJECT}/.ansible/roles/**/{files,templates}~
** DONE [#A] Write documentation on the expected conventional names to be used in the inventory file
** DONE [#A] Write documentation on the expected conventional paths to be used in the inventory file
** TODO [#A] Create Python Click library/package- based CLI
** TODO [#A] Soft-code relative paths for role files/templates in Ansible tasks/plays
** TODO [#A] Soft-code project root and paths to passwords/secrets files for Ansible tasks/plays
** TODO [#A] Rewrite dot notation usage of keys for accessing values in custom dictionary variables to bracket notation usage of keys across whole project
* IN PROGRESS