teleo-infrastructure/docker/leoclean-nosend/entrypoint.py

301 lines
12 KiB
Python

#!/usr/bin/env python3
"""Validate and launch the immutable leoclean no-send container."""
from __future__ import annotations
import ctypes
import importlib.util
import json
import os
import platform
import shutil
import stat
import subprocess
import sys
from pathlib import Path
from typing import Any
def _load_adjacent_contract() -> Any:
path = Path(__file__).resolve().with_name("package_contract.py")
spec = importlib.util.spec_from_file_location("livingip_leoclean_nosend_package_contract", path)
if spec is None or spec.loader is None:
raise ImportError("the adjacent package contract cannot be loaded")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
contract = _load_adjacent_contract()
ROOT = Path(contract.RUNTIME_ROOT)
ARTIFACT = ROOT / "artifact"
IDENTITY = ROOT / "identity"
IDENTITY_SOURCES = ROOT / "identity-sources"
PROFILE = Path(contract.PROFILE_ROOT)
RECEIPT = ROOT / "metadata" / "artifact-receipt.json"
IMAGE_INPUT = ROOT / "metadata" / "image-input.json"
DOCKERFILE = ROOT / "metadata" / "Dockerfile"
ENTRYPOINT = ROOT / "entrypoint.py"
PACKAGE_CONTRACT = ROOT / "package_contract.py"
CA = Path(contract.CA_DESTINATION)
READINESS = PROFILE / "state" / "readiness.json"
PSQL = Path("/usr/bin/psql")
RUNTIME_PYTHON = ROOT / "venv" / "bin" / "python"
BOOTSTRAP = ARTIFACT / "bootstrap.py"
STATE_DIRECTORIES = ("cache", "cron", "logs", "memories", "platforms", "sessions", "state")
class EntrypointError(RuntimeError):
"""The installed image or live process violates its release contract."""
def _require(condition: bool, message: str) -> None:
if not condition:
raise EntrypointError(message)
def _validate_installed() -> dict[str, Any]:
image_input = contract.load_json(IMAGE_INPUT, "installed image input")
contract.validate_installed_runtime_identity(
image_input,
artifact=ARTIFACT,
receipt=RECEIPT,
identity=IDENTITY,
contract_source_root=ROOT,
identity_source_root=IDENTITY_SOURCES,
)
_require(contract.sha256_file(CA) == contract.CA_SHA256, "installed Cloud SQL CA drifted")
_require(platform.python_version() == contract.PYTHON_VERSION, "installed Python version drifted")
_require(Path("/usr/bin/python3").resolve() == Path("/usr/local/bin/python3.11"), "system Python binding drifted")
psql_version = subprocess.run(
[str(PSQL), "--version"],
check=True,
capture_output=True,
text=True,
timeout=10,
).stdout.strip()
_require(
psql_version.startswith(f"psql (PostgreSQL) {contract.POSTGRES_VERSION}"), "installed psql version drifted"
)
bindings = image_input["source_bindings"]
_require(contract.sha256_file(DOCKERFILE) == bindings["Dockerfile"], "installed Dockerfile binding drifted")
_require(contract.sha256_file(ENTRYPOINT) == bindings["entrypoint.py"], "installed entrypoint binding drifted")
_require(
contract.sha256_file(PACKAGE_CONTRACT) == bindings["package_contract.py"],
"installed package contract binding drifted",
)
for relative in contract.IDENTITY_CONTRACT_SOURCES:
installed = ROOT / relative
_require(
contract.sha256_file(installed) == bindings[relative],
f"installed identity contract source drifted: {relative}",
)
return image_input
def _prepare_profile() -> None:
_require(os.geteuid() == 0, "profile preparation requires the capability-limited container bootstrap user")
_require(PROFILE.is_dir() and not PROFILE.is_symlink(), "runtime profile tmpfs is missing or unsafe")
_require(not any(PROFILE.iterdir()), "runtime profile tmpfs is not empty")
template = ARTIFACT / "profile-template"
for source in template.iterdir():
destination = PROFILE / source.name
if source.is_dir():
shutil.copytree(source, destination, symlinks=False)
else:
shutil.copy2(source, destination, follow_symlinks=False)
for name in contract.RUNTIME_IDENTITY_FILES:
shutil.copy2(IDENTITY / name, PROFILE / name, follow_symlinks=False)
(PROFILE / name).chmod(0o600)
for name in STATE_DIRECTORIES:
path = PROFILE / name
path.mkdir(mode=0o700)
profile_entries = sorted(
PROFILE.rglob("*"),
key=lambda path: len(path.relative_to(PROFILE).parts),
reverse=True,
)
for path in profile_entries:
_require(not path.is_symlink(), "prepared runtime profile contains a symlink")
for path in profile_entries:
os.chown(path, contract.RUNTIME_UID, contract.RUNTIME_GID)
runtime_identity = PROFILE / "bin" / "gcp-runtime-identity.json"
os.chown(runtime_identity, 0, 0)
runtime_identity.chmod(0o644)
os.chown(PROFILE, contract.RUNTIME_UID, contract.RUNTIME_GID)
def _drop_privileges() -> None:
if os.geteuid() == contract.RUNTIME_UID and os.getegid() == contract.RUNTIME_GID:
return
_require(os.geteuid() == 0, "container bootstrap user is unexpected")
libc = ctypes.CDLL(None, use_errno=True)
pr_capbset_drop = 24
for capability in (0, 6, 7, 8): # CHOWN, SETGID, SETUID, SETPCAP (last)
if libc.prctl(pr_capbset_drop, capability, 0, 0, 0) != 0:
raise EntrypointError("container bootstrap capability drop failed")
os.setgroups([])
os.setgid(contract.RUNTIME_GID)
os.setuid(contract.RUNTIME_UID)
_require(os.geteuid() == contract.RUNTIME_UID and os.getegid() == contract.RUNTIME_GID, "privilege drop failed")
def _runtime_environment() -> dict[str, str]:
return {
"HOME": str(PROFILE / "state"),
"HERMES_HOME": str(PROFILE),
"LANG": "C",
"LC_ALL": "C",
"PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PYTHONDONTWRITEBYTECODE": "1",
"PYTHONNOUSERSITE": "1",
"PYTHONSAFEPATH": "1",
}
def _exec_runtime(command: str) -> None:
_prepare_profile()
_drop_privileges()
argv = [str(RUNTIME_PYTHON), str(BOOTSTRAP), command, "--profile", str(PROFILE)]
if command == "service":
argv.extend(["--readiness-file", str(READINESS)])
os.execve(str(RUNTIME_PYTHON), argv, _runtime_environment())
def _validate_zero_capabilities() -> None:
status = Path("/proc/1/status").read_text(encoding="utf-8")
fields = {}
for line in status.splitlines():
key, separator, value = line.partition(":")
if separator:
fields[key] = value.strip()
for name in ("CapInh", "CapPrm", "CapEff", "CapBnd", "CapAmb"):
_require(fields.get(name) == "0000000000000000", f"runtime process retains {name}")
_require(fields.get("NoNewPrivs") == "1", "runtime process does not enforce no-new-privileges")
_require(
fields.get("Uid")
== f"{contract.RUNTIME_UID}\t{contract.RUNTIME_UID}\t{contract.RUNTIME_UID}\t{contract.RUNTIME_UID}",
"runtime uid drifted",
)
_require(
fields.get("Gid")
== f"{contract.RUNTIME_GID}\t{contract.RUNTIME_GID}\t{contract.RUNTIME_GID}\t{contract.RUNTIME_GID}",
"runtime gid drifted",
)
def _validate_readiness_behavior(image_input: dict[str, Any], value: dict[str, Any]) -> None:
expected_config_sha256 = image_input["runtime"]["config_sha256"]
live_config = PROFILE / "config.yaml"
_require(live_config.is_file() and not live_config.is_symlink(), "runtime profile config is missing or unsafe")
_require(value.get("config_sha256") == expected_config_sha256, "runtime readiness config binding drifted")
_require(contract.sha256_file(live_config) == expected_config_sha256, "runtime profile config drifted")
_require(value.get("tool_surface") == contract.NO_SEND_TOOL_SURFACE, "runtime tool surface drifted")
def _health(image_input: dict[str, Any]) -> dict[str, Any]:
_drop_privileges()
_validate_zero_capabilities()
_require(READINESS.is_file() and not READINESS.is_symlink(), "runtime readiness receipt is missing or unsafe")
_require(stat.S_IMODE(READINESS.stat().st_mode) == 0o600, "runtime readiness receipt mode drifted")
value = contract.load_json(READINESS, "runtime readiness receipt")
_require(
set(value)
== {
"schema",
"status",
"process_id",
"runtime_mode",
"config_sha256",
"gateway_adapter_count",
"connected_platforms",
"tool_surface",
"identity_sha256",
},
"runtime readiness fields are not exact",
)
_require(value.get("schema") == "livingip.leocleanNoSendServiceReadiness.v1", "runtime readiness schema drifted")
_require(
value.get("status") == "ready" and value.get("process_id") == 1, "runtime readiness process binding drifted"
)
_require(value.get("runtime_mode") == "gcp_staging_no_send", "runtime readiness mode drifted")
_require(
value.get("gateway_adapter_count") == 0 and value.get("connected_platforms") == [],
"runtime has a transport adapter",
)
_validate_readiness_behavior(image_input, value)
expected_identity = {name: contract.sha256_file(PROFILE / name) for name in contract.RUNTIME_IDENTITY_FILES}
_require(value.get("identity_sha256") == expected_identity, "runtime readiness identity binding drifted")
cmdline = Path("/proc/1/cmdline").read_bytes().split(b"\0")
expected_native = [
str(RUNTIME_PYTHON).encode(),
str(BOOTSTRAP).encode(),
b"service",
b"--profile",
str(PROFILE).encode(),
b"--readiness-file",
str(READINESS).encode(),
b"",
]
expected_binfmt = [expected_native[0], *expected_native]
_require(cmdline in (expected_native, expected_binfmt), "runtime process command line drifted")
return {
"schema": "livingip.leocleanNoSendContainerHealth.v1",
"status": "pass",
"process_id": 1,
"gateway_adapter_count": 0,
"send_message_present": False,
}
def _verification_result(image_input: dict[str, Any]) -> dict[str, Any]:
return {
"schema": "livingip.leocleanNoSendContainerVerification.v1",
"status": "pass",
"teleo_git_head": image_input["runtime"]["teleo_git_head"],
"artifact_sha256": image_input["runtime"]["artifact_sha256"],
"identity_sha256": image_input["identity"]["bundle_sha256"],
"input_sha256": image_input["input_sha256"],
"python_version": contract.PYTHON_VERSION,
"postgres_version": contract.POSTGRES_VERSION,
"cloudsql_ca_sha256": contract.CA_SHA256,
}
def main(argv: list[str] | None = None) -> int:
arguments = argv if argv is not None else sys.argv[1:]
arguments = arguments or ["service"]
command = arguments[0]
try:
image_input = _validate_installed()
if command in {"probe", "service"}:
_require(len(arguments) == 1, "runtime command arguments are not exact")
_exec_runtime(command)
if command == "health":
_require(len(arguments) == 1, "health command arguments are not exact")
result = _health(image_input)
elif command == "verify":
_require(len(arguments) == 1, "verify command arguments are not exact")
result = _verification_result(image_input)
elif command == "verify-build":
_require(len(arguments) == 5, "build verification arguments are not exact")
expected = (
image_input["runtime"]["teleo_git_head"],
image_input["runtime"]["artifact_sha256"],
image_input["identity"]["bundle_sha256"],
image_input["input_sha256"],
)
_require(tuple(arguments[1:]) == expected, "image build arguments drifted from image input")
result = _verification_result(image_input)
else:
raise EntrypointError("unsupported container command")
print(json.dumps(result, separators=(",", ":"), sort_keys=True))
return 0
except (EntrypointError, contract.PackageError, OSError, subprocess.SubprocessError):
print(json.dumps({"status": "fail", "error": "container_contract_failed"}, sort_keys=True), file=sys.stderr)
return 65
if __name__ == "__main__":
raise SystemExit(main())