Initial commit
commit
0dd7fb7ac0
@ -0,0 +1,21 @@
|
||||
# Colmena NixOS Config Template
|
||||
|
||||
* user gpg-keys (for them to be able to decrypt the secrets): `secrets/.gpg-id`
|
||||
* collect/generate host gpg-keys: `./lib/create-keys.sh`
|
||||
* edit stuff in password store: `./lib/pass.sh`
|
||||
|
||||
## How to deploy
|
||||
```
|
||||
./deploy.sh apply switch --on vpn7
|
||||
```
|
||||
|
||||
or to deploy all gateways (all hosts with the gateway-tag):
|
||||
|
||||
```
|
||||
./deploy.sh apply switch --on gateway
|
||||
```
|
||||
|
||||
There is a special case for the nixdeploy-host:
|
||||
```
|
||||
./deploy.sh apply-local --node nixdeploy
|
||||
```
|
@ -0,0 +1,44 @@
|
||||
{ pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
nix = {
|
||||
package = pkgs.nixFlakes;
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
trustedUsers = [ "root" "@wheel" ];
|
||||
};
|
||||
|
||||
services.openssh.enable = true;
|
||||
services.openssh.permitRootLogin = "without-password";
|
||||
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
|
||||
time.timeZone = "Europe/Berlin";
|
||||
|
||||
networking.firewall.logRefusedConnections = false;
|
||||
|
||||
programs.mtr.enable = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
bind.dnsutils
|
||||
colmena
|
||||
git
|
||||
gnupg
|
||||
htop
|
||||
rsync
|
||||
tmux
|
||||
wget
|
||||
];
|
||||
|
||||
programs.vim.defaultEditor = true;
|
||||
|
||||
users.users.root = {
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcOPtW5FWNIdlMQFoqeyA1vHw+cA8ft8oXSbXPzQNL9 n0emis@n0emis.eu"
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC8xqVakxJ+AwcIrS/wyL03N++pE09epwMFlIMXWvlpwwEp1J/0H7nygwxk/9LIZdabs/ETWn0s8oHAkc7YR1c6ajSTCDiZEYATAWt7t8t4Gw/80c8u8T50lIqmiDEEVbOVv3Vta/pAN4hAUp9U5DpYCkQbvF+NKKcK3Yp8d9usNC6ohqgTK+IGAEdMhvpbbNppDMXoWHuynBzUX7TS6ST6yEr0tD+CBbCpbfcMuwTI3lNtfywEVpuFaeHqDZx2QDrEX4bg0dRKgQstbXYdqmBfnOiBpUr8Wyl8U1J24rN+E07pBw/8KDGWbVg19/Ex8o4ht/p5voUfKVjD/DwWXTLntBirjfAgQAm4GH/qP4x3zNiTtlYlQFbXSk6VEVrTrxCB5rTWvGnhg31tk5P3YwvagDmGABazY5s/8tlttSc1yWBctWQJCjxSqcCLekxG4D1rVuGKCKOZgflQ9QFdQlKycInPBek3zi0i3GYkE1YnNFye5ggOnxT8qGuKjfdtZI9qvMJQO8lbEDzbYQvNns1V/k4ZobiihYwrG5TJUzZFEpMYetDK6tI8BRU11d+ja0jWzguj5/7wc0nrr/BiZ8FkAr2fZ60j2aI5kG0s3qjbrQbB/RXaGP9hRU0+480+IokNJJIcjv5iwH5ophdrjC8GH4So2kPPt0NXob1yNysdjw== simeon@noemis.me (OLD)"
|
||||
];
|
||||
};
|
||||
|
||||
environment.noXlibs = lib.mkForce false;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DEPLOY_HOST="nixdeploy.neo.cccgoe.de"
|
||||
|
||||
rsync -r . root@${DEPLOY_HOST}:/root/nixfiles/
|
||||
ssh -tA root@${DEPLOY_HOST} "cd /root/nixfiles && colmena $@"
|
@ -0,0 +1,65 @@
|
||||
{
|
||||
"nodes": {
|
||||
"ffnix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1649686725,
|
||||
"narHash": "sha256-t2ByQJ52I67nxdocQRtYOvBD7ZHNt6wRcWqq79EZmGw=",
|
||||
"owner": "n0emis",
|
||||
"repo": "ffnix",
|
||||
"rev": "bdf5dfb77cd474d7fbddc1297526dc1ce339fdb2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "n0emis",
|
||||
"ref": "main",
|
||||
"repo": "ffnix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1644229661,
|
||||
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1647992509,
|
||||
"narHash": "sha256-AG40Nt5OWz0LBs5p457emOuwLKOvTtcv/2fUdnEN3Ws=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d2caa9377539e3b5ff1272ac3aa2d15f3081069f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "release-21.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"ffnix": "ffnix",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
{
|
||||
description = "FFGoe NixOS Config";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/release-21.11";
|
||||
ffnix = {
|
||||
url = "github:n0emis/ffnix/main";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
outputs = { self, nixpkgs, ffnix }: {
|
||||
colmena = {
|
||||
meta = {
|
||||
nixpkgs = import nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
overlays = [
|
||||
ffnix.overlay
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
defaults = { config, lib, name, ... }: {
|
||||
deployment.targetHost = lib.mkDefault (config.networking.hostName + "." + config.networking.domain);
|
||||
|
||||
imports = [
|
||||
(./. + "/hosts/${name}")
|
||||
./common
|
||||
./modules
|
||||
ffnix.nixosModule
|
||||
];
|
||||
};
|
||||
|
||||
vpn7 = {
|
||||
deployment.tags = [ "gateway" "legacy" ];
|
||||
};
|
||||
|
||||
nixdeploy = {
|
||||
deployment.allowLocalDeployment = true;
|
||||
};
|
||||
|
||||
testhost = {
|
||||
deployment.targetHost = "10.152.32.1";
|
||||
};
|
||||
|
||||
dfz-el = {};
|
||||
};
|
||||
};
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
{ config, pkgs, modulesPath, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/virtualisation/lxc-container.nix")
|
||||
];
|
||||
|
||||
networking.hostName = "nixdeploy";
|
||||
networking.domain = "neo.cccgoe.de";
|
||||
|
||||
networking.useNetworkd = true;
|
||||
networking.useDHCP = false;
|
||||
networking.firewall.enable = false;
|
||||
networking.useHostResolvConf = false;
|
||||
|
||||
systemd.suppressedSystemUnits = [
|
||||
"dev-mqueue.mount"
|
||||
"sys-kernel-debug.mount"
|
||||
"sys-fs-fuse-connections.mount"
|
||||
];
|
||||
|
||||
systemd.network = {
|
||||
links."10-eth0" = {
|
||||
matchConfig.MACAddress = "02:a6:13:d1:e4:0b";
|
||||
linkConfig.Name = "eth0";
|
||||
};
|
||||
networks."10-eth0" = {
|
||||
name = "eth0";
|
||||
address = [ "192.168.42.101/24" "2a01:4f8:10b:7e1::1:101/64" ];
|
||||
gateway = [ "192.168.42.1" "2a01:4f8:10b:7e1::1:1" ];
|
||||
};
|
||||
};
|
||||
|
||||
services.resolved.dnssec = "false";
|
||||
|
||||
system.stateVersion = "21.11";
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
read -r -a HOSTS <<< "$(colmena eval lib/get-hosts.nix | jq -r 'to_entries | map("\(.key) \(.value)") | @tsv')"
|
||||
|
||||
p=0
|
||||
while [ "${HOSTS[$p]}" ]
|
||||
do
|
||||
hostname=${HOSTS[$p]}
|
||||
ssh_host=root@${HOSTS[$p+1]}
|
||||
|
||||
echo
|
||||
echo "##### $hostname - $ssh_host"
|
||||
ssh -o ConnectTimeout=10 $ssh_host "echo > /dev/null"
|
||||
rc=$?
|
||||
if [ $rc = 0 ]; then
|
||||
echo "$hostname is online, checking gpg-key"
|
||||
ssh $ssh_host "sudo -u root gpg --fingerprint --with-colons | grep '^fpr' | grep $(cat secrets/$hostname/.gpg-id | tail -n1) > /dev/null"
|
||||
rc=$?
|
||||
else
|
||||
echo "$hostname is offline"
|
||||
rc=0
|
||||
fi
|
||||
|
||||
if ! [ $rc = 0 ]; then
|
||||
echo "generating gpg-key"
|
||||
mkdir -p secrets/$hostname
|
||||
ssh $ssh_host "sudo rm -rf /root/.gnupg"
|
||||
cat lib/keygen | sed "s/NAME/${hostname}/" | ssh -o RequestTTY=yes $ssh_host "sudo -u root gpg --generate-key --pinentry-mode loopback --batch /dev/stdin"
|
||||
cp secrets/.gpg-id secrets/$hostname/.gpg-id
|
||||
ssh $ssh_host "sudo -u root gpg --fingerprint --with-colons | grep '^fpr' | head -n1 | cut -d: -f10" >> secrets/$hostname/.gpg-id
|
||||
ssh $ssh_host "sudo -u root gpg --fingerprint --with-colons | grep '^fpr' | head -n1 | cut -d: -f10" >> secrets/all/.gpg-id
|
||||
ssh $ssh_host "sudo -u root gpg --export --armor" > secrets/.public-keys/$hostname
|
||||
lib/pass.sh init -p $hostname $(cat secrets/$hostname/.gpg-id);
|
||||
lib/pass.sh init -p all $(cat secrets/all/.gpg-id);
|
||||
else
|
||||
echo "key does already exist..."
|
||||
fi
|
||||
|
||||
let p=p+2
|
||||
done
|
||||
|
@ -0,0 +1,3 @@
|
||||
{ nodes, pkgs, lib, ... }:
|
||||
# Feels like a NixOS module - But you can return any JSON-serializable value
|
||||
lib.attrsets.mapAttrs (k: v: v.config.deployment.targetHost) nodes
|
@ -0,0 +1,11 @@
|
||||
%echo Generating ed25519 primary and cv25519 subkey
|
||||
Key-Type: eddsa
|
||||
Key-Curve: Ed25519
|
||||
Key-Usage: sign
|
||||
Name-Real: NAME
|
||||
Subkey-Type: ecdh
|
||||
Subkey-Curve: Curve25519
|
||||
Expire-Date: 0
|
||||
%no-protection
|
||||
%commit
|
||||
%echo done
|
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
for key in secrets/.public-keys/*
|
||||
do
|
||||
gpg --import "$key" 2>/dev/null
|
||||
done
|
||||
|
||||
export PASSWORD_STORE_GPG_OPTS="--trust-model always"
|
||||
export PASSWORD_STORE_DIR="$PWD/secrets"
|
||||
pass $@
|
||||
|
@ -0,0 +1,7 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./secrets
|
||||
];
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
secret-file = types.submodule ({ ... }@moduleAttrs: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
default = moduleAttrs.config._module.args.name;
|
||||
};
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
readOnly = true;
|
||||
default = "/run/secrets/${removeSuffix ".gpg" (baseNameOf moduleAttrs.config.source-path)}";
|
||||
};
|
||||
mode = mkOption {
|
||||
type = types.str;
|
||||
default = "0400";
|
||||
};
|
||||
owner = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
};
|
||||
group-name = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
};
|
||||
source-path = mkOption {
|
||||
type = types.str;
|
||||
default = pkgs.copyPathToStore "${toString ../../secrets}/${config.networking.hostName}/${moduleAttrs.config.name}.gpg";
|
||||
};
|
||||
encrypted = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
});
|
||||
enabledFiles = filterAttrs (n: file: file.enable) config.petabyte.secrets;
|
||||
|
||||
mkDecryptSecret = file: pkgs.writeScript "decrypt-secret-${removeSuffix ".gpg" (baseNameOf file.source-path)}.sh" ''
|
||||
#!${pkgs.runtimeShell}
|
||||
set -eu pipefail
|
||||
if [ ! -f "${file.path}" ]; then
|
||||
umask 0077
|
||||
echo "${file.source-path} -> ${file.path}"
|
||||
${if file.encrypted then ''
|
||||
${pkgs.gnupg}/bin/gpg --decrypt ${escapeShellArg file.source-path} > ${file.path}
|
||||
'' else ''
|
||||
cat ${escapeShellArg file.source-path} > ${file.path}
|
||||
''}
|
||||
fi
|
||||
'';
|
||||
mkSetupSecret = file: pkgs.writeScript "setup-secret-${removeSuffix ".gpg" (baseNameOf file.source-path)}.sh" ''
|
||||
#!${pkgs.runtimeShell}
|
||||
set -eu pipefail
|
||||
chown ${escapeShellArg file.owner}:${escapeShellArg file.group-name} ${escapeShellArg file.path}
|
||||
chmod ${escapeShellArg file.mode} ${escapeShellArg file.path}
|
||||
'';
|
||||
|
||||
in {
|
||||
options.petabyte.secrets = mkOption {
|
||||
type = with types; attrsOf secret-file;
|
||||
default = {};
|
||||
};
|
||||
config = mkIf (enabledFiles != {}) {
|
||||
system.activationScripts = let
|
||||
files = unique (map (flip removeAttrs ["_module"]) (attrValues enabledFiles));
|
||||
decrypt = ''
|
||||
function fail() {
|
||||
rm $1
|
||||
echo "failed to decrypt $1"
|
||||
}
|
||||
echo setting up secrets...
|
||||
mkdir -p /run/secrets
|
||||
chown 0:0 /run/secrets
|
||||
chmod 0755 /run/secrets
|
||||
${concatMapStringsSep "\n" (file: ''
|
||||
${mkDecryptSecret file} || fail ${file.path}
|
||||
'') files}
|
||||
'';
|
||||
setup = ''
|
||||
echo setting up secrets...
|
||||
${concatMapStringsSep "\n" (file: ''
|
||||
${mkSetupSecret file} || echo "failed to set up ${file.path}"
|
||||
'') files}
|
||||
'';
|
||||
in {
|
||||
decrypt-secrets.text = "source ${pkgs.writeText "setup-secrets.sh" decrypt}";
|
||||
setup-secrets = stringAfter [ "users" "groups" ] "source ${pkgs.writeText "setup-secrets.sh" setup}";
|
||||
users.deps = [ "decrypt-secrets" ];
|
||||
};
|
||||
};
|
||||
}
|
@ -0,0 +1 @@
|
||||
6E10217E3187069E057DF5ABE0262A773B824745
|
@ -0,0 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEYiyiyxYJKwYBBAHaRw8BAQdAPsPSocI7hwg1Ll+MQtAkXB97Fs4wS6jAgHJy
|
||||
4tIV6Yq0CW5peGRlcGxveYiQBBMWCAA4FiEERpX3ufdo1Ms5XHiPp9zPzW66SHsF
|
||||
AmIsossCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQp9zPzW66SHvCUQEA
|
||||
wDc+ifC0KX1diclphsmr379u1zIyCgQnzo1CZfzbfksBAMGHrPrGC01Yhijvp8Op
|
||||
97rCKi5Tc9o3pzIGaQhxheMGuDgEYiyiyxIKKwYBBAGXVQEFAQEHQNBwRBfv1C/n
|
||||
Kj7Zwa4tW/oDO/CofWpZc/rBLW2DTQVnAwEIB4h4BBgWCAAgFiEERpX3ufdo1Ms5
|
||||
XHiPp9zPzW66SHsFAmIsossCGwwACgkQp9zPzW66SHtIvgEAm3V0VlCWh3vAu2sS
|
||||
3kolo3C3O8VNljTZpjyHX9uZb0sA/0kjj9ySpLWg9ct1w9Xq1rx8NAqg3717QfEV
|
||||
Eu93PqIH
|
||||
=sw4f
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
@ -0,0 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEYiyjMBYJKwYBBAHaRw8BAQdA6Eqvi71nq1N0YXSv2H7bQPuNhRN71OrMDCav
|
||||
hcuHz9i0BHZwbjeIkAQTFggAOBYhBIkqg13mIq22arDfh8nOp4wJbO8QBQJiLKMw
|
||||
AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEMnOp4wJbO8Q+YQBAPka4X71
|
||||
eeJ+fOLgE2JlyqXRcGzKtEz5YzAFP74oC2vBAP9w0MrbRVtzwQPa4Omyy1SMtwoP
|
||||
a2QmPB52aJ6nhfBlArg4BGIsozASCisGAQQBl1UBBQEBB0C+DsCLXf4vApdVZ71N
|
||||
wjQUGQp9nd6zyMXXsl7oPfGvDQMBCAeIeAQYFggAIBYhBIkqg13mIq22arDfh8nO
|
||||
p4wJbO8QBQJiLKMwAhsMAAoJEMnOp4wJbO8QrhMBAKcljw2BYS05IPev6kKdrlZ4
|
||||
0H3l4So/GlaI/bkhyEdHAQDytHkdN4TK4QF/p6i/6+F0pClZJINm9aOlCksq3thv
|
||||
AQ==
|
||||
=qCbs
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
@ -0,0 +1,4 @@
|
||||
6E10217E3187069E057DF5ABE0262A773B824745
|
||||
F1D6AA729DE5DDF5F94CEEE2D764341778B42777
|
||||
4695F7B9F768D4CB395C788FA7DCCFCD6EBA487B
|
||||
892A835DE622ADB66AB0DF87C9CEA78C096CEF10
|
@ -0,0 +1,2 @@
|
||||
6E10217E3187069E057DF5ABE0262A773B824745
|
||||
4695F7B9F768D4CB395C788FA7DCCFCD6EBA487B
|
@ -0,0 +1,2 @@
|
||||
6E10217E3187069E057DF5ABE0262A773B824745
|
||||
892A835DE622ADB66AB0DF87C9CEA78C096CEF10
|
Loading…
Reference in New Issue