Move profiles from ./profile-config to ./profile
This commit is contained in:
parent
79b05be7d3
commit
566643e195
|
@ -8,6 +8,7 @@
|
||||||
./groups.nix
|
./groups.nix
|
||||||
./hosts.nix
|
./hosts.nix
|
||||||
./networks.nix
|
./networks.nix
|
||||||
|
./profile.nix
|
||||||
./sites.nix
|
./sites.nix
|
||||||
./users.nix
|
./users.nix
|
||||||
./wireless-networks.nix
|
./wireless-networks.nix
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
hardware.bluetooth.enable = false;
|
hardware.bluetooth.enable = false;
|
||||||
|
|
||||||
network = {
|
networking = {
|
||||||
macvlans = {
|
macvlans = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
interface = "enp4s0f1";
|
interface = "enp4s0f1";
|
||||||
|
|
|
@ -10,10 +10,17 @@ let
|
||||||
host-fqdn = "${hostname}.${domain-name}";
|
host-fqdn = "${hostname}.${domain-name}";
|
||||||
mail-hostname = "mail.fudo.org";
|
mail-hostname = "mail.fudo.org";
|
||||||
|
|
||||||
france-secrets = config.fudo.secrets.host-secrets.france;
|
secrets = config.fudo.secrets.host-secrets.france;
|
||||||
|
secret-files = config.fudo.secrets.files;
|
||||||
|
|
||||||
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
|
letsencrypt-full-chain = name: chain: pkgs.stdenv.mkDerivation {
|
||||||
acme-certificate = hostname: "/var/lib/acme/${hostname}/fullchain.pem";
|
name = "${name}-letsencrypt-full-chain.pem";
|
||||||
|
phases = "installPhase";
|
||||||
|
installPhase = ''
|
||||||
|
cat ${chain} > $out
|
||||||
|
cat ${pkgs.letsencrypt-ca}/ca.pem >> $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
imports = let
|
imports = let
|
||||||
|
@ -28,9 +35,66 @@ in {
|
||||||
in nix-files ./france;
|
in nix-files ./france;
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
security.acme.email = "admin@fudo.org";
|
||||||
|
|
||||||
fudo = {
|
fudo = {
|
||||||
hosts.france.external-interfaces = [ "extif0" ];
|
hosts.france.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
|
acme.host-domains.france."france.fudo.org" = {
|
||||||
|
email = "admin@fudo.org";
|
||||||
|
local-copies = {
|
||||||
|
postgres = {
|
||||||
|
user = config.services.postgresql.user;
|
||||||
|
};
|
||||||
|
openldap = {
|
||||||
|
user = config.services.openldap.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
secrets.host-secrets.${hostname} = let
|
||||||
|
ldap-user = config.services.openldap.user;
|
||||||
|
ldap-group = config.services.openldap.group;
|
||||||
|
in {
|
||||||
|
ldap-ssl-certificate = {
|
||||||
|
source-file = cfg.ssl-certificate;
|
||||||
|
target-file = "/run/openldap/ssl-certificate.pem";
|
||||||
|
user = ldap-user;
|
||||||
|
group = ldap-group;
|
||||||
|
permissions = "0444";
|
||||||
|
};
|
||||||
|
ldap-ssl-private-key = {
|
||||||
|
source-file = cfg.ssl-private-key;
|
||||||
|
target-file = "/run/openldap/ssl-private-key.pem";
|
||||||
|
user = ldap-user;
|
||||||
|
group = ldap-group;
|
||||||
|
};
|
||||||
|
ldap-ssl-ca-certificate = {
|
||||||
|
source-file = cfg.ssl-ca-certificate;
|
||||||
|
target-file = "/run/openldap/ssl-ca-certificate.pem";
|
||||||
|
user = ldap-user;
|
||||||
|
group = ldap-group;
|
||||||
|
permissions = "0444";
|
||||||
|
};
|
||||||
|
ldap-keytab = {
|
||||||
|
source-file = secret-files.service-keytabs.france.ldap;
|
||||||
|
target-file = "/run/openldap/ldap.keytab";
|
||||||
|
user = ldap-user;
|
||||||
|
group = ldap-group;
|
||||||
|
};
|
||||||
|
ldap-root-passwd = {
|
||||||
|
source-file = passwd.random-passwd-file;
|
||||||
|
target-file = "/run/openldap/root.passwd";
|
||||||
|
user = ldap-user;
|
||||||
|
group = ldap-group;
|
||||||
|
};
|
||||||
|
postgres-keytab = {
|
||||||
|
source-file = secret-files.service-keytabs.france.postgres;
|
||||||
|
target-file = "/run/postgres/postgres.keytab";
|
||||||
|
user = config.services.postgresql.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
client.dns = {
|
client.dns = {
|
||||||
enable = true;
|
enable = true;
|
||||||
ipv4 = true;
|
ipv4 = true;
|
||||||
|
@ -40,16 +104,53 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
france = {
|
france = {
|
||||||
|
ldap = let
|
||||||
|
cert-copy = config.fudo.acme.host-domains.france."france.fudo.org".local-copies.openldap;
|
||||||
|
chain = "${letsencrypt-full-chain "openldap-france" cert-copy.chain}";
|
||||||
|
in {
|
||||||
|
ssl-certificate = cert-copy.certificate;
|
||||||
|
ssl-private-key = cert-copy.private-key;
|
||||||
|
ssl-ca-certificate = chain;
|
||||||
|
keytab = secrets.ldap-keytab.target-file;
|
||||||
|
root-password-file = secrets.ldap-root-passwd.target-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
kdc = {
|
||||||
|
state-directory = "/state/kerberos";
|
||||||
|
master-key-file = "";
|
||||||
|
listen-ips = [ primary-ip "127.0.0.1" "127.0.1.1" "::1" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
jabber = {
|
||||||
|
ldap-servers = [ "france.fudo.org" ];
|
||||||
|
listen-ips = [ primary-ip ];
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane = {
|
||||||
|
host-passwd-files = let
|
||||||
|
hosts = attrNames config.fudo.hosts;
|
||||||
|
in mapAttrs (hostname: hostOpts: hostOpts.backplane-password-file)
|
||||||
|
config.fudo.hosts;
|
||||||
|
service-passwd-files = genAttrs [ "dns" ]
|
||||||
|
(service-name:
|
||||||
|
lib.fudo.passwd.stablerandom-passwd-file
|
||||||
|
"${service-name}-service-backplane-passwd"
|
||||||
|
"${service-name}-service-backplane-passwd-${config.instance.build-seed}");
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane-server = {
|
||||||
|
listen-ips = [ primary-ip ];
|
||||||
|
};
|
||||||
|
|
||||||
mail = {
|
mail = {
|
||||||
mail-directory = "/state/mail-server/mail";
|
mail-directory = "/srv/mail/mailboxes";
|
||||||
state-directory = "/state/mail-server/var";
|
state-directory = "/srv/mail/var";
|
||||||
ldap-server-urls = [
|
ldap-server-urls = [
|
||||||
"ldap://france.fudo.org"
|
"ldap://france.fudo.org"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
webmail = {
|
webmail = {
|
||||||
# TODO: this is not using the database!
|
|
||||||
mail-server = mail-hostname;
|
mail-server = mail-hostname;
|
||||||
database.hostname = "localhost";
|
database.hostname = "localhost";
|
||||||
};
|
};
|
||||||
|
@ -58,6 +159,15 @@ in {
|
||||||
repository-directory = "/state/gitea/repo";
|
repository-directory = "/state/gitea/repo";
|
||||||
state-directory = "/state/gitea/state";
|
state-directory = "/state/gitea/state";
|
||||||
ssh.listen-ip = git-server-ip;
|
ssh.listen-ip = git-server-ip;
|
||||||
|
database-host = "localhost";
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql = let
|
||||||
|
cert-copy = config.fudo.acme.host-domains.france."france.fudo.org".local-copies.postgres;
|
||||||
|
in {
|
||||||
|
keytab = secrets.postgres-keytab.target-file;
|
||||||
|
ssl-certificate = cert-copy.certificate;
|
||||||
|
ssl-private-key = cert-copy.private-key;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,6 +181,9 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
|
useDHCP = false;
|
||||||
|
|
||||||
|
interfaces = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
address = "192.168.11.1";
|
address = "192.168.11.1";
|
||||||
|
@ -90,12 +203,13 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
nginx = {
|
nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
recommendedGzipSettings = true;
|
recommendedGzipSettings = true;
|
||||||
recommendedOptimisations = true;
|
recommendedOptimisation = true;
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
|
|
||||||
|
|
|
@ -7,83 +7,79 @@ let
|
||||||
site-name = config.instance.local-site;
|
site-name = config.instance.local-site;
|
||||||
fqdn = "${hostname}.${domain-name}";
|
fqdn = "${hostname}.${domain-name}";
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.france;
|
|
||||||
|
|
||||||
# same as genAttr, but takes back attrsets and merges them
|
# same as genAttr, but takes back attrsets and merges them
|
||||||
concatGenAttrs = lst: f:
|
concatGenAttrs = lst: f:
|
||||||
foldr (a0: a1: a0 // a1) {} (map f lst);
|
foldr (a0: a1: a0 // a1) {} (map f lst);
|
||||||
|
|
||||||
|
passwd = import ../../../lib/passwd.nix { inherit lib; };
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
cfg = config.fudo.france;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.france = with types; {
|
options.fudo.france = with types; {
|
||||||
ldap = {
|
ldap = {
|
||||||
ssl-certificate = mkOption {
|
ssl-certificate = mkOption {
|
||||||
type = path;
|
type = str;
|
||||||
description = "SSL certificate to use for the LDAP server.";
|
description = "SSL certificate to use for the LDAP server.";
|
||||||
};
|
};
|
||||||
ssl-private-key = mkOption {
|
ssl-private-key = mkOption {
|
||||||
type = path;
|
type = str;
|
||||||
description = "SSL private key to use for the LDAP server.";
|
description = "SSL private key to use for the LDAP server.";
|
||||||
};
|
};
|
||||||
ssl-ca-certificate = mkOption {
|
ssl-ca-certificate = mkOption {
|
||||||
type = path;
|
type = str;
|
||||||
description = "SSL certificate authority to use for the LDAP server.";
|
description = "SSL certificate authority to use for the LDAP server.";
|
||||||
};
|
};
|
||||||
|
keytab = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to the LDAP service keytab.";
|
||||||
|
};
|
||||||
|
root-password-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to the file containing the LDAP root password.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
kdc = {
|
kdc = {
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path at which to store kerberos state.";
|
description = "Path at which to store kerberos state.";
|
||||||
|
default = "/state/kerberos";
|
||||||
};
|
};
|
||||||
|
|
||||||
master-key-file = mkOption {
|
master-key-file = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Heimdal database master key file.";
|
description = "Heimdal database master key file.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
listen-ips = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "IP addresses on which to listen for connections.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
fudo = {
|
||||||
secrets.host-secrets.${hostname} = {
|
secrets.host-secrets.${hostname}.kdc-master-key = {
|
||||||
ldap-ssl-certificate = {
|
source-file = cfg.kdc.master-key-file;
|
||||||
source-file = cfg.ssl-certificate;
|
target-file = "/run/kerberos/kdc/master.key";
|
||||||
target-file = "/var/run/ldap/ssl-certificate.pem";
|
user = config.fudo.auth.kdc.user;
|
||||||
user = config.services.openldap.user;
|
|
||||||
group = config.services.openldap.group;
|
|
||||||
permissions = "0444";
|
|
||||||
};
|
|
||||||
ldap-ssl-private-key = {
|
|
||||||
source-file = cfg.ssl-private-key;
|
|
||||||
target-file = "/var/run/ldap/ssl-private-key.pem";
|
|
||||||
user = config.services.openldap.user;
|
|
||||||
group = config.services.openldap.group;
|
|
||||||
permissions = "0400";
|
|
||||||
};
|
|
||||||
ldap-ssl-ca-certificate = {
|
|
||||||
source-file = cfg.ssl-ca-certificate;
|
|
||||||
target-file = "/var/run/ldap/ssl-ca-certificate.pem";
|
|
||||||
user = config.services.openldap.user;
|
|
||||||
group = config.services.openldap.group;
|
|
||||||
permissions = "0400";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auth = {
|
auth = {
|
||||||
ldap = {
|
ldap-server = {
|
||||||
enable = true;
|
enable = true;
|
||||||
base = "dc=fudo,dc=org";
|
base = "dc=fudo,dc=org";
|
||||||
organization = "Fudo";
|
organization = "Fudo";
|
||||||
rootpw-file = secrets.ldap-root-passwd;
|
rootpw-file = cfg.ldap.root-password-file;
|
||||||
kerberos-host = fqdn;
|
kerberos-host = fqdn;
|
||||||
kerberos-keytab = secrets.ldap-keytab;
|
kerberos-keytab = cfg.ldap.keytab;
|
||||||
|
ssl-certificate = cfg.ldap.ssl-certificate;
|
||||||
sslCert =
|
ssl-private-key = cfg.ldap.ssl-private-key;
|
||||||
secrets.ldap-ssl-certificate.target-file;
|
ssl-ca-certificate = cfg.ldap.ssl-ca-certificate;
|
||||||
sslKey =
|
|
||||||
secrets.ldap-ssl-private-key.target-file;
|
|
||||||
sslCACert =
|
|
||||||
secrets.ldap-ssl-ca-certificate.target-file;
|
|
||||||
|
|
||||||
listen-uris = [ "ldap:///" "ldaps:///" "ldapi:///" ];
|
listen-uris = [ "ldap:///" "ldaps:///" "ldapi:///" ];
|
||||||
|
|
||||||
|
@ -95,9 +91,9 @@ in {
|
||||||
# TODO: let build hosts create keys?
|
# TODO: let build hosts create keys?
|
||||||
kdc = {
|
kdc = {
|
||||||
enable = true;
|
enable = true;
|
||||||
realm = config.domains.${domain-name}.gssapi-realm;
|
realm = config.fudo.domains.${domain-name}.gssapi-realm;
|
||||||
state-directory = cfg.state-directory;
|
state-directory = cfg.kdc.state-directory;
|
||||||
master-key-file = cfg.master-key-file;
|
master-key-file = secrets.kdc-master-key.target-file;
|
||||||
acl = let
|
acl = let
|
||||||
admin-entries = concatGenAttrs
|
admin-entries = concatGenAttrs
|
||||||
config.instance.local-admins
|
config.instance.local-admins
|
||||||
|
@ -109,7 +105,7 @@ in {
|
||||||
"host/*.fudo.org" = { perms = [ "add" ]; };
|
"host/*.fudo.org" = { perms = [ "add" ]; };
|
||||||
"pam_migrate/*.fudo.org" = { perms = [ "add" "change-password" ]; };
|
"pam_migrate/*.fudo.org" = { perms = [ "add" "change-password" ]; };
|
||||||
} // admin-entries;
|
} // admin-entries;
|
||||||
bind-addresses = [ primary-ip "127.0.0.1" "127.0.1.1" "::1" ];
|
bind-addresses = cfg.kdc.listen-ips;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
timestamp = config.instance.build-timestamp;
|
||||||
|
domain = config.instance.local-domain;
|
||||||
|
|
||||||
|
powerdns-user = "backplane-powerdns";
|
||||||
|
backplane-dns-user = "backplane-dns";
|
||||||
|
|
||||||
|
generate-role-passwd = role:
|
||||||
|
lib.fudo.passwd.stablerandom-password-file
|
||||||
|
"backplane-${role}-password"
|
||||||
|
"${hostname}-${domain}-${role}-password-${config.instance.build-timestamp}";
|
||||||
|
|
||||||
|
powerdns-password = generate-role-passwd "powerdns-db";
|
||||||
|
|
||||||
|
backplane-dns-xmpp-password = generate-role-passwd "backplane-dns-xmpp";
|
||||||
|
|
||||||
|
backplane-dns-db-password = generate-role-passwd "backplane-dns-db";
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.france;
|
||||||
|
|
||||||
|
cfg = config.fudo.france.backplane-server;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.france.backplane-server = with types; {
|
||||||
|
listen-ips = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of IPs on which to listen for incoming backplane connections.";
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-ipv6s = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of IPv6s on which to listen for incoming backplane connections.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
users = {
|
||||||
|
users = {
|
||||||
|
${powerdns-user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
${backplane-dns-user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
groups = {
|
||||||
|
${powerdns-user} = {
|
||||||
|
members = [ powerdns-user ];
|
||||||
|
};
|
||||||
|
${backplane-dns-user} = {
|
||||||
|
members = [ backplane-dns-user ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fudo = {
|
||||||
|
secrets.host-secrets.france = {
|
||||||
|
powerdns-password = {
|
||||||
|
source-file = powerdns-password;
|
||||||
|
target-file = "/run/backplane/dns/powerdns/db.passwd";
|
||||||
|
user = config.fudo.backplane.dns.database.user;
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane-dns-db-password = {
|
||||||
|
source-file = backplane-dns-db-password;
|
||||||
|
target-file = "/run/backplane/dns/db.passwd";
|
||||||
|
user = config.fudo.backplane.dns.backplane.user;
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane-dns-xmpp-password = {
|
||||||
|
source-file = backplane-dns-db-password;
|
||||||
|
target-file = "/run/backplane/dns/xmpp.passwd";
|
||||||
|
user = config.fudo.backplane.dns.backplane.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql = {
|
||||||
|
enable = true;
|
||||||
|
required-services = [ "fudo-passwords.target" ];
|
||||||
|
|
||||||
|
users = {
|
||||||
|
${powerdns-user} = {
|
||||||
|
password-file = secrets.powerdns-password.target-file;
|
||||||
|
databases = {
|
||||||
|
backplane_dns = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
${backplane-dns-user} = {
|
||||||
|
password-file = secrets.backplane-dns-db-password;
|
||||||
|
databases = {
|
||||||
|
backplane_dns = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
databases = {
|
||||||
|
backplane_dns = {
|
||||||
|
users = ["niten"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane.dns = {
|
||||||
|
enable = true;
|
||||||
|
listen-v4-addresses = cfg.listen-ips;
|
||||||
|
listen-v6-addresses = cfg.listen-ipv6s;
|
||||||
|
user = backplane-dns-user;
|
||||||
|
group = backplane-dns-user;
|
||||||
|
database = {
|
||||||
|
username = powerdns-user;
|
||||||
|
database = "backplane_dns";
|
||||||
|
# Uses an IP to avoid cyclical dependency...
|
||||||
|
host = "127.0.0.1";
|
||||||
|
password-file = secrets.powerdns-password.target-file;
|
||||||
|
};
|
||||||
|
backplane = {
|
||||||
|
host = "backplane.fudo.org";
|
||||||
|
role = "service-dns";
|
||||||
|
password-file = secrets.backplane-dns-xmpp-password.target-file;
|
||||||
|
database = {
|
||||||
|
username = backplane-dns-user;
|
||||||
|
database = backplane-dns-user;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
password-file = secrets.backplane-dns-db-password.target-file;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,14 +7,16 @@ let
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
cfg = config.fudo.france.git;
|
||||||
|
|
||||||
sshOpts = { ... }: {
|
sshOpts = { ... }: {
|
||||||
options = {
|
options = with types; {
|
||||||
listen-ip = mkOption {
|
listen-ip = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "IP address on which to listen for SSH connections.";
|
description = "IP address on which to listen for SSH connections.";
|
||||||
};
|
};
|
||||||
listen-port = mkOption {
|
listen-port = mkOption {
|
||||||
type = str;
|
type = port;
|
||||||
description = "Port on which to listen for SSH connections.";
|
description = "Port on which to listen for SSH connections.";
|
||||||
default = 22;
|
default = 22;
|
||||||
};
|
};
|
||||||
|
@ -23,7 +25,7 @@ let
|
||||||
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.france.git = with types; {
|
options.fudo.france.git = with types; {
|
||||||
repository-directory = mkOption {
|
repository-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path to store git repositories.";
|
description = "Path to store git repositories.";
|
||||||
|
@ -43,6 +45,14 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config.fudo = {
|
config.fudo = {
|
||||||
|
secrets.host-secrets.${hostname}.git-database-password = {
|
||||||
|
source-file = lib.fudo.passwd.stablerandom-passwd-file
|
||||||
|
"gitea-database-passwd"
|
||||||
|
"${hostname}-gitea-database-passwd-${config.instance.build-seed}";
|
||||||
|
target-file = "/var/gitea/database.passwd";
|
||||||
|
user = config.services.gitea.user;
|
||||||
|
};
|
||||||
|
|
||||||
postgresql = {
|
postgresql = {
|
||||||
databases.fudo_git.users =
|
databases.fudo_git.users =
|
||||||
config.instance.local_admins;
|
config.instance.local_admins;
|
||||||
|
|
|
@ -5,23 +5,107 @@ let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
cfg = config.fudo.france;
|
||||||
|
|
||||||
|
generate-auth-file = name: files: let
|
||||||
|
make-entry = name: passwd-file:
|
||||||
|
''("${name}" . "${readFile passwd-file}")'';
|
||||||
|
entries = mapAttrsToList make-entry files;
|
||||||
|
content = concatStringsSep "\n" entries;
|
||||||
|
in writeText "${name}-backplane-auth.scm" "'(${content})'";
|
||||||
|
|
||||||
|
host-auth-file = generate-auth-file "host" cfg.host-passwd-files;
|
||||||
|
service-auth-file = generate-auth-filre "service" cfg.service-passwd-files;
|
||||||
|
|
||||||
|
ldap-password-file =
|
||||||
|
lib.fudo.passwd.random-passwd-file "ejabberd-ldap-auth-user";
|
||||||
|
|
||||||
|
ldap-hashed-password =
|
||||||
|
hash-ldap-passwd "ejabberd-ldap-hashed-passwd" ldap-password-file;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
options.fudo.france = with types; {
|
||||||
|
jabber = {
|
||||||
|
ldap-user = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "System user as which to authenticate to LDAP.";
|
||||||
|
default = "ejabberd";
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap-servers = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "LDAP servers to use for user authentication.";
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-ips = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "IPs on which to listen for incoming connections.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane = {
|
||||||
|
host-passwd-files = mkOption {
|
||||||
|
type = attrsOf str;
|
||||||
|
description = "Map of hostname to password file, for backplane host authentication.";
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
service-passwd-files = mkOption {
|
||||||
|
type = attrsOf str;
|
||||||
|
description = "Map of service to password file, for backplane service authentication.";
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
fudo = {
|
||||||
|
system-users.${cfg.jabber.ldap-user} = {
|
||||||
|
description = "ejabberd authentication user.";
|
||||||
|
hashed-password = ldap-hashed-password;
|
||||||
|
};
|
||||||
|
|
||||||
|
secrets.host-secrets.${hostname} = let
|
||||||
|
user = config.services.ejabberd.user;
|
||||||
|
in {
|
||||||
|
host-auth = {
|
||||||
|
source-file = host-auth-file;
|
||||||
|
target-file = "/run/backplane/host-auth-file.scm";
|
||||||
|
user = user;
|
||||||
|
};
|
||||||
|
service-auth = {
|
||||||
|
source-file = service-auth-file;
|
||||||
|
target-file = "/run/backplane/service-auth-file.scm";
|
||||||
|
user = user;
|
||||||
|
};
|
||||||
|
ldap-password = {
|
||||||
|
source-file = ldap-password-file;
|
||||||
|
target-file = "/run/ejabberd/ldap.passwd";
|
||||||
|
user = user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
jabber = {
|
jabber = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
|
listen-ips = cfg.jabber.listen-ips;
|
||||||
|
|
||||||
|
environment = {
|
||||||
|
FUDO_HOST_PASSWD_FILE = secrets.host-auth.target-file;
|
||||||
|
FUDO_SERVICE_PASSWD_FILE = secrets.service-auth.target-file;
|
||||||
|
};
|
||||||
|
|
||||||
secret-files = {
|
secret-files = {
|
||||||
LDAP_PASSWORD = secrets.jabber-ldap-password.target-file;
|
LDAP_PASSWORD = secrets.ldap-password.target-file;
|
||||||
};
|
};
|
||||||
|
|
||||||
sites = {
|
sites = {
|
||||||
"fudo.im" = {
|
"fudo.im" = {
|
||||||
site-config = {
|
site-config = {
|
||||||
auth_method = "ldap";
|
auth_method = "ldap";
|
||||||
ldap_servers = [ "auth.fudo.org" ];
|
ldap_servers = cfg.jabber.ldap-servers;
|
||||||
ldap_port = 389;
|
ldap_port = 389;
|
||||||
ldap_rootdn = "cn=jabber,dc=fudo,dc=org";
|
ldap_rootdn = "cn=${cfg.jabber.ldap-user},dc=fudo,dc=org";
|
||||||
ldap_password = ''"LDAP_PASSWD"'';
|
ldap_password = ''"LDAP_PASSWD"'';
|
||||||
ldap_base = "ou=members,dc=fudo,dc=org";
|
ldap_base = "ou=members,dc=fudo,dc=org";
|
||||||
ldap_filter = "(objectClass=posixAccount)";
|
ldap_filter = "(objectClass=posixAccount)";
|
||||||
|
@ -69,7 +153,7 @@ in {
|
||||||
"backplane.fudo.org" = {
|
"backplane.fudo.org" = {
|
||||||
site-config = {
|
site-config = {
|
||||||
auth_method = "external";
|
auth_method = "external";
|
||||||
extauth_program = "${pkgs.guile}/bin/guile -s ${backplane-auth}";
|
extauth_program = "${pkgs.guile}/bin/guile -s ${pkgs.backplane-auth}/backplane-auth.scm";
|
||||||
extauth_pool_size = 3;
|
extauth_pool_size = 3;
|
||||||
auth_use_cache = true;
|
auth_use_cache = true;
|
||||||
|
|
||||||
|
@ -100,7 +184,6 @@ in {
|
||||||
mod_time = {};
|
mod_time = {};
|
||||||
mod_version = {};
|
mod_version = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ let
|
||||||
|
|
||||||
mail-reader-dn = "mail-auth-reader";
|
mail-reader-dn = "mail-auth-reader";
|
||||||
in {
|
in {
|
||||||
options.france.mail = with types; {
|
options.fudo.france.mail = with types; {
|
||||||
mail-directory = mkOption {
|
mail-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Directory to contain user maildirs.";
|
description = "Directory to contain user maildirs.";
|
||||||
|
@ -39,16 +39,19 @@ in {
|
||||||
enableContainer = true;
|
enableContainer = true;
|
||||||
monitoring = true;
|
monitoring = true;
|
||||||
|
|
||||||
hostname = "mail.${domain-name}";
|
domain = domain-name;
|
||||||
|
mail-hostname = "mail.${domain-name}";
|
||||||
|
|
||||||
state-directory = cfg.state-directory;
|
dovecot = {
|
||||||
mail-directory = cfg.mail-directory;
|
ldap = {
|
||||||
|
reader-dn = "cn=${mail-reader-dn},${config.fudo.auth.ldap.base}";
|
||||||
dovecot.ldap = {
|
|
||||||
reader-dn = "cn=mail-reader-dn,${config.fudo.auth.ldap.base}";
|
|
||||||
reader-password-file = secrets.mail-reader-passwd.target-file;
|
reader-password-file = secrets.mail-reader-passwd.target-file;
|
||||||
server-urls = cfg.ldap-server-urls;
|
server-urls = cfg.ldap-server-urls;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
state-directory = cfg.state-directory;
|
||||||
|
mail-directory = cfg.mail-directory;
|
||||||
|
|
||||||
clamav.enable = true;
|
clamav.enable = true;
|
||||||
dkim.signing = true;
|
dkim.signing = true;
|
||||||
|
|
|
@ -5,14 +5,28 @@ let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
in {
|
in {
|
||||||
|
options.fudo.france.postgresql = with types; {
|
||||||
|
ssl-certificate = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "SSL certificate to use for the LDAP server.";
|
||||||
|
};
|
||||||
|
ssl-private-key = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "SSL private key to use for the LDAP server.";
|
||||||
|
};
|
||||||
|
keytab = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "Postgres service keytab.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
config.fudo.postgresql = {
|
config.fudo.postgresql = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
local-networks = config.instance.local-networks;
|
local-networks = config.instance.local-networks;
|
||||||
admin-users = config.instance.admin-users;
|
|
||||||
|
|
||||||
ssl-private-key = secrets.postgres-ssl-key;
|
ssl-private-key = cfg.ssl-private-key;
|
||||||
ssl-certificate = secrets.postgres-ssl-certificate;
|
ssl-certificate = cfg.ssl-certificate;
|
||||||
keytab = secrets.postgres-keytab.target-file;
|
keytab = cfg.keytab;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ let
|
||||||
db-passwd = pkgs.lib.fudo.passwd.random-passwd-file "webmail" 40;
|
db-passwd = pkgs.lib.fudo.passwd.random-passwd-file "webmail" 40;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.france.webmail = with types; {
|
options.fudo.france.webmail = with types; {
|
||||||
mail-server = mkOption {
|
mail-server = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Mail server to use for webmail.";
|
description = "Mail server to use for webmail.";
|
||||||
|
|
|
@ -22,6 +22,8 @@ let
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.procul;
|
secrets = config.fudo.secrets.host-secrets.procul;
|
||||||
|
|
||||||
|
passwd = pkgs.lib.fudo.passwd;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
networking = {
|
networking = {
|
||||||
dhcpcd.enable = false;
|
dhcpcd.enable = false;
|
||||||
|
@ -85,75 +87,17 @@ in {
|
||||||
fudo = {
|
fudo = {
|
||||||
hosts.procul.external-interfaces = [ "extif0" ];
|
hosts.procul.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
jabber = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
secret-files = {
|
|
||||||
SECRET = secrets.jabber-ldap-password.traget-file;
|
|
||||||
};
|
|
||||||
|
|
||||||
sites."informis.land" = {
|
|
||||||
site-config = {
|
|
||||||
auth_method = "ldap";
|
|
||||||
ldap_servers = [ "auth.fudo.org" ];
|
|
||||||
ldap_port = 636;
|
|
||||||
ldap_rootdn = "cn=jabber,dc=fudo,dc=org";
|
|
||||||
ldap_password = ''"LDAP_PASSWD"'';
|
|
||||||
ldap_base = "ou=members,dc=fudo,dc=org";
|
|
||||||
ldap_filter = "(objectClass=posixAccount)";
|
|
||||||
ldap_uids = { uid = "%u"; };
|
|
||||||
|
|
||||||
modules = {
|
|
||||||
mod_adhoc = {};
|
|
||||||
mod_announce = {};
|
|
||||||
mod_avatar = {};
|
|
||||||
mod_blocking = {};
|
|
||||||
mod_caps = {};
|
|
||||||
mod_carboncopy = {};
|
|
||||||
mod_client_state = {};
|
|
||||||
mod_configure = {};
|
|
||||||
mod_disco = {};
|
|
||||||
mod_fail2ban = {};
|
|
||||||
mod_last = {};
|
|
||||||
mod_offline = {
|
|
||||||
access_max_user_messages = 5000;
|
|
||||||
};
|
|
||||||
mod_ping = {};
|
|
||||||
mod_privacy = {};
|
|
||||||
mod_private = {};
|
|
||||||
mod_pubsub = {
|
|
||||||
access_createnode = "pubsub_createnode";
|
|
||||||
ignore_pep_from_offline = true;
|
|
||||||
last_item_cache = false;
|
|
||||||
plugins = [
|
|
||||||
"flat"
|
|
||||||
"pep"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
mod_roster = {};
|
|
||||||
mod_stream_mgmt = {};
|
|
||||||
mod_time = {};
|
|
||||||
mod_vcard = {
|
|
||||||
search = false;
|
|
||||||
};
|
|
||||||
mod_vcard_xupdate = {};
|
|
||||||
mod_version = {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
secrets.host-secrets.procul = let
|
secrets.host-secrets.procul = let
|
||||||
secrets = config.fudo.secrets.files;
|
files = config.fudo.secrets.files;
|
||||||
in {
|
in {
|
||||||
postgres-keytab = {
|
postgres-keytab = {
|
||||||
source-file = secrets.service-keytabs.procul.postgres;
|
source-file = files.service-keytabs.procul.postgres;
|
||||||
target-file = "/srv/postgres/secure/postgres.keytab";
|
target-file = "/srv/postgres/secure/postgres.keytab";
|
||||||
user = "root";
|
user = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
gitea-database-password = {
|
gitea-database-password = {
|
||||||
source-file = secrets.service-passwords.procul.gitea-database;
|
source-file = files.service-passwords.procul.gitea-database;
|
||||||
target-file = "/srv/gitea/secure/database.passwd";
|
target-file = "/srv/gitea/secure/database.passwd";
|
||||||
user = config.fudo.git.user;
|
user = config.fudo.git.user;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
let
|
let
|
||||||
syslib = pkgs.callPackage ../lib/hosts.nix {};
|
syslib = pkgs.callPackage ../lib/hosts.nix {};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
config.fudo.hosts = syslib.base-host-config ./hosts;
|
config.fudo.hosts = let
|
||||||
|
build-seed = config.instance.build-seed;
|
||||||
|
base-config = syslib.base-host-config ./hosts;
|
||||||
|
in mapAttrs (hostname: base-config:
|
||||||
|
base-config // {
|
||||||
|
backplane-password-file =
|
||||||
|
pkgs.lib.fudo.passwd.stablerandom-passwd-file
|
||||||
|
"${hostname}-host-backplane-passwd"
|
||||||
|
"${hostname}-host-backplane-passwd-${build-seed}";
|
||||||
|
}) base-config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,140 +1,4 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
{
|
||||||
let
|
|
||||||
hostname = config.instance.hostname;
|
|
||||||
enable-gui = config.fudo.hosts.${hostname}.enable-gui;
|
|
||||||
|
|
||||||
in {
|
|
||||||
imports = [ ./common.nix ];
|
|
||||||
|
|
||||||
boot.plymouth.enable = false;
|
|
||||||
|
|
||||||
boot.tmpOnTmpfs = true;
|
|
||||||
|
|
||||||
environment = mkIf enable-gui {
|
|
||||||
systemPackages = [
|
|
||||||
#libva
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# We're deploying via nixops, this is just annoying
|
|
||||||
system = { autoUpgrade.enable = false; };
|
|
||||||
|
|
||||||
services = {
|
|
||||||
xserver = mkIf enable-gui {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
desktopManager.gnome.enable = true;
|
|
||||||
|
|
||||||
displayManager.gdm = {
|
|
||||||
enable = true;
|
|
||||||
wayland = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
windowManager.stumpwm.enable = true;
|
|
||||||
|
|
||||||
# windowManager.session = pkgs.lib.singleton {
|
|
||||||
# name = "stumpwm";
|
|
||||||
# start = ''
|
|
||||||
# ${pkgs.lispPackages.stumpwm}/bin/stumpwm &
|
|
||||||
# waidPID=$!
|
|
||||||
# '';
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
|
|
||||||
trezord.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
hardware = {
|
|
||||||
bluetooth.enable = true;
|
|
||||||
|
|
||||||
opengl = mkIf enable-gui {
|
|
||||||
enable = true;
|
|
||||||
driSupport = true;
|
|
||||||
driSupport32Bit = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sound.enable = true;
|
|
||||||
hardware.pulseaudio = {
|
|
||||||
enable = true;
|
|
||||||
support32Bit = config.hardware.pulseaudio.enable;
|
|
||||||
};
|
|
||||||
|
|
||||||
console.font =
|
|
||||||
lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-g18n.psf.gz";
|
|
||||||
|
|
||||||
services.gnome = mkIf enable-gui {
|
|
||||||
evolution-data-server.enable = mkForce false;
|
|
||||||
gnome-user-share.enable = mkForce false;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.flatpak.enable = enable-gui;
|
|
||||||
|
|
||||||
# programs.steam.enable = enable-gui;
|
|
||||||
|
|
||||||
fonts = mkIf enable-gui {
|
|
||||||
fontDir.enable = true;
|
|
||||||
fontconfig.enable = true;
|
|
||||||
#fontconfig.antialias = true;
|
|
||||||
#fontconfig.penultimate.enable = true;
|
|
||||||
#fontconfig.subpixel.lcdfilter = "default";
|
|
||||||
|
|
||||||
fonts = with pkgs; [
|
|
||||||
cantarell_fonts
|
|
||||||
dejavu_fonts
|
|
||||||
dina-font
|
|
||||||
dosemu_fonts
|
|
||||||
fira-code
|
|
||||||
fira-code-symbols
|
|
||||||
freefont_ttf
|
|
||||||
liberation_ttf
|
|
||||||
mplus-outline-fonts
|
|
||||||
nerdfonts
|
|
||||||
noto-fonts
|
|
||||||
noto-fonts-cjk
|
|
||||||
noto-fonts-emoji
|
|
||||||
proggyfonts
|
|
||||||
terminus_font
|
|
||||||
ubuntu_font_family
|
|
||||||
ucsFonts
|
|
||||||
ultimate-oldschool-pc-font-pack
|
|
||||||
unifont
|
|
||||||
xorg.fontadobe100dpi
|
|
||||||
xorg.fontadobe75dpi
|
|
||||||
xorg.fontadobeutopia100dpi
|
|
||||||
xorg.fontadobeutopia75dpi
|
|
||||||
xorg.fontadobeutopiatype1
|
|
||||||
xorg.fontarabicmisc
|
|
||||||
xorg.fontbh100dpi
|
|
||||||
xorg.fontbh75dpi
|
|
||||||
xorg.fontbhlucidatypewriter100dpi
|
|
||||||
xorg.fontbhlucidatypewriter75dpi
|
|
||||||
xorg.fontbhttf
|
|
||||||
xorg.fontbhtype1
|
|
||||||
xorg.fontbitstream100dpi
|
|
||||||
xorg.fontbitstream75dpi
|
|
||||||
xorg.fontbitstreamtype1
|
|
||||||
xorg.fontcronyxcyrillic
|
|
||||||
xorg.fontcursormisc
|
|
||||||
xorg.fontdaewoomisc
|
|
||||||
xorg.fontdecmisc
|
|
||||||
xorg.fontibmtype1
|
|
||||||
xorg.fontisasmisc
|
|
||||||
xorg.fontjismisc
|
|
||||||
xorg.fontmicromisc
|
|
||||||
xorg.fontmisccyrillic
|
|
||||||
xorg.fontmiscethiopic
|
|
||||||
xorg.fontmiscmeltho
|
|
||||||
xorg.fontmiscmisc
|
|
||||||
xorg.fontmuttmisc
|
|
||||||
xorg.fontschumachermisc
|
|
||||||
xorg.fontscreencyrillic
|
|
||||||
xorg.fontsonymisc
|
|
||||||
xorg.fontsunmisc
|
|
||||||
xorg.fontwinitzkicyrillic
|
|
||||||
xorg.fontxfree86type1
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,142 +1,5 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
{
|
||||||
# Available to all users on the system. Keep it minimal.
|
|
||||||
global-packages = with pkgs; [
|
|
||||||
bind
|
|
||||||
cryptsetup
|
|
||||||
git
|
|
||||||
heimdal
|
|
||||||
openssh_gssapi
|
|
||||||
tldr
|
|
||||||
vim
|
|
||||||
wget
|
|
||||||
];
|
|
||||||
|
|
||||||
in {
|
|
||||||
environment = {
|
|
||||||
etc.nixos-live.source = ../../.;
|
|
||||||
|
|
||||||
systemPackages = global-packages;
|
|
||||||
|
|
||||||
# shellInit = ''
|
|
||||||
# ${pkgs.gnupg}/bin/gpg-connect-agent /bye
|
|
||||||
# export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)
|
|
||||||
# '';
|
|
||||||
};
|
|
||||||
|
|
||||||
nix = {
|
|
||||||
package = pkgs.nixFlakes;
|
|
||||||
extraOptions = ''
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
security.acme.acceptTerms = true;
|
|
||||||
hardware.enableRedistributableFirmware = true;
|
|
||||||
|
|
||||||
krb5 = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
appdefaults = {
|
|
||||||
forwardable = true;
|
|
||||||
proxiable = true;
|
|
||||||
encrypt = true;
|
|
||||||
forward = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
libdefaults = {
|
|
||||||
allow_weak_crypto = true;
|
|
||||||
dns_lookup_kdc = true;
|
|
||||||
dns_lookup_realm = true;
|
|
||||||
forwardable = true;
|
|
||||||
proxiable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
kerberos = pkgs.heimdalFull;
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
openssh = {
|
|
||||||
enable = true;
|
|
||||||
startWhenNeeded = true;
|
|
||||||
useDns = true;
|
|
||||||
permitRootLogin = "prohibit-password";
|
|
||||||
extraConfig = ''
|
|
||||||
GSSAPIAuthentication yes
|
|
||||||
GSSAPICleanupCredentials yes
|
|
||||||
GSSAPIKeyExchange yes
|
|
||||||
GSSAPIStoreCredentialsOnRekey yes
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
fail2ban =
|
|
||||||
let domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
|
|
||||||
in {
|
|
||||||
enable = config.networking.firewall.enable;
|
|
||||||
bantime-increment.enable = true;
|
|
||||||
ignoreIP = config.fudo.domains.${domain-name}.local-networks;
|
|
||||||
};
|
|
||||||
|
|
||||||
xserver = {
|
|
||||||
layout = "us";
|
|
||||||
xkbVariant = "dvp";
|
|
||||||
xkbOptions = "ctrl:nocaps";
|
|
||||||
};
|
|
||||||
|
|
||||||
# pcscd.enable = true;
|
|
||||||
# udev.packages = with pkgs; [ yubikey-personalization ];
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall = {
|
|
||||||
# Allow mosh connections if the firewall is enabled
|
|
||||||
allowedUDPPortRanges = [{
|
|
||||||
from = 60000;
|
|
||||||
to = 60100;
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
|
|
||||||
console.useXkbConfig = true;
|
|
||||||
|
|
||||||
i18n.defaultLocale = "en_US.UTF-8";
|
|
||||||
|
|
||||||
programs = {
|
|
||||||
mosh.enable = true;
|
|
||||||
|
|
||||||
bash.enableCompletion = true;
|
|
||||||
|
|
||||||
fish.enable = true;
|
|
||||||
|
|
||||||
gnupg.agent = {
|
|
||||||
enable = true;
|
|
||||||
# enableSSHSupport = true;
|
|
||||||
# pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses";
|
|
||||||
};
|
|
||||||
|
|
||||||
ssh = {
|
|
||||||
startAgent = true;
|
|
||||||
|
|
||||||
package = pkgs.openssh_gssapi;
|
|
||||||
|
|
||||||
extraConfig = ''
|
|
||||||
GSSAPIAuthentication yes
|
|
||||||
GSSAPIDelegateCredentials yes
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
security.pam = {
|
|
||||||
enableSSHAgentAuth = true;
|
|
||||||
|
|
||||||
services = {
|
|
||||||
sshd = {
|
|
||||||
makeHomeDir = true;
|
|
||||||
sshAgentAuth = true;
|
|
||||||
# This isn't supposed to ask for a code unless ~/.google_authenticator exists...but it does
|
|
||||||
# googleAuthenticator.enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib; {
|
with lib; {
|
||||||
imports = [ ./common-ui.nix ];
|
|
||||||
|
|
||||||
config = { networking = { networkmanager.enable = mkForce false; }; };
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,31 +2,4 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{
|
||||||
imports = [ ./common-ui.nix ];
|
|
||||||
|
|
||||||
options.fudo.profile.laptop = {
|
|
||||||
use-network-manager =
|
|
||||||
mkEnableOption "Use NetworkManager instead of wpa_supplicant.";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [ acpi upower wpa_supplicant ];
|
|
||||||
|
|
||||||
networking = if (config.fudo.profile.laptop.use-network-manager) then {
|
|
||||||
networkmanager.enable = true;
|
|
||||||
} else {
|
|
||||||
networkmanager.enable = false;
|
|
||||||
wireless = {
|
|
||||||
enable = true;
|
|
||||||
userControlled = {
|
|
||||||
enable = true;
|
|
||||||
group = "wheel";
|
|
||||||
};
|
|
||||||
networks = mapAttrs (network: networkOpts: {
|
|
||||||
psk = networkOpts.key;
|
|
||||||
}) config.fudo.wireless-networks;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,75 +1,5 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
{
|
||||||
serverPackages = with pkgs; [ emacs-nox reboot-if-necessary test-config ];
|
|
||||||
|
|
||||||
reboot-if-necessary = pkgs.writeShellScriptBin "reboot-if-necessary" ''
|
|
||||||
if [ $# -ne 1 ]; then
|
|
||||||
echo "FAILED: no sync file provided."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
WALL=${pkgs.utillinux}/bin/wall
|
|
||||||
|
|
||||||
if [ -f $1 ]; then
|
|
||||||
$WALL "$1 exists, rebooting system"
|
|
||||||
${pkgs.systemd}/bin/reboot
|
|
||||||
else
|
|
||||||
$WALL "$1 does not exist, switching config."
|
|
||||||
nixos-rebuild switch
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
'';
|
|
||||||
|
|
||||||
test-config = pkgs.writeShellScriptBin "fudo-test-config" ''
|
|
||||||
if [ $# -gt 1 ]; then
|
|
||||||
echo "usage: $0 [timeout]"
|
|
||||||
exit 1
|
|
||||||
elif [ $# -eq 1 ]; then
|
|
||||||
TIMEOUT=$1
|
|
||||||
else
|
|
||||||
TIMEOUT=15m
|
|
||||||
fi
|
|
||||||
|
|
||||||
SYNCFILE=$TMP/sync-$(date +"%Y%m%d-%H%M%N")
|
|
||||||
touch $SYNCFILE
|
|
||||||
${pkgs.utillinux}/bin/wall "Launching config. System will restart in $TIMEOUT if $SYNCFILE still exists."
|
|
||||||
systemd-run --on-active=$TIMEOUT ${reboot-if-necessary} $SYNCFILE
|
|
||||||
nixos-rebuild test
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
'';
|
|
||||||
|
|
||||||
in {
|
|
||||||
imports = [ ./common.nix ];
|
|
||||||
|
|
||||||
config = {
|
|
||||||
environment = { systemPackages = serverPackages; };
|
|
||||||
|
|
||||||
system.autoUpgrade.enable = false;
|
|
||||||
|
|
||||||
networking.networkmanager.enable = mkForce false;
|
|
||||||
|
|
||||||
services = { xserver.enable = false; };
|
|
||||||
|
|
||||||
sound.enable = false;
|
|
||||||
hardware.pulseaudio.enable = false;
|
|
||||||
|
|
||||||
powerManagement =
|
|
||||||
if config.fudo.hosts.${config.instance.hostname}.keep-cool then {
|
|
||||||
enable = true;
|
|
||||||
cpuFreqGovernor = "ondemand";
|
|
||||||
} else {
|
|
||||||
enable = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.targets = {
|
|
||||||
sleep.enable = false;
|
|
||||||
suspend.enable = false;
|
|
||||||
hibernate.enable = false;
|
|
||||||
hybrid-sleep.enable = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
enable-gui = config.fudo.hosts.${hostname}.enable-gui;
|
||||||
|
|
||||||
|
in {
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
|
||||||
|
boot = {
|
||||||
|
plymouth.enable = false;
|
||||||
|
tmpOnTmpfs = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
xserver = mkIf enable-gui {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
desktopManager.gnome.enable = true;
|
||||||
|
|
||||||
|
displayManager.gdm = {
|
||||||
|
enable = true;
|
||||||
|
wayland = false;
|
||||||
|
autoSuspend = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
windowManager.stumpwm.enable = true;
|
||||||
|
|
||||||
|
# windowManager.session = pkgs.lib.singleton {
|
||||||
|
# name = "stumpwm";
|
||||||
|
# start = ''
|
||||||
|
# ${pkgs.lispPackages.stumpwm}/bin/stumpwm &
|
||||||
|
# waidPID=$!
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
trezord.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
hardware = {
|
||||||
|
bluetooth.enable = true;
|
||||||
|
|
||||||
|
opengl = mkIf enable-gui {
|
||||||
|
enable = true;
|
||||||
|
driSupport = true;
|
||||||
|
driSupport32Bit = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sound.enable = true;
|
||||||
|
hardware.pulseaudio = {
|
||||||
|
enable = true;
|
||||||
|
support32Bit = config.hardware.pulseaudio.enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
# console.font =
|
||||||
|
# lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-g18n.psf.gz";
|
||||||
|
|
||||||
|
services.gnome = mkIf enable-gui {
|
||||||
|
evolution-data-server.enable = mkForce false;
|
||||||
|
gnome-user-share.enable = mkForce false;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.flatpak.enable = enable-gui;
|
||||||
|
|
||||||
|
fonts = mkIf enable-gui {
|
||||||
|
fontDir.enable = true;
|
||||||
|
fontconfig.enable = true;
|
||||||
|
#fontconfig.antialias = true;
|
||||||
|
#fontconfig.penultimate.enable = true;
|
||||||
|
#fontconfig.subpixel.lcdfilter = "default";
|
||||||
|
|
||||||
|
fonts = with pkgs; [
|
||||||
|
cantarell_fonts
|
||||||
|
dejavu_fonts
|
||||||
|
dina-font
|
||||||
|
dosemu_fonts
|
||||||
|
fira-code
|
||||||
|
fira-code-symbols
|
||||||
|
freefont_ttf
|
||||||
|
liberation_ttf
|
||||||
|
mplus-outline-fonts
|
||||||
|
nerdfonts
|
||||||
|
noto-fonts
|
||||||
|
noto-fonts-cjk
|
||||||
|
noto-fonts-emoji
|
||||||
|
proggyfonts
|
||||||
|
terminus_font
|
||||||
|
ubuntu_font_family
|
||||||
|
ucsFonts
|
||||||
|
ultimate-oldschool-pc-font-pack
|
||||||
|
unifont
|
||||||
|
xorg.fontadobe100dpi
|
||||||
|
xorg.fontadobe75dpi
|
||||||
|
xorg.fontadobeutopia100dpi
|
||||||
|
xorg.fontadobeutopia75dpi
|
||||||
|
xorg.fontadobeutopiatype1
|
||||||
|
xorg.fontarabicmisc
|
||||||
|
xorg.fontbh100dpi
|
||||||
|
xorg.fontbh75dpi
|
||||||
|
xorg.fontbhlucidatypewriter100dpi
|
||||||
|
xorg.fontbhlucidatypewriter75dpi
|
||||||
|
xorg.fontbhttf
|
||||||
|
xorg.fontbhtype1
|
||||||
|
xorg.fontbitstream100dpi
|
||||||
|
xorg.fontbitstream75dpi
|
||||||
|
xorg.fontbitstreamtype1
|
||||||
|
xorg.fontcronyxcyrillic
|
||||||
|
xorg.fontcursormisc
|
||||||
|
xorg.fontdaewoomisc
|
||||||
|
xorg.fontdecmisc
|
||||||
|
xorg.fontibmtype1
|
||||||
|
xorg.fontisasmisc
|
||||||
|
xorg.fontjismisc
|
||||||
|
xorg.fontmicromisc
|
||||||
|
xorg.fontmisccyrillic
|
||||||
|
xorg.fontmiscethiopic
|
||||||
|
xorg.fontmiscmeltho
|
||||||
|
xorg.fontmiscmisc
|
||||||
|
xorg.fontmuttmisc
|
||||||
|
xorg.fontschumachermisc
|
||||||
|
xorg.fontscreencyrillic
|
||||||
|
xorg.fontsonymisc
|
||||||
|
xorg.fontsunmisc
|
||||||
|
xorg.fontwinitzkicyrillic
|
||||||
|
xorg.fontxfree86type1
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
# Available to all users on the system. Keep it minimal.
|
||||||
|
global-packages = with pkgs; [
|
||||||
|
bind
|
||||||
|
cryptsetup
|
||||||
|
git
|
||||||
|
heimdal
|
||||||
|
openssh_gssapi
|
||||||
|
tldr
|
||||||
|
vim
|
||||||
|
wget
|
||||||
|
];
|
||||||
|
|
||||||
|
in {
|
||||||
|
environment = {
|
||||||
|
etc.nixos-live.source = ../../.;
|
||||||
|
|
||||||
|
systemPackages = global-packages;
|
||||||
|
|
||||||
|
# shellInit = ''
|
||||||
|
# ${pkgs.gnupg}/bin/gpg-connect-agent /bye
|
||||||
|
# export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)
|
||||||
|
# '';
|
||||||
|
};
|
||||||
|
|
||||||
|
system.autoUpgrade.enable = false;
|
||||||
|
|
||||||
|
nix = {
|
||||||
|
package = pkgs.nixFlakes;
|
||||||
|
extraOptions = ''
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
security.acme.acceptTerms = true;
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
|
||||||
|
krb5 = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
appdefaults = {
|
||||||
|
forwardable = true;
|
||||||
|
proxiable = true;
|
||||||
|
encrypt = true;
|
||||||
|
forward = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
libdefaults = {
|
||||||
|
allow_weak_crypto = true;
|
||||||
|
dns_lookup_kdc = true;
|
||||||
|
dns_lookup_realm = true;
|
||||||
|
forwardable = true;
|
||||||
|
proxiable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
kerberos = pkgs.heimdalFull;
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
openssh = {
|
||||||
|
enable = true;
|
||||||
|
startWhenNeeded = true;
|
||||||
|
useDns = true;
|
||||||
|
permitRootLogin = "prohibit-password";
|
||||||
|
extraConfig = ''
|
||||||
|
GSSAPIAuthentication yes
|
||||||
|
GSSAPICleanupCredentials yes
|
||||||
|
GSSAPIKeyExchange yes
|
||||||
|
GSSAPIStoreCredentialsOnRekey yes
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
fail2ban = let
|
||||||
|
domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
|
||||||
|
in {
|
||||||
|
enable = config.networking.firewall.enable;
|
||||||
|
bantime-increment.enable = true;
|
||||||
|
ignoreIP = config.instance.local-networks;
|
||||||
|
};
|
||||||
|
|
||||||
|
xserver = {
|
||||||
|
layout = "us";
|
||||||
|
xkbVariant = "dvp";
|
||||||
|
xkbOptions = "ctrl:nocaps";
|
||||||
|
};
|
||||||
|
|
||||||
|
# pcscd.enable = true;
|
||||||
|
# udev.packages = with pkgs; [ yubikey-personalization ];
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall = {
|
||||||
|
# Allow mosh connections if the firewall is enabled
|
||||||
|
allowedUDPPortRanges = [{
|
||||||
|
from = 60000;
|
||||||
|
to = 60100;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
console.useXkbConfig = true;
|
||||||
|
|
||||||
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
|
|
||||||
|
programs = {
|
||||||
|
mosh.enable = true;
|
||||||
|
|
||||||
|
bash.enableCompletion = true;
|
||||||
|
|
||||||
|
fish.enable = true;
|
||||||
|
|
||||||
|
gnupg.agent = {
|
||||||
|
enable = true;
|
||||||
|
# enableSSHSupport = true;
|
||||||
|
# pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses";
|
||||||
|
};
|
||||||
|
|
||||||
|
ssh = {
|
||||||
|
startAgent = true;
|
||||||
|
|
||||||
|
package = pkgs.openssh_gssapi;
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
GSSAPIAuthentication yes
|
||||||
|
GSSAPIDelegateCredentials yes
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam = {
|
||||||
|
enableSSHAgentAuth = true;
|
||||||
|
|
||||||
|
services = {
|
||||||
|
sshd = {
|
||||||
|
makeHomeDir = true;
|
||||||
|
sshAgentAuth = true;
|
||||||
|
# This isn't supposed to ask for a code unless ~/.google_authenticator exists...but it does
|
||||||
|
# googleAuthenticator.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
imports = [ ./common-ui.nix ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
networking.networkmanager.enable = mkForce false;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
imports = [ ./common-ui.nix ];
|
||||||
|
|
||||||
|
options.fudo.profile.laptop = {
|
||||||
|
use-network-manager =
|
||||||
|
mkEnableOption "Use NetworkManager instead of wpa_supplicant.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [ acpi upower wpa_supplicant ];
|
||||||
|
|
||||||
|
networking = if (config.fudo.profile.laptop.use-network-manager) then {
|
||||||
|
networkmanager.enable = true;
|
||||||
|
} else {
|
||||||
|
networkmanager.enable = false;
|
||||||
|
wireless = {
|
||||||
|
enable = true;
|
||||||
|
userControlled = {
|
||||||
|
enable = true;
|
||||||
|
group = "wheel";
|
||||||
|
};
|
||||||
|
networks = mapAttrs (network: networkOpts: {
|
||||||
|
psk = networkOpts.key;
|
||||||
|
}) config.fudo.wireless-networks;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
reboot-if-necessary = pkgs.writeShellScriptBin "reboot-if-necessary" ''
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "FAILED: no sync file provided."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
WALL=${pkgs.utillinux}/bin/wall
|
||||||
|
|
||||||
|
if [ -f $1 ]; then
|
||||||
|
$WALL "$1 exists, rebooting system"
|
||||||
|
${pkgs.systemd}/bin/reboot
|
||||||
|
else
|
||||||
|
$WALL "$1 does not exist, switching config."
|
||||||
|
nixos-rebuild switch
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
|
||||||
|
test-config = pkgs.writeShellScriptBin "fudo-test-config" ''
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
echo "usage: $0 [timeout]"
|
||||||
|
exit 1
|
||||||
|
elif [ $# -eq 1 ]; then
|
||||||
|
TIMEOUT=$1
|
||||||
|
else
|
||||||
|
TIMEOUT=15m
|
||||||
|
fi
|
||||||
|
|
||||||
|
SYNCFILE=$TMP/sync-$(date +"%Y%m%d-%H%M%N")
|
||||||
|
touch $SYNCFILE
|
||||||
|
${pkgs.utillinux}/bin/wall "Launching config. System will restart in $TIMEOUT if $SYNCFILE still exists."
|
||||||
|
systemd-run --on-active=$TIMEOUT ${reboot-if-necessary} $SYNCFILE
|
||||||
|
nixos-rebuild test
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
|
||||||
|
in {
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
environment = {
|
||||||
|
serverPackages = with pkgs;
|
||||||
|
[ emacs-nox reboot-if-necessary test-config ];
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.networkmanager.enable = mkForce false;
|
||||||
|
|
||||||
|
services.xserver.enable = false;
|
||||||
|
|
||||||
|
sound.enable = false;
|
||||||
|
hardware.pulseaudio.enable = false;
|
||||||
|
|
||||||
|
powerManagement =
|
||||||
|
if config.fudo.hosts.${config.instance.hostname}.keep-cool then {
|
||||||
|
enable = true;
|
||||||
|
cpuFreqGovernor = "ondemand";
|
||||||
|
} else {
|
||||||
|
enable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.targets = {
|
||||||
|
sleep.enable = false;
|
||||||
|
suspend.enable = false;
|
||||||
|
hibernate.enable = false;
|
||||||
|
hybrid-sleep.enable = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -38,29 +38,31 @@ in {
|
||||||
options = [ "comment=systemd.automount" ];
|
options = [ "comment=systemd.automount" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# NOTE: these are pointing directly to nostromo so the krb lookup works
|
||||||
"/net/documents" = {
|
"/net/documents" = {
|
||||||
device = "sea-store.sea.fudo.org:/export/documents";
|
device = "nostromo.sea.fudo.org:/export/documents";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [ "comment=systemd.automount" "sec=krb5p" ];
|
options = [ "comment=systemd.automount" "sec=krb5p" "proto=tcp" ];
|
||||||
};
|
};
|
||||||
"/net/downloads" = {
|
"/net/downloads" = {
|
||||||
device = "sea-store.sea.fudo.org:/export/downloads";
|
device = "nostromo.sea.fudo.org:/export/downloads";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [ "comment=systemd.automount" "sec=krb5i" ];
|
options = [ "comment=systemd.automount" "sec=krb5i" "proto=tcp" ];
|
||||||
};
|
};
|
||||||
"/net/projects" = {
|
"/net/projects" = {
|
||||||
device = "sea-store.sea.fudo.org:/export/projects";
|
device = "nostromo.sea.fudo.org:/export/projects";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [ "comment=systemd.automount" "sec=krb5p" ];
|
options = [ "comment=systemd.automount" "sec=krb5p" "proto=tcp" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd = {
|
systemd = {
|
||||||
tmpfiles.rules = [
|
## This fails if the filesystems already exist
|
||||||
"d /net/documents - root sea-documents - -"
|
# tmpfiles.rules = [
|
||||||
"d /net/downloads - root sea-downloads - -"
|
# "d /net/documents - root sea-documents - -"
|
||||||
"d /net/projects - root sea-projects - -"
|
# "d /net/downloads - root sea-downloads - -"
|
||||||
];
|
# "d /net/projects - root sea-projects - -"
|
||||||
|
# ];
|
||||||
|
|
||||||
# mounts = [
|
# mounts = [
|
||||||
# {
|
# {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
{
|
||||||
|
replicator = {
|
||||||
|
description = "Database Replicator";
|
||||||
|
hashed-password = "{SHA}HpiRMyxLR+0ZFHz/COvG9lcNYyQ=";
|
||||||
|
};
|
||||||
|
|
||||||
|
auth_reader = {
|
||||||
|
description = "System Authenticator";
|
||||||
|
hashed-password = "{MD5}N36/kQ64mev1HARddvVk7Q==";
|
||||||
|
};
|
||||||
|
|
||||||
|
user_db_reader = {
|
||||||
|
description = "User Database Reader";
|
||||||
|
hashed-password = "{SSHA}IVKhrB+wMOCI/CCzbJW8sNDbH67ZTMBv";
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
{ hostname, site, domain, profile, build-timestamp, ... }:
|
{ lib, pkgs, hostname, site, domain, profile, build-timestamp, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
# Get info on this host so we know what to load
|
# Get info on this host so we know what to load
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{ lib, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with pkgs.lib;
|
||||||
let
|
let
|
||||||
join-lines = concatStringsSep "\n";
|
join-lines = concatStringsSep "\n";
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
let
|
# NOTE: OBSOLETE! See overlay.nix
|
||||||
ip = import ./ip.nix { inherit lib; };
|
|
||||||
dns = import ./dns.nix { inherit lib; };
|
|
||||||
passwd = import ./passwd.nix { inherit lib; };
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
lib.overlays = [
|
lib.overlays = [
|
||||||
(final: prev:
|
(final: prev:
|
||||||
prev.lib // {
|
prev.lib // {
|
||||||
fudo = {
|
fudo = let
|
||||||
inherit ip dns passwd;
|
lib = prev.lib;
|
||||||
|
in {
|
||||||
|
ip = import ./ip.nix { inherit lib; };
|
||||||
|
dns = import ./dns.nix { inherit lib; };
|
||||||
|
passwd = import ./passwd.nix { inherit lib; };
|
||||||
|
lisp = import ./lisp.nix { inherit lib; };
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
|
@ -30,7 +30,9 @@ let
|
||||||
# };
|
# };
|
||||||
# };
|
# };
|
||||||
|
|
||||||
domainOpts = { domain, ... }: {
|
domainOpts = { name, ... }: let
|
||||||
|
domain = name;
|
||||||
|
in {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
email = mkOption {
|
email = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
|
@ -45,8 +47,12 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
local-copies = let
|
local-copies = let
|
||||||
localCopyOpts = { copy, ... }: {
|
localCopyOpts = { name, ... }: let
|
||||||
options = with types; {
|
copy = name;
|
||||||
|
in {
|
||||||
|
options = with types; let
|
||||||
|
target-path = "/var/run/${domain}/${copy}";
|
||||||
|
in {
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "User to which this copy belongs.";
|
description = "User to which this copy belongs.";
|
||||||
|
@ -58,17 +64,35 @@ let
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
path = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Path at which to store the local copy.";
|
|
||||||
default = "/var/run/${domain}/${copy}";
|
|
||||||
};
|
|
||||||
|
|
||||||
service = mkOption {
|
service = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "systemd job to copy certs.";
|
description = "systemd job to copy certs.";
|
||||||
default = "fudo-${domain}-${copy}-certs.service";
|
default = "fudo-${domain}-${copy}-certs.service";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
certificate = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Full path to the local copy certificate.";
|
||||||
|
default = "${target-path}/cert.pem";
|
||||||
|
};
|
||||||
|
|
||||||
|
full-certificate = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Full path to the local copy certificate.";
|
||||||
|
default = "${target-path}/fullchain.pem";
|
||||||
|
};
|
||||||
|
|
||||||
|
chain = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Full path to the local copy certificate.";
|
||||||
|
default = "${target-path}/chain.pem";
|
||||||
|
};
|
||||||
|
|
||||||
|
private-key = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Full path to the local copy certificate.";
|
||||||
|
default = "${target-path}/key.pem";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in mkOption {
|
in mkOption {
|
||||||
|
@ -92,7 +116,7 @@ let
|
||||||
cfg.host-domains.${hostname} else {};
|
cfg.host-domains.${hostname} else {};
|
||||||
|
|
||||||
optionalStringOr = str: default:
|
optionalStringOr = str: default:
|
||||||
if cond then str else default;
|
if (str != null) then str else default;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.acme = with types; {
|
options.fudo.acme = with types; {
|
||||||
|
@ -113,26 +137,41 @@ in {
|
||||||
tmpfiles.rules = let
|
tmpfiles.rules = let
|
||||||
copies = concatMapAttrs (domain: domainOpts:
|
copies = concatMapAttrs (domain: domainOpts:
|
||||||
domainOpts.local-copies) localDomains;
|
domainOpts.local-copies) localDomains;
|
||||||
|
perms = copyOpts: if (copyOpts.group != null) then "0550" else "0500";
|
||||||
copy-paths = mapAttrsToList (copy: copyOpts:
|
copy-paths = mapAttrsToList (copy: copyOpts:
|
||||||
"D '${path}' 0550 ${copyOpts.user} ${optionalStringOr copyOpts.group "-"} - -")
|
let
|
||||||
copies;
|
dir-entry = copyOpts: file: "D '${dirOf file}' ${perms copyOpts} ${copyOpts.user} ${optionalStringOr copyOpts.group "-"} - -";
|
||||||
in copy-paths;
|
in map (dir-entry copyOpts) [
|
||||||
|
copyOpts.certificate
|
||||||
|
copyOpts.full-certificate
|
||||||
|
copyOpts.chain
|
||||||
|
copyOpts.private-key
|
||||||
|
]) copies;
|
||||||
|
in unique copy-paths;
|
||||||
|
|
||||||
# TODO: Make this a Fudo service?
|
|
||||||
services = concatMapAttrs (domain: domainOpts:
|
services = concatMapAttrs (domain: domainOpts:
|
||||||
mapAttrs' (copy: copyOpts: let
|
mapAttrs' (copy: copyOpts: let
|
||||||
|
key-perms = copyOpts: if (copyOpts.group != null) then "0440" else "0400";
|
||||||
source = config.security.acme.certs.${domain}.directory;
|
source = config.security.acme.certs.${domain}.directory;
|
||||||
target = copyOpts.path;
|
target = copyOpts.path;
|
||||||
install-certs = pkgs.writeShellScript "fudo-install-${domain}-${site}-certs.sh" ''
|
install-certs = pkgs.writeShellScript "fudo-install-${domain}-${copy}-certs.sh" ''
|
||||||
for cert in cert chain fullchain full key; do
|
cp cert.pem ${copyOpts.certificate}
|
||||||
cp ${source}/$cert.pem ${target}/$cert.pem
|
chmod 0444 ${copyOpts.certificate}
|
||||||
chmod 0440 ${source}/$cert.pem
|
|
||||||
done
|
cp full.pem ${copyOpts.full-certificate}
|
||||||
|
chmod 0444 ${copyOpts.full-certificate}
|
||||||
|
|
||||||
|
cp chain.pem ${copyOpts.chain}
|
||||||
|
chmod 0444 ${copyOpts.chain}
|
||||||
|
|
||||||
|
cp key.pem ${copyOpts.private-key}
|
||||||
|
chmod ${key-perms copyOpts} ${copyOpts.private-key}
|
||||||
'';
|
'';
|
||||||
remove-certs = pkgs.writeShellScript "fudo-remove-${domain}-${site}-certs.sh" ''
|
remove-certs = pkgs.writeShellScript "fudo-remove-${domain}-${copy}-certs.sh" ''
|
||||||
for cert in cert chain fullchain full key; do
|
rm -f ${copyOpts.private-key}
|
||||||
rm -rf ${target}/$cert.pem
|
rm -f ${copyOpts.chainy}
|
||||||
done
|
rm -f ${copyOpts.full-certificate}
|
||||||
|
rm -f ${copyOpts.certificate}
|
||||||
'';
|
'';
|
||||||
in nameValuePair
|
in nameValuePair
|
||||||
(rm-service-ext copyOpts.service) {
|
(rm-service-ext copyOpts.service) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{ ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./dns.nix
|
./dns.nix
|
||||||
|
|
|
@ -1,63 +1,10 @@
|
||||||
|
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.backplane.dns;
|
cfg = config.fudo.backplane.dns;
|
||||||
|
|
||||||
lisp-pkgs = with pkgs.localLispPackages; [
|
powerdns-conf-dir = "${cfg.powerdns-home}/conf.d";
|
||||||
arrows
|
|
||||||
backplane-dns
|
|
||||||
backplane-server
|
|
||||||
cl-sasl
|
|
||||||
cl-xmpp
|
|
||||||
ip-utils
|
|
||||||
|
|
||||||
alexandria
|
|
||||||
babel
|
|
||||||
bordeaux-threads
|
|
||||||
cffi
|
|
||||||
cl-base64
|
|
||||||
cl-json
|
|
||||||
cl-postgres
|
|
||||||
cl-ppcre
|
|
||||||
cl-unicode
|
|
||||||
cl_plus_ssl
|
|
||||||
closer-mop
|
|
||||||
closure-common
|
|
||||||
cxml
|
|
||||||
flexi-streams
|
|
||||||
global-vars
|
|
||||||
introspect-environment
|
|
||||||
ironclad
|
|
||||||
iterate
|
|
||||||
lisp-namespace
|
|
||||||
md5
|
|
||||||
nibbles
|
|
||||||
postmodern
|
|
||||||
puri
|
|
||||||
s-sql
|
|
||||||
split-sequence
|
|
||||||
trivia
|
|
||||||
trivia_dot_balland2006
|
|
||||||
trivia_dot_level0
|
|
||||||
trivia_dot_level1
|
|
||||||
trivia_dot_level2
|
|
||||||
trivia_dot_trivial
|
|
||||||
trivial-cltl2
|
|
||||||
trivial-features
|
|
||||||
trivial-garbage
|
|
||||||
trivial-gray-streams
|
|
||||||
type-i
|
|
||||||
uax-15
|
|
||||||
usocket
|
|
||||||
];
|
|
||||||
|
|
||||||
backup-directory = "/var/lib/fudo/backplane/dns";
|
|
||||||
|
|
||||||
powerdns-home = "/var/lib/powerdns";
|
|
||||||
|
|
||||||
powerdns-conf-dir = "${powerdns-home}/conf.d";
|
|
||||||
|
|
||||||
backplaneOpts = { ... }: {
|
backplaneOpts = { ... }: {
|
||||||
options = {
|
options = {
|
||||||
|
@ -117,53 +64,59 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.backplane.dns = {
|
options.fudo.backplane.dns = with types; {
|
||||||
enable = mkEnableOption "Enable backplane dynamic DNS server.";
|
enable = mkEnableOption "Enable backplane dynamic DNS server.";
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.port;
|
type = port;
|
||||||
description = "Port on which to serve authoritative DNS requests.";
|
description = "Port on which to serve authoritative DNS requests.";
|
||||||
default = 53;
|
default = 53;
|
||||||
};
|
};
|
||||||
|
|
||||||
listen-v4-addresses = mkOption {
|
listen-v4-addresses = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = "IPv4 addresses on which to listen for dns requests.";
|
description = "IPv4 addresses on which to listen for dns requests.";
|
||||||
default = [ "0.0.0.0" ];
|
default = [ "0.0.0.0" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
listen-v6-addresses = mkOption {
|
listen-v6-addresses = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = "IPv6 addresses on which to listen for dns requests.";
|
description = "IPv6 addresses on which to listen for dns requests.";
|
||||||
example = [ "[abcd::1]" ];
|
example = [ "[abcd::1]" ];
|
||||||
default = [ ];
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
required-services = mkOption {
|
required-services = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description =
|
description =
|
||||||
"A list of services required before the DNS server can start.";
|
"A list of services required before the DNS server can start.";
|
||||||
};
|
};
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "User as which to run DNS backplane listener service.";
|
description = "User as which to run DNS backplane listener service.";
|
||||||
default = "backplane-dns";
|
default = "backplane-dns";
|
||||||
};
|
};
|
||||||
|
|
||||||
group = mkOption {
|
group = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Group as which to run DNS backplane listener service.";
|
description = "Group as which to run DNS backplane listener service.";
|
||||||
default = "backplane-dns";
|
default = "backplane-dns";
|
||||||
};
|
};
|
||||||
|
|
||||||
database = mkOption {
|
database = mkOption {
|
||||||
type = with types; submodule databaseOpts;
|
type = submodule databaseOpts;
|
||||||
description = "Database settings for the DNS server.";
|
description = "Database settings for the DNS server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
powerdns-home = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Directory at which to store powerdns configuration and state.";
|
||||||
|
default = "/run/backplane-dns/powerdns";
|
||||||
|
};
|
||||||
|
|
||||||
backplane = mkOption {
|
backplane = mkOption {
|
||||||
type = with types; submodule backplaneOpts;
|
type = submodule backplaneOpts;
|
||||||
description = "Backplane Jabber settings for the DNS server.";
|
description = "Backplane Jabber settings for the DNS server.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -177,7 +130,11 @@ in {
|
||||||
createHome = true;
|
createHome = true;
|
||||||
home = "/var/home/${cfg.user}";
|
home = "/var/home/${cfg.user}";
|
||||||
};
|
};
|
||||||
backplane-powerdns = { isSystemUser = true; };
|
backplane-powerdns = {
|
||||||
|
isSystemUser = true;
|
||||||
|
home = cfg.powerdns-home;
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
groups = {
|
groups = {
|
||||||
|
@ -186,65 +143,17 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd = {
|
fudo.system.services = {
|
||||||
targets = {
|
backplane-powerdns-config-generator = {
|
||||||
backplane-dns = {
|
|
||||||
description = "Fudo DNS backplane services.";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
|
|
||||||
backplane-powerdns = let
|
|
||||||
configDir = pkgs.writeTextDir "pdns.conf" ''
|
|
||||||
local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
|
|
||||||
local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
|
|
||||||
local-port=${toString cfg.port}
|
|
||||||
launch=
|
|
||||||
include-dir=${powerdns-conf-dir}/
|
|
||||||
'';
|
|
||||||
|
|
||||||
psql-user = config.services.postgresql.superUser;
|
|
||||||
|
|
||||||
in {
|
|
||||||
unitConfig.Documentation = "man:pdns_server(1) man:pdns_control(1)";
|
|
||||||
description = "Backplane PowerDNS name server";
|
|
||||||
requires = [
|
|
||||||
"postgresql.service"
|
|
||||||
"backplane-dns-config-generator.service"
|
|
||||||
"backplane-dns.target"
|
|
||||||
];
|
|
||||||
after = [ "network.target" "postgresql.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
|
|
||||||
path = with pkgs; [ postgresql ];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = "10";
|
|
||||||
StartLimitInterval = "0";
|
|
||||||
PrivateDevices = true;
|
|
||||||
# CapabilityBoundingSet="CAP_CHOWN CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT";
|
|
||||||
# NoNewPrivileges=true;
|
|
||||||
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${powerdns-home}";
|
|
||||||
ExecStart =
|
|
||||||
"${pkgs.powerdns}/bin/pdns_server --setuid=backplane-powerdns --setgid=backplane-powerdns --chroot=${powerdns-home} --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${configDir}";
|
|
||||||
ProtectSystem = "full";
|
|
||||||
# ProtectHome=true;
|
|
||||||
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
backplane-dns-config-generator = {
|
|
||||||
description =
|
description =
|
||||||
"Generate postgres configuration for backplane DNS server.";
|
"Generate postgres configuration for backplane DNS server.";
|
||||||
requiredBy = [ "backplane-powerdns.service" ];
|
|
||||||
requires = cfg.required-services;
|
requires = cfg.required-services;
|
||||||
serviceConfig.Type = "oneshot";
|
type = "oneshot";
|
||||||
restartIfChanged = true;
|
restartIfChanged = true;
|
||||||
partOf = [ "backplane-dns.target" ];
|
partOf = [ "backplane-dns.target" ];
|
||||||
|
|
||||||
|
readWritePaths = [ powerdns-conf-dir ];
|
||||||
|
|
||||||
preStart = ''
|
preStart = ''
|
||||||
mkdir -p ${powerdns-conf-dir}
|
mkdir -p ${powerdns-conf-dir}
|
||||||
chown backplane-powerdns:backplane-powerdns ${powerdns-conf-dir}
|
chown backplane-powerdns:backplane-powerdns ${powerdns-conf-dir}
|
||||||
|
@ -277,30 +186,42 @@ in {
|
||||||
echo "gpgsql-dnssec=yes" >> $TMPCONF
|
echo "gpgsql-dnssec=yes" >> $TMPCONF
|
||||||
|
|
||||||
mv $TMPCONF ${powerdns-conf-dir}/pdns.local.gpgsql.conf
|
mv $TMPCONF ${powerdns-conf-dir}/pdns.local.gpgsql.conf
|
||||||
|
|
||||||
rm -rf $TMPDIR
|
rm -rf $TMPDIR
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
backplane-powerdns = let
|
||||||
|
pdns-config-dir = pkgs.writeTextDir "pdns.conf" ''
|
||||||
|
local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
|
||||||
|
local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
|
||||||
|
local-port=${toString cfg.port}
|
||||||
|
launch=
|
||||||
|
include-dir=${powerdns-conf-dir}/
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
description = "Backplane PowerDNS name server";
|
||||||
|
requires = [
|
||||||
|
"postgresql.service"
|
||||||
|
"backplane-powerdns-config-generator.service"
|
||||||
|
];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
path = with pkgs; [ powerdns postgresql ];
|
||||||
|
execStart = "pdns_server --setuid=backplane-powerdns --setgid=backplane-powerdns --chroot=${cfg.powerdns-home} --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${pdns-config-dir}";
|
||||||
|
};
|
||||||
|
|
||||||
backplane-dns = {
|
backplane-dns = {
|
||||||
description = "Fudo DNS Backplane Server";
|
description = "Fudo DNS Backplane Server";
|
||||||
restartIfChanged = true;
|
restartIfChanged = true;
|
||||||
|
path = with pkgs; [ backplane-dns-server ];
|
||||||
serviceConfig = {
|
execStart = "launch-backplane-dns.sh";
|
||||||
ExecStart =
|
pidFile = "/run/backplane-dns.$USERNAME.pid";
|
||||||
"${pkgs.backplane-dns-server}/bin/launch-backplane-dns.sh";
|
user = cfg.user;
|
||||||
Restart = "on-failure";
|
group = cfg.group;
|
||||||
PIDFile = "/run/backplane-dns.$USERNAME.pid";
|
partOf = [ "backplane-dns.target" ];
|
||||||
User = cfg.user;
|
requires = [ "postgresql.service" ];
|
||||||
Group = cfg.group;
|
|
||||||
StandardOutput = "journal";
|
|
||||||
};
|
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
# LD_LIBRARY_PATH = "${pkgs.openssl_1_1.out}/lib";
|
|
||||||
|
|
||||||
FUDO_DNS_BACKPLANE_XMPP_HOSTNAME = cfg.backplane.host;
|
FUDO_DNS_BACKPLANE_XMPP_HOSTNAME = cfg.backplane.host;
|
||||||
FUDO_DNS_BACKPLANE_XMPP_USERNAME = cfg.backplane.role;
|
FUDO_DNS_BACKPLANE_XMPP_USERNAME = cfg.backplane.role;
|
||||||
FUDO_DNS_BACKPLANE_XMPP_PASSWORD_FILE = cfg.backplane.password-file;
|
FUDO_DNS_BACKPLANE_XMPP_PASSWORD_FILE = cfg.backplane.password-file;
|
||||||
|
@ -311,15 +232,18 @@ in {
|
||||||
FUDO_DNS_BACKPLANE_DATABASE_PASSWORD_FILE =
|
FUDO_DNS_BACKPLANE_DATABASE_PASSWORD_FILE =
|
||||||
cfg.backplane.database.password-file;
|
cfg.backplane.database.password-file;
|
||||||
|
|
||||||
# CL_SOURCE_REGISTRY = "${pkgs.localLispPackages.backplane-dns}//";
|
|
||||||
|
|
||||||
CL_SOURCE_REGISTRY =
|
CL_SOURCE_REGISTRY =
|
||||||
lib.concatStringsSep ":" (map (pkg: "${pkg}//") lisp-pkgs);
|
pkgs.lib.fudo.lisp.lisp-source-registry pkgs.backplane-dns-server;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
requires = cfg.required-services;
|
systemd = {
|
||||||
partOf = [ "backplane-dns.target" ];
|
targets = {
|
||||||
|
backplane-dns = {
|
||||||
|
description = "Fudo DNS backplane services.";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
requries = cfg.required-services ++ [ "postgresql.service" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,7 +108,7 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
appName = cfg.site-name;
|
appName = cfg.site-name;
|
||||||
database = {
|
database = {
|
||||||
createDatabase = true;
|
createDatabase = false;
|
||||||
host = cfg.database.hostname;
|
host = cfg.database.hostname;
|
||||||
name = cfg.database.name;
|
name = cfg.database.name;
|
||||||
user = cfg.database.user;
|
user = cfg.database.user;
|
||||||
|
|
|
@ -34,8 +34,9 @@ in {
|
||||||
systemd = {
|
systemd = {
|
||||||
# Ensure the mountpoints exist
|
# Ensure the mountpoints exist
|
||||||
tmpfiles.rules = let
|
tmpfiles.rules = let
|
||||||
|
mpPerms = mpOpts: if mpOpts.world-readable then "755" else "750";
|
||||||
mountpointToPath = mp: mpOpts:
|
mountpointToPath = mp: mpOpts:
|
||||||
"d '${mp}' 750 root ${optionalOrDefault mpOpts.group "-"} - -";
|
"d '${mp}' ${mpPerms mpOpts} root ${optionalOrDefault mpOpts.group "-"} - -";
|
||||||
filesystemsToMountpointLists = mapAttrsToList
|
filesystemsToMountpointLists = mapAttrsToList
|
||||||
(fs: fsOpts: fsOpts.mountpoints);
|
(fs: fsOpts: fsOpts.mountpoints);
|
||||||
mountpointListsToPaths = concatMap
|
mountpointListsToPaths = concatMap
|
||||||
|
|
|
@ -6,6 +6,10 @@ let
|
||||||
|
|
||||||
host = import ../types/host.nix { inherit lib; };
|
host = import ../types/host.nix { inherit lib; };
|
||||||
|
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
|
||||||
|
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.hosts = with types;
|
options.fudo.hosts = with types;
|
||||||
mkOption {
|
mkOption {
|
||||||
|
@ -73,6 +77,8 @@ in {
|
||||||
config.environment.systemPackages;
|
config.environment.systemPackages;
|
||||||
sorted-unique = sort lessThan (unique packages);
|
sorted-unique = sort lessThan (unique packages);
|
||||||
in concatStringsSep "\n" sorted-unique;
|
in concatStringsSep "\n" sorted-unique;
|
||||||
|
|
||||||
|
build-timestamp.text = toString config.instance.build-timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemPackages = with pkgs;
|
systemPackages = with pkgs;
|
||||||
|
@ -103,10 +109,6 @@ in {
|
||||||
(keypair: keypair.private-key)
|
(keypair: keypair.private-key)
|
||||||
(try-attr hostname files.build-keypairs);
|
(try-attr hostname files.build-keypairs);
|
||||||
|
|
||||||
backplane-passwd-source = try-attr hostname files.backplane-passwords;
|
|
||||||
|
|
||||||
backplane-passwd-target = "/var/run/backplane/passwd";
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
secrets.host-secrets.${hostname} = {
|
secrets.host-secrets.${hostname} = {
|
||||||
host-keytab = mkIf (keytab-file != null) {
|
host-keytab = mkIf (keytab-file != null) {
|
||||||
|
@ -121,15 +123,15 @@ in {
|
||||||
user = "root";
|
user = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
backplane-passwd = mkIf (backplane-passwd-source != null) {
|
backplane-passwd = {
|
||||||
source-file = backplane-passwd-source;
|
source-file = host-cfg.backplane-password-file;
|
||||||
target-file = backplane-passwd-target;
|
target-file = "/run/backplane/client/passwd";
|
||||||
user = config.fudo.client.dns.user;
|
user = config.fudo.client.dns.user;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
client.dns.password-file = mkIf (backplane-passwd-source != null)
|
client.dns.password-file =
|
||||||
backplane-passwd-target;
|
host-secrets.backplane-passwd.target-file;
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.adb.enable = host-cfg.android-dev;
|
programs.adb.enable = host-cfg.android-dev;
|
||||||
|
|
|
@ -23,16 +23,16 @@ let
|
||||||
foldr (a: b: a // b) {} (mapAttrs f attrs);
|
foldr (a: b: a // b) {} (mapAttrs f attrs);
|
||||||
|
|
||||||
concatMapAttrsToList = f: attr:
|
concatMapAttrsToList = f: attr:
|
||||||
attrValues (concatMapAttrs f attr);
|
concatMap (i: i) (attrValues (mapAttrs f attr));
|
||||||
|
|
||||||
host-domains = config.fudo.acme.host-domains.${hostname};
|
host-domains = config.fudo.acme.host-domains.${hostname};
|
||||||
|
|
||||||
siteCerts = site: let
|
siteCerts = site: let
|
||||||
certPath = host-domains.${site}.local-copies.ejabberd.path;
|
cert-copy = host-domains.${site}.local-copies.ejabberd;
|
||||||
in [
|
in [
|
||||||
"${certPath}/fullchain.pem"
|
cert-copy.certificate
|
||||||
"${certPath}/privkey.pem"
|
cert-copy.private-key
|
||||||
"${certPath}/chain.pem"
|
cert-copy.chain
|
||||||
];
|
];
|
||||||
|
|
||||||
siteCertService = site:
|
siteCertService = site:
|
||||||
|
@ -60,13 +60,13 @@ let
|
||||||
|
|
||||||
hosts = attrNames cfg.sites;
|
hosts = attrNames cfg.sites;
|
||||||
|
|
||||||
listen = [{
|
listen = map (ip: {
|
||||||
port = cfg.port;
|
port = cfg.port;
|
||||||
module = "ejabberd_c2s";
|
module = "ejabberd_c2s";
|
||||||
ip = cfg.listen-ip;
|
ip = ip;
|
||||||
starttls = true;
|
starttls = true;
|
||||||
starttls_required = true;
|
starttls_required = true;
|
||||||
}];
|
}) cfg.listen-ips;
|
||||||
|
|
||||||
certfiles = concatMapAttrsToList
|
certfiles = concatMapAttrsToList
|
||||||
(site: siteOpts:
|
(site: siteOpts:
|
||||||
|
@ -94,7 +94,6 @@ let
|
||||||
swapper = concatStringsSep " | " secret-swappers;
|
swapper = concatStringsSep " | " secret-swappers;
|
||||||
in pkgs.writeShellScript "ejabberd-generate-config.sh" ''
|
in pkgs.writeShellScript "ejabberd-generate-config.sh" ''
|
||||||
cat ${template} | ${swapper} > ${target}
|
cat ${template} | ${swapper} > ${target}
|
||||||
chown ${cfg.user}:${cfg.group} ${target}
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
cfg = config.fudo.jabber;
|
cfg = config.fudo.jabber;
|
||||||
|
@ -103,6 +102,11 @@ in {
|
||||||
options.fudo.jabber = with types; {
|
options.fudo.jabber = with types; {
|
||||||
enable = mkEnableOption "Enable ejabberd server.";
|
enable = mkEnableOption "Enable ejabberd server.";
|
||||||
|
|
||||||
|
listen-ips = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "IPs on which to listen for Jabber connections.";
|
||||||
|
};
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = port;
|
type = port;
|
||||||
description = "Port on which to listen for Jabber connections.";
|
description = "Port on which to listen for Jabber connections.";
|
||||||
|
@ -122,7 +126,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
admins = mkOption {
|
admins = mkOption {
|
||||||
type = str;
|
type = listOf str;
|
||||||
description = "List of admin users for the server.";
|
description = "List of admin users for the server.";
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
|
@ -141,7 +145,23 @@ in {
|
||||||
config-file = mkOption {
|
config-file = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Location at which to generate the configuration file.";
|
description = "Location at which to generate the configuration file.";
|
||||||
default = "/var/run/ejabberd/ejabberd.yaml";
|
default = "/run/ejabberd/ejabberd.yaml";
|
||||||
|
};
|
||||||
|
|
||||||
|
log-level = mkOption {
|
||||||
|
type = int;
|
||||||
|
description = ''
|
||||||
|
Log level at which to run the server.
|
||||||
|
|
||||||
|
See: https://docs.ejabberd.im/admin/guide/troubleshooting/
|
||||||
|
'';
|
||||||
|
default = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment = mkOption {
|
||||||
|
type = attrsOf str;
|
||||||
|
description = "Environment variables to set for the ejabberd daemon.";
|
||||||
|
default = {};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,7 +176,8 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo.acme.host-domains.${hostname} = mapAttrs (site: siteCfg:
|
fudo = {
|
||||||
|
acme.host-domains.${hostname} = mapAttrs (site: siteCfg:
|
||||||
mkIf siteCfg.enableACME {
|
mkIf siteCfg.enableACME {
|
||||||
local-copies.ejabberd = {
|
local-copies.ejabberd = {
|
||||||
user = cfg.user;
|
user = cfg.user;
|
||||||
|
@ -164,18 +185,41 @@ in {
|
||||||
};
|
};
|
||||||
}) cfg.sites;
|
}) cfg.sites;
|
||||||
|
|
||||||
|
system = let
|
||||||
|
config-dir = dirOf cfg.config-file;
|
||||||
|
in {
|
||||||
|
ensure-directories.${config-dir} = {
|
||||||
|
user = cfg.user;
|
||||||
|
perms = "0700";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.ejabberd-config-generator = let
|
||||||
|
config-generator =
|
||||||
|
enter-secrets config-file-template cfg.secret-files cfg.config-file;
|
||||||
|
in {
|
||||||
|
script = "${config-generator}";
|
||||||
|
readWritePaths = [ config-dir ];
|
||||||
|
workingDirectory = config-dir;
|
||||||
|
user = cfg.user;
|
||||||
|
description = "Generate ejabberd config file with necessary passwords.";
|
||||||
|
postStart = ''
|
||||||
|
chown ${cfg.user} ${cfg.config-file}
|
||||||
|
chmod 0400 ${cfg.config-file}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
systemd = {
|
systemd = {
|
||||||
tmpfiles.rules = [
|
tmpfiles.rules = [
|
||||||
"D '${dirOf cfg.config-file}' 0550 ${cfg.user} ${cfg.group} - -"
|
"D '${dirOf cfg.config-file}' 0550 ${cfg.user} ${cfg.group} - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
services.ejabberd = let
|
services = {
|
||||||
config-generator = enter-secrets config-file-template cfg.secret-files cfg.config-file;
|
ejabberd = {
|
||||||
in {
|
|
||||||
wants = map (site: siteCertService site) (attrNames cfg.sites);
|
wants = map (site: siteCertService site) (attrNames cfg.sites);
|
||||||
environment = cfg.secret-files;
|
requires = [ "ejabberd-config-generator.service" ];
|
||||||
serviceConfig = {
|
environment = cfg.environment;
|
||||||
ExecStartPre = mkAfter "${config-generator}";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -205,6 +205,7 @@ in {
|
||||||
|
|
||||||
ssl-ca-certificate = mkOption {
|
ssl-ca-certificate = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
The path to the SSL CA cert used to sign the certificate.
|
The path to the SSL CA cert used to sign the certificate.
|
||||||
'';
|
'';
|
||||||
|
@ -220,9 +221,8 @@ in {
|
||||||
|
|
||||||
base = mkOption {
|
base = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = ''
|
description = "The base dn of the LDAP server.";
|
||||||
The base dn of the LDAP server (eg. "dc=fudo,dc=org").
|
example = "dc=fudo,dc=org";
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
rootpw-file = mkOption {
|
rootpw-file = mkOption {
|
||||||
|
@ -239,7 +239,6 @@ in {
|
||||||
A list of URIs on which the ldap server should listen.
|
A list of URIs on which the ldap server should listen.
|
||||||
'';
|
'';
|
||||||
example = [ "ldap://auth.fudo.org" "ldaps://auth.fudo.org" ];
|
example = [ "ldap://auth.fudo.org" "ldaps://auth.fudo.org" ];
|
||||||
default = [ ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
|
@ -295,12 +294,11 @@ in {
|
||||||
etc = {
|
etc = {
|
||||||
"openldap/sasl2/slapd.conf" = {
|
"openldap/sasl2/slapd.conf" = {
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
user = "openldap";
|
user = config.services.openldap.user;
|
||||||
group = "openldap";
|
group = config.services.openldap.group;
|
||||||
# FIXME: take arguments!
|
|
||||||
text = ''
|
text = ''
|
||||||
mech_list: gssapi external
|
mech_list: gssapi external
|
||||||
keytab: /etc/ldap/ldap.keytab
|
keytab: ${cfg.kerberos-keytab}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -343,72 +341,126 @@ in {
|
||||||
rootdn = "cn=admin,${cfg.base}";
|
rootdn = "cn=admin,${cfg.base}";
|
||||||
rootpwFile = "${cfg.rootpw-file}";
|
rootpwFile = "${cfg.rootpw-file}";
|
||||||
urlList = cfg.listen-uris;
|
urlList = cfg.listen-uris;
|
||||||
|
database = "mdb";
|
||||||
|
|
||||||
extraConfig = ''
|
settings = let
|
||||||
|
makeAccessLine = i: attrs: perm-map: let
|
||||||
|
perm-strings = mapAttrs (dn: perm: "by ${dn} ${perm}") perm-map;
|
||||||
|
perm-string = concatStringsSep " " perm-strings;
|
||||||
|
in "${i}to ${attrs} ${perm-string}";
|
||||||
|
|
||||||
TLSCertificateFile ${cfg.ssl-certificate}
|
makeAccess = access-map: let
|
||||||
TLSCertificateKeyFile ${cfg.ssl-private-key}
|
pairs = mapAttrsToList (target: perm-map: [target perm-map]) access-map;
|
||||||
${optionalString (cfg.ssl-ca-certificate != null)
|
in imap0 (i: pair: makeAccessLine i pair[0] pair[1]) pairs;
|
||||||
"TLSCACertificateFile ${cfg.ssl-ca-certificate}"}
|
|
||||||
|
|
||||||
authz-regexp "^uid=auth/([^.]+)\.fudo\.org,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=$1,ou=hosts,dc=fudo,dc=org"
|
in {
|
||||||
authz-regexp "^uid=[^,/]+/root,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=admin,dc=fudo,dc=org"
|
attrs = {
|
||||||
authz-regexp "^uid=([^,/]+),cn=fudo\.org,cn=gssapi,cn=auth$" "uid=$1,ou=members,dc=fudo,dc=org"
|
cn = "config";
|
||||||
authz-regexp "^uid=host/([^,/]+),cn=fudo\.org,cn=gssapi,cn=auth$" "cn=$1,ou=hosts,dc=fudo,dc=org"
|
objectClass = "olcGlobal";
|
||||||
authz-regexp "^gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth$" "cn=admin,dc=fudo,dc=org"
|
olcPidFile = "/run/slapd/slapd.pid";
|
||||||
|
olcTLSCertificateFile = cfg.ssl-certificate;
|
||||||
'';
|
olcTLSCertificateKeyFile = cfg.ssl-private-key;
|
||||||
|
olcTLSCACertificateFile = cfg.ssl-ca-certificate;
|
||||||
extraDatabaseConfig = ''
|
olcSaslSecProps = "noplain,noanonymous";
|
||||||
# access to dn=base=""
|
olcAuthzRegexp = let
|
||||||
# by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
|
authz-regex-entry = i: { regex, target}:
|
||||||
# by * read
|
"{${i}}\"${rx}\" \"${target}\"";
|
||||||
|
in imap0 authz-regex-entry [
|
||||||
access to attrs=userPassword,shadowLastChange
|
{
|
||||||
by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
|
regex = "^uid=auth/([^.]+).fudo.org,cn=fudo.org,cn=gssapi,cn=auth$";
|
||||||
by group.exact="cn=admin,ou=members,${cfg.base}" write
|
target = "cn=$1,ou=hosts,dc=fudo,dc=org";
|
||||||
by dn.exact="cn=auth_reader,${cfg.base}" read
|
}
|
||||||
by dn.exact="cn=replicator,${cfg.base}" read
|
{
|
||||||
by self write
|
regex = "^uid=[^,/]+/root,cn=fudo.org,cn=gssapi,cn=auth$";
|
||||||
by * auth
|
target = "cn=admin,dc=fudo,dc=org";
|
||||||
|
}
|
||||||
access to dn.exact="cn=admin,ou=groups,${cfg.base}"
|
{
|
||||||
by dn.exact="cn=admin,${cfg.base}" write
|
regex = "^uid=([^,/]+),cn=fudo.org,cn=gssapi,cn=auth$";
|
||||||
by users read
|
target = "uid=$1,ou=members,dc=fudo,dc=org";
|
||||||
by * none
|
}
|
||||||
|
{
|
||||||
access to dn.subtree="ou=groups,${cfg.base}" attrs=memberUid
|
regex = "^uid=host/([^,/]+),cn=fudo.org,cn=gssapi,cn=auth$";
|
||||||
by dn.regex="cn=[a-zA-Z][a-zA-Z0-9_]+,ou=hosts,${cfg.base}" write
|
target = "cn=$1,ou=hosts,dc=fudo,dc=org";
|
||||||
by group.exact="cn=admin,ou=groups,${cfg.base}" write
|
}
|
||||||
by users read
|
{
|
||||||
by * none
|
regex = "^gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth$";
|
||||||
|
target = "cn=admin,dc=fudo,dc=org";
|
||||||
access to dn.subtree="ou=members,${cfg.base}" attrs=cn,sn,homeDirectory,loginShell,gecos,description,homeDirectory,uidNumber,gidNumber
|
}
|
||||||
by group.exact="cn=admin,ou=groups,${cfg.base}" write
|
];
|
||||||
by dn.exact="cn=user_db_reader,${cfg.base}" read
|
};
|
||||||
by users read
|
children = {
|
||||||
by * none
|
"olcDatabase{-1}frontend" = {
|
||||||
|
attrs = {
|
||||||
access to dn.exact="cn=admin,ou=groups,${cfg.base}"
|
objectClass = [ "olcDatabaseConfig" "olcFrontendConfig" ];
|
||||||
by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
|
olcDatabase = "{-1}frontend";
|
||||||
by users read
|
olcAccess = makeAccess {
|
||||||
by * none
|
"*" = {
|
||||||
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
access to dn.subtree="ou=groups,${cfg.base}" attrs=memberUid
|
"dn.exact=cn=admin,dc=fudo,dc=org" = "manage";
|
||||||
by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
|
"*" = "none";
|
||||||
by dn.regex="cn=[a-zA-Z][a-zA-Z0-9_]+,ou=hosts,${cfg.base}" write
|
};
|
||||||
by group.exact="cn=admin,ou=groups,${cfg.base}" write
|
};
|
||||||
by users read
|
};
|
||||||
by * none
|
};
|
||||||
|
"olcDatabase{0}config" = {
|
||||||
access to *
|
attrs = {
|
||||||
by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
|
objectClass = [ "olcDatabaseConfig" ];
|
||||||
by users read
|
olcDatabase = "{0}config";
|
||||||
by * none
|
olcAccess = [ "by * none" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
index objectClass,uid eq
|
"olcDatabase{1}mdb" = {
|
||||||
'';
|
attrs = {
|
||||||
|
objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
|
||||||
|
olcDatabase = "{1}mdb";
|
||||||
|
olcSuffix = cfg.base;
|
||||||
|
# olcRootDN = "cn=admin,${cfg.base}";
|
||||||
|
# olcRootPW = FIXME; # NOTE: this should be hashed...
|
||||||
|
olcDbDirectory = cfg.database-directory;
|
||||||
|
olcDbIndex = [ "objectClass eq" "uid eq" ];
|
||||||
|
olcAccess = makeAccess {
|
||||||
|
"attrs=userPassword,shadowLastChange" = {
|
||||||
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
|
"group/groupOfNames/member.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"dn.exact=cn=auth_reader,${cfg.base}" = "read";
|
||||||
|
"dn.exact=cn=replicator,${cfg.base}" = "read";
|
||||||
|
"self" = "write";
|
||||||
|
"*" = "auth";
|
||||||
|
};
|
||||||
|
"dn.base=cn=admin,ou=groups,${cfg.base}" = {
|
||||||
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
|
"dn.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"users" = "read";
|
||||||
|
"*" = "none";
|
||||||
|
};
|
||||||
|
"dn.subtree=ou=groups,${cfg.base} attrs=memberUid" = {
|
||||||
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
|
"dn.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"dn.regex=cn=[a-zA-Z][a-zA-Z0-9_]+,ou=hosts,${cfg.base}" = "write";
|
||||||
|
"group/groupOfNames/member.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"users" = "read";
|
||||||
|
"*" = "none";
|
||||||
|
};
|
||||||
|
"dn.subtree=ou=members,${cfg.base} attrs=cn,sn,homeDirectory,loginShell,gecos,description,homeDirectory,uidNumber,gidNumber" = {
|
||||||
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
|
"dn.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"group/groupOfNames/member.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"dn.exact=cn=user_db_reader,${cfg.base}" = "read";
|
||||||
|
"users" = "read";
|
||||||
|
"*" = "none";
|
||||||
|
};
|
||||||
|
"*" = {
|
||||||
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
|
"dn.exact=cn=admin,ou=groups,${cfg.base}" = "write";
|
||||||
|
"group/groupOfNames/member.exact=cn=admin,ou=groups,${cfg.base}" = "read";
|
||||||
|
"users" = "read";
|
||||||
|
"*" = "none";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
declarativeContents = ''
|
declarativeContents = ''
|
||||||
dn: ${cfg.base}
|
dn: ${cfg.base}
|
||||||
|
|
|
@ -1,66 +1,31 @@
|
||||||
{ lib, config, ... }:
|
{ lib, config, ... }:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
cfg = config.fudo.mail-server;
|
cfg = config.fudo.mail-server;
|
||||||
container-maildir = "/var/lib/mail";
|
container-maildir = "/var/lib/mail";
|
||||||
container-statedir = "/var/lib/mail-state";
|
container-statedir = "/var/lib/mail-state";
|
||||||
container-shared = "container/mail-server";
|
|
||||||
container-postfix-cert = "${container-shared}/postfix/cert.pem";
|
|
||||||
container-postfix-key = "${container-shared}/postfix/key.pem";
|
|
||||||
container-dovecot-cert = "${container-shared}/dovecot/cert.pem";
|
|
||||||
container-dovecot-key = "${container-shared}/dovecot/key.pem";
|
|
||||||
container-fudo-ca-cert = "${container-shared}/fudo-ca.pem";
|
|
||||||
|
|
||||||
# Don't bother with group-id, nixos doesn't seem to use it anyway
|
# Don't bother with group-id, nixos doesn't seem to use it anyway
|
||||||
container-mail-user = "mailer";
|
container-mail-user = "mailer";
|
||||||
container-mail-user-id = 542;
|
container-mail-user-id = 542;
|
||||||
container-mail-group = "mailer";
|
container-mail-group = "mailer";
|
||||||
fudo-cfg = config.fudo.common;
|
|
||||||
|
|
||||||
in rec {
|
in rec {
|
||||||
options.fudo.mail-server.container = {
|
config = mkIf (cfg.enableContainer) {
|
||||||
ldap-url = mkOption {
|
# Disable postfix on this host--it'll be run in the container instead
|
||||||
type = types.str;
|
|
||||||
description = "URL of the LDAP server to use for authentication.";
|
|
||||||
example = "ldaps://auth.fudo.org/";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf (cfg.enableContainer && !cfg.enable) {
|
|
||||||
|
|
||||||
# Disable postfix on thi host--it'll be run in the container instead
|
|
||||||
services.postfix.enable = false;
|
services.postfix.enable = false;
|
||||||
|
|
||||||
# Copy data intended for the container to a path in /etc which can be
|
fudo.acme.host-domains.${hostname}.${cfg.mail-hostname} = {
|
||||||
# bind-mounted.
|
local-copies = {
|
||||||
environment.etc = {
|
postfix = {
|
||||||
"${container-postfix-cert}" = {
|
user = "root";
|
||||||
mode = "0444";
|
};
|
||||||
source = cfg.postfix.ssl-certificate;
|
dovecot-cert = {
|
||||||
|
user = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
"${container-postfix-key}" = {
|
|
||||||
mode = "0400";
|
|
||||||
source = cfg.postfix.ssl-private-key;
|
|
||||||
};
|
|
||||||
|
|
||||||
"${container-dovecot-cert}" = {
|
|
||||||
mode = "0444";
|
|
||||||
source = cfg.dovecot.ssl-certificate;
|
|
||||||
};
|
|
||||||
|
|
||||||
"${container-dovecot-key}" = {
|
|
||||||
mode = "0400";
|
|
||||||
source = cfg.dovecot.ssl-private-key;
|
|
||||||
};
|
|
||||||
|
|
||||||
"${container-fudo-ca-cert}" = {
|
|
||||||
mode = "0444";
|
|
||||||
source = "/etc/nixos/static/fudo_ca.pem";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme.certs.${cfg.hostname}.email = fudo-cfg.admin-email;
|
|
||||||
|
|
||||||
services.nginx = mkIf cfg.monitoring {
|
services.nginx = mkIf cfg.monitoring {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -71,14 +36,15 @@ in rec {
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
'';
|
'';
|
||||||
trusted-network-string =
|
trusted-network-string =
|
||||||
optionalString ((length fudo-cfg.local-networks) > 0)
|
optionalString ((length config.instance.local-networks) > 0)
|
||||||
(concatStringsSep "\n"
|
(concatStringsSep "\n"
|
||||||
(map (network: "allow ${network};") fudo-cfg.local-networks)) + ''
|
(map (network: "allow ${network};")
|
||||||
|
config.instance.local-networks)) + ''
|
||||||
|
|
||||||
deny all;'';
|
deny all;'';
|
||||||
|
|
||||||
in {
|
in {
|
||||||
"${cfg.hostname}" = {
|
"${cfg.mail-hostname}" = {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
|
|
||||||
|
@ -119,7 +85,9 @@ in rec {
|
||||||
|
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
|
|
||||||
bindMounts = {
|
bindMounts = let
|
||||||
|
cert-copies = config.fudo.acme.host-domains.${hostname}.${cfg.mail-hostname}.local-copies;
|
||||||
|
in {
|
||||||
"${container-maildir}" = {
|
"${container-maildir}" = {
|
||||||
hostPath = cfg.mail-directory;
|
hostPath = cfg.mail-directory;
|
||||||
isReadOnly = false;
|
isReadOnly = false;
|
||||||
|
@ -134,29 +102,73 @@ in rec {
|
||||||
hostPath = "/etc/${container-shared}";
|
hostPath = "/etc/${container-shared}";
|
||||||
isReadOnly = true;
|
isReadOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/run/mail/certs/postfix/cert.pem" = {
|
||||||
|
hostPath = cert-copies.postfix.certificate;
|
||||||
|
isReadOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/run/mail/certs/postfix/key.pem" = {
|
||||||
|
hostPath = cert-copies.postfix.private-key;
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"/run/mail/certs/dovecot/cert.pem" = {
|
||||||
|
hostPath = cert-copies.dovecot.certificate;
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"/run/mail/certs/dovecot/key.pem" = {
|
||||||
|
hostPath = cert-copies.dovecot.private-key;
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
imports = let
|
||||||
|
initialize-host = import ../../initialize-host.nix;
|
||||||
|
build-timestamp = config.instance.build-timestamp;
|
||||||
|
site = config.instance.site;
|
||||||
|
domain = config.instance.domain;
|
||||||
|
profile = "container";
|
||||||
|
in [
|
||||||
|
(initialize-host {
|
||||||
|
inherit
|
||||||
|
lib
|
||||||
|
pkgs
|
||||||
|
build-timestamp
|
||||||
|
site
|
||||||
|
domain
|
||||||
|
profile;
|
||||||
|
hostname = "mail-container";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
config = { config, pkgs, ... }: {
|
config = { config, pkgs, ... }: {
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [ nmap ];
|
environment.etc = {
|
||||||
|
"mail-server/postfix/cert.pem" = {
|
||||||
imports = [ ./mail.nix ];
|
source = "/run/mail/certs/postfix/cert.pem";
|
||||||
|
user = config.services.postfix.user;
|
||||||
environment = {
|
mode = "0444";
|
||||||
etc = {
|
};
|
||||||
"postfix-certs/key.pem" = {
|
"mail-server/postfix/key.pem" = {
|
||||||
source = "/etc/${container-postfix-key}";
|
source = "/run/mail/certs/postfix/key.pem";
|
||||||
user = config.services.postfix.user;
|
user = config.services.postfix.user;
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
};
|
};
|
||||||
|
"mail-server/dovecot/cert.pem" = {
|
||||||
"dovecot-certs/key.pem" = {
|
source = "/run/mail/certs/dovecot/cert.pem";
|
||||||
source = "/etc/${container-dovecot-key}";
|
user = config.services.dovecot.user;
|
||||||
user = config.services.dovecot2.user;
|
mode = "0444";
|
||||||
|
};
|
||||||
|
"mail-server/dovecot/key.pem" = {
|
||||||
|
source = "/run/mail/certs/dovecot/key.pem";
|
||||||
|
user = config.services.dovecot.user;
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
imports = [ ./mail.nix ];
|
||||||
|
|
||||||
fudo.mail-server = {
|
fudo.mail-server = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -169,14 +181,15 @@ in rec {
|
||||||
state-directory = container-statedir;
|
state-directory = container-statedir;
|
||||||
mail-directory = container-maildir;
|
mail-directory = container-maildir;
|
||||||
|
|
||||||
postfix.ssl-certificate = "/etc/${container-postfix-cert}";
|
postfix = {
|
||||||
postfix.ssl-private-key = "/etc/postfix-certs/key.pem";
|
ssl-certificate = "/etc/mail-server/postfix/cert.pem";
|
||||||
|
ssl-private-key = "/etc/mail-server/postfix/key.pem";
|
||||||
|
};
|
||||||
|
|
||||||
dovecot = {
|
dovecot = {
|
||||||
ssl-certificate = "/etc/${container-dovecot-cert}";
|
ssl-certificate = "/etc/mail-server/dovecot/cert.pem";
|
||||||
ssl-private-key = "/etc/dovecot-certs/key.pem";
|
ssl-private-key = "/etc/mail-server/dovecot/key.pem";
|
||||||
ldap = {
|
ldap = {
|
||||||
# ca = "/etc/${container-fudo-ca-cert}";
|
|
||||||
server-urls = cfg.dovecot.ldap.server-urls;
|
server-urls = cfg.dovecot.ldap.server-urls;
|
||||||
reader-dn = cfg.dovecot.ldap.reader-dn;
|
reader-dn = cfg.dovecot.ldap.reader-dn;
|
||||||
reader-passwd = cfg.dovecot.ldap.reader-passwd;
|
reader-passwd = cfg.dovecot.ldap.reader-passwd;
|
||||||
|
|
|
@ -21,11 +21,18 @@ in {
|
||||||
description = "The main and default domain name for this email server.";
|
description = "The main and default domain name for this email server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
hostname = mkOption {
|
mail-hostname = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "The domain name to use for the mail server.";
|
description = "The domain name to use for the mail server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ldap-url = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "URL of the LDAP server to use for authentication.";
|
||||||
|
example = "ldaps://auth.fudo.org/";
|
||||||
|
};
|
||||||
|
|
||||||
monitoring = mkEnableOption "Enable monitoring for the mail server.";
|
monitoring = mkEnableOption "Enable monitoring for the mail server.";
|
||||||
|
|
||||||
mail-user = mkOption {
|
mail-user = mkOption {
|
||||||
|
|
|
@ -4,7 +4,6 @@ with lib;
|
||||||
let
|
let
|
||||||
inherit (lib.strings) concatStringsSep;
|
inherit (lib.strings) concatStringsSep;
|
||||||
cfg = config.fudo.prometheus;
|
cfg = config.fudo.prometheus;
|
||||||
fudo-cfg = config.fudo.common;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
|
@ -76,9 +75,6 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
security.acme.certs.${cfg.hostname}.email = fudo-cfg.admin-email;
|
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
|
@ -111,7 +107,8 @@ in {
|
||||||
|
|
||||||
webExternalUrl = "https://${cfg.hostname}";
|
webExternalUrl = "https://${cfg.hostname}";
|
||||||
|
|
||||||
listenAddress = "127.0.0.1:9090";
|
listenAddress = "127.0.0.1";
|
||||||
|
port = 9090;
|
||||||
|
|
||||||
scrapeConfigs = [
|
scrapeConfigs = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,10 @@ let
|
||||||
webmail-user = cfg.user;
|
webmail-user = cfg.user;
|
||||||
webmail-group = cfg.group;
|
webmail-group = cfg.group;
|
||||||
|
|
||||||
base-data-path = "/var/run/rainloop";
|
base-data-path = "/run/rainloop";
|
||||||
|
|
||||||
|
concatMapAttrs = f: attrs:
|
||||||
|
foldr (a: b: a // b) {} (mapAttrsToList f attrs);
|
||||||
|
|
||||||
fastcgi-conf = builtins.toFile "fastcgi.conf" ''
|
fastcgi-conf = builtins.toFile "fastcgi.conf" ''
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
@ -301,7 +304,7 @@ in {
|
||||||
site-config-file = builtins.toFile "${site}-rainloop.cfg"
|
site-config-file = builtins.toFile "${site}-rainloop.cfg"
|
||||||
(import ./include/rainloop.nix lib site site-cfg site-pkgs.${site}.version);
|
(import ./include/rainloop.nix lib site site-cfg site-pkgs.${site}.version);
|
||||||
|
|
||||||
domain-cfg-file = builtins.toFile "${site}-domain.cfg" ''
|
domain-config-file = builtins.toFile "${site}-domain.cfg" ''
|
||||||
imap_host = "${site-cfg.mail-server}"
|
imap_host = "${site-cfg.mail-server}"
|
||||||
imap_port = 143
|
imap_port = 143
|
||||||
imap_secure = "TLS"
|
imap_secure = "TLS"
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
{
|
let
|
||||||
base-host-config = host-path: let
|
|
||||||
hostname-from-file = filename: builtins.replaceStrings [".nix"] [""] filename;
|
hostname-from-file = filename: builtins.replaceStrings [".nix"] [""] filename;
|
||||||
|
|
||||||
is-nix-file = filename: type: (builtins.match ".+\.nix$" filename) != null;
|
is-nix-file = filename: type: (builtins.match ".+\.nix$" filename) != null;
|
||||||
is-regular-file = filename: type: type == "regular" || type == "link";
|
is-regular-file = filename: type: type == "regular" || type == "link";
|
||||||
|
|
||||||
host-files = attrNames (filterAttrs is-nix-file (filterAttrs is-regular-file (builtins.readDir host-path)));
|
host-files = host-path:
|
||||||
hosts = map hostname-from-file host-files;
|
attrNames
|
||||||
|
(filterAttrs is-nix-file
|
||||||
|
(filterAttrs is-regular-file
|
||||||
|
(builtins.readDir host-path)));
|
||||||
|
|
||||||
|
hosts = host-path:
|
||||||
|
map hostname-from-file (host-files host-path);
|
||||||
|
in {
|
||||||
|
base-host-config = host-path: let
|
||||||
load-host-file = hostname: import (host-path + "/${hostname}.nix");
|
load-host-file = hostname: import (host-path + "/${hostname}.nix");
|
||||||
in genAttrs hosts (hostname: load-host-file hostname);
|
in genAttrs (hosts host-path) (hostname: load-host-file hostname);
|
||||||
|
|
||||||
|
host-list = host-path: hosts host-path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.informis.cl-gemini;
|
cfg = config.informis.cl-gemini;
|
||||||
|
|
||||||
lisp-helper = import ../lisp.nix { inherit pkgs; };
|
|
||||||
|
|
||||||
feedOpts = { ... }: with types; {
|
feedOpts = { ... }: with types; {
|
||||||
options = {
|
options = {
|
||||||
url = mkOption {
|
url = mkOption {
|
||||||
|
@ -163,7 +161,7 @@ in {
|
||||||
GEMINI_TEXTFILES_ROOT = cfg.textfiles-archive;
|
GEMINI_TEXTFILES_ROOT = cfg.textfiles-archive;
|
||||||
GEMINI_FEEDS = "${generate-feeds cfg.feeds}";
|
GEMINI_FEEDS = "${generate-feeds cfg.feeds}";
|
||||||
|
|
||||||
CL_SOURCE_REGISTRY = "${lisp-helper.lisp-source-registry pkgs.cl-gemini}";
|
CL_SOURCE_REGISTRY = "${pkgs.lib.fudo.lisp.lisp-source-registry pkgs.cl-gemini}";
|
||||||
};
|
};
|
||||||
|
|
||||||
path = with pkgs; [
|
path = with pkgs; [
|
||||||
|
|
|
@ -51,6 +51,11 @@ in {
|
||||||
type = attrsOf (submodule user.userOpts);
|
type = attrsOf (submodule user.userOpts);
|
||||||
description = "List of users who should have access to the local host";
|
description = "List of users who should have access to the local host";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
build-seed = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Seed used to generate configuration.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config = let
|
||||||
|
@ -86,15 +91,21 @@ in {
|
||||||
config.fudo.domains.${local-domain}.local-networks //
|
config.fudo.domains.${local-domain}.local-networks //
|
||||||
config.fudo.sites.${local-site}.local-networks;
|
config.fudo.sites.${local-site}.local-networks;
|
||||||
|
|
||||||
|
local-profile = host.profile;
|
||||||
|
|
||||||
|
build-seed = builtins.readFile config.fudo.secrets.files.build-seed;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
instance = {
|
instance = {
|
||||||
local-domain = local-domain;
|
inherit
|
||||||
local-site = local-site;
|
build-seed
|
||||||
local-users = local-users;
|
local-domain
|
||||||
local-admins = local-admins;
|
local-site
|
||||||
local-groups = local-groups;
|
local-users
|
||||||
local-hosts = local-hosts;
|
local-admins
|
||||||
local-profile = host.profile;
|
local-groups
|
||||||
|
local-hosts
|
||||||
|
local-profile;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{ lib, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with pkgs.lib;
|
||||||
let
|
let
|
||||||
pow = x: e: if (e == 0) then 1 else x * (pow x (e - 1));
|
pow = x: e: if (e == 0) then 1 else x * (pow x (e - 1));
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
with pkgs.lib;
|
with pkgs.lib;
|
||||||
let
|
rec {
|
||||||
in rec {
|
|
||||||
gather-dependencies = pkg: unique (pkg.propagatedBuildInputs ++ (concatMap gather-dependencies pkg.propagatedBuildInputs));
|
gather-dependencies = pkg: unique (pkg.propagatedBuildInputs ++ (concatMap gather-dependencies pkg.propagatedBuildInputs));
|
||||||
|
|
||||||
lisp-source-registry = pkg: concatStringsSep ":" (map (p: "${p}//") (gather-dependencies pkg));
|
lisp-source-registry = pkg: concatStringsSep ":" (map (p: "${p}//") (gather-dependencies pkg));
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
(final: prev: let
|
(final: prev: {
|
||||||
ip = import ./ip.nix { lib = prev.lib; };
|
|
||||||
dns = import ./dns.nix { lib = prev.lib; };
|
|
||||||
in {
|
|
||||||
lib = prev.lib // {
|
lib = prev.lib // {
|
||||||
fudo = {
|
fudo = let
|
||||||
inherit ip dns;
|
lib = prev.lib;
|
||||||
|
in {
|
||||||
|
ip = import ./ip.nix { pkgs = prev; };
|
||||||
|
dns = import ./dns.nix { pkgs = prev;};
|
||||||
|
passwd = import ./passwd.nix { pkgs = prev;};
|
||||||
|
lisp = import ./lisp.nix { pkgs = prev;};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{ lib, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with pkgs.lib;
|
||||||
let
|
let
|
||||||
hash-ldap-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
|
hash-ldap-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-ldap-passwd";
|
name = "${name}-ldap-passwd";
|
||||||
|
@ -14,7 +14,7 @@ let
|
||||||
'';
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir $out
|
mkdir -p $out
|
||||||
mv ldap-passwd $out
|
mv ldap-passwd $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
@ -26,17 +26,26 @@ let
|
||||||
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-random-passwd";
|
name = "${name}-random-passwd";
|
||||||
|
|
||||||
phases = [ "buildPhase" "installPhase" ];
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
buildInputs = with pkgs; [ pwgen ];
|
buildInputs = with pkgs; [ pwgen ];
|
||||||
|
|
||||||
buildPhase = ''
|
installPhase = ''
|
||||||
pwgen --symbols --num-passwords=1 ${length} > passwd
|
pwgen --secure --num-passwords=1 ${length} > $out
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
generate-stablerandom-passwd = name: { seed, length ? 20, ... }:
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${name}-stablerandom-passwd";
|
||||||
|
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [ pwgen ];
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir $out
|
echo "${name}-${seed}" > seedfile
|
||||||
mv passwd $out
|
pwgen --secure --num-passwords=1 -H seedfile ${toString length} > $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,5 +53,8 @@ in {
|
||||||
hash-ldap-passwd = hash-ldap-passwd;
|
hash-ldap-passwd = hash-ldap-passwd;
|
||||||
|
|
||||||
random-passwd-file = name: length:
|
random-passwd-file = name: length:
|
||||||
toPath "${generate-random-passwd name length}/passwd";
|
builtins.toPath "${generate-random-passwd name length}";
|
||||||
|
|
||||||
|
stablerandom-passwd-file = name: seed:
|
||||||
|
builtins.toPath "${generate-stablerandom-passwd name { seed = seed; }}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
rec {
|
let
|
||||||
|
passwd = import ../passwd.nix { inherit lib; };
|
||||||
|
|
||||||
|
in rec {
|
||||||
encryptedFSOpts = { ... }: let
|
encryptedFSOpts = { ... }: let
|
||||||
mountpoint = { mp, ... }: {
|
mountpoint = { mp, ... }: {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
|
@ -31,6 +34,12 @@ rec {
|
||||||
'';
|
'';
|
||||||
default = [ ];
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
world-readable = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Whether to leave the top level world-readable.";
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
|
@ -81,7 +90,9 @@ rec {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
hostOpts = { hostname, ... }: {
|
hostOpts = { name, ... }: let
|
||||||
|
hostname = name;
|
||||||
|
in {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
master-key = mkOption {
|
master-key = mkOption {
|
||||||
type = nullOr (submodule masterKeyOpts);
|
type = nullOr (submodule masterKeyOpts);
|
||||||
|
@ -284,6 +295,11 @@ rec {
|
||||||
description = "Configuration parameters to set up initrd SSH network.";
|
description = "Configuration parameters to set up initrd SSH network.";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
backplane-password-file = mkOption {
|
||||||
|
options = path;
|
||||||
|
description = "File containing the password used by this host to connect to the backplane.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
rec {
|
rec {
|
||||||
systemUserOpts = { username, ... }: {
|
systemUserOpts = { name, ... }: {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
username = mkOption {
|
username = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "The system user's login name.";
|
description = "The system user's login name.";
|
||||||
default = username;
|
default = name;
|
||||||
};
|
};
|
||||||
|
|
||||||
description = mkOption {
|
description = mkOption {
|
||||||
|
@ -23,7 +23,9 @@ rec {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
userOpts = { username, ... }: {
|
userOpts = { name, ... }: let
|
||||||
|
username = name;
|
||||||
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
username = mkOption {
|
username = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
|
|
Loading…
Reference in New Issue