feat(lxc): LXC-Container ausrollen, mit oder ohne Node-SSH
Container aus dem Proxmox-Template (neueste passende Version aus aplinfo), unprivilegiert, nesting automatisch für docker. Weil Proxmox keine Exec-API für Container hat, läuft die Provisionierung per SSH: bevorzugt pct exec über den Node, sonst direkt in den Container mit einem Bereitstellungsschlüssel, der am Ende wieder entfernt wird. Auf pve-demo beide Wege geprüft: Debian 13 mit docker per pct exec (hello-world läuft mit nesting allein) und Ubuntu 24.04 per SSH in den Container. Dabei gefunden: chrony scheitert ohne CAP_SYS_TIME (jetzt if: vm), sshd -t auf Ubuntu 24.04 ohne /run/sshd. Closes #009 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import ssh2 from "ssh2";
|
||||
import type { Bereitstellungsschluessel } from "@/engine/ablaeufe/lxc-ausrollen";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { entschluesseln, verschluesseln } from "@/lib/geheimnisse";
|
||||
|
||||
/**
|
||||
* Der Bereitstellungsschlüssel: damit meldet sich ProxDeploy als root in frisch angelegten
|
||||
* Containern an, wenn es keinen SSH-Zugang zum Node hat. Er steht nur während der
|
||||
* Provisionierung in /root/.ssh/authorized_keys und wird am Ende des Skripts entfernt (am
|
||||
* Kommentar `proxdeploy-bereitstellung` erkennbar). Einmal erzeugt, privat nur verschlüsselt.
|
||||
*/
|
||||
const SCHLUESSEL = "bereitstellungsschluessel";
|
||||
export const KOMMENTAR = "proxdeploy-bereitstellung";
|
||||
|
||||
export async function bereitstellungsschluessel(): Promise<Bereitstellungsschluessel> {
|
||||
const vorhanden = await prisma.einstellung.findUnique({ where: { schluessel: SCHLUESSEL } });
|
||||
if (vorhanden) {
|
||||
const wert = vorhanden.wert as { privat: string; oeffentlich: string };
|
||||
return { privat: entschluesseln(wert.privat), oeffentlich: wert.oeffentlich };
|
||||
}
|
||||
const paar = ssh2.utils.generateKeyPairSync("ed25519", { comment: KOMMENTAR });
|
||||
const neu = { privat: verschluesseln(paar.private), oeffentlich: paar.public.trim() };
|
||||
// Zwei gleichzeitige Aufträge: der erste gewinnt, der zweite liest dessen Schlüssel.
|
||||
await prisma.einstellung.upsert({
|
||||
where: { schluessel: SCHLUESSEL },
|
||||
create: { schluessel: SCHLUESSEL, wert: neu },
|
||||
update: {},
|
||||
});
|
||||
return await bereitstellungsschluessel();
|
||||
}
|
||||
Reference in New Issue
Block a user