feat: initial import of RailianceHosts starter
This commit is contained in:
commit
9860735f82
20 changed files with 355 additions and 0 deletions
7
ansible/ansible.cfg
Normal file
7
ansible/ansible.cfg
Normal 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
|
||||
34
ansible/inventory_from_yaml.py
Normal file
34
ansible/inventory_from_yaml.py
Normal 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()
|
||||
9
ansible/playbooks/bootstrap.yaml
Normal file
9
ansible/playbooks/bootstrap.yaml
Normal 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
|
||||
4
ansible/requirements.yaml
Normal file
4
ansible/requirements.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# ansible-galaxy collection install -r requirements.yaml
|
||||
collections:
|
||||
- name: community.general
|
||||
- name: ansible.posix
|
||||
45
ansible/roles/base/tasks/main.yml
Normal file
45
ansible/roles/base/tasks/main.yml
Normal 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') }}"
|
||||
30
ansible/roles/sops_agent/tasks/main.yml
Normal file
30
ansible/roles/sops_agent/tasks/main.yml
Normal 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
|
||||
8
ansible/roles/wireguard/tasks/main.yml
Normal file
8
ansible/roles/wireguard/tasks/main.yml
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue