ISO-Build: root_password_hash fuer Diagnosezugang, Geheimnisse per stdin statt Argument (ADR-0035)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e0e60ef828
commit
cec4dcb2d6
1 file changed
+25
-3
@@ -286,6 +286,9 @@ class CreateIsoBuildRequest(BaseModel):
|
||||
activation_code: str
|
||||
wifi_ssid: str | None = None
|
||||
wifi_psk: str | None = None
|
||||
# Diagnosezugang (02.10.2026): nur der SHA-512-crypt-Hash, nie das
|
||||
# Passwort selbst - das kennt allein die Kundenplattform (Root-Admin).
|
||||
root_password_hash: str | None = None
|
||||
|
||||
|
||||
class CreateOrganisationseinheitRequest(BaseModel):
|
||||
@@ -3721,7 +3724,13 @@ def compute_file_sha256(path) -> str:
|
||||
|
||||
return hasher.hexdigest()
|
||||
|
||||
def run_iso_build(build_id, organization_id: str, activation_code: str, wifi_ssid: str | None, wifi_psk: str | None) -> None:
|
||||
ROOT_PASSWORD_HASH_PATTERN = re.compile(r"^\$6\$[./A-Za-z0-9]{1,16}\$[./A-Za-z0-9]{86}$")
|
||||
|
||||
|
||||
def run_iso_build(
|
||||
build_id, organization_id: str, activation_code: str, wifi_ssid: str | None, wifi_psk: str | None,
|
||||
root_password_hash: str | None = None,
|
||||
) -> None:
|
||||
output_path = ISO_BUILD_OUTPUT_DIR / f"{build_id}.iso"
|
||||
|
||||
update_iso_build(build_id, status="running", mark_started=True)
|
||||
@@ -3745,9 +3754,13 @@ def run_iso_build(build_id, organization_id: str, activation_code: str, wifi_ssi
|
||||
str(output_path),
|
||||
activation_code,
|
||||
wifi_ssid or "",
|
||||
wifi_psk or "",
|
||||
# Geheimnisse per stdin statt als Argument (Kunden-ISO-Test
|
||||
# 02.10.2026, Befund B6): Argumente landen ueber sudo im
|
||||
# Klartext im Journal - siehe build_customer_iso.sh.
|
||||
"-",
|
||||
volid,
|
||||
],
|
||||
input=f"WIFI_PSK={wifi_psk or ''}\nROOT_PASSWORD_HASH={root_password_hash or ''}\n",
|
||||
cwd=TUXFLOTTE_INSTALLER_DIR,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
@@ -5000,13 +5013,22 @@ def create_iso_build_endpoint(
|
||||
if not payload.activation_code.strip():
|
||||
return {"success": False, "error": "invalid_request", "message": "activation_code darf nicht leer sein."}
|
||||
|
||||
if payload.root_password_hash and not ROOT_PASSWORD_HASH_PATTERN.match(payload.root_password_hash):
|
||||
return {"success": False, "error": "invalid_request", "message": "root_password_hash ist kein gültiger SHA-512-crypt-Hash."}
|
||||
|
||||
if payload.wifi_psk and "\n" in payload.wifi_psk:
|
||||
return {"success": False, "error": "invalid_request", "message": "wifi_psk darf keinen Zeilenumbruch enthalten."}
|
||||
|
||||
ISO_BUILD_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
iso_build = create_iso_build(organization_id)
|
||||
|
||||
thread = threading.Thread(
|
||||
target=run_iso_build,
|
||||
args=(UUID(iso_build["id"]), organization_id, payload.activation_code, payload.wifi_ssid, payload.wifi_psk),
|
||||
args=(
|
||||
UUID(iso_build["id"]), organization_id, payload.activation_code, payload.wifi_ssid, payload.wifi_psk,
|
||||
payload.root_password_hash,
|
||||
),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
|
||||
Reference in new issue
Block a user