Bind production cold start to installed Lazaret authorities

This commit is contained in:
ms2k 2026-07-16 20:41:40 +09:00
commit bc04112c77
2 changed files with 573 additions and 25 deletions

View file

@ -24,6 +24,7 @@ pub const CREDENTIALS_DESTINATION: &str = "/run/lazaret/credentials";
pub const MAILBOX_REQUESTS_DESTINATION: &str = "/run/lazaret/mailbox/requests";
pub const MAILBOX_RESULTS_DESTINATION: &str = "/run/lazaret/mailbox/results";
pub const ESCALATION_CLIENT_DESTINATION: &str = "/run/lazaret/bin/lazaret-escalate";
pub const SANDBOX_INIT_DESTINATION: &str = "/run/lazaret/bin/lazaret-sandbox-init";
pub const TERMINFO_ROOT_DESTINATION: &str = "/run/lazaret/terminfo";
pub const NETWORK_NAMESPACE_PATH: &str = "/proc/self/ns/net";
@ -678,6 +679,10 @@ fn handoff_runtime_sources(
container.join("bin/lazaret-escalate"),
HandoffPathType::RegularFile,
),
(
container.join("bin/lazaret-sandbox-init"),
HandoffPathType::RegularFile,
),
]
.into_iter()
.map(|(relative_path, expected_type)| {
@ -851,16 +856,22 @@ fn build_linux() -> Result<oci_spec::runtime::Linux, SandboxBuildError> {
.map_err(oci_error),
))
.collect::<Result<Vec<_>, _>>()?;
let identity_mapping = LinuxIdMappingBuilder::default()
let uid_mapping = LinuxIdMappingBuilder::default()
.container_id(0_u32)
.host_id(0_u32)
.host_id(rustix::process::getuid().as_raw())
.size(1_u32)
.build()
.map_err(oci_error)?;
let gid_mapping = LinuxIdMappingBuilder::default()
.container_id(0_u32)
.host_id(rustix::process::getgid().as_raw())
.size(1_u32)
.build()
.map_err(oci_error)?;
LinuxBuilder::default()
.namespaces(private_namespaces)
.uid_mappings(vec![identity_mapping])
.gid_mappings(vec![identity_mapping])
.uid_mappings(vec![uid_mapping])
.gid_mappings(vec![gid_mapping])
.rootfs_propagation("rprivate")
.build()
.map_err(oci_error)
@ -1021,6 +1032,12 @@ fn control_mounts(control_sources: &Path) -> Result<Vec<Mount>, SandboxBuildErro
true,
false,
),
(
"bin/lazaret-sandbox-init",
SANDBOX_INIT_DESTINATION,
true,
false,
),
]
.into_iter()
.map(|(source, destination, read_only, no_exec)| {

View file

@ -11,8 +11,9 @@ use lazaret_core::identity::{ContainerId, DeviceId, InodeId, NamespaceIdentity};
use lazaret_runtime_supervisor::sandbox::{
CREDENTIALS_DESTINATION, ESCALATION_CLIENT_DESTINATION, HostTerminal,
MAILBOX_REQUESTS_DESTINATION, MAILBOX_RESULTS_DESTINATION, NETWORK_NAMESPACE_PATH, RootProcess,
SandboxBuildErrorKind, SandboxBuildRequest, TERMINFO_ROOT_DESTINATION, WORKSPACE_DESTINATION,
build_sandbox_bundle, production_sandbox_layout, stage_host_terminal,
SANDBOX_INIT_DESTINATION, SandboxBuildErrorKind, SandboxBuildRequest,
TERMINFO_ROOT_DESTINATION, WORKSPACE_DESTINATION, build_sandbox_bundle,
production_sandbox_layout, stage_host_terminal,
};
use serde_json::Value;
use tempfile::TempDir;
@ -41,6 +42,9 @@ impl Fixture {
[storage]
data_root = "{}"
[network]
default_allow = ["192.0.2.10/32"]
[profiles.default]
image = "example.invalid/agent:v1"
persistent_dirs = ["/root"]
@ -50,6 +54,11 @@ volumes = [
{{ host = "{{profile_dir}}/read-write", container = "/root/read-write", kind = "directory", access = "read-write", create = true }},
]
[profiles.default.readiness]
denied = [{{ address = "10.20.30.40", port = 443 }}]
permitted = [{{ address = "192.0.2.10", port = 443 }}]
dns = [{{ resolver = "198.51.100.53", query = "example.invalid" }}]
[profiles.unselected]
image = "example.invalid/unselected:v1"
env = {{ UNSELECTED_SECRET = "env:UNSELECTED_HOST_SECRET" }}
@ -172,6 +181,13 @@ env = {{ UNSELECTED_SECRET = "env:UNSELECTED_HOST_SECRET" }}
b"executable",
)
.unwrap();
fs::write(
runtime.join(format!(
"sandbox-control/{container}/bin/lazaret-sandbox-init"
)),
b"executable",
)
.unwrap();
}
fn bundle_config_path(&self) -> PathBuf {
@ -274,11 +290,15 @@ fn deterministic_snapshot_has_only_private_namespaces_and_fixed_runtime_shape()
assert_eq!(namespaces[5]["path"], NETWORK_NAMESPACE_PATH);
assert_eq!(
specification["linux"]["uidMappings"],
serde_json::json!([{ "hostID": 0, "containerID": 0, "size": 1 }])
serde_json::json!([{
"hostID": rustix::process::getuid().as_raw(), "containerID": 0, "size": 1
}])
);
assert_eq!(
specification["linux"]["gidMappings"],
serde_json::json!([{ "hostID": 0, "containerID": 0, "size": 1 }])
serde_json::json!([{
"hostID": rustix::process::getgid().as_raw(), "containerID": 0, "size": 1
}])
);
assert_eq!(first.command().program(), OsStr::new("runsc"));
@ -328,6 +348,48 @@ fn deterministic_snapshot_has_only_private_namespaces_and_fixed_runtime_shape()
}));
}
#[test]
fn product_init_role_has_exact_terminal_neutral_rootless_bundle_shape() {
let fixture = Fixture::new();
let root = RootProcess::new(
SANDBOX_INIT_DESTINATION,
["--lazaret-private-sandbox-init-v1".to_owned()],
)
.unwrap();
let specification = value(&build_sandbox_bundle(fixture.request(root)).unwrap());
assert_eq!(specification["process"]["terminal"], false);
assert_eq!(
specification["process"]["args"],
serde_json::json!([
SANDBOX_INIT_DESTINATION,
"--lazaret-private-sandbox-init-v1"
])
);
assert_eq!(specification["process"]["user"]["uid"], 0);
assert_eq!(specification["process"]["user"]["gid"], 0);
assert_eq!(
specification["linux"]["uidMappings"],
serde_json::json!([{
"hostID": rustix::process::getuid().as_raw(), "containerID": 0, "size": 1
}])
);
assert_eq!(
mounts(&specification)[SANDBOX_INIT_DESTINATION]["source"],
host_path(
fixture
.configuration
.runtime_domain_root()
.canonical_label()
.as_bytes(),
)
.join("sandbox-control")
.join("11".repeat(32))
.join("bin/lazaret-sandbox-init")
.display()
.to_string()
);
}
#[test]
fn selected_environment_volume_modes_and_host_terminal_are_preserved() {
let fixture = Fixture::new();