Restructure into one folder per private repo/host, not a flat Docker/ dump

rocky-docker-lxc/, caddy-vm/, monitoring-vm/ (was missing entirely -
Grafana+Loki+Prometheus stack, refreshed and CA mount stripped same as
everything else), and automation/{ansible,automation-vm,iac}/ for the
three repos that live on the automation VM. Hawser is genuinely
deployed on all three of caddy-vm/monitoring-vm/automation-vm so it's
duplicated in each rather than picking one canonical home.

Old Ansible/ and "Infrastrucutre as Code/" content moved under
automation/ansible/old-playbooks and automation/iac/old-content as-is
for now - contents still need refreshing against the current repos and
a per-folder README, that's the next pass.
This commit is contained in:
thesabear committed 2026-07-06 02:41:53 +03:00
1 parent 08f705ffd7
commit c05c7164c8
146 files changed
+101 -84

No files matched your search

@@ -0,0 +1,20 @@
Coming Soon...
A description of how I use a minimal ISO to built out create a base image with defaults configurations which is perfect for its use as a base for creating Proxmox templates from.
#ROCKY10-CIS
cd /mnt/storage/template/iso
qm create 5000 --memory 2048 --core 2 --name rocky10-cis --net0 virtio,bridge=vmbr0
qm importdisk 5000 packer-rocky10.iso storage --format qcow2
qm set 5000 \
--scsihw virtio-scsi-pci \
--scsi0 storage:5000/vm-5000-disk-0.qcow2,discard=on,ssd=1 \
--cpu host \
--numa 1 \
--balloon 0
qm set 5000 --agent enabled=1,freeze-fs-on-backup=1,fstrim_cloned_disks=1
qm set 5000 --boot c --bootdisk scsi0
qm set 5000 --serial0 socket --vga serial0
@@ -0,0 +1 @@
SuperSecretPasswordToUnlock.vault_pass.txtFile
@@ -0,0 +1,82 @@
#version=RHEL10
lang en_US.UTF-8
keyboard us
timezone Europe/Sofia --utc
authselect --enablefeatures=with-faillock
selinux --enforcing
firewall --disabled
services --enabled=sshd,qemu-guest-agent
firstboot --disable
network --bootproto=dhcp --device=link --onboot=on --hostname=rocky10 --activate
ignoredisk --only-use=vda
rootpw --plaintext thisisatemporarypassword
reboot
# Clear all partitions and create new MBR label
clearpart --all --initlabel --drives=vda --disklabel=msdos
# /boot with ext4
part /boot --fstype="ext4" --size=1024 --ondisk=vda --label=BOOT
# LVM physical volume on rest of disk
part pv.01 --fstype="lvmpv" --ondisk=vda --grow --size=1 --label=PV01
volgroup rocky pv.01
# Logical volumes
logvol /tmp --fstype=xfs --size=2048 --name=lv_tmp --vgname=rocky --fsoptions="defaults,nodev,nosuid"
logvol /home --fstype=xfs --size=2048 --name=lv_home --vgname=rocky --fsoptions="defaults,nodev"
logvol /var --fstype=xfs --size=4096 --name=lv_var --vgname=rocky --fsoptions="defaults,nodev"
logvol /var/tmp --fstype=xfs --size=1024 --name=lv_vartmp --vgname=rocky --fsoptions="defaults,nodev,nosuid,noexec"
logvol /var/log --fstype=xfs --size=2048 --name=lv_varlog --vgname=rocky --fsoptions="defaults,nodev,noexec,nosuid"
logvol /var/log/audit --fstype=xfs --size=2048 --name=lv_audit --vgname=rocky --fsoptions="defaults,nodev,noexec,nosuid"
logvol / --fstype=xfs --name=lv_root --vgname=rocky --grow --size=512 --fsoptions="defaults"
# BIOS-compatible bootloader
bootloader --location=mbr --boot-drive=vda
# Repositories
repo --name="base" --baseurl=https://download.rockylinux.org/pub/rocky/10/BaseOS/x86_64/os/
repo --name="appstream" --baseurl=https://download.rockylinux.org/pub/rocky/10/AppStream/x86_64/os/
%packages
@^minimal-environment
openssh-server
openssh-clients
qemu-guest-agent
nano
zsh
git
curl
sudo
util-linux-user
rsync
tree
nmap-ncat
%end
%post --erroronfail
# Enable Docker repository
dnf install -y epel-release dnf-plugins-core
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker fastfetch jq
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin fastfetch jq
# Enable services
systemctl enable sshd
systemctl enable docker
systemctl restart docker
systemctl restart sshd
# Enable password authentication for SSH
cat > /etc/ssh/sshd_config.d/99-password-login.conf <<EOF
PermitRootLogin yes
PasswordAuthentication yes
Subsystem sftp /usr/libexec/openssh/sftp-server
EOF
# Optional: enable LVM resize service (if available)
systemctl enable resize-lvm.service || true
%end
@@ -0,0 +1,105 @@
packer {
required_plugins {
qemu = {
version = ">=1.0.0"
source = "github.com/hashicorp/qemu"
}
}
}
variable "admin_username" {
type = string
}
variable "admin_password_hash" {
type = string
sensitive = true
}
variable "admin_ssh_key" {
type = string
}
variable "ansible_username" {
type = string
}
variable "ansible_ssh_key" {
type = string
}
variable "iso_url" {
type = string
default = "https://download.rockylinux.org/pub/rocky/10/isos/x86_64/Rocky-10-latest-x86_64-minimal.iso"
}
variable "iso_checksum" {
type = string
default = "sha256:de75c2f7cc566ea964017a1e94883913f066c4ebeb1d356964e398ed76cadd12"
}
source "qemu" "rocky10" {
iso_url = var.iso_url
iso_checksum = var.iso_checksum
output_directory = "output-rocky10"
shutdown_command = "shutdown -h now"
format = "qcow2"
disk_size = 20480
http_directory = "http"
communicator = "ssh"
ssh_username = "root"
ssh_password = "HaveATemporaryPasswordHere"
ssh_timeout = "20m"
boot_wait = "20s"
boot_command = [
"<up><wait>",
"e<wait>", # edit boot entry
"<down><down><end><wait>", # go to linux line end
" inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg",
" console=tty0 console=ttyS0,115200n8",
" ip=dhcp",
"<f10><wait>" # boot with edited entry
]
headless = true
qemu_binary = "/usr/bin/qemu-system-x86_64"
accelerator = "kvm"
cpus = 2
memory = 2048
qemuargs = [
["-serial", "file:serial.log"],
["-cpu", "host"],
["-display", "none"]
]
}
build {
sources = ["source.qemu.rocky10"]
provisioner "file" {
source = "scripts/setup-admin-user.sh"
destination = "/tmp/setup-admin-user.sh"
}
provisioner "file" {
source = "scripts/setup-ansible-user.sh"
destination = "/tmp/setup-ansible-user.sh"
}
# Run setup-admin-user.sh
provisioner "shell" {
inline = [
"chmod +x /tmp/setup-admin-user.sh",
"/tmp/setup-admin-user.sh \"${var.admin_username}\" \"${var.admin_password_hash}\" \"${var.admin_ssh_key}\""
]
}
provisioner "shell" {
inline = [
"chmod +x /tmp/setup-ansible-user.sh",
"/tmp/setup-ansible-user.sh \"${var.ansible_username}\" \"${var.ansible_ssh_key}\""
]
}
}
@@ -0,0 +1,108 @@
#!/bin/bash
set -euo pipefail
USERNAME="$1"
HASHED_PASSWORD="$2"
SSH_KEY="$3"
echo "Creating admin user: $USERNAME"
# --- Install dependencies early
if command -v dnf &>/dev/null; then
dnf install -y zsh git curl sudo util-linux-user
elif command -v apt-get &>/dev/null; then
apt-get update
apt-get install -y zsh git curl sudo
else
echo "Unsupported package manager"
exit 1
fi
# --- Create user if not exists
if ! id "$USERNAME" &>/dev/null; then
useradd -m -s /bin/zsh "$USERNAME"
echo "${USERNAME}:${HASHED_PASSWORD}" | chpasswd -e
# Disable forced password change and expiration
chage -M 99999 -I -1 -E -1 "$USERNAME"
else
echo "User $USERNAME already exists, skipping creation"
fi
USER_HOME=$(eval echo "~$USERNAME")
# --- Create fastfetch config
mkdir -p "$USER_HOME/.config/fastfetch"
cat <<'EOF' > "$USER_HOME/.config/fastfetch/config.jsonc"
{
"displayMode": "default",
"modules": [
"os", "host", "kernel", "uptime", "packages", "shell",
"cpu", "memory",
{
"type": "disk",
"folders": ["/", "/home", "/tmp", "/var", "/var/log", "/var/log/audit", "/var/tmp"]
},
"locale"
]
}
EOF
chown -R "$USERNAME:$USERNAME" "$USER_HOME/.config"
chmod -R 700 "$USER_HOME/.config"
# --- SSH Setup
mkdir -p "$USER_HOME/.ssh"
echo "$SSH_KEY" > "$USER_HOME/.ssh/authorized_keys"
chmod 700 "$USER_HOME/.ssh"
chmod 600 "$USER_HOME/.ssh/authorized_keys"
chown -R "$USERNAME:$USERNAME" "$USER_HOME/.ssh"
# --- Groups and Sudo
if ! getent group docker >/dev/null; then
groupadd docker
fi
if getent group sudo >/dev/null; then
usermod -aG sudo,docker "$USERNAME"
elif getent group wheel >/dev/null; then
usermod -aG wheel,docker "$USERNAME"
else
echo "No sudo-equivalent group found, skipping"
fi
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/99_$USERNAME"
chmod 440 "/etc/sudoers.d/99_$USERNAME"
# --- Install Oh My Zsh and config as the user
runuser -l "$USERNAME" -c 'export RUNZSH=no CHSH=no KEEP_ZSHRC=yes && \
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended'
# --- Install autosuggestions plugin
runuser -l "$USERNAME" -c "git clone https://github.com/zsh-users/zsh-autosuggestions \
~/.oh-my-zsh/custom/plugins/zsh-autosuggestions"
# --- Generate custom .zshrc
cat << 'EOF' > "$USER_HOME/.zshrc"
export ZSH="\$HOME/.oh-my-zsh"
ZSH_THEME="robbyrussell"
plugins=(git zsh-autosuggestions)
source \$ZSH/oh-my-zsh.sh
PS1='%F{51}%n%F{255}@%F{227}%m %F{84}%~%f %F{15}$ '
fastfetch
EOF
chown "$USERNAME:$USERNAME" "$USER_HOME/.zshrc"
chmod 644 "$USER_HOME/.zshrc"
# --- Set shell (do this last to avoid breaking script if user shell changes mid-run)
chsh -s "$(command -v zsh)" "$USERNAME"
# --- Deny admin from using Ansible
cat <<EOF > /etc/sudoers.d/99_no_ansible_for_admin
$USERNAME ALL=(ALL) !/usr/bin/ansible, !/usr/bin/ansible-playbook
EOF
chmod 440 /etc/sudoers.d/99_no_ansible_for_admin
echo "✅ User $USERNAME configured successfully"
@@ -0,0 +1,33 @@
#!/bin/bash
set -euo pipefail
USERNAME="$1"
SSH_KEY="$2"
echo "Creating ansible user: $USERNAME"
# --- Create user if not exists
if ! id "$USERNAME" &>/dev/null; then
useradd -m "$USERNAME"
mkdir -p "/home/$USERNAME/.ssh"
echo "$SSH_KEY" > "/home/$USERNAME/.ssh/authorized_keys"
chmod 700 "/home/$USERNAME/.ssh"
chmod 600 "/home/$USERNAME/.ssh/authorized_keys"
chown -R "$USERNAME:$USERNAME" "/home/$USERNAME/.ssh"
else
echo "User $USERNAME already exists, skipping creation"
fi
# --- Harden the ansible user
# Disable password (no password login)
passwd -d "$USERNAME"
passwd -l "$USERNAME"
# Allow full passwordless sudo (needed for playbook tasks)
cat <<EOF > "/etc/sudoers.d/99_${USERNAME}"
${USERNAME} ALL=(ALL) NOPASSWD: ALL
EOF
chmod 0440 "/etc/sudoers.d/99_${USERNAME}"
echo "✅ User $USERNAME hardened for automation-only access"
@@ -0,0 +1,27 @@
#!/bin/bash
set -euo pipefail
VAULT_FILE=".vault_pass.txt"
VARS_FILE="terraform.pkrvar.hcl"
PACKER_TEMPLATE="packer.pkr.hcl"
# Check if vault password file exists
if [[ ! -f "$VAULT_FILE" ]]; then
echo "❌ Vault password file '$VAULT_FILE' not found."
exit 1
fi
# Decrypt the vars file temporarily
echo "🔓 Decrypting $VARS_FILE..."
ansible-vault decrypt "$VARS_FILE" --vault-password-file "$VAULT_FILE"
# Run packer build
echo "🏗️ Running Packer build..."
packer build -var-file="$VARS_FILE" "$PACKER_TEMPLATE"
# Re-encrypt the vars file
echo "🔒 Re-encrypting $VARS_FILE..."
ansible-vault encrypt "$VARS_FILE" --vault-password-file "$VAULT_FILE"
echo "✅ Done!"
@@ -0,0 +1,27 @@
$ANSIBLE_VAULT;1.1;AES256
37323332646365326338303234343138326439366364323631663634653136363935363865636334
6534666264666666326235393861356362353932633630390a366334646166623237623233663763
32323438646339353263366361323632646433643134663666616631316262363539373330633536
3966623765323965650a613664306466353931643234333837376237303131643932306563346532
65363634643964613936376661386639303431623534373464636638333238626130316664663666
33356661313632366531646564366465366530663366326135326133313662323939393566653333
62393839316330303164646131393162373138613764303864616562666130663035323864383031
31303536346332393164306162343062616436303138643138653734633630666462633565326234
66636562663165333863373563373535666533396334363865303237373331633761633838653961
38383634326530333531656438346238336133613636356238653264303137333839313233656339
38323730626234643963636662326663353737346332366263373139353962663239663363623736
38656434386261316136323130646235666139643131313132396536393234373263323735336631
37623537613164346663363138343238386362646533343837363165353539636539323434393839
32323633636534623738356338336561653033633939366537653662643430396364383033343663
37306666353432643636353464333362343162306435363236623866366639663339363339353736
64663332386662353864303634653539323831396136383565363462316638613530623236623038
63613262393035303730376164656239646336343133363931613136393362383734363235336637
34613830633136636130303737636339306332393062656538616133393638613564326534336233
35623764366232366538363464383334386539333963373066373065323466313033663735626466
30366430323565333365343036343566663133316236663431393335353930323731633934346636
38653039653930356633666336333365663833316635353866313965653632363365303165393538
30666431663838633434363637656365613133323834343630383133396435333061373832633361
30393730653963303933303934626562373663623265356562376633366238323563623462343162
32626164663630393831316136303835613362663534383938353965366538653838343539663263
65663833343834356137366263623331373236323065376536633237613030346135663563333763
6539613565366337613162366434373430643634393665326666
@@ -0,0 +1,15 @@
variable "admin_username" {
default = "admin"
}
variable "admin_password_hash" {
type = string
sensitive = true
}
variable "admin_ssh_key" {
type = string
}
variable "ansible_username" {}
variable "ansible_ssh_key" {}