Author:
Hash:
Timestamp:
+172 -214 +/-13 browse
Kevin Schoon [me@kevinschoon.com]
2c5281f425eda6502bbd3a6cf71644d8e29c4e70
Fri, 25 Jul 2025 21:19:27 +0000 (7 months ago)
| 1 | diff --git a/Cargo.lock b/Cargo.lock |
| 2 | index b2dd797..de317ae 100644 |
| 3 | --- a/Cargo.lock |
| 4 | +++ b/Cargo.lock |
| 5 | @@ -372,12 +372,9 @@ name = "ayllu-keys" |
| 6 | version = "0.1.0" |
| 7 | dependencies = [ |
| 8 | "ayllu_config", |
| 9 | - "ayllu_logging", |
| 10 | + "ayllu_identity", |
| 11 | "clap 4.5.41", |
| 12 | "serde", |
| 13 | - "thiserror 2.0.12", |
| 14 | - "tracing", |
| 15 | - "tracing-subscriber", |
| 16 | ] |
| 17 | |
| 18 | [[package]] |
| 19 | @@ -429,6 +426,14 @@ dependencies = [ |
| 20 | ] |
| 21 | |
| 22 | [[package]] |
| 23 | + name = "ayllu_identity" |
| 24 | + version = "0.1.0" |
| 25 | + dependencies = [ |
| 26 | + "openssh-keys", |
| 27 | + "serde", |
| 28 | + ] |
| 29 | + |
| 30 | + [[package]] |
| 31 | name = "ayllu_logging" |
| 32 | version = "0.1.0" |
| 33 | dependencies = [ |
| 34 | diff --git a/Cargo.toml b/Cargo.toml |
| 35 | index 7ae401c..e428cbe 100644 |
| 36 | --- a/Cargo.toml |
| 37 | +++ b/Cargo.toml |
| 38 | @@ -5,7 +5,8 @@ members = [ |
| 39 | "crates/config", |
| 40 | "crates/git", |
| 41 | "crates/logging", |
| 42 | - "crates/timeutil", |
| 43 | + "crates/timeutil", |
| 44 | + "crates/identity", |
| 45 | # "crates/scheduler", |
| 46 | # "crates/database", |
| 47 | "ayllu", |
| 48 | @@ -15,7 +16,7 @@ members = [ |
| 49 | "ayllu-keys", |
| 50 | # "ayllu-jobs", |
| 51 | # "ayllu-xmpp", |
| 52 | - "quipu", |
| 53 | + "quipu", "crates/identity", |
| 54 | ] |
| 55 | |
| 56 | [workspace.dependencies] |
| 57 | @@ -33,6 +34,7 @@ futures = "0.3.31" |
| 58 | futures-util = "0.3.31" |
| 59 | sqlx = { version = "0.8.6", features = [ "runtime-tokio-rustls", "sqlite", "macros", "time" ] } |
| 60 | tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } |
| 61 | + openssh-keys = "0.6.4" |
| 62 | |
| 63 | tokio = { version = "1.46.1", features = ["full"] } |
| 64 | tokio-util = { version = "0.7.15", features = ["io", "compat"] } |
| 65 | diff --git a/ayllu-keys/Cargo.toml b/ayllu-keys/Cargo.toml |
| 66 | index 4d7ddbd..b35b9f2 100644 |
| 67 | --- a/ayllu-keys/Cargo.toml |
| 68 | +++ b/ayllu-keys/Cargo.toml |
| 69 | @@ -6,10 +6,7 @@ edition = "2021" |
| 70 | [dependencies] |
| 71 | |
| 72 | ayllu_config = { path = "../crates/config" } |
| 73 | - ayllu_logging = { path = "../crates/logging" } |
| 74 | + ayllu_identity = { path = "../crates/identity" } |
| 75 | |
| 76 | clap = { workspace = true } |
| 77 | serde = { workspace = true } |
| 78 | - tracing = { workspace = true } |
| 79 | - tracing-subscriber = { workspace = true } |
| 80 | - thiserror = {workspace = true} |
| 81 | diff --git a/ayllu-keys/src/config.rs b/ayllu-keys/src/config.rs |
| 82 | deleted file mode 100644 |
| 83 | index a466687..0000000 |
| 84 | --- a/ayllu-keys/src/config.rs |
| 85 | +++ /dev/null |
| 86 | @@ -1,23 +0,0 @@ |
| 87 | - use std::path::PathBuf; |
| 88 | - |
| 89 | - use ayllu_config::Configurable; |
| 90 | - use serde::{Deserialize, Serialize}; |
| 91 | - |
| 92 | - /// An identity defines a known user in the Ayllu environment |
| 93 | - #[derive(Serialize, Deserialize, Clone)] |
| 94 | - pub struct Identity { |
| 95 | - pub username: String, |
| 96 | - pub shell: Option<PathBuf>, |
| 97 | - pub authorized_keys: Option<Vec<String>>, |
| 98 | - } |
| 99 | - |
| 100 | - #[derive(Serialize, Deserialize, Clone, Default)] |
| 101 | - pub struct Config { |
| 102 | - pub log_level: String, |
| 103 | - // path to the ayllu-shell executable |
| 104 | - pub ayllu_shell: Option<PathBuf>, |
| 105 | - #[serde(default = "Vec::new")] |
| 106 | - pub identities: Vec<Identity>, |
| 107 | - } |
| 108 | - |
| 109 | - impl Configurable for Config {} |
| 110 | diff --git a/ayllu-keys/src/keys.rs b/ayllu-keys/src/keys.rs |
| 111 | deleted file mode 100644 |
| 112 | index b0721fa..0000000 |
| 113 | --- a/ayllu-keys/src/keys.rs |
| 114 | +++ /dev/null |
| 115 | @@ -1,63 +0,0 @@ |
| 116 | - #[derive(thiserror::Error, Debug)] |
| 117 | - pub enum Error { |
| 118 | - #[error("Missing Key Type")] |
| 119 | - MissingKeyType, |
| 120 | - #[error("Missing Key Body")] |
| 121 | - MissingKeyBody, |
| 122 | - } |
| 123 | - |
| 124 | - #[derive(Clone, Debug)] |
| 125 | - pub struct Entry { |
| 126 | - key_type: String, |
| 127 | - key_body: String, |
| 128 | - } |
| 129 | - |
| 130 | - #[derive(Clone, Debug)] |
| 131 | - pub struct Entries(Vec<Entry>); |
| 132 | - |
| 133 | - impl TryFrom<String> for Entry { |
| 134 | - type Error = Error; |
| 135 | - |
| 136 | - fn try_from(value: String) -> Result<Self, Self::Error> { |
| 137 | - let mut split = value.splitn(3, " "); |
| 138 | - let key_type = split |
| 139 | - .next() |
| 140 | - .map(|kt| Ok(kt.to_string())) |
| 141 | - .unwrap_or(Err(Error::MissingKeyType))?; |
| 142 | - let key_body = split |
| 143 | - .next() |
| 144 | - .map(|kb| Ok(kb.to_string())) |
| 145 | - .unwrap_or(Err(Error::MissingKeyBody))?; |
| 146 | - Ok(Entry { key_type, key_body }) |
| 147 | - } |
| 148 | - } |
| 149 | - |
| 150 | - impl TryFrom<&Vec<String>> for Entries { |
| 151 | - type Error = Error; |
| 152 | - |
| 153 | - fn try_from(value: &Vec<String>) -> Result<Self, Self::Error> { |
| 154 | - Ok(Entries(value.iter().try_fold( |
| 155 | - Vec::new(), |
| 156 | - |mut accm, entry| { |
| 157 | - let entry = Entry::try_from(entry.clone())?; |
| 158 | - accm.push(entry); |
| 159 | - Ok(accm) |
| 160 | - }, |
| 161 | - )?)) |
| 162 | - } |
| 163 | - } |
| 164 | - |
| 165 | - impl Entries { |
| 166 | - pub fn find(&self, key_type: &str, key_body: &str) -> Option<Entry> { |
| 167 | - self.0 |
| 168 | - .iter() |
| 169 | - .filter_map(|entry| { |
| 170 | - if key_type == entry.key_type && key_body == entry.key_body { |
| 171 | - Some(entry.clone()) |
| 172 | - } else { |
| 173 | - None |
| 174 | - } |
| 175 | - }) |
| 176 | - .next() |
| 177 | - } |
| 178 | - } |
| 179 | diff --git a/ayllu-keys/src/main.rs b/ayllu-keys/src/main.rs |
| 180 | index b9439f9..914bdf4 100644 |
| 181 | --- a/ayllu-keys/src/main.rs |
| 182 | +++ b/ayllu-keys/src/main.rs |
| 183 | @@ -5,44 +5,74 @@ |
| 184 | /// requesting shell access via a regular ssh channel. |
| 185 | /// * An Ayllu managed user is requesting shell access. |
| 186 | /// * An Ayllu managed user is running git operations as the git service. |
| 187 | - use std::path::{Path, PathBuf}; |
| 188 | + use std::{ |
| 189 | + path::{Path, PathBuf}, |
| 190 | + process::ExitCode, |
| 191 | + }; |
| 192 | |
| 193 | + use ayllu_config::Configurable; |
| 194 | + use ayllu_identity::Identity; |
| 195 | use clap::Parser; |
| 196 | |
| 197 | - mod config; |
| 198 | - mod keys; |
| 199 | + use serde::{Deserialize, Serialize}; |
| 200 | |
| 201 | - use tracing::Level; |
| 202 | + const GLOBAL_AYLLU_CONFIG: &str = "/etc/ayllu/config.toml"; |
| 203 | + const DEFAULT_AYLLU_SHELL_PATH: &str = "/usr/bin/ayllu-shell"; |
| 204 | |
| 205 | - /// User git is a special case that allows users without shell access to |
| 206 | - /// login over ssh with the git user. |
| 207 | - const GIT_USER: &str = "git"; |
| 208 | + #[derive(Serialize, Deserialize, Clone, Default)] |
| 209 | + pub struct Config { |
| 210 | + // path to the ayllu-shell executable |
| 211 | + pub ayllu_shell: Option<PathBuf>, |
| 212 | + #[serde(default = "Vec::new")] |
| 213 | + pub identities: Vec<Identity>, |
| 214 | + } |
| 215 | |
| 216 | - const DEFAULT_AYLLU_SHELL_PATH: &str = "/usr/bin/ayllu-shell"; |
| 217 | + impl Configurable for Config {} |
| 218 | |
| 219 | #[derive(Parser, Debug)] |
| 220 | #[clap(version, about, long_about = "Ayllu Keys")] |
| 221 | struct Arguments { |
| 222 | username: String, |
| 223 | - home_dir: String, |
| 224 | + home_dir: PathBuf, |
| 225 | ca_key_type: String, |
| 226 | certificate: String, |
| 227 | #[clap(short, long, value_name = "FILE")] |
| 228 | config: Option<PathBuf>, |
| 229 | - #[clap(short, long, value_name = "log_path")] |
| 230 | - log_path: Option<PathBuf>, |
| 231 | #[clap(long, value_name = "ayllu-shell")] |
| 232 | ayllu_shell: Option<PathBuf>, |
| 233 | } |
| 234 | |
| 235 | - fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 236 | - let args = Arguments::parse(); |
| 237 | - if let Some(log_path) = args.log_path { |
| 238 | - ayllu_logging::init_file(Level::INFO, log_path.as_path()) |
| 239 | + fn authorized_keys(home_dir: &Path) -> ExitCode { |
| 240 | + let authorized_keys_path = home_dir.join(".ssh/authorized_keys"); |
| 241 | + if let Ok(mut fp) = std::fs::File::open(authorized_keys_path) { |
| 242 | + match std::io::copy(&mut fp, &mut std::io::stdout()) { |
| 243 | + Ok(_) => ExitCode::SUCCESS, |
| 244 | + Err(e) => { |
| 245 | + // results in access denied |
| 246 | + eprintln!("Failed to read authorized keys file: {}", e); |
| 247 | + ExitCode::FAILURE |
| 248 | + } |
| 249 | + } |
| 250 | } else { |
| 251 | - ayllu_logging::init(Level::DEBUG) |
| 252 | + ExitCode::FAILURE |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + fn main() -> ExitCode { |
| 257 | + let args = Arguments::parse(); |
| 258 | + |
| 259 | + if args.username != "ayllu" { |
| 260 | + return authorized_keys(&args.home_dir); |
| 261 | + } |
| 262 | + |
| 263 | + let config: Config = match ayllu_config::Reader::load(args.config.as_deref()) { |
| 264 | + Ok(cfg) => cfg, |
| 265 | + Err(e) => { |
| 266 | + eprintln!("Cannot read configuration: {e:?}"); |
| 267 | + return ExitCode::FAILURE; |
| 268 | + } |
| 269 | }; |
| 270 | - let config: config::Config = ayllu_config::Reader::load(args.config.as_deref())?; |
| 271 | + |
| 272 | let ayllu_shell_path = args |
| 273 | .ayllu_shell |
| 274 | .as_ref() |
| 275 | @@ -50,88 +80,42 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 276 | pb.to_string_lossy().to_string() |
| 277 | }); |
| 278 | |
| 279 | - tracing::info!( |
| 280 | - "Login attempt for user: {} home={}, key_type={}, certificate={}", |
| 281 | - args.username, |
| 282 | - args.home_dir, |
| 283 | - args.ca_key_type, |
| 284 | - args.certificate |
| 285 | + eprintln!( |
| 286 | + "Login attempt for user: {} home={:?}, key_type={}, certificate={}", |
| 287 | + args.username, args.home_dir, args.ca_key_type, args.certificate |
| 288 | ); |
| 289 | |
| 290 | - let authenticating_as_git = args.username == GIT_USER; |
| 291 | - |
| 292 | - let identity = config |
| 293 | - .identities |
| 294 | - .iter() |
| 295 | - .find_map(|identity| { |
| 296 | - if let Some(authorized_keys) = identity.authorized_keys.as_ref() { |
| 297 | - match crate::keys::Entries::try_from(authorized_keys) { |
| 298 | - Ok(entries) => { |
| 299 | - if entries.find(&args.ca_key_type, &args.certificate).is_some() { |
| 300 | - Some(Ok(identity.clone())) |
| 301 | - } else { |
| 302 | - None |
| 303 | - } |
| 304 | - } |
| 305 | - Err(err) => Some(Err(err)), |
| 306 | - } |
| 307 | - } else { |
| 308 | - None |
| 309 | - } |
| 310 | - }) |
| 311 | - .transpose()?; |
| 312 | - |
| 313 | - if let Some(identity) = identity { |
| 314 | - let shell = identity.shell.as_ref(); |
| 315 | - if !authenticating_as_git { |
| 316 | - // if not authenticating as the git user we have to verify the |
| 317 | - // user is who they say they are by comparing their username to |
| 318 | - // what their identity is configured as. |
| 319 | - if args.username != identity.username { |
| 320 | - tracing::warn!( |
| 321 | - "User {} attempted to impersonate {}", |
| 322 | - identity.username, |
| 323 | - args.username |
| 324 | - ); |
| 325 | - return Ok(()); |
| 326 | - } |
| 327 | + let user_key = match ayllu_identity::PublicKey::parse(&format!( |
| 328 | + "{} {}", |
| 329 | + args.ca_key_type, args.certificate |
| 330 | + )) { |
| 331 | + Ok(key) => key, |
| 332 | + Err(e) => { |
| 333 | + eprintln!("Cannot parse SSH key from sshd: {e:?}"); |
| 334 | + return ExitCode::FAILURE; |
| 335 | } |
| 336 | - if let Some(authorized_keys) = &identity.authorized_keys { |
| 337 | - authorized_keys.iter().for_each(|public_key| { |
| 338 | - let mut preamble = String::from("restrict"); |
| 339 | - if shell.is_some() { |
| 340 | - // If the global configuration permits shell access we |
| 341 | - // allow for the allocation of a pty, otherwise this is |
| 342 | - // disabled. |
| 343 | - preamble.push_str(",pty"); |
| 344 | - } |
| 345 | - preamble.push_str(&format!(",command=\"{}\"", ayllu_shell_path)); |
| 346 | - preamble.push_str(&format!( |
| 347 | - ",environment=\"AYLLU_USERNAME={}\"", |
| 348 | - identity.username |
| 349 | - )); |
| 350 | - preamble.push_str(&format!(" {}", public_key)); |
| 351 | - tracing::info!("{}", preamble); |
| 352 | - println!("{}", preamble); |
| 353 | - }) |
| 354 | - }; |
| 355 | - } else { |
| 356 | - tracing::info!( |
| 357 | - "No Ayllu managed user {} found, falling back to OS", |
| 358 | - args.username |
| 359 | - ); |
| 360 | - // fallback to ~/.ssh/authorized_keys if identity is not known |
| 361 | - let authorized_keys_path = Path::new(&args.home_dir).join(".ssh/authorized_keys"); |
| 362 | - if let Ok(mut fp) = std::fs::File::open(authorized_keys_path) { |
| 363 | - match std::io::copy(&mut fp, &mut std::io::stdout()) { |
| 364 | - Ok(_) => {} |
| 365 | - Err(e) => { |
| 366 | - // results in access denied |
| 367 | - tracing::error!("Failed to read authorized keys file: {}", e); |
| 368 | - return Err(Box::new(e)); |
| 369 | - } |
| 370 | - } |
| 371 | + }; |
| 372 | + |
| 373 | + let identity = match config.identities.iter().find(|identity| { |
| 374 | + identity |
| 375 | + .authorized_keys |
| 376 | + .iter() |
| 377 | + .find(|authorized_key| authorized_key.0 == user_key) |
| 378 | + .is_some() |
| 379 | + }) { |
| 380 | + Some(identity) => identity, |
| 381 | + None => { |
| 382 | + eprintln!("Cannot identity a valid Ayllu user"); |
| 383 | + return ExitCode::FAILURE; |
| 384 | } |
| 385 | - } |
| 386 | - Ok(()) |
| 387 | + }; |
| 388 | + |
| 389 | + identity.authorized_keys.iter().for_each(|authorized_key| { |
| 390 | + println!( |
| 391 | + "restrict,pty,command=\"{ayllu_shell_path} --config {GLOBAL_AYLLU_CONFIG}\",environment=\"AYLLU_USERNAME={}\" {}", |
| 392 | + identity.username, authorized_key.0 |
| 393 | + ); |
| 394 | + }); |
| 395 | + |
| 396 | + ExitCode::SUCCESS |
| 397 | } |
| 398 | diff --git a/ayllu-shell/src/main.rs b/ayllu-shell/src/main.rs |
| 399 | index 2de4240..6a05851 100644 |
| 400 | --- a/ayllu-shell/src/main.rs |
| 401 | +++ b/ayllu-shell/src/main.rs |
| 402 | @@ -9,19 +9,19 @@ mod ui; |
| 403 | #[derive(Parser, Debug)] |
| 404 | #[clap(version, about, long_about = "Ayllu Shell Access")] |
| 405 | struct Arguments { |
| 406 | - #[clap(short, long, value_name = "FILE")] |
| 407 | - config: Option<PathBuf>, |
| 408 | /// logging level [ERROR,WARN,INFO,DEBUG,TRACE] |
| 409 | #[clap(short, long)] |
| 410 | level: Option<String>, |
| 411 | + #[clap(short, long)] |
| 412 | + config: Option<PathBuf>, |
| 413 | } |
| 414 | |
| 415 | fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 416 | let args = Arguments::parse(); |
| 417 | let config: config::Config = ayllu_config::Reader::load(args.config.as_deref())?; |
| 418 | - // This value must already exist and is validated in ayllu-keys, thus no |
| 419 | - // authentication is required here. |
| 420 | - let username = std::env::var("USER").unwrap(); |
| 421 | + // If AYLLU_USERNAME is set then it's authenticated via ayllu-keys and we assume that identity |
| 422 | + // otherwise we assume the identity of the user who is calling it. |
| 423 | + let username = std::env::var("AYLLU_USERNAME").unwrap_or(std::env::var("USER").unwrap()); |
| 424 | let identity = config |
| 425 | .identities |
| 426 | .iter() |
| 427 | diff --git a/ayllu-shell/src/ui.rs b/ayllu-shell/src/ui.rs |
| 428 | index bbc614d..c612791 100644 |
| 429 | --- a/ayllu-shell/src/ui.rs |
| 430 | +++ b/ayllu-shell/src/ui.rs |
| 431 | @@ -165,7 +165,7 @@ mod menu { |
| 432 | |
| 433 | // Main Menu Items |
| 434 | |
| 435 | - pub const INITIAL_ITEMS: &[Item] = &[Item::Create, Item::Browse, Item::Shell, Item::Exit]; |
| 436 | + pub const INITIAL_ITEMS: &[Item] = &[Item::Create, Item::Browse, Item::Exit]; |
| 437 | pub enum Item<'a> { |
| 438 | /// Select a collection |
| 439 | Collection(&'a Collection), |
| 440 | @@ -194,8 +194,6 @@ mod menu { |
| 441 | description: Option<String>, |
| 442 | path: PathBuf, |
| 443 | }, |
| 444 | - /// Drop into a shell |
| 445 | - Shell, |
| 446 | /// Exit the prompt |
| 447 | Exit, |
| 448 | } |
| 449 | @@ -213,7 +211,6 @@ mod menu { |
| 450 | name: _, |
| 451 | } => write!(f, "Delete"), |
| 452 | Item::Browse => write!(f, "Browse Repositories"), |
| 453 | - Item::Shell => write!(f, "Drop into a Shell"), |
| 454 | Item::Exit => write!(f, "Exit"), |
| 455 | Item::Repository { |
| 456 | collection, |
| 457 | @@ -399,7 +396,6 @@ impl Prompt<'_> { |
| 458 | None => self.execute(None, None), |
| 459 | } |
| 460 | } |
| 461 | - Some(menu::Item::Shell) => todo!(), |
| 462 | Some(menu::Item::Exit) => return Ok(()), |
| 463 | Some(menu::Item::Repository { |
| 464 | collection, |
| 465 | diff --git a/crates/identity/Cargo.toml b/crates/identity/Cargo.toml |
| 466 | new file mode 100644 |
| 467 | index 0000000..343b20c |
| 468 | --- /dev/null |
| 469 | +++ b/crates/identity/Cargo.toml |
| 470 | @@ -0,0 +1,8 @@ |
| 471 | + [package] |
| 472 | + name = "ayllu_identity" |
| 473 | + version = "0.1.0" |
| 474 | + edition = "2024" |
| 475 | + |
| 476 | + [dependencies] |
| 477 | + serde = { workspace = true } |
| 478 | + openssh-keys = { workspace = true } |
| 479 | diff --git a/crates/identity/src/lib.rs b/crates/identity/src/lib.rs |
| 480 | new file mode 100644 |
| 481 | index 0000000..e8871e3 |
| 482 | --- /dev/null |
| 483 | +++ b/crates/identity/src/lib.rs |
| 484 | @@ -0,0 +1,33 @@ |
| 485 | + use serde::{Deserialize, Serialize}; |
| 486 | + |
| 487 | + pub use openssh_keys::PublicKey; |
| 488 | + |
| 489 | + #[derive(Clone, Debug)] |
| 490 | + pub struct WrappedKey(pub PublicKey); |
| 491 | + |
| 492 | + impl Serialize for WrappedKey { |
| 493 | + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 494 | + where |
| 495 | + S: serde::Serializer, |
| 496 | + { |
| 497 | + self.0.to_string().serialize(serializer) |
| 498 | + } |
| 499 | + } |
| 500 | + |
| 501 | + impl<'de> Deserialize<'de> for WrappedKey { |
| 502 | + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 503 | + where |
| 504 | + D: serde::Deserializer<'de>, |
| 505 | + { |
| 506 | + let key_str = String::deserialize(deserializer)?; |
| 507 | + let pub_key = openssh_keys::PublicKey::parse(&key_str).map_err(serde::de::Error::custom)?; |
| 508 | + Ok(WrappedKey(pub_key)) |
| 509 | + } |
| 510 | + } |
| 511 | + |
| 512 | + #[derive(Serialize, Deserialize, Clone, Default)] |
| 513 | + pub struct Identity { |
| 514 | + pub username: String, |
| 515 | + #[serde(default = "Vec::new")] |
| 516 | + pub authorized_keys: Vec<WrappedKey>, |
| 517 | + } |
| 518 | diff --git a/packaging/archlinux/ayllu-git/PKGBUILD b/packaging/archlinux/ayllu-git/PKGBUILD |
| 519 | index a729e1e..f2756ea 100644 |
| 520 | --- a/packaging/archlinux/ayllu-git/PKGBUILD |
| 521 | +++ b/packaging/archlinux/ayllu-git/PKGBUILD |
| 522 | @@ -20,7 +20,7 @@ makedepends=( |
| 523 | provides=("ayllu-git") |
| 524 | optdepends=() |
| 525 | source=( |
| 526 | - "$_pkgname::git+https://ayllu-forge.org/ayllu/${_pkgname}" |
| 527 | + "$_pkgname::git+https://ayllu-forge.org/ayllu/ayllu#branch=main" |
| 528 | ) |
| 529 | # See: https://gitlab.archlinux.org/archlinux/packaging/packages/pacman/-/issues/20 |
| 530 | options=(!lto) |
| 531 | diff --git a/scripts/ayllu_shell_ssh.sh b/scripts/ayllu_shell_ssh.sh |
| 532 | index fd7ed1c..1e393aa 100755 |
| 533 | --- a/scripts/ayllu_shell_ssh.sh |
| 534 | +++ b/scripts/ayllu_shell_ssh.sh |
| 535 | @@ -1,4 +1,7 @@ |
| 536 | #!/bin/sh |
| 537 | - set -e |
| 538 | + set -e |
| 539 | |
| 540 | - ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no demo@127.0.0.1 -p 2222 |
| 541 | + # USERNAME="demo" |
| 542 | + USERNAME="ayllu" |
| 543 | + |
| 544 | + ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$USERNAME@127.0.0.1" -p 2222 |
| 545 | diff --git a/scripts/ayllu_shell_test.sh b/scripts/ayllu_shell_test.sh |
| 546 | index de5f9eb..f03e69a 100755 |
| 547 | --- a/scripts/ayllu_shell_test.sh |
| 548 | +++ b/scripts/ayllu_shell_test.sh |
| 549 | @@ -1,22 +1,38 @@ |
| 550 | #!/bin/sh |
| 551 | set -e |
| 552 | # Run a test server suitable for developing ayllu-shell and related code. |
| 553 | + # Your public SSH keys are passed into the container |
| 554 | # Expects a recent version of ayllu:multiuser-main on your system |
| 555 | |
| 556 | + # NOTE that the session will terminate after closing the first connection. |
| 557 | + DEBUGGING="-d" |
| 558 | + |
| 559 | AYLLU_SRC="$PWD" |
| 560 | LOCAL_SSH_PORT="2222" |
| 561 | - KEYS_COMMAND="/src/target/x86_64-unknown-linux-musl/debug/ayllu-keys --ayllu-shell=/src/target/x86_64-unknown-linux-musl/debug/ayllu-shell --log-path=/tmp/ayllu.log %%u %%h %%t %%k" |
| 562 | + KEYS_COMMAND="/src/target/x86_64-unknown-linux-musl/debug/ayllu-keys --ayllu-shell=/src/target/x86_64-unknown-linux-musl/debug/ayllu-shell %u %h %t %k" |
| 563 | |
| 564 | cargo build --target x86_64-unknown-linux-musl --package ayllu-keys |
| 565 | cargo build --target x86_64-unknown-linux-musl --package ayllu-shell |
| 566 | |
| 567 | + PUBLIC_KEY="$(find ~/.ssh -name '*.pub' -exec cat {} \; | head -n 1)" |
| 568 | + |
| 569 | init_env() { |
| 570 | - printf "passwd -d root\n" |
| 571 | - printf "adduser -h /home/demo -D demo\n" |
| 572 | - printf "passwd -d demo\n" |
| 573 | - printf "ssh-keygen -A\n" |
| 574 | - printf "/usr/sbin/sshd -d -D -o PermitTTY=yes -o PermitUserEnvironment=AYLLU_USERNAME -o PasswordAuthentication=no -o AuthorizedKeysCommand=\"$KEYS_COMMAND\" -o AuthorizedKeysCommandUser=ayllu\n" |
| 575 | - printf "cat /tmp/ayllu.log\n" |
| 576 | + cat<<EOF |
| 577 | + passwd -d root |
| 578 | + adduser -h /home/demo -D demo |
| 579 | + passwd -d demo |
| 580 | + adduser -h /home/ayllu -D ayllu |
| 581 | + passwd -d ayllu |
| 582 | + ssh-keygen -A |
| 583 | + mkdir -p /home/demo/.ssh |
| 584 | + echo $PUBLIC_KEY > /home/demo/.ssh/authorized_keys |
| 585 | + chmod 644 /home/demo/.ssh/authorized_keys |
| 586 | + cat /etc/ayllu/config.example.toml > /etc/ayllu/config.toml |
| 587 | + echo "[[identities]]" >> /etc/ayllu/config.toml |
| 588 | + echo username = \"demo\" >> /etc/ayllu/config.toml |
| 589 | + echo authorized_keys = [\"$PUBLIC_KEY\"] >> /etc/ayllu/config.toml |
| 590 | + /usr/sbin/sshd $DEBUGGING -D -o PermitTTY=yes -o PermitUserEnvironment=AYLLU_USERNAME -o PasswordAuthentication=no -o AuthorizedKeysCommand="$KEYS_COMMAND" -o AuthorizedKeysCommandUser=root |
| 591 | + EOF |
| 592 | } |
| 593 | |
| 594 | echo "To open a remote shell:" |
| 595 | @@ -25,5 +41,5 @@ echo "Or run scripts/ayllu_shell_ssh.sh" |
| 596 | |
| 597 | podman run \ |
| 598 | --name ayllu-shell-test \ |
| 599 | - --rm -ti --user root -v $AYLLU_SRC:/src -v $PWD/config.example.toml:/etc/ayllu/config.toml \ |
| 600 | + --rm -ti --user root -v $AYLLU_SRC:/src -v $PWD/config.example.toml:/etc/ayllu/config.example.toml:ro \ |
| 601 | -p $LOCAL_SSH_PORT:22 registry.ayllu-forge.org/ayllu/ayllu:multiuser-main sh -c "$(init_env)" |