Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rootless option for spec #350

Merged
merged 6 commits into from Oct 3, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -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
Expand Down
98 changes: 93 additions & 5 deletions src/commands/spec_json.rs
@@ -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()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use unwrap? I know it may take a few more line to return results, but let's avoid unwrap in general.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use unwrap? I know it may take a few more line to return results, but let's avoid unwrap in general.

how about use unwrap_or ?

.namespaces()
.as_ref()
.unwrap()
.iter()
{
if ns.typ() != LinuxNamespaceType::Network && ns.typ() != LinuxNamespaceType::User {
chenyukang marked this conversation as resolved.
Show resolved Hide resolved
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" {
chenyukang marked this conversation as resolved.
Show resolved Hide resolved
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(())
Expand Down