feat: initial import of RailianceHosts starter

This commit is contained in:
Bernd Worsch 2025-09-13 20:26:11 +02:00
commit 9860735f82
20 changed files with 355 additions and 0 deletions

7
ansible/ansible.cfg Normal file
View file

@ -0,0 +1,7 @@
[defaults]
inventory = ./inventory_from_yaml.py
host_key_checking = False
retry_files_enabled = False
interpreter_python = auto
stdout_callback = yaml
forks = 20

View file

@ -0,0 +1,34 @@
#!/usr/bin/env python3
import json, yaml, subprocess, os, sys, pathlib
def load_servers():
with open(os.path.join(os.path.dirname(__file__), '..', 'inventory', 'servers.yaml')) as f:
data = yaml.safe_load(f)
servers = data.get('servers', [])
return servers
def load_tf_outputs():
# Try to read terraform outputs to attach IPs, if available.
try:
out = subprocess.check_output(['terraform', '-chdir=../terraform/hetzner', 'output', '-json'], stderr=subprocess.DEVNULL, text=True)
j = json.loads(out)
servers = j.get('servers', {}).get('value', {})
return servers # {name: ip}
except Exception:
return {}
def main():
server_list = load_servers()
tf = load_tf_outputs()
hosts = {}
for s in server_list:
name = s['name']
hosts[name] = {
"ansible_host": tf.get(name) or s.get('ip'),
"ansible_user": s.get('ssh_user', 'admin')
}
inv = {"all": {"hosts": hosts}}
print(json.dumps(inv))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,9 @@
- hosts: all
become: true
vars_files:
- ../inventory/group_vars/all.yaml
- ../inventory/group_vars/secrets.sops.yaml
roles:
- role: base
- role: sops_agent
# - role: wireguard # enable if you configure WireGuard variables

View file

@ -0,0 +1,4 @@
# ansible-galaxy collection install -r requirements.yaml
collections:
- name: community.general
- name: ansible.posix

View file

@ -0,0 +1,45 @@
---
- name: Ensure base packages
ansible.builtin.package:
name:
- apt-transport-https
- ca-certificates
- curl
- git
- vim
- ufw
- python3
- python3-venv
state: present
update_cache: true
- name: Harden SSH
ansible.builtin.copy:
dest: /etc/ssh/sshd_config.d/10-hardening.conf
owner: root
group: root
mode: '0644'
content: |
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
- name: Restart sshd
ansible.builtin.service:
name: ssh
state: restarted
- name: Configure UFW
ansible.builtin.ufw:
state: enabled
policy: deny
direction: incoming
- name: Allow SSH in UFW
ansible.builtin.ufw:
rule: allow
name: OpenSSH
- name: Set timezone
community.general.timezone:
name: "{{ timezone | default('UTC') }}"

View file

@ -0,0 +1,30 @@
---
- name: Install age
ansible.builtin.shell: |
set -euo pipefail
if ! command -v age >/dev/null; then
curl -fsSL https://github.com/FiloSottile/age/releases/download/v1.1.1/age-v1.1.1-linux-amd64.tar.gz | tar xz -C /usr/local/bin --strip-components=1 age/age
fi
args:
executable: /bin/bash
- name: Install sops
ansible.builtin.get_url:
url: https://github.com/getsops/sops/releases/download/v3.9.0/sops-v3.9.0.linux.amd64
dest: /usr/local/bin/sops
mode: '0755'
- name: Create SOPS age dir
ansible.builtin.file:
path: /root/.config/sops/age
state: directory
mode: '0700'
# In production, you would inject the private key at runtime; do NOT store it on hosts by default.
# This task is intentionally a placeholder (disabled by default).
# - name: (optional) Drop SOPS_AGE_KEY for automation
# ansible.builtin.copy:
# dest: /root/.config/sops/age/keys.txt
# content: "{{ sops_age_private_key }}"
# mode: '0600'
# when: sops_age_private_key is defined

View file

@ -0,0 +1,8 @@
---
# Placeholder role. Define variables:
# wireguard_interface, wireguard_private_key (from SOPS), peers[], etc.
- name: Install wireguard
ansible.builtin.package:
name: wireguard
state: present
update_cache: true