2 Commits

12 changed files with 242 additions and 66 deletions
@@ -0,0 +1,19 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA XXuM89kA+Hnc4nKJ005H+IDYV5qk4nEx/IUWk/CbKiM
sPJrUh6RI+Anzwy/nSR/dbCkZQvpJ3dGYSkChfJEv2Q
-> ssh-ed25519 zNC8SA mg1uB6DPLT/3DE2Hh+EIGv9N4ZmDSi1w7UeW91u0cHs
qBAmL0fgdRNuM4VYiDx0g6T2ZJFiqhgXpC/4C/RsVqU
-> ssh-ed25519 EiAAKw EL0tfmXf6b2DWA3Ty4fhYdJL6AYdvknGv/To81dJ2zU
KtZZx4//yDaAU6bt9JWYdBRbpqn79YHAu46857SBBPI
-> ssh-rsa eFi+Zw
jDWmTVRF7H9rhPAVEV2HkHtXpc/g16jlPDxvxzfnftyGF6aGfgoRwKtOwtqZtaB/
UDE6Pzo3n5yg5/B8d0JhabBMfZpSJ8xiJcJfti8sY5tno97HhL0Fzd2r/0VM74iO
TZ/ZA8xJACFfm9VclUz3gZWNG7qU4CrMYXQxWcwacphCiIFyFJVuaQEDf1rQnqEd
3C8bMYxgRmUI64lLaRHdYD84hQ49xXrtuEQbJu6e/B3zCWsAMzpVciE/maDBBBGz
EFRhhvP3Y8riBt4FLgYRVpvwge44LrX0N9NHeOyFmgP/S62ShDP+xLBnw9V3Tcuz
9iuyJS4lz/mSWE9ISa1y21emQAuXOwdMkFM0b6tSCBL1zwKUNAzmEV/S4BMydNex
/1m1ZaWDrOpfrBzRU+kN02a5sCHNGjO2/4T0dCjoGOeHUvpOw0IxniSQiKZj03nQ
mWnWDp1sA/DK0ySs0AcYXJUs9EoeDQ1ny6tQ1Loc9xzX6uMFnFLfYIWXiI4erldl
--- 9ryp8lwLiw/0MYGf1zSVR8ML6l5h83D0Flaks10d7Yg
¹´m“Õ¶œK[.›šLÛãKÜ Õr'4†ÿÎÂû*­«ÖÜý­¬ßÏñ-¨À–T,Cê$ЦŸ¦f·E:pu*wdwe[óR¦ŒëëwŸP§Qøhªi½è0L×0J"©eþD÷l‡‡gõ®’üœ’ù„&9õ™5éÑjZÀÞÇ«ßd
Binary file not shown.
@@ -0,0 +1,19 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA 86jJdtfiJBUnXAh0R+VjMeX5NTB+kGQlOioe/9Us6GI
i0EPVHWazwgTCracN1bn9mvbpynd1x+XNE+5Hh09bKM
-> ssh-ed25519 zNC8SA hL+Axpc8Qy8iosArb+JdAaQdf6gPlUaLRQ0w4YJJU1c
k4prWpg+pyuykv8N2RjQQT7Ow53QjXBYxsqBwjtgFjw
-> ssh-ed25519 EiAAKw /+UyD03g2OVWeJzooMrMxNH0otkY6Km9BDSJ+f8zVGQ
kFSmApLaIFQ1F1ZaLThFlb7ZOfIDWDYZByuYfEvn2FU
-> ssh-rsa eFi+Zw
p5uxnSM+9jojTeHlzDycwEKqklY6F1oDU87e0pn/WhNBtSo3SzNI0aHtwKDLN548
m4RQNQ6wKWAl36VvQDJmWiP6LJNKx5oQvgCLqqJ+fGTAx1mUUL+hpVC+Y2siONbN
WWbFXVD1FHk+enHkRA9ZERiVPqV7Zg5b55t+E2dwRh2fas8IlOwBEEceIggYKi85
Dywr8dhdL1VeAHG1l4fdkgn9A3oLqMHIw0oUHX16CawCYrQZt9bezDR6mb8HuEdM
KVHSd6y+Aq0wYgcmGEkknw45VlG9Mjor0qhW9y+cJQ941niiPr1Q7LPcpdLAUmHP
KbGDnnt/vvMEXaa5G1HDytvedHbAygx/fWGfm3Ngq8qUAV7kEHz2kUclJ5OOBTRm
M0081XNKZF2QdmN+O8eMFMor1OcKsNe3Ril0Y8rPtMd+iwOulLbbV3b8LZ/Jd1+9
ePUoOyj0wP4gVzXo5INiNVtYK+sK6Ek1Gt+UCHhAlJwj5RulmIvEzISZjHJAt4yU
--- hljwKKncDABYcm9RHZtEdHhRlKqSFtoE6GihIfBqowU
ošã…Œ üFÔÑr u·«¢sð­(ÿg»NÇšØÄø¬äƒÇ¤gIsã„ý¡^•Õíõ‚›Ò1¼ÁQé¥]¶aE”^Áœiw«Ne2:4Ì ö®bH†ŠŽÆyf¸ nü‰$+ÉÃ_Ö •éjòê4Ý>Þ $?”<“³·IЍ……‘˜'±
+18 -15
View File
@@ -1,17 +1,20 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA JMymqEdh+xJbl8VcL5wg7Y2Dk4667DzNO85RCskX+0Q
ZQqF0eYpvrLujGdIvAMbfwPnKGa+mfNvAhHGMdXiYaI
-> ssh-ed25519 zNC8SA UCQhQA4f3OiNoxejDBMabnls3LjS0GQmvIqPpjB/FH8
0qvv6W1heZiE1DDYEj1U5N2e99DZLxlJ6A8EoZ31DhM
-> ssh-rsa 3G83yA
Gnpw8t6njIXGm98jTS47Afx6TogPnIJP59rapF0CkYkDXZNrW7WK+fcERHLN2+a+
PSkjwkql3LfAtCNqrIJZwWLj/URnKQF5N3ZKwOa1+wsM3GeUzjvaQwPZunj4jyFs
IJlL+ika2sBk/HvOa1r6ntj2cvLM1fIhbs9bOEZW3br3M3sfXk386TgrytqzM248
3xS2iIwIBmBiI5Xem8KO2+J/2Vk9Px/ZPkBpdIAaZAmihe3g/VWNKHhXrwdM9ZA7
tHgw5ohK8ug88ep9XCIFD75DPeK/60wqAdkGs4PE6THcsKqhN061TAEq3SWRl8wp
Kd17yAzHDLhsbdWXT/Q912Y4YJCB3TnD0MFGzPF7sks2NknB6yowwjnCGlqzf5rW
RBKHp6PTM+x/eDi89vS+uIBtyGFaFU7wBTl4FzJpKoOsRIDYNktGkJSxdTzrMO1n
XqXtJtqZaXN7UExA+ko9ln446I7RG8c3hNGx4A4bR1xUEUE8WD/TMhjzrbzysYSl
-> ssh-ed25519 Wl2fDA 8rfiRx7+Gr9BtiSXsVEs2W+pXoms6ynODC1TL90+Wi4
/uMnYMJovbaPjwX1qCAtIokov40RYIAm2Mup5XKBJvw
-> ssh-ed25519 zNC8SA FlxMK7kMYnKHY9MBJ+HYDI4GNS0nSgZxVuRe4yTWBgg
HPOV31k8Ueb1W5usG7iLXDQxyAlISrgHThddHpGY2+s
-> ssh-ed25519 EiAAKw Bu7+NJXivoRA07glNWUlBGu03J0ueth7XDU7SWQYT30
r/DBmf4TRDJBgFF0KdeHuKL5hLdU1z6HtfAAVbc6Y0I
-> ssh-rsa eFi+Zw
Nu4gAM/vbh0kpEUIaT4P6iTe9qFFM/9IVxiiKPYHdPnCmPJHrug1afLLFrrrpqkd
o1NrfYIM9gW6jl5QMCcP5DpzMTppokX0P1Tz1ZeOEtZUVtGeZ7Q2wmL4zftwmG9J
qoDjsCd0z6MPDUdU46qc7kjQBhOwGLfHXTfGLXGNZxqj0oLvEoEKpdvFNBvMSyxK
oGZRwGsHQcUXKhCPtf6PVtSkHMABzpUAhgS8oqjp4RVurD0lcrPgsx8pSRRarfyE
ll1QbFCjftuJfeIEshgRkaLGjIQpZDFA3w2XMqDddFz5H/9Ak+F8/rkNnUrN2x4M
amca8s4Sbls6RjyysarIytilCtpaKEI2sgkD2fERao6ayTSnWF45qqh635OLaP5A
b7qcru9gO0C3Ik+UuiZMgovxo/+yBYe3+8x8q/uKR4apPAkt/2q28Uilw1WboIEB
rIjBr0BN1JeHvkiyljJGcvGf5jHdmOrpQu/L1xuSDjsTnh+U6BshQC8bbkJNsVoL
--- BuKW3bW48i1OD38J2bj5sRkn+zg/WKiLtf8zgycCr2A
g­©2Ôkâ5 ÀóìØ!]0kÉW€³ÍØ¡t>éQžk[I3Vâ4EÔàwc`L;UvžVe)m©mé¿€ Û¸
--- GCTLfa/BICL9AWTaqGC13M101Z8sqSqPP4ysJVv5zvg
]
ý­¢Ôÿi¹‡7c·f`b@%X”¿J )û[<+;x-ÇKmTõ@ãÌ„ýŸK]7sc*ë­Ÿ‡¼2Ý®5
+6 -3
View File
@@ -6,7 +6,10 @@ in
{
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
# tsig-keygen sub.domain.tld.
"dns/tuxcord.key".publicKeys = [ tuxcord-ca ] ++ [ users.error users.javalsai ];
# "dns/users/XXX.key".publicKeys = [ users.XXX ];
# tsig-keygen etc.sub.domain.tld.
"dns/tuxcord.net/tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ [ users.error users.javalsai ];
# "dns/tuxcord.net/XXX.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ [ users.XXX ];
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
}
+9 -1
View File
@@ -42,7 +42,15 @@ Host specific configuration can be found at `nixos/hosts/tuxcord-XX`. This is us
To learn how to get started, refer to the [Getting Started guide](./GETTING_STARTED.md).
The guide contains basic instructions as to how to use Nix for this repository, as well as tools to help in certain tasks.
The guide contains basic instructions as to how to use Nix for this repository, as well as tools to help in certain tasks, some of this tools might be assumed accross document resources.
It might also be useful to read the [installation section](#installation) to learn how to configure your testing environment.
# Installation
Though the nix configuration already does most heavy-lifting already. There's some minor configuration that has to be done to the mutable state of the machine.
Each aspect of it should be carefully explained in the [Setup Guide](./SETUP.md).
# Contributions
+28
View File
@@ -0,0 +1,28 @@
# Secrets
Secrets are managed with `agenix` in the `agenix/` directory. This allows to declaratively define secrets as well as which keys are allowed to decrypt them.
# Usage
The `agenix` help menu is already very helpful, but here you have a survival guide:
- `agenix` commands should run relative to the `agenix/` direcotry.
- `agenix -d` allows you to descrypt such file if you possess any of the decryption keys.
- `agenix -e` decrypts (if present) and opens the file in your editor to re-encrypt when exited.
- `agenix -r` re-encypts `*.age` files in the case you ever change its decryption keys.
# Secrets
<!-- TODO: missing ntfy.sh secret docs -->
## DNS TSIG Keys
The DNS server takes zone updates through `nsupdate` with symmetric TSIG keys.
These keys can be generated using `tsig-keygen <key-name>` (historically they were done with `dnssec-keygen` and `HMAC` algorithms, but this is no longer supported).
When DNS is enabled for a host, it will look for `dns/${fqdn}/${zone}.key` secrets.
- The key whose zone matches the `${fqdn}` will be allowed to tramit updates for all the domain.
- Keys restrained to a specific `${subdomain}` will only be allowed to edit records of such subdomain.
- All keys must be named with the zone they affect, final dot included, so that (e.g. `tuxcord.net/javalsai.tuxcord.net.key` must be generated by `tsig-keygen javalsai.tuxcord.net.`).
+60
View File
@@ -0,0 +1,60 @@
# Setup Steps
The first configuration of the server needs some configuration of its mutable state:
Setup also heavily relies on the secrets configured, make sure you [undestand agenix](./SECRETS.md) good enough.
# SSH Keys
Most agenix secrets have to be decrypted by the machine nixos is being installed to. For this, agenix uses the ssh host keys.
This also means that no secrets will be accessible on the host right after a base installation, with the default fresh ssh keys.
Will will need to either migrate ssh keys from another host, if you are doing a migration, or take the public keys of the new host out to encrypt agenix secrets against them. These keys, both public and private are present in `/etc/ssh/ssh_host_*`, we have a strong preference in favor of elliptic curve cryptography.
Also note that ssh keys are persistent and will be saved across machine boots and virtual machine rebuilds, so you don't need to repeat this process every time.
# DNS SOA Record
If the DNS server is enabled for the host (`dns.enable`), the host will have a DNS server for itself that can take updates with `nsupdate`.
This section assumes surface-level knowledge of DNS records, as well as a IPv4-only server.
First of all, make sure that the secrets for `nsudpate` ([DNS TSIG Keys](./SECRETS.md)) are in place, otherwise the server won't be able to take updates and will remain on an empty useless state.
You need to tell it it has authority over itself (`SOA` -> `Start Of Authority`) for it to take updates and serve changes properly, as well as configure the base `A` records.
`/var/dns/${fqdn}.zone`:
```zone
$ORIGIN ${fqdn}.
$TTL 14400 ; 4 hours
@ IN SOA ${fqdn}. ${adminEmail} (
2026050301 ; serial
3600 ; refresh (1 hour)
1800 ; retry (30 minutes)
604800 ; expire (1 week)
86400 ; minimum (1 day)
)
@ A ${ip}
ns1 A ${ip}
@ NS ns1
ns2 A ${ip}
@ NS ns2
* CNAME ${fqdn}.
```
Note the template variables:
- You need to place your FQDN in `${fqdn}` (there are shorter ways, but this guarantees functionality even if the hostname and domain don't match).
- Also an IPv4 address at `${ip}`.
- And lastly, `${adminEmail}` the SOA record has a `RNAME` field that takes the administrator's email address with dot notation (`test@example.com` would be written as `test.example.com.`).
- The values related to serial number and lifetimes can and should be tweaked depending on the use-case. Especially `serial`, note that it resembles a date.
Then restart bind with `systemctl restart bind`. Make sure that the file is owned by `named:named`.
> [!NOTE]
> This file is **mutable**, bind can and **will** change it with `nsupdate`s, it also tends to format and compact this template into a certain layout.
-8
View File
@@ -28,14 +28,6 @@ in
./vm.nix
];
age.secrets = {
dns-root-key = {
file = ../agenix/dns/tuxcord.key;
group = "named";
owner = "named";
};
};
nix = {
package = inputs'.nix-super.packages.default;
+1
View File
@@ -4,6 +4,7 @@
./storage.nix
];
dns.enable = true;
networking.fqdn = "tuxcord.net";
time.timeZone = "Canada/Eastern";
}
+1
View File
@@ -1,3 +1,4 @@
{
dns.enable = true;
networking.fqdn = "tuxcord.test";
}
+81 -39
View File
@@ -1,58 +1,100 @@
{ config, ... }:
{ config, lib, ... }:
let
fqdn = "tuxcord.net";
# fqdn = config.networking.fqdn;
agenixDnsDir = ../../agenix/dns + "/${config.dns.domain}";
agenixKeys = builtins.attrNames (builtins.readDir agenixDnsDir);
zonesub = _: "zonesub";
subdomain = name: "subdomain ${name}";
keys = map (
filename:
let
zonesub = _: "zonesub";
subdomain = name: "subdomain ${name}";
# careful, assumes the fqdn (name) matches the key name content
keys = [
zoneDomain =
if lib.strings.hasSuffix ".key.age" filename then
lib.strings.removeSuffix ".key.age" filename
else
throw "${filename} is not a `.key.age` file";
in
{
name = "tuxcord.net";
path = config.age.secrets.dns-root-key.path;
type = zonesub;
name = zoneDomain;
path = config.age.secrets."dns/${filename}".path;
type = if zoneDomain == config.dns.domain then zonesub else subdomain;
}
];
) agenixKeys;
cfg = config.dns;
inherit (lib)
mkEnableOption
mkOption
mkIf
;
in
{
services.bind = {
enable = true;
options.dns = {
enable = mkEnableOption "" // {
default = true;
};
extraConfig = builtins.concatStringsSep "\n" (map (key: "include \"${key.path}\";") keys);
zones = {
"${fqdn}" = {
# grant "tuxcord.net" zonesub ANY;
extraConfig = ''
update-policy {
${builtins.concatStringsSep "\n" (
map (key: "grant \"${key.name}\" ${key.type key.name} ANY;") keys
)}
};
'';
file = "/var/dns/${fqdn}.zone"; # need to put default stuff
master = true;
};
domain = mkOption {
type = with lib.types; str;
default = config.networking.fqdn;
};
};
environment.persistence."/persist" = {
directories = [
config = mkIf cfg.enable {
age.secrets = builtins.listToAttrs (
map (
filename:
let
path = "${agenixDnsDir}/${filename}";
in
{
name = "dns/${filename}";
value = {
file = path;
group = "named";
owner = "named";
};
}
) agenixKeys
);
services.bind = {
enable = true;
extraConfig = builtins.concatStringsSep "\n" (map (key: "include \"${key.path}\";") keys);
zones = {
"${config.dns.domain}" = {
# grant "tuxcord.net" zonesub ANY;
extraConfig = ''
update-policy {
${builtins.concatStringsSep "\n" (
map (key: "grant \"${key.name}\" ${key.type key.name} ANY;") keys
)}
};
'';
file = "/var/dns/${config.dns.domain}.zone"; # need to put default stuff
master = true;
};
};
};
environment.persistence."/persist".directories = [
{
directory = "/var/dns";
group = "named";
user = "named";
}
];
};
networking.firewall =
let
ports = [ config.services.bind.listenOnPort ];
in
{
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};
networking.firewall =
let
ports = [ config.services.bind.listenOnPort ];
in
{
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};
};
}