300 lines
12 KiB
Python
300 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"",
|
|
]
|
|
_require(contract.pid_one_command_line_is_exact(cmdline, expected_native), "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())
|