Evolution in Seattle
This commit is contained in:
+22
-16
@@ -25,20 +25,22 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
sshOpts = { ... }: with types; {
|
||||
options = {
|
||||
listen-ip = mkOption {
|
||||
type = str;
|
||||
description = "IP on which to listen for SSH connections.";
|
||||
};
|
||||
sshOpts = { ... }:
|
||||
with types; {
|
||||
options = {
|
||||
listen-ip = mkOption {
|
||||
type = str;
|
||||
description = "IP on which to listen for SSH connections.";
|
||||
};
|
||||
|
||||
listen-port = mkOption {
|
||||
type = port;
|
||||
description = "Port on which to listen for SSH connections, on <listen-ip>.";
|
||||
default = 22;
|
||||
listen-port = mkOption {
|
||||
type = port;
|
||||
description =
|
||||
"Port on which to listen for SSH connections, on <listen-ip>.";
|
||||
default = 22;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
options.fudo.git = with types; {
|
||||
@@ -81,7 +83,8 @@ in {
|
||||
|
||||
local-port = mkOption {
|
||||
type = port;
|
||||
description = "Local port to which the Gitea server will bind. Not globally accessible.";
|
||||
description =
|
||||
"Local port to which the Gitea server will bind. Not globally accessible.";
|
||||
default = 3543;
|
||||
};
|
||||
|
||||
@@ -93,9 +96,12 @@ in {
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
security.acme.certs.${cfg.hostname}.email = let
|
||||
domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
|
||||
in config.fudo.domains.${domain-name}.admin-email;
|
||||
security.acme.certs.${cfg.hostname}.email =
|
||||
let domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
|
||||
in config.fudo.domains.${domain-name}.admin-email;
|
||||
|
||||
networking.firewall.allowedTCPPorts =
|
||||
mkIf (cfg.ssh != null) [ cfg.ssh.listen-port ];
|
||||
|
||||
services = {
|
||||
gitea = {
|
||||
@@ -123,7 +129,7 @@ in {
|
||||
settings = mkIf (cfg.ssh != null) {
|
||||
server = {
|
||||
SSH_DOMAIN = cfg.hostname;
|
||||
SSH_LISTEN_PORT = cfg.ssh.listen-port;
|
||||
# SSH_LISTEN_PORT = cfg.ssh.listen-port;
|
||||
SSH_LISTEN_HOST = cfg.ssh.listen-ip;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -125,6 +125,12 @@ let
|
||||
description = "A list of interfaces on which to enable the firewall.";
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
keytab-secret-file = mkOption {
|
||||
type = nullOr str;
|
||||
description = "Keytab from which to create a keytab secret.";
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -208,6 +214,20 @@ in {
|
||||
|
||||
boot.tmpOnTmpfs = host-cfg.tmp-on-tmpfs;
|
||||
|
||||
fudo.secrets.host-secrets.${hostname}.host-keytab = let
|
||||
mapOptional = f: val: if (val != null) then (f val) else null;
|
||||
keytab-file = mapOptional (keytab-path:
|
||||
if (pathExists keytab-path) then
|
||||
/. + builtins.toPath keytab-path
|
||||
else
|
||||
null) (mapOptional (keytab-dir: "${keytab-dir}/${hostname}.keytab")
|
||||
site.keytab-directory);
|
||||
in mkIf (keytab-file != null) {
|
||||
source-file = /. + builtins.toPath keytab-file;
|
||||
target-file = "/etc/krb5.keytab";
|
||||
user = "root";
|
||||
};
|
||||
|
||||
programs.ssh.knownHosts = let
|
||||
keyed-hosts =
|
||||
filterAttrs (host: opts: opts.ssh-pubkey != null) config.fudo.hosts;
|
||||
|
||||
+71
-24
@@ -2,6 +2,8 @@
|
||||
|
||||
with lib;
|
||||
let
|
||||
cfg = config.fudo.secrets;
|
||||
|
||||
encrypt-on-disk = { secret-name, target-host, source-file }:
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "${target-host}-${secret-name}-secret";
|
||||
@@ -39,9 +41,6 @@ let
|
||||
mkdir -p "$TARGET_DIR"
|
||||
fi
|
||||
'';
|
||||
ExecStop = pkgs.writeShellScript "clear-${secret-name}-secret.sh" ''
|
||||
rm -f ${target-file}
|
||||
'';
|
||||
ExecStart = let
|
||||
decrypt-keys =
|
||||
filter (key: key.type == key-type) config.services.openssh.hostKeys;
|
||||
@@ -57,7 +56,7 @@ let
|
||||
secretOpts = { ... }: {
|
||||
options = with types; {
|
||||
source-file = mkOption {
|
||||
type = str;
|
||||
type = path; # CAREFUL: this will copy the file to nixstore...I think?
|
||||
description = "File from which to load the secret.";
|
||||
};
|
||||
|
||||
@@ -86,32 +85,80 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
nix-build-users = let usernames = attrNames config.users.users;
|
||||
in filter (user: (builtins.match "^nixbld[0-9]{1,2}$" user) != null)
|
||||
usernames;
|
||||
|
||||
in {
|
||||
options.fudo.secrets = with types;
|
||||
mkOption {
|
||||
options.fudo.secrets = with types; {
|
||||
host-secrets = mkOption {
|
||||
type = attrsOf (attrsOf (submodule secretOpts));
|
||||
description = "Map of hosts, to secrets, to secret config.";
|
||||
description = "Map of hosts to host secrets";
|
||||
default = { };
|
||||
example = {
|
||||
my-host = {
|
||||
my-host-secret = {
|
||||
source-file = /path/to/file/on/this/host;
|
||||
target-file = "/target/path/on/host";
|
||||
user = "some-user";
|
||||
};
|
||||
|
||||
secret-users = mkOption {
|
||||
type = listOf str;
|
||||
description = "List of users with read-access to secrets.";
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
secret-group = mkOption {
|
||||
type = str;
|
||||
description = "Group to which secrets will belong.";
|
||||
default = "nixops-secrets";
|
||||
};
|
||||
|
||||
secret-paths = mkOption {
|
||||
type = listOf str;
|
||||
description =
|
||||
"Paths which contain (only) secrets. The contents will be reabable by the secret-group.";
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
users.groups = {
|
||||
${cfg.secret-group} = { members = cfg.secret-users ++ nix-build-users; };
|
||||
};
|
||||
|
||||
systemd = let
|
||||
hostname = config.instance.hostname;
|
||||
host-secrets = if (hasAttr hostname cfg.host-secrets) then
|
||||
cfg.host-secrets.${hostname}
|
||||
else
|
||||
{ };
|
||||
host-secret-services = mapAttrs' (secret: secretOpts:
|
||||
(nameValuePair "fudo-secret-${hostname}-${secret}"
|
||||
(secret-service hostname secret secretOpts))) host-secrets;
|
||||
|
||||
in {
|
||||
services = host-secret-services // {
|
||||
fudo-secrets-watcher = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description =
|
||||
"Ensure access for group ${cfg.secret-group} to fudo secret paths.";
|
||||
serviceConfig = {
|
||||
ExecStart = pkgs.writeShellScript "fudo-secrets-watcher.sh"
|
||||
(concatStringsSep "\n" (map (path: ''
|
||||
chown -R root:${cfg.secret-group} ${path}
|
||||
chmod -R u=rwX,g=rX,o= ${path}
|
||||
'') cfg.secret-paths));
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.services = let
|
||||
hostname = config.instance.hostname;
|
||||
host-secrets = if (hasAttr hostname config.fudo.secrets) then
|
||||
config.fudo.secrets.${hostname}
|
||||
else
|
||||
{ };
|
||||
in mapAttrs' (secret: secretOpts:
|
||||
(nameValuePair "fudo-secret-${hostname}-${secret}"
|
||||
(secret-service hostname secret secretOpts))) host-secrets;
|
||||
paths.fudo-secrets-watcher = mkIf ((length cfg.secret-paths) > 0) {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description = "Watch fudo secret paths, and correct perms on changes.";
|
||||
pathConfig = {
|
||||
PathChanged = cfg.secret-paths;
|
||||
Unit = "fudo-secrets-watcher.service";
|
||||
};
|
||||
};
|
||||
|
||||
tmpfiles.rules = map (path: "d '${path}' - root ${cfg.secret-group} - -")
|
||||
cfg.secret-paths;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,6 +139,16 @@ let
|
||||
description = "List of networks to consider local at this site.";
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
keytab-directory = mkOption {
|
||||
type = nullOr str;
|
||||
description = ''
|
||||
Directory containing site keytabs (files named $hostname.keytab).
|
||||
|
||||
Should exist only on build host.
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user