Verified Commit bfd6f3a1 authored by Katharina Fey's avatar Katharina Fey 🏴
Browse files

Adding random shit

parent a96656e8
This diff is collapsed.
[workspace]
members = [
"libforge",
"forge-server",
"forge-cli"
]
# ⚙️ forge
# forge
A small toolkit for managing and rebuilding [NixOS] servers.
- base configurations
- configuration diff's for features
- meta configs to assemble diffs
[NixOS]: https://nixos.org/nixos
What am I trying to solve?
It provides a simple HTTP server which listens for certain token-hashes
which are sent out by our git backend (gitlab in my case).
If the hash matches, a request is handled.
The actual token is used as a secret for a rebuild key.
- Keep all configuration in a git repo, generate symlinks
- Easy config updates without having to manually operate `git`
- Allow for slight (or not so slight) differences between machines
- examples: `.ssh/config` is _very_ device specific (but can share all the global flags)
- Is this specific and can be solved with `poke` ?
- Account for different versions of software per machine
- Might it just be enough to have a metaconfig which defines what configs are activated?
\ No newline at end of file
This way an attacker would need to know the actual token
to get access to the rebuild-key,
but the hash can be stored as part of the configuration
for request checking, without revealing the token secret
## Setup
There's two ways to use `forge`
* As part of the `forge.nix` module (recommended)
* As a standalone server
The server has the ability to either read it's configuration from
`forge.yml` which can be provided as a path via a CLI flag
or the `FORGE_CONFIG_PATH` env variable.
In case it is run via the `forge.nix` module (oh yea!)
you can configure the server with the following code:
```nix
services.forge = {
enable = true; # Enable `forge`
route = "/rebuild"; # The route to handle (on port 443)
token = "<validation token here>";
};
```
There are many more options exposed via the `forge.nix` module so do check those out
if you want to have more fine-grained control over your server.
[package]
name = "forge-cli"
version = "0.1.0"
authors = ["Katharina Fey <kookie@spacekookie.de>"]
edition = "2018"
[dependencies]
libforge = { path = "../libforge" }
use libforge::clap::{App, AppSettings, Arg, SubCommand};
mod secret;
mod setup;
fn main() {
let app = App::new("forge-cli")
.version("0.1.0")
.about("Management CLI for forge")
.setting(AppSettings::SubcommandRequired)
.setting(AppSettings::ColorAuto)
.subcommand(
SubCommand::with_name("secret")
.about("Create embeddable configuration secrets")
.version(secret::VERSION)
.arg(
Arg::with_name("TYPE")
.short("t")
.long("type")
.takes_value(true)
.required(true)
.help("The type of secret")
.possible_values(&["token", "key"]),
).arg(
Arg::with_name("SECRET")
.takes_value(true)
.required(true)
.help("Some secret data"),
),
).subcommand(
SubCommand::with_name("setup")
.about("A guided setup of the forge server (recommended)")
.version(setup::VERSION),
);
match app.get_matches().subcommand() {
("setup", _) => setup::run(),
("secret", Some(m)) => {
secret::run(m.value_of("TYPE").unwrap(), m.value_of("SECRET").unwrap())
}
_ => unreachable!(),
}
}
//! The `secret` utility module which hashes tokens and encrypts user keys
use libforge;
/// The module version
pub const VERSION: &'static str = "0.1.0";
/// Run the `secret` module
pub fn run(tt: &str, secret: &str) {
}
/// The module version
pub const VERSION: &'static str = "0.1.0";
pub fn run() {
}
[package]
name = "forge-server"
version = "0.1.0"
authors = ["Katharina Fey <kookie@spacekookie.de>"]
edition = "2018"
[dependencies]
libforge = { path = "../libforge" }
actix-web = "*"
json = "*"
use actix_web::{http, HttpMessage, server, App, HttpRequest, Json, Responder};
use libforge::clap::{App as ClapApp, Arg, ArgMatches};
use std::convert::From;
use std::env;
#[derive(Clone, Debug)]
struct Params {
bind: String,
port: u16,
route: String,
token: String,
}
impl<'a> From<ArgMatches<'a>> for Params {
fn from(m: ArgMatches<'a>) -> Self {
Self {
bind: m
.value_of("BIND")
.unwrap_or(&env::var("FORGE_BIND").unwrap_or("0.0.0.0".into()))
.into(),
port: m
.value_of("PORT")
.unwrap_or(&env::var("FORGE_PORT").unwrap_or("12220".into()))
.parse::<u16>()
.unwrap(),
route: m
.value_of("ROUTE")
.unwrap_or(&env::var("FORGE_ROUTE").unwrap_or("/rebuild".into()))
.into(),
token: m.value_of("TOKEN").unwrap().into(),
}
}
}
fn handle_token(req: &HttpRequest) -> impl Responder {
println!("{:?}", req);
format!("")
}
fn main() {
let app = ClapApp::new("forge-server")
.version("0.1.0")
.about("The `forge` deployment server")
.arg(
Arg::with_name("BIND")
.long("bind")
.short("b")
.takes_value(true)
.help("Address to bind to (default 0.0.0.0)"),
).arg(
Arg::with_name("PORT")
.long("port")
.short("p")
.takes_value(true)
.help("Port to bind to (default 12220)"),
).arg(
Arg::with_name("ROUTE")
.long("route")
.short("r")
.takes_value(true)
.help("Route to bind to (default \"/rebuild\")"),
).arg(
Arg::with_name("TOKEN")
.long("token")
.short("t")
.takes_value(true)
.required(true)
.help("Token to accept (required)"),
);
// Get parameters from CLI, env vars or default values
let params: Params = app.get_matches().into();
let route = params.route.clone();
server::new(move || {
App::new().resource(&params.bind, |r| {
r.method(http::Method::POST).f(handle_token)
})
}).bind(&format!("{}:{}", params.bind, params.port))
.unwrap()
.run();
}
{ ... }:
{
options = {};
config = {};
}
[package]
name = "libforge"
version = "0.1.0"
authors = ["Katharina Fey <kookie@spacekookie.de>"]
edition = "2018"
[dependencies]
miscreant = "*"
base64 = "*"
clap = "*"
//! Common forge library
pub use clap;
/// Hash some data
pub fn sha256_hash(data: &str, salt: &str ) -> String {
salt.to_owned() + "::" + data
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment