Autoinstall-Seed und Repo-Struktur
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
f5da6fd3b3
25
README.md
Normal file
25
README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# espo-deploy
|
||||||
|
|
||||||
|
Öffentliche, **geheimnisfreie** Artefakte für EspoCRM-Kunden-VMs. Alles hier wird von den VMs ohne Anmeldung abgerufen –
|
||||||
|
es steht deshalb **kein Passwort, kein Token und keine Kundenangabe** in diesem Repository.
|
||||||
|
|
||||||
|
| Verzeichnis | Inhalt |
|
||||||
|
|---|---|
|
||||||
|
| `autoinstall/` | NoCloud-Seed für die Basis-VM (`user-data`, `meta-data`) |
|
||||||
|
| `rmm-tasks/` | Skripte, die als Task im ConnectWise RMM hinterlegt sind (Quelle für Änderungen) |
|
||||||
|
| `bin/` | Skripte, die auf der VM unter `/srv/espo/bin/` liegen und von Tasks aufgerufen werden |
|
||||||
|
|
||||||
|
Konzept, Entscheidungen und Runbooks liegen im internen Repository `espoCRM/espo-fleet-ops`.
|
||||||
|
|
||||||
|
## Autoinstall
|
||||||
|
|
||||||
|
```
|
||||||
|
autoinstall ds=nocloud-net\;s=https://gitea.subcura.net/EspoCRM_Public/espo-deploy/raw/branch/main/autoinstall/
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Semikolon muss maskiert werden – in GRUB trennt ein unmaskiertes `;` zwei Befehle.
|
||||||
|
|
||||||
|
## Kundenspezifisches
|
||||||
|
|
||||||
|
Gehört **nicht** hierher, sondern in die Custom Fields des RMM (FQDN, Ring, Wartungsfenster) und in die `.env` auf der
|
||||||
|
jeweiligen VM. Geheimnisse entstehen auf der VM und verlassen sie nicht.
|
||||||
85
autoinstall/README.md
Normal file
85
autoinstall/README.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Autoinstall-Seed für die EspoCRM-Kunden-VM
|
||||||
|
|
||||||
|
`user-data` und `meta-data` bilden eine NoCloud-Quelle. Das Verzeichnis ist öffentlich abrufbar – es enthält deshalb
|
||||||
|
**keine Geheimnisse** (kein benutzbares Passwort, kein RMM-Token; siehe [ADR 0004](../docs/decisions/0004-bootstrap-der-kunden-vm.md)).
|
||||||
|
|
||||||
|
## Ablageort
|
||||||
|
|
||||||
|
**Für den Testbetrieb (Entscheidung 22.09.2026, Variante 1):** Der Seed liegt zusätzlich in
|
||||||
|
`gordon.zimm/ubuntu-autoinstall` unter `espocrm/`, weil der Installer ohne Anmeldung abruft und die Organisation
|
||||||
|
`espoCRM` anonym nicht lesbar ist. Boot-Zeile:
|
||||||
|
|
||||||
|
```
|
||||||
|
autoinstall ds=nocloud-net\;s=https://gitea.subcura.net/EspoCRM_Public/espo-deploy/raw/branch/main/autoinstall/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dieses Verzeichnis ist die Quelle.** Änderungen hier vornehmen und anschließend nach `ubuntu-autoinstall/espocrm/`
|
||||||
|
kopieren (`user-data`, `meta-data`). Der endgültige Ablageort bleibt offen → O-26.
|
||||||
|
|
||||||
|
## Hintergrund zur Wahl (O-26)
|
||||||
|
|
||||||
|
Der Installer ruft die Dateien **ohne Anmeldung** ab. Dieses Repo liegt in der Organisation `espoCRM`, die nicht öffentlich
|
||||||
|
sichtbar ist: Ein anonymer Abruf von
|
||||||
|
`https://gitea.subcura.net/espoCRM/espo-fleet-ops/raw/branch/main/autoinstall/user-data` liefert **404**, obwohl das Repo
|
||||||
|
selbst als „nicht privat“ geführt wird (geprüft am 22.09.2026; dasselbe gilt für `espoCRM/espo-dev`).
|
||||||
|
Anonym erreichbar ist dagegen `gordon.zimm/ubuntu-autoinstall`.
|
||||||
|
|
||||||
|
Solange das nicht entschieden ist, kommt der Seed dort hin, wo er abrufbar ist. Kandidaten:
|
||||||
|
|
||||||
|
| Variante | Boot-Zeile | Bemerkung |
|
||||||
|
|---|---|---|
|
||||||
|
| Unterverzeichnis im bestehenden öffentlichen Repo | `autoinstall ds=nocloud-net\;s=https://gitea.subcura.net/EspoCRM_Public/espo-deploy/raw/branch/main/autoinstall/` | schnellster Weg, stört den bestehenden Seed im Wurzelverzeichnis nicht |
|
||||||
|
| eigenes öffentliches Repo, z. B. `gordon.zimm/espo-autoinstall` | `… ds=nocloud-net\;s=…/gordon.zimm/espo-autoinstall/raw/branch/main/` | klar abgegrenzt, ein Zweck |
|
||||||
|
| Organisation `espoCRM` auf „öffentlich“ stellen | `… ds=nocloud-net\;s=…/espoCRM/espo-fleet-ops/raw/branch/main/autoinstall/` | macht auch `espoCRM/espo-dev` für jeden lesbar – nicht empfohlen |
|
||||||
|
| Seed auf der Installationsmedium-Seite (zweites CIDATA-Image) | keine URL nötig | für die Flotte die sauberste Lösung, in Phase 3 zu prüfen |
|
||||||
|
|
||||||
|
### Das Semikolon muss maskiert werden
|
||||||
|
|
||||||
|
In der GRUB-Kommandozeile trennt `;` zwei GRUB-Befehle. Unmaskiert bekommt der Kernel nur `autoinstall ds=nocloud-net`,
|
||||||
|
die Seed-URL fällt weg – der Installer startet dann ganz normal interaktiv. Deshalb **`\;`** schreiben (so steht es auch
|
||||||
|
in der README von `ubuntu-autoinstall`). Gleichwertig: die ganze Angabe in Anführungszeichen setzen,
|
||||||
|
`autoinstall "ds=nocloud-net;s=https://…/espocrm/"`.
|
||||||
|
|
||||||
|
Nach dem Booten der Ubuntu-Server-24.04-ISO im GRUB-Menü `e` drücken, die gewählte Zeile vor `---` einfügen, Strg+X.
|
||||||
|
Die Installation läuft ohne Rückfragen durch und **schaltet die VM am Ende aus**. Vor dem nächsten Start das ISO trennen,
|
||||||
|
sonst startet die Installation erneut.
|
||||||
|
|
||||||
|
## Nach dem ersten Start (einmal je VM)
|
||||||
|
|
||||||
|
Die Schritte liegen auch als `/root/ERSTINBETRIEBNAHME.txt` auf der VM:
|
||||||
|
|
||||||
|
1. An der Hyper-V-Konsole anmelden. Das **Initialpasswort** steht über dem Login-Prompt (`/etc/issue`); der Wechsel wird
|
||||||
|
erzwungen. Neues Passwort im Secure Information Store der Site hinterlegen.
|
||||||
|
2. RMM-Agent installieren – Token aus *Endpoints → Devices → Manage → Download Agent*:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /tmp && curl -fsSLOJ "<Download-Link aus dem Portal>" && chmod +x *_ITSPlatform_TKN*.run && sudo ./*_ITSPlatform_TKN*.run; rm -f *_ITSPlatform_TKN*.run
|
||||||
|
```
|
||||||
|
|
||||||
|
`-O -J` behält den vom Server vorgegebenen Dateinamen samt `_TKN<uuid>` – daraus liest der Installer den Token.
|
||||||
|
Das abschließende `rm` hängt an `;`, damit die Datei mit dem Token auch nach einem Abbruch verschwindet.
|
||||||
|
|
||||||
|
Der Token steckt im Dateinamen; der Installer liest ihn aus seiner eigenen Aufrufzeile. Wird die Datei umbenannt
|
||||||
|
(`-o name.run`) oder nur mit `-O` geladen (dann heißt sie `setup`), fehlt der Token und muss gesetzt werden:
|
||||||
|
`sudo env TOKEN=<uuid> ./datei.run`.
|
||||||
|
|
||||||
|
Prüfen: `systemctl status ITSPlatform` und `tail /var/log/ITSPlatform-install.log`; das Gerät erscheint nach
|
||||||
|
wenigen Minuten in der Site. Einzelheiten zur Token-Übergabe:
|
||||||
|
[../docs/quellen/connectwise-rmm-notizen.md](../docs/quellen/connectwise-rmm-notizen.md)
|
||||||
|
|
||||||
|
3. Hinweiszeile mit dem Initialpasswort aus `/etc/issue` entfernen.
|
||||||
|
4. Prüfen, dass das Gerät binnen weniger Minuten in der richtigen Site erscheint.
|
||||||
|
|
||||||
|
## Was der Seed einrichtet
|
||||||
|
|
||||||
|
| Bereich | Wert |
|
||||||
|
|---|---|
|
||||||
|
| Sprache/Tastatur/Zeitzone | de_DE.UTF-8, de, Europe/Berlin |
|
||||||
|
| Netz | erste Ethernet-Schnittstelle (`match: e*`), DHCPv4, kein DHCPv6 |
|
||||||
|
| Konto | `administrator`, Passwort je VM zufällig, Wechsel beim ersten Anmelden erzwungen |
|
||||||
|
| SSH | Server installiert, Passwortanmeldung erlaubt ([ADR 0003](../docs/decisions/0003-zugangsmodell-ssh.md)) |
|
||||||
|
| Pakete | `linux-cloud-tools-virtual` (Hyper-V-Integrationsdienste), `curl`, `bzip2` |
|
||||||
|
| Platten | `/` 20 GiB, swap 4 GiB, `/var/lib/docker` 20 GiB, `/srv` 80 % des Rests, ~20 % frei in der VG |
|
||||||
|
| Zum Schluss | vollständiges `apt full-upgrade`, `autoremove`, `clean`, dann `poweroff` |
|
||||||
|
|
||||||
|
Hintergrund zur Aufteilung: [plattenlayout-erlaeuterung.md](../docs/entwuerfe/plattenlayout-erlaeuterung.md).
|
||||||
0
autoinstall/meta-data
Normal file
0
autoinstall/meta-data
Normal file
128
autoinstall/user-data
Normal file
128
autoinstall/user-data
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#cloud-config
|
||||||
|
# Autoinstall-Seed für die EspoCRM-Kunden-VM (Ubuntu Server 24.04 LTS auf Hyper-V).
|
||||||
|
# Stand 2026-09-22, abgeleitet aus gitea gordon.zimm/ubuntu-autoinstall (Commit 0cd9fc6).
|
||||||
|
# Auf einer Test-VM am 22.09.2026 vollständig durchgelaufen (Ubuntu 24.04.5, Hyper-V, 127-GiB-Platte).
|
||||||
|
#
|
||||||
|
# Grundsätze:
|
||||||
|
# * Der Seed wird per NoCloud über HTTP geladen und kann sich nicht authentisieren
|
||||||
|
# -> er enthält KEIN Geheimnis: kein benutzbares Passwort, kein RMM-Token.
|
||||||
|
# * Die ISO richtet nur das Minimum ein. Docker, Härtung, Logrotation, Firewall, Hostname und
|
||||||
|
# Instanz kommen reproduzierbar über RMM-Tasks ("alles Weitere erfolgt über ConnectWise RMM").
|
||||||
|
autoinstall:
|
||||||
|
version: 1
|
||||||
|
|
||||||
|
source:
|
||||||
|
id: ubuntu-server
|
||||||
|
|
||||||
|
updates: all
|
||||||
|
|
||||||
|
locale: de_DE.UTF-8
|
||||||
|
keyboard:
|
||||||
|
layout: de
|
||||||
|
timezone: Europe/Berlin
|
||||||
|
|
||||||
|
# Schnittstellennamen nicht festnageln: Hyper-V meldet je nach Kernel eth0 oder enp*.
|
||||||
|
network:
|
||||||
|
version: 2
|
||||||
|
ethernets:
|
||||||
|
primary:
|
||||||
|
match:
|
||||||
|
name: "e*"
|
||||||
|
dhcp4: true
|
||||||
|
dhcp6: false
|
||||||
|
|
||||||
|
identity:
|
||||||
|
realname: administrator
|
||||||
|
username: administrator
|
||||||
|
hostname: unkonfiguriert # setzt der RMM-Baseline-Task auf crm-<site>
|
||||||
|
# Hash eines einmalig erzeugten 48-Zeichen-Zufallspassworts; der Klartext wurde nirgends abgelegt.
|
||||||
|
# Das Konto ist damit faktisch gesperrt, bis die late-commands je VM ein Initialpasswort setzen.
|
||||||
|
password: '$6$KDLfMzLPV6wWtwA4$9VnUET9kFWUVp07z2hkN9Kv9.WjgdIPGLmm7zb4Te47Ms7lyrw/9Ewpqf759xVfXcOfAkWJSFrxUClfeyxeuI0'
|
||||||
|
|
||||||
|
ssh:
|
||||||
|
install-server: true
|
||||||
|
allow-pw: true
|
||||||
|
authorized-keys: []
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- linux-cloud-tools-virtual # hv_kvp_daemon, hv_vss_daemon, hv_fcopy_daemon
|
||||||
|
- curl # Voraussetzung des RMM-Agenten (libcurl4 kommt mit)
|
||||||
|
- bzip2 # der .run-Installer entpackt sich damit
|
||||||
|
# kein linux-azure: der Azure-Kernel ist für Azure gebaut. Soll er trotzdem bleiben,
|
||||||
|
# gehört linux-cloud-tools-azure dazu, sonst fehlen die Hyper-V-Integrationsdienste.
|
||||||
|
|
||||||
|
# Explizite Aufteilung: klein für das Betriebssystem, groß für die Nutzdaten.
|
||||||
|
# `layout: {name: lvm, sizing-policy: scaled}` wäre kürzer, gibt aber rund die Hälfte der Platte an "/" –
|
||||||
|
# auf einer reinen Docker-VM ist das an der falschen Stelle.
|
||||||
|
storage:
|
||||||
|
config:
|
||||||
|
- {type: disk, id: disk0, ptable: gpt, match: {size: largest}, wipe: superblock-recursive, preserve: false, grub_device: false}
|
||||||
|
|
||||||
|
- {type: partition, id: part-esp, device: disk0, size: 1G, flag: boot, grub_device: true, preserve: false}
|
||||||
|
- {type: format, id: fmt-esp, volume: part-esp, fstype: fat32, preserve: false}
|
||||||
|
- {type: mount, id: mnt-esp, device: fmt-esp, path: /boot/efi}
|
||||||
|
|
||||||
|
- {type: partition, id: part-boot, device: disk0, size: 2G, preserve: false}
|
||||||
|
- {type: format, id: fmt-boot, volume: part-boot, fstype: ext4, preserve: false}
|
||||||
|
- {type: mount, id: mnt-boot, device: fmt-boot, path: /boot}
|
||||||
|
|
||||||
|
- {type: partition, id: part-pv, device: disk0, size: -1, flag: lvm, preserve: false}
|
||||||
|
- {type: lvm_volgroup, id: vg0, name: ubuntu-vg, devices: [part-pv], preserve: false}
|
||||||
|
|
||||||
|
# Betriebssystem, RMM-Agent, Logs – 20 GiB sind reichlich (Bedarf real 8–12 GiB)
|
||||||
|
- {type: lvm_partition, id: lv-root, name: root-lv, volgroup: vg0, size: 20G, preserve: false}
|
||||||
|
- {type: format, id: fmt-root, volume: lv-root, fstype: ext4, preserve: false}
|
||||||
|
- {type: mount, id: mnt-root, device: fmt-root, path: /}
|
||||||
|
|
||||||
|
# `path: none` für Swap ist am 22.09.2026 auf einer Test-VM bestätigt worden.
|
||||||
|
- {type: lvm_partition, id: lv-swap, name: swap-lv, volgroup: vg0, size: 4G, preserve: false}
|
||||||
|
- {type: format, id: fmt-swap, volume: lv-swap, fstype: swap, preserve: false}
|
||||||
|
- {type: mount, id: mnt-swap, device: fmt-swap, path: none}
|
||||||
|
|
||||||
|
# Images, Container, Container-Logs – reproduzierbar, wird nicht gesichert
|
||||||
|
- {type: lvm_partition, id: lv-docker, name: docker-lv, volgroup: vg0, size: 20G, preserve: false}
|
||||||
|
- {type: format, id: fmt-docker, volume: lv-docker, fstype: ext4, preserve: false}
|
||||||
|
- {type: mount, id: mnt-docker, device: fmt-docker, path: /var/lib/docker}
|
||||||
|
|
||||||
|
# /srv (Nutzdaten) wird in late-commands anteilig angelegt, damit der Seed für jede Plattengröße passt.
|
||||||
|
|
||||||
|
late-commands:
|
||||||
|
# 1. /srv bekommt 80 % des verbliebenen Platzes; ~20 % bleiben unbelegt als Reserve und für LVM-Snapshots.
|
||||||
|
# Beispiel 128-GiB-Platte: / 20, swap 4, docker 20, /srv ~65, frei ~16 GiB.
|
||||||
|
- lvcreate -y -l 80%FREE -n srv-lv ubuntu-vg
|
||||||
|
- mkfs.ext4 -q -L srv /dev/ubuntu-vg/srv-lv
|
||||||
|
- mkdir -p /target/srv
|
||||||
|
# Eintrag über UUID, wie curtin es für die übrigen Dateisysteme tut.
|
||||||
|
- >-
|
||||||
|
SRVUUID=$(blkid -s UUID -o value /dev/ubuntu-vg/srv-lv);
|
||||||
|
printf 'UUID=%s /srv ext4 defaults 0 2\n' "$SRVUUID" >> /target/etc/fstab
|
||||||
|
# 2. Je VM zufälliges Initialpasswort, am Konsolen-Login sichtbar, Wechsel beim ersten Anmelden erzwungen.
|
||||||
|
- >-
|
||||||
|
PW=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 20);
|
||||||
|
echo "administrator:$PW" | curtin in-target -- chpasswd;
|
||||||
|
curtin in-target -- chage -d 0 administrator;
|
||||||
|
printf '\n Initialpasswort administrator: %s\n (beim ersten Anmelden ändern, danach diese Zeile aus /etc/issue entfernen)\n' "$PW" >> /target/etc/issue
|
||||||
|
# 3. Hyper-V-Integrationsdienste (Zeit/IP-Meldung, Dateisystem-Quiesce für Veeam).
|
||||||
|
# Normalerweise startet udev sie selbst; enable schadet nicht und darf fehlschlagen.
|
||||||
|
- curtin in-target -- systemctl enable hv-kvp-daemon.service hv-vss-daemon.service || true
|
||||||
|
# 4. Kurze Anleitung für den einen Handgriff nach dem ersten Start (Passwort + RMM-Agent).
|
||||||
|
- >-
|
||||||
|
printf '%s\n'
|
||||||
|
'# Erstinbetriebnahme dieser VM (Entscheidung 2026-09-22: Registrierung im RMM von Hand)'
|
||||||
|
'# 1. Initialpasswort steht am Konsolen-Login (/etc/issue), Wechsel wird erzwungen.'
|
||||||
|
'# Neues Passwort im Secure Information Store der Site hinterlegen.'
|
||||||
|
'# 2. RMM-Agent installieren (Token aus: Endpoints > Devices > Manage > Download Agent):'
|
||||||
|
'# cd /tmp && curl -fsSLOJ "<Download-Link aus dem Portal>" && chmod +x *_ITSPlatform_TKN*.run && sudo ./*_ITSPlatform_TKN*.run; rm -f *_ITSPlatform_TKN*.run'
|
||||||
|
'# Pruefen: systemctl status ITSPlatform ; tail /var/log/ITSPlatform-install.log'
|
||||||
|
'# 3. Zeile mit dem Initialpasswort aus /etc/issue entfernen.'
|
||||||
|
'# Alles Weitere erledigt der Baseline-Task, den der Trigger "First check-in" anstoesst.'
|
||||||
|
> /target/root/ERSTINBETRIEBNAHME.txt
|
||||||
|
# 5. Zum Schluss alles auf den neuesten Stand bringen. `updates: all` deckt den Stand zu Beginn der
|
||||||
|
# Installation ab; dieser Durchgang holt, was währenddessen dazugekommen ist, und räumt auf.
|
||||||
|
# NEEDRESTART_SUSPEND verhindert Dienst-Neustarts im chroot.
|
||||||
|
- curtin in-target -- sh -c 'DEBIAN_FRONTEND=noninteractive NEEDRESTART_SUSPEND=1 apt-get update'
|
||||||
|
- curtin in-target -- sh -c 'DEBIAN_FRONTEND=noninteractive NEEDRESTART_SUSPEND=1 apt-get -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef full-upgrade'
|
||||||
|
- curtin in-target -- sh -c 'DEBIAN_FRONTEND=noninteractive apt-get -y autoremove --purge'
|
||||||
|
- curtin in-target -- sh -c 'apt-get clean'
|
||||||
|
|
||||||
|
shutdown: poweroff
|
||||||
Loading…
x
Reference in New Issue
Block a user