psql-terraform-db #12
15 changed files with 225 additions and 75 deletions
4
.envrc
4
.envrc
|
@ -1 +1,5 @@
|
||||||
use_flake
|
use_flake
|
||||||
|
export PGSSLROOTCERT=~/.config/home/postgresql_server.crt
|
||||||
|
export PGSSLMODE=verify-ca
|
||||||
|
export PGSSLCERT=~/.config/home/postgresql_client.crt
|
||||||
|
export PGSSLKEY=~/.config/home/postgresql_client.key
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
imports = [
|
imports = [
|
||||||
(modulesPath + "/installer/scan/not-detected.nix")
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
./modules/disk-config.nix
|
./modules/disk-config.nix
|
||||||
./modules/agenix.nix
|
./modules/custom
|
||||||
./modules/custom.nix
|
|
||||||
./modules/uptimed.nix
|
./modules/uptimed.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -55,12 +54,6 @@
|
||||||
PasswordAuthentication = false;
|
PasswordAuthentication = false;
|
||||||
KbdInteractiveAuthentication = false;
|
KbdInteractiveAuthentication = false;
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
|
||||||
HostCertificate ${
|
|
||||||
builtins.toFile "host_ed25519-cert.pub" config.custom.ssh.hostCert
|
|
||||||
}
|
|
||||||
HostKey ${config.age.secrets.host_ed25519.path}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
xserver = {
|
xserver = {
|
||||||
|
@ -92,12 +85,6 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
extraConfig = ''
|
|
||||||
CertificateFile ${
|
|
||||||
builtins.toFile "user_ed25519-cert.pub" config.custom.ssh.userCert
|
|
||||||
}
|
|
||||||
IdentityFile ${config.age.secrets.user_ed25519.path}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
neovim = {
|
neovim = {
|
||||||
|
@ -186,4 +173,6 @@
|
||||||
|
|
||||||
hardware.cpu.intel.updateMicrocode =
|
hardware.cpu.intel.updateMicrocode =
|
||||||
lib.mkDefault config.hardware.enableRedistributableFirmware;
|
lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|
||||||
|
age.identityPaths = [ "/root/age_ed25519" ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
# Should wait until this is merged in nixos-unstable.
|
# Should wait until this is merged in nixos-unstable.
|
||||||
# pkgs-unstable.nixos-anywhere
|
# pkgs-unstable.nixos-anywhere
|
||||||
pkgs-unstable.deploy-rs
|
pkgs-unstable.deploy-rs
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.postgresql_15
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
hostCert = builtins.readFile ./jefke_host_ed25519-cert.pub;
|
hostCert = builtins.readFile ./jefke_host_ed25519-cert.pub;
|
||||||
userCert = builtins.readFile ./jefke_user_ed25519-cert.pub;
|
userCert = builtins.readFile ./jefke_user_ed25519-cert.pub;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
terraformDatabase.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
{ config, ... }: {
|
|
||||||
age = {
|
|
||||||
identityPaths = [ "/root/age_ed25519" ];
|
|
||||||
|
|
||||||
secrets = {
|
|
||||||
"host_ed25519".file = config.custom.ssh.hostKey;
|
|
||||||
"user_ed25519".file = config.custom.ssh.userKey;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
{ lib, config, ... }: {
|
|
||||||
options = {
|
|
||||||
custom = {
|
|
||||||
dataDisk.enable = lib.mkOption {
|
|
||||||
default = false;
|
|
||||||
type = lib.types.bool;
|
|
||||||
description = ''
|
|
||||||
Whether to automatically mount /dev/sda1 on /mnt/data
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
ssh = {
|
|
||||||
hostCert = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
SSH host certificate
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
userCert = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
SSH user certificate
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
hostKey = lib.mkOption {
|
|
||||||
default = ../secrets/${config.networking.hostName}_host_ed25519.age;
|
|
||||||
type = lib.types.path;
|
|
||||||
description = ''
|
|
||||||
SSH host key
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
userKey = lib.mkOption {
|
|
||||||
default = ../secrets/${config.networking.hostName}_user_ed25519.age;
|
|
||||||
type = lib.types.path;
|
|
||||||
description = ''
|
|
||||||
SSH user key
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
fileSystems."/dev/data" =
|
|
||||||
lib.mkIf config.custom.dataDisk.enable { device = "/dev/sda1"; };
|
|
||||||
};
|
|
||||||
}
|
|
19
modules/custom/data-disk.nix
Normal file
19
modules/custom/data-disk.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{ lib, config, ... }:
|
||||||
|
let cfg = config.custom.dataDisk;
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
custom = {
|
||||||
|
dataDisk.enable = lib.mkOption {
|
||||||
|
default = false;
|
||||||
|
type = lib.types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether to automatically mount /dev/sda1 on /mnt/data
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
fileSystems."/mnt/data" = { device = "/dev/sda1"; };
|
||||||
|
};
|
||||||
|
}
|
3
modules/custom/default.nix
Normal file
3
modules/custom/default.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
imports = [ ./terraform-database.nix ./data-disk.nix ./ssh-certificates.nix ];
|
||||||
|
}
|
65
modules/custom/ssh-certificates.nix
Normal file
65
modules/custom/ssh-certificates.nix
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
{ lib, config, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.custom.ssh;
|
||||||
|
hostCert = builtins.toFile "host_ed25519-cert.pub" cfg.hostCert;
|
||||||
|
userCert = builtins.toFile "user_ed25519-cert.pub" cfg.userCert;
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
custom = {
|
||||||
|
ssh = {
|
||||||
|
hostCert = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
SSH host certificate
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
userCert = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
SSH user certificate
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
hostKey = lib.mkOption {
|
||||||
|
default =
|
||||||
|
../../secrets/${config.networking.hostName}_host_ed25519.age;
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
SSH host key
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
userKey = lib.mkOption {
|
||||||
|
default =
|
||||||
|
../../secrets/${config.networking.hostName}_user_ed25519.age;
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
SSH user key
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
services.openssh = {
|
||||||
|
extraConfig = ''
|
||||||
|
HostCertificate ${hostCert}
|
||||||
|
HostKey ${config.age.secrets.host_ed25519.path}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.ssh = {
|
||||||
|
extraConfig = ''
|
||||||
|
CertificateFile ${userCert}
|
||||||
|
IdentityFile ${config.age.secrets.user_ed25519.path}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
age.secrets = {
|
||||||
|
"host_ed25519".file = cfg.hostKey;
|
||||||
|
"user_ed25519".file = cfg.userKey;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
49
modules/custom/terraform-database.nix
Normal file
49
modules/custom/terraform-database.nix
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
let cfg = config.custom.terraformDatabase;
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
custom = {
|
||||||
|
terraformDatabase.enable = lib.mkOption {
|
||||||
|
default = false;
|
||||||
|
type = lib.types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether to start a postgreSQL database for Terraform states
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = [ "terraformstates" ];
|
||||||
|
package = pkgs.postgresql_15;
|
||||||
|
enableTCPIP = true;
|
||||||
|
dataDir = lib.mkIf config.custom.dataDisk.enable
|
||||||
|
"/mnt/data/postgresql/${config.services.postgresql.package.psqlSchema}";
|
||||||
|
authentication = ''
|
||||||
|
hostssl terraformstates terraform all cert
|
||||||
|
'';
|
||||||
|
settings = let
|
||||||
|
serverCert = builtins.toFile "postgresql_server.crt"
|
||||||
|
(builtins.readFile ../../postgresql_server.crt);
|
||||||
|
in {
|
||||||
|
ssl = true;
|
||||||
|
ssl_cert_file = serverCert;
|
||||||
|
ssl_key_file = config.age.secrets."postgresql_server.key".path;
|
||||||
|
ssl_ca_file = serverCert;
|
||||||
|
};
|
||||||
|
ensureUsers = [{
|
||||||
|
name = "terraform";
|
||||||
|
ensurePermissions = { "DATABASE terraformstates" = "ALL PRIVILEGES"; };
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
age.secrets."postgresql_server.key" = {
|
||||||
|
file = ../../secrets/postgresql_server.key.age;
|
||||||
|
mode = "400";
|
||||||
|
owner = builtins.toString config.ids.uids.postgres;
|
||||||
|
group = builtins.toString config.ids.gids.postgres;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ table inet nixos-fw {
|
||||||
|
|
||||||
chain input-allow {
|
chain input-allow {
|
||||||
tcp dport 22 accept
|
tcp dport 22 accept
|
||||||
|
tcp dport 5432 accept comment "PostgreSQL server"
|
||||||
icmp type echo-request accept comment "allow ping"
|
icmp type echo-request accept comment "allow ping"
|
||||||
icmpv6 type != { nd-redirect, 139 } accept comment "Accept all ICMPv6 messages except redirects and node information queries (type 139). See RFC 4890, section 4.4."
|
icmpv6 type != { nd-redirect, 139 } accept comment "Accept all ICMPv6 messages except redirects and node information queries (type 139). See RFC 4890, section 4.4."
|
||||||
ip6 daddr fe80::/64 udp dport 546 accept comment "DHCPv6 client"
|
ip6 daddr fe80::/64 udp dport 546 accept comment "DHCPv6 client"
|
||||||
|
|
67
postgresql_server.crt
Normal file
67
postgresql_server.crt
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 1 (0x0)
|
||||||
|
Serial Number:
|
||||||
|
ef:2f:4d:d4:26:7e:33:1b
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
Issuer: CN=jefke.hyp
|
||||||
|
Validity
|
||||||
|
Not Before: Nov 22 19:12:03 2023 GMT
|
||||||
|
Not After : Oct 29 19:12:03 2123 GMT
|
||||||
|
Subject: CN=jefke.hyp
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public-Key: (2048 bit)
|
||||||
|
Modulus:
|
||||||
|
00:c7:ab:eb:9c:d0:7f:4f:f1:ba:65:0a:8b:07:7b:
|
||||||
|
2e:5b:f0:26:82:33:c9:73:e6:91:cc:11:94:05:1c:
|
||||||
|
8d:67:29:cb:5e:67:35:02:80:54:af:99:4b:aa:ce:
|
||||||
|
e8:56:62:be:63:cb:b2:4a:b0:a9:28:12:e2:77:50:
|
||||||
|
7d:d5:d2:3b:48:d8:32:59:25:26:ff:a6:5c:f6:eb:
|
||||||
|
ae:5b:3d:7a:14:10:ba:90:9c:6f:1f:b9:d8:99:0e:
|
||||||
|
b7:09:5e:62:69:c4:c0:c6:27:b0:d3:60:0d:47:4c:
|
||||||
|
a5:11:53:f2:f1:4a:f9:a6:bc:d6:a3:35:a2:e8:e5:
|
||||||
|
a9:d1:60:e8:e5:18:ce:d2:60:80:4e:dc:48:ae:7f:
|
||||||
|
b7:ea:76:51:28:39:a4:b0:95:82:95:93:98:b2:9f:
|
||||||
|
23:c9:81:69:59:a3:e4:f7:5a:1c:01:31:96:c1:4b:
|
||||||
|
59:21:f8:a2:e6:9e:21:78:0e:6b:c1:68:c7:5c:16:
|
||||||
|
9a:06:54:df:b6:77:1d:2d:89:d0:c8:9e:db:b5:d4:
|
||||||
|
8c:fb:b9:4f:b7:6e:39:5f:39:8e:48:73:76:7d:46:
|
||||||
|
6e:1f:8d:14:cb:40:b5:ff:c6:f0:c0:44:3c:ed:52:
|
||||||
|
3f:4f:7b:69:63:93:c6:41:e6:5e:ed:33:50:20:46:
|
||||||
|
db:93:bf:e8:52:51:95:f1:81:73:58:da:67:21:7b:
|
||||||
|
12:bd
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
aa:5c:89:41:a6:b7:3d:65:87:ca:50:c4:f3:58:aa:d3:b4:55:
|
||||||
|
b1:a7:8d:18:26:17:e5:8a:21:24:a1:49:53:77:31:5b:55:63:
|
||||||
|
be:01:d8:fe:b7:06:7c:da:07:1f:94:6a:de:96:ad:ca:3b:20:
|
||||||
|
2a:e1:35:90:19:83:6d:37:d1:15:12:de:3c:0e:46:be:66:a1:
|
||||||
|
6a:1d:ec:72:dc:46:79:69:e4:af:77:c8:ff:cd:d6:7d:16:88:
|
||||||
|
ab:44:fd:70:fc:40:47:ff:43:95:11:5a:9a:56:0c:d2:dd:7c:
|
||||||
|
3b:87:aa:10:26:fa:25:a3:a0:43:8a:1b:ec:54:11:7e:65:67:
|
||||||
|
d2:06:e1:3e:3b:e1:0e:b0:80:ef:4b:35:3f:fc:34:1d:95:2e:
|
||||||
|
ee:c1:67:38:da:b3:74:86:4b:95:8c:0c:1d:51:28:c1:42:e9:
|
||||||
|
77:68:d7:ec:3b:66:30:c6:e5:2a:62:ea:15:fb:24:56:cf:02:
|
||||||
|
d0:25:54:a7:58:15:b5:2a:71:93:56:c0:69:7a:36:18:6c:31:
|
||||||
|
b1:8e:3c:77:d7:77:ac:fc:e1:94:c5:08:bb:35:ac:48:5f:6b:
|
||||||
|
8b:c8:c8:78:f4:a9:ca:4f:9d:51:54:89:97:c9:af:a1:fa:71:
|
||||||
|
df:58:f6:ff:04:7c:c8:1c:95:6b:1a:e3:a7:f6:43:1c:27:94:
|
||||||
|
10:03:ce:ec
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICpjCCAY4CCQDvL03UJn4zGzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlq
|
||||||
|
ZWZrZS5oeXAwIBcNMjMxMTIyMTkxMjAzWhgPMjEyMzEwMjkxOTEyMDNaMBQxEjAQ
|
||||||
|
BgNVBAMMCWplZmtlLmh5cDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AMer65zQf0/xumUKiwd7LlvwJoIzyXPmkcwRlAUcjWcpy15nNQKAVK+ZS6rO6FZi
|
||||||
|
vmPLskqwqSgS4ndQfdXSO0jYMlklJv+mXPbrrls9ehQQupCcbx+52JkOtwleYmnE
|
||||||
|
wMYnsNNgDUdMpRFT8vFK+aa81qM1oujlqdFg6OUYztJggE7cSK5/t+p2USg5pLCV
|
||||||
|
gpWTmLKfI8mBaVmj5PdaHAExlsFLWSH4ouaeIXgOa8Fox1wWmgZU37Z3HS2J0Mie
|
||||||
|
27XUjPu5T7duOV85jkhzdn1Gbh+NFMtAtf/G8MBEPO1SP097aWOTxkHmXu0zUCBG
|
||||||
|
25O/6FJRlfGBc1jaZyF7Er0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAqlyJQaa3
|
||||||
|
PWWHylDE81iq07RVsaeNGCYX5YohJKFJU3cxW1VjvgHY/rcGfNoHH5Rq3patyjsg
|
||||||
|
KuE1kBmDbTfRFRLePA5Gvmahah3sctxGeWnkr3fI/83WfRaIq0T9cPxAR/9DlRFa
|
||||||
|
mlYM0t18O4eqECb6JaOgQ4ob7FQRfmVn0gbhPjvhDrCA70s1P/w0HZUu7sFnONqz
|
||||||
|
dIZLlYwMHVEowULpd2jX7DtmMMblKmLqFfskVs8C0CVUp1gVtSpxk1bAaXo2GGwx
|
||||||
|
sY48d9d3rPzhlMUIuzWsSF9ri8jIePSpyk+dUVSJl8mvofpx31j2/wR8yByVaxrj
|
||||||
|
p/ZDHCeUEAPO7A==
|
||||||
|
-----END CERTIFICATE-----
|
5
secrets/README.md
Normal file
5
secrets/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
To create a secret:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run github:ryantm/agenix# -- -e secret.age
|
||||||
|
``
|
BIN
secrets/postgresql_server.key.age
Normal file
BIN
secrets/postgresql_server.key.age
Normal file
Binary file not shown.
|
@ -6,7 +6,11 @@ let
|
||||||
publicKeys = [
|
publicKeys = [
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIJUSH2IQg8Y/CCcej7J6oe4co++6HlDo1MYDCR3gV3a pim@x260"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIJUSH2IQg8Y/CCcej7J6oe4co++6HlDo1MYDCR3gV3a pim@x260"
|
||||||
];
|
];
|
||||||
encryptedFiles = [ "jefke_host_ed25519.age" "jefke_user_ed25519.age" ];
|
encryptedFiles = [
|
||||||
|
"jefke_host_ed25519.age"
|
||||||
|
"jefke_user_ed25519.age"
|
||||||
|
"postgresql_server.key.age"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in lib.attrsets.mergeAttrsList (builtins.map ({ publicKeys, encryptedFiles }:
|
in lib.attrsets.mergeAttrsList (builtins.map ({ publicKeys, encryptedFiles }:
|
||||||
|
|
Loading…
Reference in a new issue