Verwaltung durch Personen (Weg 1), AGENTS.md, project-map.md, known-issues.md
ci / test (push) Failing after 24s

Admin-Schlüssel je Person auf ops (Bastion) aus sites/knaster/proxmox.yaml
(access.ops_ssh_keys/_revoked), Playbook admins.yml, Test, Übergabe in
BETRIEB §15. Einstieg für Agenten und neue Admins: AGENTS.md, Projektkarte,
bekannte Probleme. Weg 2 (Verwaltung über NEX) als Entwurf in Phase 9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Rapp
2026-10-19 18:54:02 +02:00
co-authored by Claude Opus 5.5
parent 039f57a435
commit 50acfa6a95
9 changed files with 379 additions and 0 deletions
@@ -0,0 +1,52 @@
# Verwaltung durch Personen statt durch ein Gerät („Weg 1“, 19.10.): SSH-Schlüssel der Admins auf ops (Bastion).
# Quelle: sites/<site>/proxmox.yaml, access.ops_ssh_keys und access.ops_ssh_keys_revoked. Läuft auf ops:
# ansible-playbook playbooks/admins.yml
# Fügt nur hinzu bzw. entfernt die ausdrücklich entzogenen Schlüssel; fremde Einträge (z. B. Notfallschlüssel) bleiben.
# Proxmox-Weboberfläche: access.admin_users + playbooks/cluster.yml + scripts/pve-admin-user.sh, Gerät in
# firewall.management (BETRIEB §8, §10, §15).
- name: ops – SSH-Schlüssel der Admins
hosts: localhost
connection: local
gather_facts: false
vars:
site_file: "{{ playbook_dir }}/../../../../sites/{{ knaster_site | default('knaster') }}/proxmox.yaml"
access: "{{ (lookup('file', site_file) | from_yaml).access }}"
admin_keys: "{{ access.ops_ssh_keys | default([]) }}"
revoked_keys: "{{ access.ops_ssh_keys_revoked | default([]) }}"
tasks:
- name: Liste prüfen (mindestens ein Schlüssel, Namen eindeutig, kein Schlüssel zugleich entzogen)
ansible.builtin.assert:
that:
- admin_keys | length > 0
- admin_keys | map(attribute='name') | unique | length == admin_keys | length
- admin_keys | map(attribute='key') | select('match', '^ssh-(ed25519|rsa) ') | list | length == admin_keys | length
- (admin_keys | map(attribute='key') | map('split', ' ') | map(attribute=1) | list)
| intersect(revoked_keys | map(attribute='key') | map('split', ' ') | map(attribute=1) | list) | length == 0
fail_msg: "access.ops_ssh_keys in {{ site_file }} prüfen"
- name: Schlüssel eintragen
ansible.posix.authorized_key:
user: root
key: "{{ item.key }}"
state: present
loop: "{{ admin_keys }}"
loop_control:
label: "{{ item.name }}"
- name: Entzogene Schlüssel entfernen
ansible.posix.authorized_key:
user: root
key: "{{ item.key }}"
state: absent
loop: "{{ revoked_keys }}"
loop_control:
label: "{{ item.name }}"
- name: Schlüssel auf ops (Fingerabdrücke)
ansible.builtin.command: ssh-keygen -lf /root/.ssh/authorized_keys
register: fingerprints
changed_when: false
- name: Ergebnis
ansible.builtin.debug:
msg: "{{ fingerprints.stdout_lines }}"