3 Commits

Author SHA1 Message Date
Mikaël Cluseau b5c79756e4 chore: Release init version 2.5.3 2026-02-10 17:38:19 +01:00
Mikaël Cluseau d72cc10234 bump deps 2026-02-10 17:34:19 +01:00
Mikaël Cluseau 9115024d34 lvm: PV also match udev filter 2026-02-10 17:30:16 +01:00
9 changed files with 856 additions and 732 deletions
Generated
+763 -411
View File
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "init" name = "init"
version = "2.6.0" version = "2.5.3"
edition = "2024" edition = "2024"
[profile.release] [profile.release]
@@ -25,10 +25,9 @@ shell-escape = "0.1.5"
tokio = { version = "1.38.0", features = ["rt", "net", "fs", "process", "io-std", "io-util", "sync", "macros", "signal"] } tokio = { version = "1.38.0", features = ["rt", "net", "fs", "process", "io-std", "io-util", "sync", "macros", "signal"] }
termios = "0.3.3" termios = "0.3.3"
unix_mode = "0.1.4" unix_mode = "0.1.4"
base64 = "0.22.1"
sys-info = "0.9.1" sys-info = "0.9.1"
dkl = { git = "https://novit.tech/direktil/dkl", version = "1.0.0" } dkl = { git = "https://novit.tech/direktil/dkl", version = "1.0.0" }
openssl = "0.10.73" openssl = "0.10.73"
#reqwest = { version = "0.13.1", features = ["native-tls", "system-proxy"], default-features = false } reqwest = { version = "0.13.1", features = ["native-tls"] }
reqwest = { git = "https://github.com/mcluseau/rs-reqwest", version = "0.13.1", features = ["native-tls", "system-proxy", "socks"], default-features = false }
glob = "0.3.3" glob = "0.3.3"
hex = "0.4.3"
+6 -22
View File
@@ -1,4 +1,4 @@
from rust:1.95.0-alpine as rust from rust:1.93.0-alpine as rust
run apk add --no-cache git musl-dev libudev-zero-dev openssl-dev cryptsetup-dev lvm2-dev clang-libs clang-dev run apk add --no-cache git musl-dev libudev-zero-dev openssl-dev cryptsetup-dev lvm2-dev clang-libs clang-dev
@@ -9,7 +9,8 @@ run --mount=type=cache,id=novit-rs,target=/usr/local/cargo/registry \
RUSTFLAGS="-C target-feature=-crt-static" cargo install --path . --root /dist RUSTFLAGS="-C target-feature=-crt-static" cargo install --path . --root /dist
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
from alpine:3.23.4 as system from alpine:3.23.3 as initrd
run apk add zstd lz4
workdir /system workdir /system
@@ -30,26 +31,9 @@ run mkdir -p bin run var/log; cd bin && for cmd in init-version init-connect boo
# check viability # check viability
run chroot . init-version run chroot . init-version
# ------------------------------------------------------------------------ run find * |cpio -H newc -oF /initrd
from alpine:3.23.4 as initrd
copy --from=system /system /system
run cd /system && find * |cpio -H newc -oF /initrd
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
from debian:stable-backports as initramfs from alpine:3.23.2
run apt update && apt install -y erofs-utils copy --from=initrd /initrd /
copy --from=system /system /system
run mkfs.erofs \
-z lzma -C131072 -Efragments,ztailpacking \
-T0 --all-time --ignore-mtime \
/initramfs /system
# ------------------------------------------------------------------------
from alpine:3.23.4
copy --from=initrd /initrd /initrd
entrypoint ["base64","/initrd"] entrypoint ["base64","/initrd"]
#copy --from=initramfs /initramfs /
#entrypoint ["base64","/initramfs"]
+11 -51
View File
@@ -54,10 +54,10 @@ pub async fn run() {
info!("Linux version {kernel_version}"); info!("Linux version {kernel_version}");
// mount basic filesystems // mount basic filesystems
mount(None::<&str>, "/proc", "proc", None).await; mount(None, "/proc", "proc", None).await;
mount(None::<&str>, "/sys", "sysfs", None).await; mount(None, "/sys", "sysfs", None).await;
mount(None::<&str>, "/dev", "devtmpfs", None).await; mount(None, "/dev", "devtmpfs", None).await;
mount(None::<&str>, "/dev/pts", "devpts", Some("gid=5,mode=620")).await; mount(None, "/dev/pts", "devpts", Some("gid=5,mode=620")).await;
if utils::bool_param("debug") { if utils::bool_param("debug") {
log::set_max_level(log::LevelFilter::Debug); log::set_max_level(log::LevelFilter::Debug);
@@ -144,9 +144,6 @@ pub async fn run() {
warn!("failed to copy {INIT_LOG} to system: {e}"); warn!("failed to copy {INIT_LOG} to system: {e}");
} }
if let Err(e) = nix::mount::umount2("/modules", nix::mount::MntFlags::MNT_DETACH) {
warn!("failed to umount /modules: {e}");
}
retry(async || switch_root("/system").await).await; retry(async || switch_root("/system").await).await;
} }
@@ -177,27 +174,15 @@ async fn chmod(path: impl AsRef<Path>, mode: u32) -> std::io::Result<()> {
fs::set_permissions(path, perms).await fs::set_permissions(path, perms).await
} }
async fn mount<S: AsRef<Path>>( async fn mount(src: Option<&str>, dst: &str, fstype: &str, opts: Option<&str>) {
src: Option<S>,
dst: impl AsRef<Path>,
fstype: &str,
opts: Option<&str>,
) {
let src = src.as_ref().map(|s| s.as_ref());
let src_str = src.map(|s| s.display().to_string());
let src_str = src_str.as_deref();
let dst = dst.as_ref();
let dst_str = &dst.display().to_string();
if let Err(e) = fs::create_dir_all(dst).await { if let Err(e) = fs::create_dir_all(dst).await {
error!("failed to create dir {dst_str}: {e}"); error!("failed to create dir {dst}: {e}");
} }
retry_or_ignore(async || { retry_or_ignore(async || {
let mut is_file = false; let mut is_file = false;
if let Some(src) = src_str { if let Some(src) = src {
is_file = (fs::metadata(src).await) is_file = (fs::metadata(src).await)
.map_err(|e| format_err!("stat {src} failed: {e}"))? .map_err(|e| format_err!("stat {src} failed: {e}"))?
.is_file(); .is_file();
@@ -209,7 +194,7 @@ async fn mount<S: AsRef<Path>>(
} }
} }
let mut args = vec![src_str.unwrap_or("none"), dst_str, "-t", fstype]; let mut args = vec![src.unwrap_or("none"), dst, "-t", fstype];
if let Some(opts) = opts { if let Some(opts) = opts {
args.extend(["-o", opts]); args.extend(["-o", opts]);
} }
@@ -221,17 +206,11 @@ async fn mount<S: AsRef<Path>>(
} }
let (cmd_str, _) = cmd_str("mount", &args); let (cmd_str, _) = cmd_str("mount", &args);
let flags = nix::mount::MsFlags::empty();
info!("# {cmd_str}",); info!("# {cmd_str}",);
nix::mount::mount(src, dst, Some(fstype), flags, opts)
let mount = |flags| nix::mount::mount(src, dst, Some(fstype), flags, opts); .map_err(|e| format_err!("mount {dst} failed: {e}"))
use nix::{errno::Errno, mount::MsFlags};
match mount(MsFlags::empty()) {
Err(Errno::EACCES) => mount(MsFlags::MS_RDONLY),
r => r,
}
.map_err(|e| format_err!("mount {dst_str} failed: {e}"))
}) })
.await .await
} }
@@ -246,25 +225,6 @@ async fn start_daemon(prog: &str, args: &[&str]) {
.await; .await;
} }
async fn try_exec_cmd(mut cmd: tokio::process::Command) -> Result<()> {
info!(
"# {} {}",
cmd.as_std().get_program().to_string_lossy(),
cmd.as_std()
.get_args()
.map(|a| a.to_string_lossy())
.collect::<Vec<_>>()
.join(" ")
);
let s = cmd.status().await?;
if s.success() {
Ok(())
} else {
Err(format_err!("command failed: {s}"))
}
}
async fn try_exec(prog: &str, args: &[&str]) -> Result<()> { async fn try_exec(prog: &str, args: &[&str]) -> Result<()> {
let (cmd_str, mut cmd) = cmd_str(prog, args); let (cmd_str, mut cmd) = cmd_str(prog, args);
info!("# {cmd_str}"); info!("# {cmd_str}");
+55 -221
View File
@@ -1,24 +1,22 @@
use eyre::{format_err, Result}; use eyre::{format_err, Result};
use log::{debug, info, warn}; use log::{info, warn};
use std::path::{Path, PathBuf};
use tokio::{ use tokio::{
fs, fs,
io::{AsyncBufReadExt, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader}, io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
}; };
use dkl::{ use dkl::{
self, self,
apply::{self, chroot, set_perms}, apply::{self, chroot, set_perms},
base64_decode,
bootstrap::Config, bootstrap::Config,
}; };
use super::{exec, mount, retry, retry_or_ignore, try_exec, try_exec_cmd}; use super::{exec, mount, retry, retry_or_ignore, try_exec};
use crate::{fs::walk_dir, utils}; use crate::{fs::walk_dir, utils};
pub async fn bootstrap(cfg: Config) { pub async fn bootstrap(cfg: Config) {
let verifier = retry(async || Verifier::from_config(&cfg)).await; let verifier = retry(async || Verifier::from_config(&cfg)).await;
let bs = &cfg.bootstrap; let bs = cfg.bootstrap;
mount(Some(&bs.dev), "/bootstrap", "ext4", None).await; mount(Some(&bs.dev), "/bootstrap", "ext4", None).await;
@@ -49,12 +47,12 @@ pub async fn bootstrap(cfg: Config) {
.await; .await;
let sys_cfg: dkl::Config = retry(async || { let sys_cfg: dkl::Config = retry(async || {
let sys_cfg_bytes = seed_config(base_dir, &bs, &verifier).await?; let sys_cfg_bytes = seed_config(base_dir, &bs.seed, &verifier).await?;
Ok(serde_yaml::from_slice(&sys_cfg_bytes)?) Ok(serde_yaml::from_slice(&sys_cfg_bytes)?)
}) })
.await; .await;
mount_system(&sys_cfg, &cfg, base_dir, &verifier).await; mount_system(&sys_cfg, base_dir, &verifier).await;
retry_or_ignore(async || { retry_or_ignore(async || {
let path = "/etc/resolv.conf"; let path = "/etc/resolv.conf";
@@ -66,7 +64,7 @@ pub async fn bootstrap(cfg: Config) {
}) })
.await; .await;
retry_or_ignore(async || apply::files(&sys_cfg.files, "/system", false).await).await; retry_or_ignore(async || apply::files(&sys_cfg.files, "/system").await).await;
apply_groups(&sys_cfg.groups, "/system").await; apply_groups(&sys_cfg.groups, "/system").await;
apply_users(&sys_cfg.users, "/system").await; apply_users(&sys_cfg.users, "/system").await;
@@ -91,27 +89,24 @@ impl Verifier {
return Ok(Self { pubkey: None }); return Ok(Self { pubkey: None });
}; };
let pubkey = base64_decode(pubkey)?; use base64::{prelude::BASE64_STANDARD, Engine};
let pubkey = BASE64_STANDARD.decode(pubkey)?;
let pubkey = Some(pubkey); let pubkey = Some(pubkey);
return Ok(Self { pubkey }); return Ok(Self { pubkey });
} }
async fn verify_path(&self, path: impl AsRef<Path>) -> Result<Vec<u8>> { async fn verify_path(&self, path: &str) -> Result<Vec<u8>> {
let path = path.as_ref(); let data = (fs::read(path).await).map_err(|e| format_err!("failed to read {path}: {e}"))?;
let p = path.display();
let data = (fs::read(path).await).map_err(|e| format_err!("failed to read {p}: {e}"))?;
let Some(ref pubkey) = self.pubkey else { let Some(ref pubkey) = self.pubkey else {
return Ok(data); return Ok(data);
}; };
info!("verifying {p}"); info!("verifying {path}");
let sig = path.with_added_extension("sig"); let sig = &format!("{path}.sig");
let sig = (fs::read(&sig).await) let sig = (fs::read(sig).await).map_err(|e| format_err!("failed to read {sig}: {e}"))?;
.map_err(|e| format_err!("failed to read {}: {e}", sig.display()))?;
use openssl::{hash::MessageDigest, pkey::PKey, sign::Verifier}; use openssl::{hash::MessageDigest, pkey::PKey, sign::Verifier};
let pubkey = PKey::public_key_from_der(pubkey)?; let pubkey = PKey::public_key_from_der(pubkey)?;
@@ -123,14 +118,14 @@ impl Verifier {
if sig_ok { if sig_ok {
Ok(data) Ok(data)
} else { } else {
Err(format_err!("signature verification failed for {p}")) Err(format_err!("signature verification failed for {path}"))
} }
} }
} }
async fn seed_config( async fn seed_config(
base_dir: &str, base_dir: &str,
bs: &dkl::bootstrap::Bootstrap, seed_url: &Option<String>,
verifier: &Verifier, verifier: &Verifier,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
let cfg_path = &format!("{base_dir}/config.yaml"); let cfg_path = &format!("{base_dir}/config.yaml");
@@ -141,12 +136,13 @@ async fn seed_config(
let bs_tar = "/bootstrap.tar"; let bs_tar = "/bootstrap.tar";
if !fs::try_exists(bs_tar).await? { if !fs::try_exists(bs_tar).await? {
if bs.seed.is_none() { if let Some(seed_url) = seed_url.as_ref() {
fetch_bootstrap(seed_url, bs_tar).await?;
} else {
return Err(format_err!( return Err(format_err!(
"no {cfg_path}, no {bs_tar} and no seed URL, can't bootstrap" "no {cfg_path}, no {bs_tar} and no seed, can't bootstrap"
)); ));
} }
fetch_bootstrap(bs, bs_tar).await?;
} }
try_exec("tar", &["xf", bs_tar, "-C", base_dir]).await?; try_exec("tar", &["xf", bs_tar, "-C", base_dir]).await?;
@@ -158,41 +154,15 @@ async fn seed_config(
verifier.verify_path(&cfg_path).await verifier.verify_path(&cfg_path).await
} }
async fn fetch_bootstrap(bs: &dkl::bootstrap::Bootstrap, output_file: &str) -> Result<()> { async fn fetch_bootstrap(seed_url: &str, output_file: &str) -> Result<()> {
let seed_url: reqwest::Url = (bs.seed.as_ref()) let seed_url: reqwest::Url = seed_url.parse()?;
.ok_or(format_err!("no seed URL"))?
.parse()
.map_err(|e| format_err!("invalid seed URL: {e}"))?;
info!( info!(
"fetching {output_file} from {}", "fetching {output_file} from {}",
seed_url.host_str().unwrap_or("<no host>") seed_url.host_str().unwrap_or("<no host>")
); );
let mut builder = reqwest::Client::builder(); let resp = reqwest::get(seed_url).await?;
if let Some(ref proxy) = bs.seed_proxy {
debug!("using proxy {proxy}");
let proxy = reqwest::Proxy::all(proxy) //
.map_err(|e| format_err!("seed proxy setup failed: {e}"))?;
builder = builder.proxy(proxy);
}
if let Some(ref ca) = bs.seed_ca {
debug!("using custom CA certificate");
let ca = base64_decode(ca).map_err(|e| format_err!("invalid seed CA: decode: {e}"))?;
let ca = reqwest::Certificate::from_der(&ca)
.map_err(|e| format_err!("invalid seed CA: parse: {e}"))?;
builder = builder.tls_certs_only([ca]);
}
if let Some(ref sn) = bs.seed_servername {
debug!("tls server name: {sn}");
builder = builder.tls_server_name(bs.seed_servername.clone());
}
let req = builder.build()?.get(seed_url);
let resp = req.send().await?;
if !resp.status().is_success() { if !resp.status().is_success() {
return Err(format_err!("HTTP request failed: {}", resp.status())); return Err(format_err!("HTTP request failed: {}", resp.status()));
@@ -217,135 +187,47 @@ fn default_root_tmpfs_opts() -> Option<String> {
Some(format!("size={fs_size}m")) Some(format!("size={fs_size}m"))
} }
struct LayerMounter<'t> { async fn mount_system(cfg: &dkl::Config, bs_dir: &str, verifier: &Verifier) {
bs_dir: &'t str,
layers_dir: &'t str,
verifier: &'t Verifier,
lower_dir: String,
}
impl LayerMounter<'_> {
fn src_path(&self, name: &str) -> PathBuf {
let mut p = PathBuf::from(self.bs_dir);
p.push(name);
if name != "merged" {
p.add_extension("fs");
}
p
}
async fn exists(&self, name: &str) -> bool {
retry(async || Ok(fs::try_exists(self.src_path(name)).await?)).await
}
async fn mount(&mut self, name: &str) {
self.mount_path(self.src_path(name), name, true).await
}
async fn mount_path(&mut self, src: impl AsRef<Path>, name: &str, verify: bool) {
let src = src.as_ref();
let tgt_dir = PathBuf::from(self.layers_dir).join(name);
let tgt = tgt_dir.with_added_extension("fs");
if let Err(e) = fs::create_dir_all(&tgt_dir).await {
warn!("mkdir -p {}: {e}", tgt_dir.display());
}
let mount_src = if name == "merged" {
retry(async || {
let data = self.verifier.verify_path(src).await?;
let data = MergedLayer::from_bytes(&data)
.ok_or(format_err!("{}: invalid data", src.display()))?;
data.create(&tgt)
.await
.map_err(|e| format_err!("write {}: {e}", tgt.display()))?;
let dm_name = &format!("system");
let mut cmd = tokio::process::Command::new("veritysetup");
cmd.arg("open")
.arg(format!("--hash-offset={}", data.hash_offset()))
.arg(&tgt)
.arg(dm_name)
.arg(&tgt)
.arg(data.root_hash_hex());
try_exec_cmd(cmd).await?;
Ok(PathBuf::from("/dev/mapper").join(dm_name))
})
.await
} else {
retry(async || {
let src = if verify {
self.verifier.verify_path(src).await?
} else {
fs::read(src).await?
};
fs::write(&tgt, &src).await?;
Ok(tgt.clone())
})
.await
};
retry(async || {
let mut buf = [0u8; 1028];
fs::File::open(&mount_src)
.await
.map_err(|e| format_err!("open {}: {e}", mount_src.display()))?
.read_exact(&mut buf)
.await
.map_err(|e| format_err!("read {}: {e}", mount_src.display()))?;
let fstype = if buf[1024..1028] == 0xE0F5E1E2u32.to_le_bytes() {
"erofs"
} else {
"squashfs"
};
mount(Some(&mount_src), &tgt_dir, fstype, None).await;
Ok(())
})
.await;
if !self.lower_dir.is_empty() {
self.lower_dir.push(':');
}
self.lower_dir.push_str(&tgt_dir.to_string_lossy());
}
}
async fn mount_system(cfg: &dkl::Config, bs_cfg: &Config, bs_dir: &str, verifier: &Verifier) {
let opts = match utils::param("root-opts") { let opts = match utils::param("root-opts") {
Some(s) => Some(s.to_string()), Some(s) => Some(s.to_string()),
None => default_root_tmpfs_opts(), None => default_root_tmpfs_opts(),
}; };
let mem_dir = "/mem"; let mem_dir = "/mem";
mount(None::<&str>, mem_dir, "tmpfs", opts.as_deref()).await; mount(None, mem_dir, "tmpfs", opts.as_deref()).await;
let mut mounter = LayerMounter { let layers_dir = &format!("{mem_dir}/layers");
bs_dir, let mut lower_dir = String::new();
layers_dir: &format!("{mem_dir}/layers"),
verifier,
lower_dir: String::new(),
};
if mounter.exists("merged").await { for layer in &cfg.layers {
mounter.mount("merged").await; let src = retry(async || {
} else { if layer == "modules" {
for layer in &cfg.layers { let src = "/modules.sqfs";
if layer == "modules" && bs_cfg.modules.is_some() { (fs::read(src).await).map_err(|e| format_err!("read {src} failed: {e}"))
continue; // take modules from initrd } else {
verifier.verify_path(&format!("{bs_dir}/{layer}.fs")).await
} }
mounter.mount(layer).await; })
} .await;
}
if let Some(ref modules) = bs_cfg.modules { let tgt = &format!("{mem_dir}/{layer}.fs");
mounter.mount_path(modules, "modules", false).await; retry(async || {
info!("copying layer {layer}");
let mut out = (fs::File::create(tgt).await)
.map_err(|e| format_err!("create {tgt} failed: {e}"))?;
(out.write_all(&src).await).map_err(|e| format_err!("write failed: {e}"))?;
(out.flush().await).map_err(|e| format_err!("write failed: {e}"))
})
.await;
let layer_dir = &format!("{layers_dir}/{layer}");
mount(Some(tgt), layer_dir, "squashfs", None).await;
if !lower_dir.is_empty() {
lower_dir.push(':');
}
lower_dir.push_str(&layer_dir);
} }
let upper_dir = &format!("{mem_dir}/upper"); let upper_dir = &format!("{mem_dir}/upper");
@@ -358,9 +240,8 @@ async fn mount_system(cfg: &dkl::Config, bs_cfg: &Config, bs_dir: &str, verifier
}) })
.await; .await;
let lower_dir = &mounter.lower_dir;
let opts = format!("lowerdir={lower_dir},upperdir={upper_dir},workdir={work_dir}"); let opts = format!("lowerdir={lower_dir},upperdir={upper_dir},workdir={work_dir}");
mount(None::<&str>, "/system", "overlay", Some(&opts)).await; mount(None, "/system", "overlay", Some(&opts)).await;
// make root rshared (default in systemd, required by Kubernetes 1.10+) // make root rshared (default in systemd, required by Kubernetes 1.10+)
// equivalent to "mount --make-rshared /" // equivalent to "mount --make-rshared /"
@@ -374,53 +255,6 @@ async fn mount_system(cfg: &dkl::Config, bs_cfg: &Config, bs_dir: &str, verifier
.await; .await;
} }
struct MergedLayer<'t> {
#[allow(unused)]
root_hash_sig: &'t [u8],
root_hash: &'t [u8],
data: &'t [u8],
hash: &'t [u8],
}
impl<'t> MergedLayer<'t> {
fn from_bytes(mut src: &'t [u8]) -> Option<Self> {
let mut next = || {
let (len, rem) = src.split_at_checked(8)?;
let len = u64::from_be_bytes(len.try_into().ok()?);
let (data, rem) = rem.split_at_checked(len as usize)?;
src = rem;
Some(data)
};
Some(Self {
root_hash_sig: next()?,
root_hash: next()?,
data: next()?,
hash: next()?,
})
}
async fn create(&self, path: impl AsRef<Path>) -> std::io::Result<()> {
let mut out = fs::File::create(path).await?;
self.write_to(&mut out).await?;
out.shutdown().await
}
async fn write_to(&self, mut out: impl AsyncWrite + Unpin) -> std::io::Result<()> {
out.write_all(self.data).await?;
out.write_all(self.hash).await?;
Ok(())
}
fn hash_offset(&self) -> usize {
self.data.len()
}
fn root_hash_hex(&self) -> String {
hex::encode(self.root_hash)
}
}
async fn apply_groups(groups: &[dkl::Group], root: &str) { async fn apply_groups(groups: &[dkl::Group], root: &str) {
for group in groups { for group in groups {
let mut args = vec![root, "groupadd", "-r"]; let mut args = vec![root, "groupadd", "-r"];
+1 -1
View File
@@ -208,7 +208,7 @@ async fn find_devs(pvs: &LvmPV) -> Result<Vec<String>> {
let filter: udev::Filter = filter.clone().into(); let filter: udev::Filter = filter.clone().into();
(udev::all().await?.iter()) (udev::all().await?.iter())
.filter(|dev| dev.subsystem() == Some("block") && filter.matches(dev)) .filter(|dev| dev.subsystem() == Some("block") && filter.matches(dev))
.filter_map(|dev| dev.property("DEVNAME").map(|s| s.to_string())) .filter_map(|dev| dev.path().map(|s| s.to_string()))
.collect() .collect()
} else if !pvs.regexps.is_empty() { } else if !pvs.regexps.is_empty() {
let regexps: Vec<regex::Regex> = (pvs.regexps.iter()) let regexps: Vec<regex::Regex> = (pvs.regexps.iter())
+17 -22
View File
@@ -21,6 +21,8 @@ auths:
sshKey: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICkpbU6sf4t0f6XAv9DuW3XH5iLM0AI5rc8PT2jwea1N sshKey: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICkpbU6sf4t0f6XAv9DuW3XH5iLM0AI5rc8PT2jwea1N
password: bXlzZWVk:HMSxrg1cYphaPuUYUbtbl/htep/tVYYIQAuvkNMVpw0 # mypass password: bXlzZWVk:HMSxrg1cYphaPuUYUbtbl/htep/tVYYIQAuvkNMVpw0 # mypass
signer_public_key: MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQA29glSqk7MqoUIjD+UQG+b4v59pTFkn8rYtNhOftTe7uiLUvGFsjNdzP3tW64t/c6YD2p6dtI3oQXGOVQO1vIWPEBc6Sq++BRpQ0FVna+dgNQx8/kLXN9Na0ZYbK7q0haCI7/EHWOX79JFFxJE9HJ67AOMmXwGJ2jrfa1CUnWvfCmT+E=
ssh: ssh:
listen: "[::]:22" listen: "[::]:22"
user_ca: /user_ca.pub user_ca: /user_ca.pub
@@ -39,24 +41,22 @@ networks:
udev: !has ID_NET_NAME_MAC udev: !has ID_NET_NAME_MAC
script: | script: |
ip li set $iface up ip li set $iface up
ip a add 192.168.12.42/24 dev $iface udhcpc -i $iface -b -t1 -T1 -A5 ||
ip a add fd12:6e76:7474::1337:2eed/64 dev $iface ip a add 2001:41d0:306:168f::1337:2eed/64 dev $iface
ip route add default via 192.168.12.254
ip route add default via fd12:6e76:7474::1 dev $iface
#pre_lvm_crypt: pre_lvm_crypt:
#- name: sys-${name} - name: sys-${name}
# udev: !glob [ DEVNAME, /dev/vd* ] udev: !glob [ DEVNAME, /dev/vd* ]
lvm: lvm:
- vg: storage - vg: storage
pvs: pvs:
n: 2 n: 2
regexps: regexps:
#- ^/dev/mapper/sys- - ^/dev/mapper/sys-
# to match full disks # to match full disks
#- /dev/nvme[0-9]+n[0-9]+ #- /dev/nvme[0-9]+n[0-9]+
- /dev/vd[a-z]+ #- /dev/vd[a-z]+
#- /dev/sd[a-z]+ #- /dev/sd[a-z]+
#- /dev/hd[a-z]+ #- /dev/hd[a-z]+
# to match partitions: # to match partitions:
@@ -72,16 +72,11 @@ lvm:
lvs: lvs:
- name: bootstrap - name: bootstrap
size: 1g size: 2g
- name: varlog - name: varlog
size: 256m extents: 10%FREE
- name: kubelet # size: 10g
size: 256m
- name: containerd
size: 1g
- name: etcd
size: 256m
- name: podman - name: podman
extents: 10%FREE extents: 10%FREE
@@ -95,11 +90,11 @@ lvm:
#- dev: /dev/storage/bootstrap #- dev: /dev/storage/bootstrap
#- dev: /dev/storage/dls #- dev: /dev/storage/dls
signer_public_key: 'MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBe6Y3zGQUIHvVXoS5GI8irY8yoB0ozFpzn/cUykA46TkHdJ8xCEaaM1MpqMrfWgDtP/rA2KeE9HjVerLnEFD01uUAUh4/OYgCBDYJPhridVDoC78KOJpkWBj7Shl0Rp0AtETvatNPa1RRe15V7nDF/Nm75Y6O3IL29lYPQ6jqEGhR810='
bootstrap: bootstrap:
#dev: /dev/mapper/bootstrap
dev: /dev/storage/bootstrap dev: /dev/storage/bootstrap
seed_proxy: "http://[fd6e:7674:6f70::1]:8888" # TODO seed: https://direktil.novit.io/bootstraps/dls-crypt
seed_ca: 'MIIBhTCCASugAwIBAgIRAMiu/MXPMl/6vjR2HZHwflQwCgYIKoZIzj0EAwIwIjEgMB4GA1UEAxMXbm92aXQtaW50ZXJuYWwtY2EtZWNkc2EwHhcNMjYwNDIxMDkzMTEyWhcNMjYwNzIwMDkzMTEyWjAiMSAwHgYDVQQDExdub3ZpdC1pbnRlcm5hbC1jYS1lY2RzYTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABC87aJX1WltmkZQ2Am4kCIQTFLqkLE4zTAznP5K9k3RH4kxuB2IjkQyyii6zk/9bus0q76UmennubDxtH5Y7ZgGjQjBAMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSlmVUj3CIWL1CW7K1BgOXjR6j6kjAKBggqhkjOPQQDAgNIADBFAiEAhIvi4eGFjC4xu80yKKYFeZ5X3f2RPfnOg4hK3GqZgc0CIF97A9An2Pt4TkKkC/W+TX/tEXGxcDyJHBpB3BdpN7QW' seed: http://192.168.10.254:7606/hosts/m1/bootstrap.tar
seed: https://dls.edicia-prod.nv/public/downloads/V6VWZWQEGX7T7Q524Z4HLL2ZAG42YRXHVGXSTVAL4WEC2VIG4GWQ/bootstrap.tar # TODO seed_sign_key: "..."
#seed: https://192.168.12.254:7606/public/download-set/host/m1/bootstrap.tar?set=IDZTK4AUNCYCTKF3GIEGSNZF3I7XCINCTJSOWL2JPHCJ2IAZWDECY2XCGQ5MCTJBNFIKBNCLIA3PJSN7IOH7URGXYRYZRCGF4VSW4RIAAQRE2GDEOC4RWAAAQA3DSZJZMU4TGOL4NA5G2MJ2MJXW65DTORZGC4BOORQXEAAAAAADJMFLUE # TODO load_and_close: true
Binary file not shown.
BIN
View File
Binary file not shown.