Add storage_box playbook and fix HCLOUD_TOKEN extraction
- Add storage_box role: generates SSH key pair, creates Hetzner Storage Box with known password, installs public key via install-ssh-key, writes storagebox.yml to stack config. Idempotent: skips key install if SSH key auth already works. - Add deploy.yml: one-shot playbook chaining provision → dns → storage_box → bootstrap → site for fresh deployments - Fix .envrc HCLOUD_TOKEN extraction stripping surrounding quotes from vault YAML values - Add restic_storagebox_password to vault template and setup.sh prompt - Add sshpass to README prerequisites Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
203bd5bf6e
commit
db70b4ba06
13 changed files with 218 additions and 18 deletions
|
|
@ -2,6 +2,11 @@ restic_backend_type: "sftp"
|
|||
restic_password: ""
|
||||
# restic_repo: set explicitly when restic_backend_type is not 'sftp'
|
||||
|
||||
# SFTP backend: path to the SSH private key on the controller and on the target server
|
||||
# Both are written by storage_box.yml — no need to set these manually
|
||||
restic_local_key_path: "{{ lookup('env', 'LINDERHOF_DIR') }}/restic_backup"
|
||||
restic_ssh_key: /root/.ssh/restic_backup
|
||||
|
||||
restic_backup_paths: >-
|
||||
{{
|
||||
['/etc/letsencrypt', '/srv/caddy']
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
- name: Deploy Restic SSH key
|
||||
ansible.builtin.copy:
|
||||
src: restic_backup # local path in your playbook repo
|
||||
dest: "{{ restic_ssh_key }}" # e.g. /root/.ssh/restic_backup
|
||||
src: "{{ restic_local_key_path }}"
|
||||
dest: "{{ restic_ssh_key }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
|
|
|
|||
20
roles/storage_box/defaults/main.yml
Normal file
20
roles/storage_box/defaults/main.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
# Storage box name used to identify (or create) the box
|
||||
restic_storagebox_name: "{{ server_name }}-backup"
|
||||
|
||||
# Set these only when creating a new storage box from scratch.
|
||||
# Leave unset if the box already exists (identified by restic_storagebox_name above).
|
||||
# restic_storagebox_type: bx11
|
||||
# restic_storagebox_location: fsn1
|
||||
|
||||
# SSH port for Hetzner Storage Boxes
|
||||
restic_ssh_port: 23
|
||||
|
||||
# Path where the private key is stored on the Ansible controller (per-stack)
|
||||
restic_local_key_path: "{{ lookup('env', 'LINDERHOF_DIR') }}/restic_backup"
|
||||
|
||||
# Path on the target server where the private key will be deployed
|
||||
restic_ssh_key: /root/.ssh/restic_backup
|
||||
|
||||
# Remote path on the storage box for this server's backups
|
||||
restic_remote_path: "backups/{{ server_name }}"
|
||||
86
roles/storage_box/tasks/main.yml
Normal file
86
roles/storage_box/tasks/main.yml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
- name: Generate restic SSH key pair
|
||||
ansible.builtin.command:
|
||||
cmd: >-
|
||||
ssh-keygen -t ed25519
|
||||
-f {{ restic_local_key_path }}
|
||||
-N ""
|
||||
-C "restic-{{ server_name }}"
|
||||
creates: "{{ restic_local_key_path }}"
|
||||
check_mode: false
|
||||
|
||||
- name: Check if SSH public key exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ restic_local_key_path }}.pub"
|
||||
register: ssh_pub_key_stat
|
||||
|
||||
- name: Read SSH public key
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ restic_local_key_path }}.pub"
|
||||
register: ssh_pub_key_raw
|
||||
when: ssh_pub_key_stat.stat.exists
|
||||
|
||||
- name: Set public key fact
|
||||
ansible.builtin.set_fact:
|
||||
restic_ssh_pub_key: "{{ ssh_pub_key_raw.content | b64decode | trim }}"
|
||||
when: ssh_pub_key_stat.stat.exists
|
||||
|
||||
- name: Configure Hetzner Storage Box
|
||||
hetzner.hcloud.storage_box:
|
||||
name: "{{ restic_storagebox_name }}"
|
||||
storage_box_type: "{{ restic_storagebox_type | default(omit) }}"
|
||||
location: "{{ restic_storagebox_location | default(omit) }}"
|
||||
password: "{{ restic_storagebox_password }}"
|
||||
api_token: "{{ hcloud_token }}"
|
||||
access_settings:
|
||||
ssh_enabled: true
|
||||
state: present
|
||||
register: storagebox_result
|
||||
when: ssh_pub_key_stat.stat.exists
|
||||
|
||||
- name: Check SSH key auth on Storage Box
|
||||
ansible.builtin.shell: |
|
||||
echo "bye" | sftp -i {{ restic_local_key_path }} \
|
||||
-o BatchMode=yes -o StrictHostKeyChecking=no \
|
||||
-P 23 \
|
||||
{{ storagebox_result.hcloud_storage_box.username }}@{{ storagebox_result.hcloud_storage_box.server }}
|
||||
register: ssh_key_check
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
when: ssh_pub_key_stat.stat.exists
|
||||
|
||||
- name: Install SSH public key on Storage Box
|
||||
ansible.builtin.shell: |
|
||||
cat {{ restic_local_key_path }}.pub | \
|
||||
sshpass -p "{{ restic_storagebox_password }}" \
|
||||
ssh -o StrictHostKeyChecking=no -p 23 \
|
||||
{{ storagebox_result.hcloud_storage_box.username }}@{{ storagebox_result.hcloud_storage_box.server }} \
|
||||
install-ssh-key
|
||||
no_log: true
|
||||
when: ssh_pub_key_stat.stat.exists and ssh_key_check.rc != 0
|
||||
|
||||
- name: Write storagebox.yml to stack config directory
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
---
|
||||
# Storage box config — written automatically by storage_box.yml, do not edit manually
|
||||
restic_user: {{ storagebox_result.hcloud_storage_box.username }}
|
||||
restic_host: {{ storagebox_result.hcloud_storage_box.server }}
|
||||
restic_ssh_port: {{ restic_ssh_port }}
|
||||
restic_remote_path: {{ restic_remote_path }}
|
||||
restic_ssh_key: {{ restic_ssh_key }}
|
||||
restic_local_key_path: {{ restic_local_key_path }}
|
||||
dest: "{{ lookup('env', 'ANSIBLE_INVENTORY') | dirname }}/group_vars/all/storagebox.yml"
|
||||
mode: "0600"
|
||||
when: ssh_pub_key_stat.stat.exists
|
||||
|
||||
- name: Print connection info
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Storage box configured successfully"
|
||||
- "User: {{ storagebox_result.hcloud_storage_box.username }}"
|
||||
- "Host: {{ storagebox_result.hcloud_storage_box.server }}"
|
||||
- "Remote path: {{ restic_remote_path }}"
|
||||
- "Local key: {{ restic_local_key_path }}"
|
||||
- "Next: set enable_restic: true and run site.yml or restic.yml"
|
||||
when: ssh_pub_key_stat.stat.exists
|
||||
Loading…
Add table
Add a link
Reference in a new issue