Cluster secrets #100

Merged
max merged 17 commits from pr-cluster-secrets into master 2024-07-08 22:23:11 +03:00
90 changed files with 396 additions and 361 deletions

View file

@ -1,52 +1,6 @@
{ config, lib, ... }:
let
inherit (config) cluster flake;
in
{
perSystem = { config, pkgs, ... }: {
catalog.cluster = {
services = lib.mapAttrs (name: svc: {
description = "Cluster service: ${name}";
actions = let
mkDeployAction = { description, agents }: {
inherit description;
packages = [
config.packages.cachix
pkgs.tmux
];
command = let
cachixDeployJson = pkgs.writeText "cachix-deploy.json" (builtins.toJSON {
agents = lib.genAttrs agents (name: builtins.unsafeDiscardStringContext flake.nixosConfigurations.${name}.config.system.build.toplevel);
});
in ''
set -e
echo building ${toString (lib.length agents)} configurations in parallel
tmux new-session ${lib.concatStringsSep " split-window " (
map (host: let
drvPath = builtins.unsafeDiscardStringContext flake.nixosConfigurations.${host}.config.system.build.toplevel.drvPath;
in '' 'echo building configuration for ${host}; nix build -L --no-link --store "ssh-ng://${host}" --eval-store auto "${drvPath}^*"'\; '') agents
)} select-layout even-vertical
source ~/.config/cachix/deploy
cachix deploy activate ${cachixDeployJson}
echo
'';
};
in {
deployAll = mkDeployAction {
description = "Deploy ALL groups of this service.";
agents = lib.unique (lib.concatLists (lib.attrValues svc.nodes));
};
} // lib.mapAttrs' (group: agents: {
name = "deployGroup-${group}";
value = mkDeployAction {
description = "Deploy the '${group}' group of this service.";
inherit agents;
};
}) svc.nodes;
}) cluster.config.services;
};
};
imports = [
./services.nix
./secrets.nix
];
}

View file

@ -0,0 +1,73 @@
{ config, lib, withSystem, ... }:
let
inherit (config) cluster hours;
in
{
perSystem = { config, pkgs, system, ... }: {
catalog.cluster = {
secrets = lib.pipe cluster.config.services [
(lib.mapAttrsToList (svcName: svcConfig: lib.mapAttrsToList (secretName: secretConfig: {
name = "${svcName}/${secretName}";
value = {
description = "Cluster secret '${secretName}' of service '${svcName}'";
actions = let
agenixRules = builtins.toFile "agenix-rules-shim.nix" /*nix*/ ''
builtins.fromJSON (builtins.readFile (builtins.getEnv "AGENIX_KEYS_JSON"))
'';
mkKeys = secretFile: nodes: builtins.toFile "agenix-keys.json" (builtins.toJSON {
"${secretFile}".publicKeys = (map (hour: hours.${hour}.ssh.id.publicKey) nodes) ++ cluster.config.secrets.extraKeys;
});
setupCommands = secretFile: nodes: let
agenixKeysJson = mkKeys secretFile nodes;
in ''
export RULES='${agenixRules}'
export AGENIX_KEYS_JSON='${agenixKeysJson}'
mkdir -p "$PRJ_ROOT/cluster/secrets"
cd "$PRJ_ROOT/cluster/secrets"
'';
in (lib.optionalAttrs (secretConfig.generate != null) {
generateSecret = {
description = "Generate this secret";
command = if secretConfig.shared then let
secretFile = "${svcName}-${secretName}.age";
in ''
${setupCommands secretFile secretConfig.nodes}
${withSystem system secretConfig.generate} | agenix -e '${secretFile}'
'' else lib.concatStringsSep "\n" (map (node: let
secretFile = "${svcName}-${secretName}-${node}.age";
in ''
${setupCommands secretFile [ node ]}
${withSystem system secretConfig.generate} | agenix -e '${secretFile}'
'') secretConfig.nodes);
};
}) // (if secretConfig.shared then let
secretFile = "${svcName}-${secretName}.age";
in {
editSecret = {
description = "Edit this secret";
command = ''
${setupCommands secretFile secretConfig.nodes}
agenix -e '${secretFile}'
'';
};
} else lib.mapAttrs' (name: lib.nameValuePair "editSecretInstance-${name}") (lib.genAttrs secretConfig.nodes (node: let
secretFile = "${svcName}-${secretName}-${node}.age";
in {
description = "Edit this secret for '${node}'";
command = ''
${setupCommands secretFile [ node ]}
agenix -e '${secretFile}'
'';
})));
};
}) svcConfig.secrets))
lib.concatLists
lib.listToAttrs
];
};
};
}

View file

@ -0,0 +1,52 @@
{ config, lib, ... }:
let
inherit (config) cluster flake;
in
{
perSystem = { config, pkgs, ... }: {
catalog.cluster = {
services = lib.mapAttrs (name: svc: {
description = "Cluster service: ${name}";
actions = let
mkDeployAction = { description, agents }: {
inherit description;
packages = [
config.packages.cachix
pkgs.tmux
];
command = let
cachixDeployJson = pkgs.writeText "cachix-deploy.json" (builtins.toJSON {
agents = lib.genAttrs agents (name: builtins.unsafeDiscardStringContext flake.nixosConfigurations.${name}.config.system.build.toplevel);
});
in ''
set -e
echo building ${toString (lib.length agents)} configurations in parallel
tmux new-session ${lib.concatStringsSep " split-window " (
map (host: let
drvPath = builtins.unsafeDiscardStringContext flake.nixosConfigurations.${host}.config.system.build.toplevel.drvPath;
in '' 'echo building configuration for ${host}; nix build -L --no-link --store "ssh-ng://${host}" --eval-store auto "${drvPath}^*"'\; '') agents
)} select-layout even-vertical
source ~/.config/cachix/deploy
cachix deploy activate ${cachixDeployJson}
echo
'';
};
in {
deployAll = mkDeployAction {
description = "Deploy ALL groups of this service.";
agents = lib.unique (lib.concatLists (lib.attrValues svc.nodes));
};
} // lib.mapAttrs' (group: agents: {
name = "deployGroup-${group}";
value = mkDeployAction {
description = "Deploy the '${group}' group of this service.";
inherit agents;
};
}) svc.nodes;
}) cluster.config.services;
};
};
}

View file

@ -15,6 +15,7 @@ lib.evalModules {
./lib/inject-nixos-config.nix
./lib/port-magic-multi.nix
./lib/mesh.nix
./lib/secrets.nix
./import-services.nix
];

14
cluster/lib/secrets.nix Normal file
View file

@ -0,0 +1,14 @@
{ lib, ... }:
{
options.secrets = {
extraKeys = lib.mkOption {
type = with lib.types; listOf str;
description = "Additional keys with which to encrypt all secrets.";
default = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL5C7mC5S2gM0K6x0L/jNwAeQYbFSzs16Q73lONUlIkL max@TITAN"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMmdWfmAs/0rno8zJlhBFMY2SumnHbTNdZUXJqxgd9ON max@jericho"
];
};
};
}

View file

@ -7,6 +7,10 @@ let
in
{
imports = [
./services/secrets.nix
];
options = {
nodes = mkOption {
description = ''

View file

@ -2,10 +2,29 @@
with lib;
let
getHostConfigurations = hostName: svcConfig:
lib.mapAttrsToList (groupName: _: svcConfig.nixos.${groupName})
(lib.filterAttrs (_: lib.elem hostName) svcConfig.nodes);
getHostConfigurations = hostName: svcName: svcConfig: let
serviceConfigs =
lib.mapAttrsToList (groupName: _: svcConfig.nixos.${groupName})
(lib.filterAttrs (_: lib.elem hostName) svcConfig.nodes);
secretsConfig = let
secrets = lib.filterAttrs (_: secret: lib.any (node: node == hostName) secret.nodes) svcConfig.secrets;
in {
age.secrets = lib.mapAttrs' (secretName: secretConfig: {
name = "cluster-${svcName}-${secretName}";
value = {
inherit (secretConfig) path mode owner group;
file = ../secrets/${svcName}-${secretName}${lib.optionalString (!secretConfig.shared) "-${hostName}"}.age;
};
}) secrets;
systemd.services = lib.mkMerge (lib.mapAttrsToList (secretName: secretConfig: lib.genAttrs secretConfig.services (systemdServiceName: {
restartTriggers = [ "${../secrets/${svcName}-${secretName}${lib.optionalString (!secretConfig.shared) "-${hostName}"}.age}" ];
})) secrets);
};
in serviceConfigs ++ [
secretsConfig
];
introspectionModule._module.args.cluster = {
inherit (config) vars;
@ -20,7 +39,7 @@ in
default = {};
};
config.out.injectNixosConfig = hostName: (lib.flatten (lib.mapAttrsToList (_: getHostConfigurations hostName) config.services)) ++ [
config.out.injectNixosConfig = hostName: (lib.flatten (lib.mapAttrsToList (getHostConfigurations hostName) config.services)) ++ [
introspectionModule
];
}

View file

@ -0,0 +1,57 @@
{ lib, name, ... }:
let
serviceName = name;
in
{
options.secrets = lib.mkOption {
type = lib.types.lazyAttrsOf (lib.types.submodule ({ config, name, ... }: {
options = {
shared = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether this secret should be the same on all nodes.";
};
nodes = lib.mkOption {
type = with lib.types; listOf str;
default = [ ];
};
generate = lib.mkOption {
type = with lib.types; nullOr (functionTo str);
description = "Command used to generate this secret.";
default = null;
};
path = lib.mkOption {
type = lib.types.path;
default = "/run/agenix/cluster-${serviceName}-${name}";
};
mode = lib.mkOption {
type = lib.types.str;
default = "0400";
};
owner = lib.mkOption {
type = lib.types.str;
default = "root";
};
group = lib.mkOption {
type = lib.types.str;
default = "root";
};
services = lib.mkOption {
type = with lib.types; listOf str;
description = "Services to restart when this secret changes.";
default = [];
};
};
}));
default = {};
};
}

View file

@ -12,6 +12,21 @@
./nar-serve.nix
];
};
secrets = let
inherit (config.services.attic) nodes;
in {
serverToken = {
nodes = nodes.server;
};
dbCredentials = {
nodes = nodes.server;
owner = "atticd";
};
s3Credentials = {
nodes = nodes.server;
owner = "atticd";
};
};
};
garage = {

View file

@ -1,7 +1,7 @@
{ cluster, config, depot, lib, ... }:
let
inherit (config.networking) hostName;
inherit (cluster.config.services.attic) secrets;
in
{
@ -9,26 +9,12 @@ in
depot.inputs.attic.nixosModules.atticd
];
age.secrets = {
atticServerToken.file = ./attic-server-token.age;
atticDBCredentials = {
file = ./attic-db-credentials.age;
owner = "atticd";
};
atticS3Credentials = {
file = ./attic-s3-credentials.age;
owner = "atticd";
};
};
links.atticServer.protocol = "http";
services.atticd = {
enable = true;
credentialsFile = config.age.secrets.atticServerToken.path;
credentialsFile = secrets.serverToken.path;
settings = {
listen = config.links.atticServer.tuple;
@ -74,8 +60,8 @@ in
DynamicUser = lib.mkForce false;
};
environment = {
AWS_SHARED_CREDENTIALS_FILE = config.age.secrets.atticS3Credentials.path;
PGPASSFILE = config.age.secrets.atticDBCredentials.path;
AWS_SHARED_CREDENTIALS_FILE = secrets.s3Credentials.path;
PGPASSFILE = secrets.dbCredentials.path;
};
};

View file

@ -1,11 +1,9 @@
{ config, depot, ... }:
{ cluster, depot, ... }:
{
age.secrets.cachixDeployToken.file = ./credentials/${config.networking.hostName}.age;
services.cachix-agent = {
enable = true;
credentialsFile = config.age.secrets.cachixDeployToken.path;
credentialsFile = cluster.config.services.cachix-deploy-agent.secrets.token.path;
package = depot.packages.cachix;
};
}

View file

@ -1,6 +1,10 @@
{
services.cachix-deploy-agent = {
services.cachix-deploy-agent = { config, ... }: {
nodes.agent = [ "checkmate" "grail" "prophet" "VEGAS" "thunderskin" ];
nixos.agent = ./agent.nix;
secrets.token = {
nodes = config.nodes.agent;
shared = false;
};
};
}

View file

@ -8,6 +8,15 @@
name = "forge";
link.protocol = "http";
};
secrets = with config.services.forge.nodes; {
oidcSecret = {
nodes = server;
owner = "forgejo";
};
dbCredentials.nodes = server;
s3AccessKeyID.nodes = server;
s3SecretAccessKey.nodes = server;
};
};
ways.forge.target = let

View file

@ -2,8 +2,7 @@
let
inherit (depot.lib.meta) domain;
inherit (depot.lib.nginx) vhosts;
inherit (config.age) secrets;
inherit (cluster.config.services.forge) secrets;
patroni = cluster.config.links.patroni-pg-access;
@ -24,25 +23,6 @@ in
];
};
age.secrets = {
forgejoOidcSecret = {
file = ./credentials/forgejo-oidc-secret.age;
owner = "forgejo";
};
forgejoDbCredentials = {
file = ./credentials/forgejo-db-credentials.age;
owner = "forgejo";
};
forgejoS3AccessKeyID = {
file = ./credentials/forgejo-s3-access-key-id.age;
owner = "forgejo";
};
forgejoS3SecretAccessKey = {
file = ./credentials/forgejo-s3-secret-access-key.age;
owner = "forgejo";
};
};
services.forgejo = {
enable = true;
package = depot.packages.forgejo;
@ -54,7 +34,7 @@ in
inherit (patroni) port;
name = "forge";
user = "forge";
passwordFile = secrets.forgejoDbCredentials.path;
passwordFile = secrets.dbCredentials.path;
};
settings = {
DEFAULT = {
@ -93,8 +73,8 @@ in
};
secrets = {
storage = {
MINIO_ACCESS_KEY_ID = secrets.forgejoS3AccessKeyID.path;
MINIO_SECRET_ACCESS_KEY = secrets.forgejoS3SecretAccessKey.path;
MINIO_ACCESS_KEY_ID = secrets.s3AccessKeyID.path;
MINIO_SECRET_ACCESS_KEY = secrets.s3SecretAccessKey.path;
};
};
};
@ -112,9 +92,9 @@ in
in lib.mkAfter /*bash*/ ''
providerId="$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1)"
if [[ -z "$providerId" ]]; then
FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${secrets.forgejoOidcSecret.path})" ${exe} admin auth add-oauth ${args}
FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${secrets.oidcSecret.path})" ${exe} admin auth add-oauth ${args}
else
FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${secrets.forgejoOidcSecret.path})" ${exe} admin auth update-oauth --id "$providerId" ${args}
FORGEJO_ADMIN_OAUTH2_SECRET="$(< ${secrets.oidcSecret.path})" ${exe} admin auth update-oauth --id "$providerId" ${args}
fi
'';
}

View file

@ -1,7 +1,9 @@
{ config, depot, lib, pkgs, ... }:
{ cluster, depot, lib, ... }:
let
mapAgents = lib.flip lib.mapAttrs config.services.hercules-ci-agents;
inherit (cluster.config.services.hercules-ci-multi-agent) nodes secrets;
mapAgents = lib.flip lib.mapAttrs nodes;
mergeMap = f: let
outputs = mapAgents f;
@ -20,32 +22,26 @@ in
./modules/multi-agent-refactored
];
age.secrets = mergeMap (name: _: {
hci-token = {
file = ./secrets + "/hci-token-${name}-${config.networking.hostName}.age";
owner = "hci-${name}";
group = "hci-${name}";
};
hci-cache-credentials = {
file = ./secrets + "/hci-cache-credentials-${config.networking.hostName}.age";
owner = "hci-${name}";
group = "hci-${name}";
};
hci-cache-config = {
file = ./secrets/hci-cache-config.age;
owner = "hci-${name}";
group = "hci-${name}";
};
});
systemd.services = mergeMap (name: _: {
systemd.services = mergeMap (_: _: {
hercules-ci-agent = {
# hercules-ci-agent-restarter should take care of this
restartIfChanged = false;
environment = {
AWS_SHARED_CREDENTIALS_FILE = config.age.secrets."hci-cache-credentials-${name}".path;
AWS_SHARED_CREDENTIALS_FILE = secrets.cacheCredentials.path;
AWS_EC2_METADATA_DISABLED = "true";
};
serviceConfig.Slice = "builder.slice";
};
});
services.hercules-ci-agents = lib.genAttrs (lib.attrNames nodes) (org: {
enable = true;
package = depot.inputs.hercules-ci-agent.packages.hercules-ci-agent;
settings = {
clusterJoinTokenPath = secrets."clusterJoinToken-${org}".path;
binaryCachesPath = secrets.cacheConfig.path;
};
});
users.groups.hercules-ci-agent.members = map (org: "hci-${org}") (lib.attrNames nodes);
}

View file

@ -1,4 +1,4 @@
{ config, lib, depot, ... }:
{ config, lib, ... }:
{
services.hercules-ci-multi-agent = {
@ -11,21 +11,49 @@
nixos = {
private-void = [
./common.nix
./orgs/private-void.nix
{
services.hercules-ci-agents.private-void.settings = {
secretsJsonPath = config.services.hercules-ci-multi-agent.secrets.effectsSecrets.path;
};
}
];
nixpak = [
./common.nix
./orgs/nixpak.nix
];
max = [
./common.nix
./orgs/max.nix
];
hyprspace = [
./common.nix
./orgs/hyprspace.nix
];
};
secrets = let
inherit (config.services.hercules-ci-multi-agent) nodes;
allNodes = lib.unique (lib.concatLists (lib.attrValues nodes));
in {
cacheConfig = {
nodes = allNodes;
mode = "0440";
group = "hercules-ci-agent";
};
cacheCredentials = {
nodes = allNodes;
shared = false;
mode = "0440";
group = "hercules-ci-agent";
};
effectsSecrets = {
nodes = nodes.private-void;
owner = "hci-private-void";
};
} // lib.mapAttrs' (org: nodes: {
name = "clusterJoinToken-${org}";
value = {
inherit nodes;
shared = false;
owner = "hci-${org}";
};
}) nodes;
};
garage = let
hciAgentKeys = lib.pipe config.services.hercules-ci-multi-agent.nodes [

View file

@ -1,12 +0,0 @@
{ config, lib, depot, pkgs, ... }:
{
services.hercules-ci-agents.hyprspace = {
enable = true;
package = depot.inputs.hercules-ci-agent.packages.hercules-ci-agent;
settings = {
clusterJoinTokenPath = config.age.secrets.hci-token-hyprspace.path;
binaryCachesPath = config.age.secrets.hci-cache-config-hyprspace.path;
};
};
}

View file

@ -1,12 +0,0 @@
{ config, lib, depot, pkgs, ... }:
{
services.hercules-ci-agents.max = {
enable = true;
package = depot.inputs.hercules-ci-agent.packages.hercules-ci-agent;
settings = {
clusterJoinTokenPath = config.age.secrets.hci-token-max.path;
binaryCachesPath = config.age.secrets.hci-cache-config-max.path;
};
};
}

View file

@ -1,12 +0,0 @@
{ config, lib, depot, pkgs, ... }:
{
services.hercules-ci-agents.nixpak = {
enable = true;
package = depot.inputs.hercules-ci-agent.packages.hercules-ci-agent;
settings = {
clusterJoinTokenPath = config.age.secrets.hci-token-nixpak.path;
binaryCachesPath = config.age.secrets.hci-cache-config-nixpak.path;
};
};
}

View file

@ -1,18 +0,0 @@
{ config, lib, depot, pkgs, ... }:
{
age.secrets.hci-effects-secrets-private-void = {
file = ../secrets/hci-effects-secrets-private-void.age;
owner = "hci-private-void";
group = "hci-private-void";
};
services.hercules-ci-agents.private-void = {
enable = true;
package = depot.inputs.hercules-ci-agent.packages.hercules-ci-agent;
settings = {
clusterJoinTokenPath = config.age.secrets.hci-token-private-void.path;
binaryCachesPath = config.age.secrets.hci-cache-config-private-void.path;
secretsJsonPath = config.age.secrets.hci-effects-secrets-private-void.path;
};
};
}

View file

@ -5,10 +5,8 @@ let
in
{
age.secrets.idmServiceAccountCredentials.file = ./secrets/service-account-${config.networking.hostName}.age;
systemd.services.kanidm-unixd.serviceConfig = {
EnvironmentFile = config.age.secrets.idmServiceAccountCredentials.path;
EnvironmentFile = cluster.config.services.idm.secrets.serviceAccountCredentials.path;
};
services.kanidm = {

View file

@ -33,6 +33,10 @@
./policies/soda.nix
];
};
secrets.serviceAccountCredentials = {
nodes = config.services.idm.nodes.client;
shared = false;
};
};
dns.records = let

View file

@ -1,8 +1,9 @@
{ config, depot, lib, pkgs, ... }:
{ cluster, config, depot, lib, ... }:
let
inherit (depot.lib.meta) domain;
inherit (depot.lib.nginx) vhosts;
inherit (cluster.config.services.ipfs) secrets;
cfg = config.services.ipfs-cluster;
ipfsCfg = config.services.ipfs;
@ -19,20 +20,12 @@ in {
incantations = i: [ ];
};
age.secrets = {
ipfs-cluster-secret.file = ./cluster-secret.age;
ipfs-cluster-pinsvc-credentials = {
file = ./cluster-pinsvc-credentials.age;
owner = cfg.user;
};
};
services.ipfs-cluster = {
enable = true;
consensus = "crdt";
dataDir = "/srv/storage/ipfs/cluster";
secretFile = config.age.secrets.ipfs-cluster-secret.path;
pinSvcBasicAuthFile = config.age.secrets.ipfs-cluster-pinsvc-credentials.path;
secretFile = secrets.clusterSecret.path;
pinSvcBasicAuthFile = secrets.pinningServiceCredentials.path;
openSwarmPort = true;
settings = {
cluster = {

View file

@ -47,6 +47,17 @@
io-tweaks = ./io-tweaks.nix;
remote-api = ./remote-api.nix;
};
secrets = let
inherit (config.services.ipfs) nodes;
in {
clusterSecret = {
nodes = nodes.clusterPeer;
};
pinningServiceCredentials = {
nodes = nodes.clusterPeer;
owner = "ipfs";
};
};
};
monitoring.blackbox.targets.ipfs-gateway = {

View file

@ -12,11 +12,6 @@ let
in
{
vars = {
ircPeerKey = {
file = ./irc-peer-key.age;
owner = "ngircd";
group = "ngircd";
};
ircOpers = [ "max" "num" "ark" ];
};
hostLinks = lib.genAttrs config.services.irc.nodes.host (name: {
@ -50,6 +45,11 @@ in
./irc-host.nix
];
};
secrets.peerKey = {
nodes = config.services.irc.nodes.host;
owner = "ngircd";
services = [ "ngircd" ];
};
};
monitoring.blackbox.targets = {

View file

@ -93,17 +93,15 @@ in {
auth required ${pkgs.kanidm}/lib/pam_kanidm.so
'';
};
age.secrets = { inherit (vars) ircPeerKey; };
systemd.services.ngircd = {
after = [ "acme-finished-${serverName}.target" "dhparams-gen-ngircd.service" ];
wants = [ "acme-finished-${serverName}.target" "dhparams-gen-ngircd.service" ];
restartTriggers = [ "${config.age.secrets.ircPeerKey.file}" ];
serviceConfig.RuntimeDirectory = "ngircd";
preStart = ''
install -d -m700 /run/ngircd/secrets
for cfg in ${builtins.concatStringsSep " " otherServerFiles}; do
install -m600 $cfg /run/ngircd/secrets/
${pkgs.replace-secret}/bin/replace-secret '@PEER_PASSWORD@' '${config.age.secrets.ircPeerKey.path}' /run/ngircd/secrets/$(basename $cfg)
${pkgs.replace-secret}/bin/replace-secret '@PEER_PASSWORD@' '${cluster.config.services.irc.secrets.peerKey.path}' /run/ngircd/secrets/$(basename $cfg)
done
'';
};

View file

@ -1,19 +1,11 @@
{ config, depot, ... }:
{ cluster, depot, ... }:
let
inherit (depot.lib.meta) domain;
in
{
age.secrets = {
matrix-appservice-discord-token = {
file = ../../../../secrets/matrix-appservice-discord-token.age;
owner = "root";
group = "root";
mode = "0400";
};
};
services.matrix-appservice-discord = {
enable = true;
environmentFile = config.age.secrets.matrix-appservice-discord-token.path;
environmentFile = cluster.config.services.matrix.secrets.discordAppServiceToken.path;
settings = {
bridge = {
inherit domain;

View file

@ -1,13 +1,5 @@
{ config, depot, ... }:
{ cluster, depot, ... }:
{
age.secrets = {
coturn-static-auth = {
file = ../../../secrets/coturn-static-auth.age;
owner = "turnserver";
group = "root";
mode = "0400";
};
};
services.coturn = {
enable = true;
no-cli = true;
@ -22,7 +14,7 @@
lt-cred-mech = true;
use-auth-secret = true;
static-auth-secret-file = config.age.secrets.coturn-static-auth.path;
static-auth-secret-file = cluster.config.services.matrix.secrets.coturnStaticAuth.path;
# TODO: acme
cert = "/etc/coturn/certs/fullchain.pem";
pkey = "/etc/coturn/certs/privkey.pem";

View file

@ -17,6 +17,23 @@
./web-client.nix
];
};
secrets = let
inherit (config.services.matrix) nodes;
default = {
nodes = nodes.homeserver;
owner = "matrix-synapse";
};
in {
ldapConfig = default;
dbConfig = default;
turnConfig = default;
keysConfig = default;
coturnStaticAuth = {
nodes = nodes.homeserver;
owner = "turnserver";
};
discordAppServiceToken.nodes = nodes.homeserver;
};
};
monitoring.blackbox.targets.matrix = {

View file

@ -1,6 +1,7 @@
{ cluster, config, lib, pkgs, depot, ... }:
let
inherit (depot.lib.meta) domain;
inherit (cluster.config.services.matrix) secrets;
patroni = cluster.config.links.patroni-pg-access;
@ -51,36 +52,10 @@ let
clientConfigJSON = pkgs.writeText "matrix-client-config.json" (builtins.toJSON clientConfig);
logConfigJSON = pkgs.writeText "matrix-log-config.json" (builtins.toJSON logConfig);
dbConfigJSON = pkgs.writeText "matrix-log-config.json" (builtins.toJSON dbConfig);
dbPasswordFile = config.age.secrets.synapse-db.path;
dbPasswordFile = secrets.dbConfig.path;
dbConfigOut = "${cfg.dataDir}/synapse-db-config-generated.yml";
cfg = config.services.matrix-synapse;
in {
age.secrets = {
synapse-ldap = {
file = ../../../secrets/synapse-ldap.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0400";
};
synapse-db = {
file = ../../../secrets/synapse-db.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0400";
};
synapse-turn = {
file = ../../../secrets/synapse-turn.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0400";
};
synapse-keys = {
file = ../../../secrets/synapse-keys.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0400";
};
};
services.matrix-synapse = {
enable = true;
plugins = [ pkgs.matrix-synapse-plugins.matrix-synapse-ldap3 ];
@ -114,10 +89,10 @@ in {
in map makeTurnServer combinations;
};
extraConfigFiles = (map (x: config.age.secrets.${x}.path) [
"synapse-ldap"
"synapse-turn"
"synapse-keys"
extraConfigFiles = (map (x: secrets."${x}Config".path) [
"ldap"
"turn"
"keys"
]) ++ [ dbConfigOut ];
};

View file

@ -1,13 +1,6 @@
{ config, lib, ... }:
{
vars.patroni = {
passwords = {
PATRONI_REPLICATION_PASSWORD = ./passwords/replication.age;
PATRONI_SUPERUSER_PASSWORD = ./passwords/superuser.age;
PATRONI_REWIND_PASSWORD = ./passwords/rewind.age;
};
};
links = {
patroni-pg-internal.ipv4 = "0.0.0.0";
patroni-api.ipv4 = "0.0.0.0";
@ -25,5 +18,17 @@
];
haproxy = ./haproxy.nix;
};
secrets = let
inherit (config.services.patroni) nodes;
default = {
nodes = nodes.worker;
owner = "patroni";
};
in {
PATRONI_REPLICATION_PASSWORD = default;
PATRONI_SUPERUSER_PASSWORD = default;
PATRONI_REWIND_PASSWORD = default;
metricsCredentials.nodes = nodes.worker;
};
};
}

View file

@ -2,13 +2,12 @@
let
inherit (cluster.config) links vars;
inherit (cluster.config.services.patroni) secrets;
getMeshIp = name: vars.mesh.${name}.meshIp;
in
{
age.secrets.postgres-metrics-db-credentials.file = ./passwords/metrics.age;
services.grafana-agent = {
settings.integrations.postgres_exporter = {
enabled = true;
@ -19,7 +18,7 @@ in
autodiscover_databases = true;
};
credentials = {
PG_METRICS_DB_PASSWORD = config.age.secrets.postgres-metrics-db-credentials.path;
PG_METRICS_DB_PASSWORD = secrets.metricsCredentials.path;
};
};
}

View file

@ -2,6 +2,7 @@
let
inherit (cluster.config) vars;
inherit (cluster.config.services.patroni) secrets;
inherit (config.networking) hostName;
getMeshIp = name: vars.mesh.${name}.meshIp;
@ -20,13 +21,6 @@ in
depot.nixosModules.patroni
];
age.secrets = lib.mapAttrs (_: file: {
inherit file;
mode = "0400";
owner = "patroni";
group = "patroni";
}) vars.patroni.passwords;
systemd.tmpfiles.rules = [
"d '${baseDir}' 0700 patroni patroni - -"
"d '${walDir}' 0700 patroni patroni - -"
@ -83,6 +77,6 @@ in
];
};
};
environmentFiles = lib.mapAttrs (n: _: config.age.secrets.${n}.path) vars.patroni.passwords;
environmentFiles = lib.mapAttrs (_: secret: secret.path) (lib.filterAttrs (name: _: lib.hasPrefix "PATRONI_" name) secrets);
};
}

View file

@ -4,6 +4,7 @@
services.search = {
nodes.host = [ "VEGAS" ];
nixos.host = ./host.nix;
secrets.default.nodes = config.services.search.nodes.host;
};
monitoring.blackbox.targets.search = {

View file

@ -1,16 +1,15 @@
{ config, depot, lib, ... }:
{ cluster, config, depot, lib, ... }:
let
inherit (config) links;
in
{
links.searxng.protocol = "http";
age.secrets.searxng-secrets.file = ../../../secrets/searxng-secrets.age;
services.searx = {
enable = true;
runInUwsgi = true;
package = depot.packages.searxng;
environmentFile = config.age.secrets.searxng-secrets.path;
environmentFile = cluster.config.services.search.secrets.default.path;
settings = {
server = {
secret_key = "@SEARXNG_SECRET@";

View file

@ -23,7 +23,6 @@ in
meshIp = "10.1.1.32";
inherit meshNet;
pubKey = "fZMB9CDCWyBxPnsugo3Uxm/TIDP3VX54uFoaoC0bP3U=";
privKeyFile = ./mesh-keys/checkmate.age;
extraRoutes = [];
};
};
@ -33,7 +32,6 @@ in
meshIp = "10.1.1.6";
inherit meshNet;
pubKey = "0WAiQGdWySsGWFUk+a9e0I+BDTKwTyWQdFT2d7BMfDQ=";
privKeyFile = ./mesh-keys/grail.age;
extraRoutes = [];
};
};
@ -43,7 +41,6 @@ in
meshIp = "10.1.1.4";
inherit meshNet;
pubKey = "xvSsFvCVK8h2wThZJ7E5K0fniTBIEIYOblkKIf3Cwy0=";
privKeyFile = ./mesh-keys/thunderskin.age;
extraRoutes = [];
};
};
@ -53,7 +50,6 @@ in
meshIp = "10.1.1.5";
inherit meshNet;
pubKey = "NpeB8O4erGTas1pz6Pt7qtY9k45YV6tcZmvvA4qXoFk=";
privKeyFile = ./mesh-keys/VEGAS.age;
extraRoutes = [ "${hours.VEGAS.interfaces.vstub.addr}/32" "10.10.0.0/16" ];
};
};
@ -63,7 +59,6 @@ in
meshIp = "10.1.1.9";
inherit meshNet;
pubKey = "MMZAbRtNE+gsLm6DJy9VN/Y39E69oAZnvOcFZPUAVDc=";
privKeyFile = ./mesh-keys/prophet.age;
extraRoutes = [];
};
};
@ -75,5 +70,9 @@ in
nixos = {
mesh = ./mesh.nix;
};
secrets.meshPrivateKey = {
nodes = config.services.wireguard.nodes.mesh;
shared = false;
};
};
}

View file

@ -13,11 +13,6 @@ let
};
in
{
age.secrets.wireguard-key-core = {
file = link.extra.privKeyFile;
mode = "0400";
};
networking = {
firewall = {
trustedInterfaces = [ "wgmesh" ];
@ -29,7 +24,7 @@ in
interfaces.wgmesh = {
ips = [ "${link.extra.meshIp}/24" ];
listenPort = link.port;
privateKeyFile = config.age.secrets.wireguard-key-core.path;
privateKeyFile = cluster.config.services.wireguard.secrets.meshPrivateKey.path;
peers = map mkPeer (cluster.config.services.wireguard.otherNodes.mesh hostName);
};
};

View file

@ -5,60 +5,17 @@ let
systemKeys = x: x.ssh.id.publicKey or null;
in with hosts;
{
"cluster/services/attic/attic-db-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/attic/attic-s3-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/attic/attic-server-token.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/cachix-deploy-agent/credentials/checkmate.age".publicKeys = max ++ map systemKeys [ checkmate ];
"cluster/services/cachix-deploy-agent/credentials/grail.age".publicKeys = max ++ map systemKeys [ grail ];
"cluster/services/cachix-deploy-agent/credentials/prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/cachix-deploy-agent/credentials/VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/cachix-deploy-agent/credentials/thunderskin.age".publicKeys = max ++ map systemKeys [ thunderskin ];
"cluster/services/dns/acme-dns-direct-key.age".publicKeys = max ++ map systemKeys [ checkmate grail thunderskin VEGAS prophet ];
"cluster/services/dns/acme-dns-db-credentials.age".publicKeys = max ++ map systemKeys [ checkmate VEGAS prophet ];
"cluster/services/forge/credentials/forgejo-oidc-secret.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/forge/credentials/forgejo-db-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/forge/credentials/forgejo-s3-access-key-id.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/forge/credentials/forgejo-s3-secret-access-key.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-cache-config.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-cache-credentials-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-cache-credentials-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-effects-secrets-private-void.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-hyprspace-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-hyprspace-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-max-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-max-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-nixpak-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-nixpak-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-private-void-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/hercules-ci-multi-agent/secrets/hci-token-private-void-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/idm/secrets/service-account-checkmate.age".publicKeys = max ++ map systemKeys [ checkmate ];
"cluster/services/idm/secrets/service-account-grail.age".publicKeys = max ++ map systemKeys [ grail ];
"cluster/services/idm/secrets/service-account-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/idm/secrets/service-account-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/idm/secrets/service-account-soda.age".publicKeys = max ++ map systemKeys [ soda ];
"cluster/services/idm/secrets/service-account-thunderskin.age".publicKeys = max ++ map systemKeys [ thunderskin ];
"cluster/services/ipfs/cluster-secret.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/ipfs/cluster-pinsvc-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/irc/irc-peer-key.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/monitoring/secrets/grafana-db-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/monitoring/secrets/grafana-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
"cluster/services/monitoring/secrets/loki-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/monitoring/secrets/secret-monitoring/blackbox.age".publicKeys = max ++ map systemKeys [ checkmate grail prophet ];
"cluster/services/monitoring/secrets/tempo-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/patroni/passwords/metrics.age".publicKeys = max ++ map systemKeys [ grail thunderskin VEGAS ];
"cluster/services/patroni/passwords/replication.age".publicKeys = max ++ map systemKeys [ grail thunderskin VEGAS ];
"cluster/services/patroni/passwords/rewind.age".publicKeys = max ++ map systemKeys [ grail thunderskin VEGAS ];
"cluster/services/patroni/passwords/superuser.age".publicKeys = max ++ map systemKeys [ grail thunderskin VEGAS ];
"cluster/services/storage/secrets/heresy-encryption-key.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/storage/secrets/external-storage-auth-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"cluster/services/storage/secrets/garage-rpc-secret.age".publicKeys = max ++ map systemKeys [ grail VEGAS prophet ];
"cluster/services/storage/secrets/storage-box-credentials.age".publicKeys = max ++ map systemKeys [ grail VEGAS prophet ];
"cluster/services/wireguard/mesh-keys/checkmate.age".publicKeys = max ++ map systemKeys [ checkmate ];
"cluster/services/wireguard/mesh-keys/grail.age".publicKeys = max ++ map systemKeys [ grail ];
"cluster/services/wireguard/mesh-keys/thunderskin.age".publicKeys = max ++ map systemKeys [ thunderskin ];
"cluster/services/wireguard/mesh-keys/VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"cluster/services/wireguard/mesh-keys/prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"secrets/coturn-static-auth.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/dovecot-ldap-token.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/gitlab-db-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/gitlab-initial-root-password.age".publicKeys = max ++ map systemKeys [ VEGAS ];
@ -77,15 +34,9 @@ in with hosts;
"secrets/hyprspace-key-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/hyprspace-key-prophet.age".publicKeys = max ++ map systemKeys [ prophet ];
"secrets/keycloak-dbpass.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/matrix-appservice-discord-token.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/nextcloud-adminpass.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/nextcloud-dbpass.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/oauth2_proxy-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/postfix-ldap-mailboxes.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/searxng-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/synapse-db.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/synapse-keys.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/synapse-ldap.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/synapse-turn.age".publicKeys = max ++ map systemKeys [ VEGAS ];
"secrets/wireguard-key-storm-VEGAS.age".publicKeys = max ++ map systemKeys [ VEGAS ];
}

View file

@ -1,11 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 NO562A eDXO2rf1oCP7G9J7pB03shPO9BMIZ2pEhBqlaEiO+DI
Nb6n+yZJ3+ZQQWefjUbV6xiem+4gpOdE0IoA5F9L4zs
-> ssh-ed25519 5/zT0w I/KivuQEA2nwCF0qq4G81dKvwU/Zni2Fuz+xSraW52E
osPx87gVzeEEIPBnhTn0APxBuA/IL8ySuMzzVrjYqEI
-> ssh-ed25519 d3WGuA yrjBtwpNIgsCHG835akTfrwYdncm+yEHT1GnmWQvVnQ
Myfat35n/tjZzsqeaLEZLpZGxwgBKo7lBVi1uMIzsRo
-> 1.=T-grease )oe@8$5 _OQDI/o^ &l$G\
aR164gwY7SDkig
--- 32woYizDIa931hDX2PO8wLOYmnOhSscYaI38pvUmBLs
ÿ2ã(<06>ì°cZÄBý„»¸o" Ê´¡±•¿%¡·W9<01>ãd'ØikCàFƒÆž ˈkPÃVÊNü>ö˜²×[Ý<>»

Binary file not shown.

View file

@ -1,13 +0,0 @@
age-encryption.org/v1
-> ssh-ed25519 NO562A 2h+cvDs0ZF/4KjtEdZVAt82fol+7LpAZPDDn6AvUOTg
NhTqPo8kezw8958g6XStj+zwfgLtsAVUFZ6Utj5SgUM
-> ssh-ed25519 5/zT0w CxBTfWH4/UfDAdo3G30bHleMU9FdRdTA4RapQN25ISU
F+fvzsSuMv3kINJmEodraZcC16WbslE0w4oDo6sSjqA
-> ssh-ed25519 d3WGuA IdssM5x5IKzLJeQNyGS6CFDcre0w6yG+X8WToFU66R8
95lNHp1fepWe6CqecaGNZhg7Oh7lBw86UeSRGY7w1wE
-> y>hqw-grease m, z7 ;#ddi
/DsgoGG5+p/B7Dri153Ta5PxZT5IsMF9e8ispSE0E8sA2QkPxT2GGNRRlvYkzXSF
6b9vv3P9IvPA4m2VQRJ6IlUPAmx00n0G9U5BqxrCknSZ242+QG3zFA
--- eJGQ5eUCAuhrs7ozhissFClHKDQVgBbkU7ZXbAA4xNg
Bñt<C3B1>7ç²û„ÊT]P®°÷7<C3B7>þe†J$_´
j*ôH%"žX•â 0Æê‡ë¼$¯Ä/vòÐa¾‰¡>L<>Q*Ç>}ð±/kËÁgç