1
0
Fork 0
mirror of https://github.com/containers/youki synced 2024-05-10 09:36:13 +02:00

add rootless option for spec

This commit is contained in:
yukang 2021-10-01 20:44:10 +08:00
parent 6cb89fcdfa
commit 5714615b80
3 changed files with 101 additions and 5 deletions

7
Cargo.lock generated
View File

@ -948,6 +948,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "path-clean"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd"
[[package]]
name = "pentacle"
version = "1.0.0"
@ -1529,6 +1535,7 @@ dependencies = [
"nix",
"oci-spec",
"once_cell",
"path-clean",
"pentacle",
"prctl",
"procfs",

View File

@ -51,6 +51,7 @@ fastrand = "1.4.1"
crossbeam-channel = "0.5"
seccomp = { version = "0.1.0", path = "./seccomp" }
pentacle = "1.0.0"
path-clean = "0.1.0"
[dev-dependencies]
# TODO: Fetch from crate.io instead of git when next release oci-spec-rs

View File

@ -1,18 +1,106 @@
use anyhow::Result;
use clap::Clap;
use oci_spec::runtime::Spec;
use std::path::PathBuf;
use nix;
use oci_spec::runtime::{
LinuxBuilder, LinuxIdMappingBuilder, LinuxNamespaceBuilder, LinuxNamespaceType, MountBuilder,
Spec, SpecBuilder,
};
use path_clean;
use serde_json::to_writer_pretty;
use std::fs::File;
/// Create a new runtime specification
/// Command generates a config.json
#[derive(Clap, Debug)]
pub struct SpecJson;
pub struct SpecJson {
/// Generate a configuration for a rootless container
#[clap(long)]
pub rootless: bool,
}
pub fn set_for_rootless(spec: &Spec) -> Result<Spec> {
let uid = nix::unistd::geteuid().as_raw();
let gid = nix::unistd::getegid().as_raw();
// Remove network from the default spec
let mut namespaces = vec![];
for ns in spec
.linux()
.as_ref()
.unwrap()
.namespaces()
.as_ref()
.unwrap()
.iter()
{
if ns.typ() != LinuxNamespaceType::Network && ns.typ() != LinuxNamespaceType::User {
namespaces.push(ns.clone());
}
}
// Add user namespace
namespaces.push(
LinuxNamespaceBuilder::default()
.typ(LinuxNamespaceType::User)
.build()?,
);
let linux_builder = LinuxBuilder::default()
.namespaces(namespaces)
.uid_mappings(vec![LinuxIdMappingBuilder::default()
.host_id(uid)
.container_id(0_u32)
.size(1_u32)
.build()?])
.gid_mappings(vec![LinuxIdMappingBuilder::default()
.host_id(gid)
.container_id(0_u32)
.size(1_u32)
.build()?]);
// Fix the mounts
let mut mounts = vec![];
for mount in spec.mounts().as_ref().unwrap().iter() {
let dest = mount.destination().clone();
if path_clean::clean(dest.as_path().to_str().unwrap()) == "/sys" {
let mount = MountBuilder::default()
.destination(PathBuf::from("/sys"))
.source(PathBuf::from("/sys"))
.typ("none".to_string())
.options(vec![
"rbind".to_string(),
"nosuid".to_string(),
"noexec".to_string(),
"nodev".to_string(),
"ro".to_string(),
])
.build()?;
mounts.push(mount);
} else {
let options: Vec<String> = mount
.options()
.as_ref()
.unwrap_or(&vec![])
.iter()
.filter(|&o| !o.starts_with("gid=") && !o.starts_with("uid="))
.map(|o| o.to_string())
.collect();
let mount_builder = MountBuilder::default().options(options);
mounts.push(mount_builder.build()?);
}
}
let spec_builder = SpecBuilder::default()
.linux(linux_builder.build()?)
.mounts(mounts);
Ok(spec_builder.build()?)
}
/// spec Cli command
impl SpecJson {
pub fn exec(&self) -> Result<()> {
// get default values for Spec
let default_json: Spec = Default::default();
let mut default_json: Spec = Default::default();
if self.rootless {
default_json = set_for_rootless(&default_json)?
};
// write data to config.json
to_writer_pretty(&File::create("config.json")?, &default_json)?;
Ok(())