Skip to content

Commit 1fa16fe

Browse files
committed
Add binary agnos-generate-accounts-keys
Closes: #21
1 parent cdc20e4 commit 1fa16fe

File tree

4 files changed

+80
-3
lines changed

4 files changed

+80
-3
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ or if you prefer a larger key:
121121
openssl genrsa 4096 > /path/to/store/the/key.pem
122122
```
123123

124+
Alternatively, you can use the provided `agnos-generate-accounts-keys` binary to automatically generate private keys for the accounts listed in the configuration file.
125+
124126
## Agnos configuration
125127

126128
Agnos is configured via a single [TOML](https://toml.io/) file. A commented example is available in [config_example.toml](https://github.com/krtab/agnos/blob/main/config_example.toml).
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use std::io::Write;
2+
3+
use agnos::config::Config;
4+
use clap::{Arg, ArgAction};
5+
6+
fn main() -> anyhow::Result<()> {
7+
let mut stdin_lines = std::io::stdin().lines();
8+
let cli_ops = clap::command!()
9+
.about("Generate non existing private accounts keys from agnos' configuration.")
10+
.arg_required_else_help(true)
11+
.arg(
12+
Arg::new("config")
13+
.required(true)
14+
.action(ArgAction::Set)
15+
.value_name("config.toml")
16+
.help("Path to the configuration file."),
17+
)
18+
.arg(
19+
Arg::new("key-size")
20+
.long("key-size")
21+
.action(ArgAction::Set)
22+
.default_value("4096")
23+
.help("Size in bits of the RSA private key.")
24+
.value_parser(clap::value_parser!(u32)),
25+
)
26+
.arg(
27+
Arg::new("no-confirm")
28+
.long("no-confirm")
29+
.action(ArgAction::SetTrue)
30+
.help("Do not prompt user and create all non-existing keys."),
31+
)
32+
.get_matches();
33+
let key_size = cli_ops.get_one("key-size").unwrap();
34+
let no_confirm = cli_ops.get_flag("no-confirm");
35+
let config_file = std::fs::read_to_string(cli_ops.get_one::<String>("config").unwrap())?;
36+
let config: Config = toml::from_str(&config_file)?;
37+
'accounts_loop: for account in config.accounts {
38+
if !account.private_key_path.exists() {
39+
println!(
40+
"Private key for account <{}> expected to be located at {} does not exist.",
41+
account.email,
42+
account.private_key_path.display()
43+
);
44+
if !no_confirm {
45+
'input_loop: loop {
46+
print!("Do you want to create it? (y(es) | n(o) -- default: yes)? ");
47+
std::io::stdout().flush()?;
48+
let l = match stdin_lines.next() {
49+
None => return Ok(()),
50+
Some(l) => l?,
51+
};
52+
match l.trim() {
53+
"" | "y" | "yes" | "Y" | "YES" => break 'input_loop,
54+
"n" | "no" | "N" | "NO" => continue 'accounts_loop,
55+
_ => continue 'input_loop,
56+
}
57+
}
58+
}
59+
print!("Generating private key... ");
60+
std::io::stdout().flush()?;
61+
let key = openssl::rsa::Rsa::generate(*key_size)?;
62+
let pem = key.private_key_to_pem()?;
63+
std::fs::write(account.private_key_path, &pem)?;
64+
println!("Private key generated!")
65+
}
66+
}
67+
Ok(())
68+
}

src/main_logic.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ pub async fn process_config_account(
6565
) -> anyhow::Result<()> {
6666
tracing::info!("Processing account {}", &config_account.email);
6767
let priv_key = {
68+
if !config_account.private_key_path.exists() {
69+
bail!(
70+
"Private key for account <{}>, expected to be located at {} does not exist. \
71+
Consider generating it with agnos-generate-accounts-keys.",
72+
config_account.email,
73+
config_account.private_key_path.display()
74+
)
75+
}
6876
let buf = tokio::fs::read(&config_account.private_key_path).await?;
6977
openssl::pkey::PKey::private_key_from_pem(&buf)?
7078
};

test-docker/agnos/Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ FROM chef AS builder
1212
COPY --from=planner /app/recipe.json recipe.json
1313
# Build dependencies - this is the caching Docker layer!
1414
RUN cargo chef cook --recipe-path recipe.json
15-
RUN openssl genrsa 2048 > priv_key_1.pem
16-
RUN openssl genrsa 2048 > priv_key_2.pem
1715
RUN wget https://raw.githubusercontent.com/letsencrypt/pebble/main/test/certs/pebble.minica.pem -O pebbleCA.pem
1816
RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O wait-for-it.sh
1917
# Build application
2018
COPY ./src ./src
2119
COPY ./Cargo.toml ./Cargo.lock ./
2220
COPY ./test-docker/agnos/config_test.toml ./test-docker/agnos/config_test.toml
2321

24-
RUN cargo build --bin agnos
22+
RUN cargo build --bins
23+
RUN /app/target/debug/agnos-generate-accounts-keys --key-size 2048 --no-confirm test-docker/agnos/config_test.toml
2524

2625
EXPOSE 53/tcp 53/udp
2726

0 commit comments

Comments
 (0)