The Simulacrum: Stage 1 #108

Merged
max merged 15 commits from pr-simulacrum-stage-1 into master 2024-08-13 22:06:49 +03:00
3 changed files with 131 additions and 3 deletions
Showing only changes of commit f37fed0ebb - Show all commits

View file

@ -17,7 +17,8 @@ let
}; };
nodes = lib.attrNames config.gods.fromLight; nodes = lib.attrNames config.gods.fromLight;
digits = lib.attrsets.listToAttrs (lib.zipListsWith lib.nameValuePair nodes (lib.range 1 255)); nodes' = lib.attrNames (config.gods.fromLight // { nowhere = null; });
digits = lib.attrsets.listToAttrs (lib.zipListsWith lib.nameValuePair nodes' (lib.range 1 255));
depot' = extendModules { depot' = extendModules {
modules = [ modules = [
({ config, ... }: { ({ config, ... }: {
@ -51,6 +52,12 @@ testers.runNixOSTest {
imports = [ imports = [
serviceConfig.simulacrum.settings serviceConfig.simulacrum.settings
./nowhere
{
nodes.nowhere.imports = [
config.flake.nixosModules.port-magic
];
}
] ++ allAugments; ] ++ allAugments;
_module.args = { _module.args = {
@ -73,12 +80,15 @@ testers.runNixOSTest {
${hour.interfaces.primary.link} = { ${hour.interfaces.primary.link} = {
useDHCP = lib.mkForce false; useDHCP = lib.mkForce false;
virtual = true; virtual = true;
ipv4.addresses = lib.mkForce [ ipv4.addresses = lib.mkForce ([
{ {
address = hour.interfaces.primary.addr; address = hour.interfaces.primary.addr;
prefixLength = 32; prefixLength = 32;
} }
]; ] ++ lib.optional hour.interfaces.primary.isNat {
address = hour.interfaces.primary.addrPublic;
prefixLength = 32;
});
}; };
eth1.ipv4.routes = lib.pipe nodes [ eth1.ipv4.routes = lib.pipe nodes [
(lib.filter (n: n != node)) (lib.filter (n: n != node))
@ -95,6 +105,7 @@ testers.runNixOSTest {
firewall.extraCommands = lib.mkAfter (lib.optionalString (hour.interfaces.primary.isNat) '' firewall.extraCommands = lib.mkAfter (lib.optionalString (hour.interfaces.primary.isNat) ''
# self-nat # self-nat
iptables -t nat -A PREROUTING -d ${hour.interfaces.primary.addrPublic} -j DNAT --to-destination ${hour.interfaces.primary.addr} iptables -t nat -A PREROUTING -d ${hour.interfaces.primary.addrPublic} -j DNAT --to-destination ${hour.interfaces.primary.addr}
iptables -t nat -A OUTPUT -d ${hour.interfaces.primary.addrPublic} -j DNAT --to-destination ${hour.interfaces.primary.addr}
iptables -t nat -A POSTROUTING -s ${hour.interfaces.primary.addr} -j SNAT --to-source ${hour.interfaces.primary.addrPublic} iptables -t nat -A POSTROUTING -s ${hour.interfaces.primary.addr} -j SNAT --to-source ${hour.interfaces.primary.addrPublic}
''); '');
}; };

View file

@ -0,0 +1,101 @@
{ cluster, config, lib, pkgs, ... }:
let
lift = config;
cfsslConfigIntermediateCA = pkgs.writeText "simulacrum-cfssl-config.json" (builtins.toJSON {
signing = {
default.expiry = "8760h";
profiles.intermediate = {
expiry = "8760h";
usages = [
"cert sign"
"crl sign"
];
ca_constraint = {
is_ca = true;
max_path_len = 1;
};
};
};
});
caCsr = pkgs.writeText "simulacrum-ca-csr.json" (builtins.toJSON {
CN = "Simulacrum Root CA";
});
ca = pkgs.runCommand "simulacrum-snakeoil-ca" {
nativeBuildInputs = [
pkgs.cfssl
];
} ''
mkdir $out
cfssl gencert --initca ${caCsr} | cfssljson --bare $out/ca
'';
genCert = extraFlags: csrData: let
csr = pkgs.writeText "simulacrum-csr.json" (builtins.toJSON csrData);
in pkgs.runCommand "simulacrum-snakeoil-cert" {
nativeBuildInputs = [
pkgs.cfssl
];
} ''
mkdir $out
cfssl gencert ${lib.escapeShellArgs ([
"--ca=file:${ca}/ca.pem"
"--ca-key=file:${ca}/ca-key.pem"
] ++ extraFlags ++ [
csr
])} | cfssljson --bare $out/cert
'';
genHostCert = hostname: genCert [ "--hostname=${hostname}" ] { CN = hostname; };
getNodeAddr = node: (builtins.head config.nodes.${node}.networking.interfaces.eth1.ipv4.addresses).address;
in
{
imports = [
./options.nix
];
defaults = {
networking.hosts."${getNodeAddr "nowhere"}" = lib.attrNames config.nowhere.names;
security.pki.certificateFiles = [
"${ca}/ca.pem"
];
};
nowhere.certs = {
inherit ca;
intermediate = genCert [ "--config=${cfsslConfigIntermediateCA}" "--profile=intermediate" ] {
CN = "Simulacrum Intermediate CA";
};
};
nodes.nowhere = { config, depot, ... }: {
networking = {
firewall.allowedTCPPorts = [ 443 ];
interfaces.eth1.ipv4.routes = lib.mapAttrsToList (name: hour: {
address = hour.interfaces.primary.addrPublic;
prefixLength = 32;
via = getNodeAddr name;
}) depot.gods.fromLight;
nameservers = map (name: depot.hours.${name}.interfaces.primary.addrPublic) cluster.config.services.dns.nodes.authoritative;
};
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts = lib.mapAttrs (name: link: let
cert = genHostCert name;
in {
forceSSL = true;
sslCertificate = "${cert}/cert.pem";
sslCertificateKey = "${cert}/cert-key.pem";
locations."/" = {
proxyPass = config.links.${link}.url;
extraConfig = "proxy_ssl_verify off;";
};
}) lift.nowhere.names;
};
};
}

View file

@ -0,0 +1,16 @@
{ lib, ... }:
{
options.nowhere = {
names = lib.mkOption {
description = "Hostnames that point Nowhere.";
type = with lib.types; attrsOf str;
default = {};
};
certs = lib.mkOption {
description = "Snakeoil certificate packages.";
type = with lib.types; attrsOf package;
default = {};
};
};
}