Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
83ba8dffb2
|
|||
|
82c76dc390
|
|||
| edf7aab2f0 | |||
|
760c5c8284
|
|||
|
3a5d5d27f4
|
|||
|
015bbc3d66
|
|||
|
dc374e8c04
|
|||
|
a708c04a9a
|
|||
| a2534a3dab | |||
| b78c41a5f7 | |||
| e1f2dc3161 | |||
|
f1c5f038ec
|
|||
|
ae0d4f5958
|
|||
|
ded0374c57
|
|||
|
ab0f9a2ff2
|
|||
| fb9526fec2 | |||
|
0692e680b8
|
|||
|
3a940586d5
|
|||
| 7e7097f457 | |||
| 22b3a95bf8 | |||
| de4b8833bd | |||
| ac9b80573f | |||
| 66a15a5d19 | |||
| 7e331f5e1a | |||
| a8374e231f | |||
| 27b861d5a5 | |||
| 6a29ac005c | |||
|
0b9f76dcb4
|
|||
| cc52b0e6cb | |||
|
d4d560c30f
|
@@ -0,0 +1,19 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 Wl2fDA sLlStq5Hzb2JNQubLtMk5/kyIp81aTyjUB/Ysv1gRR0
|
||||
lTLWsvT5Oxk8ut/g+o9o0DMOIQVDmi9o4EO0fYeIToo
|
||||
-> ssh-ed25519 zNC8SA G0XcS2gzF0RopI2DqkWaTYXwjUpkVtdrxSQ+p8bfE0w
|
||||
pZVIg/1P8BbnpRfV5F0FG3xgLSiA8M+nosQ8iNeYmcU
|
||||
-> ssh-ed25519 EiAAKw qWmO0IjKoUFVxbxFUx36JIhME2PU7lkD+3agKO7+6nA
|
||||
yEIw8IzQmM8C9dZoPajtvdUOF5kJ/C+rtgLczcmP1bs
|
||||
-> ssh-rsa eFi+Zw
|
||||
O5XRvS+Y/1mm9nQ7IZmxEp7RmFjAH0OTKPkRTME7BybnePPZLL0l6wMP26hx88Nv
|
||||
dOqdaS07Xb26EIgCS/4xCY4sPWZNEfAfnDVoF4/SNbmfbN0XpNpR981AWcxiTL35
|
||||
Fngk0lPa1NtuUH4S4zTda21kXHE0zv2mYLNMuek8dTrUd2piC+Z0WJJdrG1LK0hN
|
||||
dDuLzX/mNibNXDvYxyD6mtkO2S1wO9QL88ucNZptT29vcaD48EZM/SsAwgf3OoqH
|
||||
kd7jSTTdZ/yk8ccTMiT5eskQ3ZZcqc7JaF+M2d88DP6LcSaJnNzyVSEMAHHfpoY1
|
||||
/kHxZ88/ehwPDXrp0bL448jdPuWqPSerzCWyyZFbc8Jj6zRUtC5joL0Vq2Rqs+EH
|
||||
rmKMfi1l2+utleGYfCyHI5/czsMhJ2jXLGPguWQQdixNtb/RWFw6DeRP9xdO9QJR
|
||||
LkoAFgv0ykP+L+C6sA7bpJqIGNftl4x8OUQxrKtf3YQ8K2LhUZb23JPn4Ob/QXo/
|
||||
|
||||
--- W7eUDhB/RBUYV1gaM4ktPEOVU6l5IRgOoRDpKKpvAnM
|
||||
O\òŒMúOýJä ÍÅ!ÒHûËÄpK¥Õ:gßÙ[6™M¡VÞÃbYæÌí;è€F'¡#ä7&Žs1„ 󨱉6º�²5_nÂ’mõÔ.¼qñ'à˜ƒq®6Êf-ÖÄW™w›½ß#5³¯6ˆ¼ŸêªrÒð�„Ð#œÅÄ€=�4EÎËlžÕÿ[
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 Wl2fDA 3CWPYLgoTMGb9gBbDzZIQxYJ9Gfm49g6lqQyqlegUDQ
|
||||
ryhsPP5+Byus2e5GSXDJlKYX1o3HfQ87CLRv2htU4n4
|
||||
-> ssh-ed25519 EiAAKw B2uGdkeC3OZISN2iH2DR1J7L3/mbuFvebzqaTdAURCw
|
||||
ze0X/MmHP78rRqAn0O3VBtnMJsiOXPk8RIe82tdQMeg
|
||||
--- kLBxPuJdbPmJ1Lz3iBu8EPItdZtpNHIyV6pz1QzhcUY
|
||||
ä3ÛÿÉèŸP>gòh@ö•AZ’üz-í6R€¸zèÚ¢[ÇÝÍPÂòㆿy?•ÉŽU�SNÝ©&ú#}ÝR+o?.B¶&´5]ÇW€OΉPuh‹½ŽÞ=t¶5|¿×“s×€ú&!‰Î-�æTÝSÆfÕ™-j"#žiÂwzºš›ãjö¯“HŒí�
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+17
-31
@@ -1,34 +1,20 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 Wl2fDA dM0TgKtswZcbEV9tGGY26YCksV2xadHWXv7D/KksAWk
|
||||
1vCcuHmVP2xiHd/7hh0z2Hiq/EeA8uvdsRtQReC5hNY
|
||||
-> ssh-ed25519 zNC8SA uTO/3ePjgiKqk3jeRGZX5D3LjzhSBlp2rD2ZakKmfX0
|
||||
tVkEEcP/KfD9x52l7iz5F3hKK0LSckjXWK5YP2aeBt4
|
||||
-> ssh-ed25519 EiAAKw Etu0I4IzJ3BB2SzCeiexx+dhcLUO5d2Ws+WiJyLk/Sw
|
||||
9GBcZPsIXO3mXbri3lFYjtBBu0wFYul6hKsCvBKVLFs
|
||||
-> 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
|
||||
uOZsBC+IMHdX2h9Jq/CF/L3BsxDW+dULk04JQbDeM85Mrxxdrv2X3w7AW8YU2KS+
|
||||
Xg8LnzH01z4Nfs89uysM/lsWptc9qMeaK9o0oHC+tSJH4Ch43MejbmFYjFibHaCm
|
||||
krQM7dAGIJwc/o0+ykaCrbXSvXAyfd6Nw1izou2ZcDRI7mTipOZO8F949SIk//Rc
|
||||
UJgPLqpGwScEfrHf4f6tySC4LmD0bPIV1xDpmmXcS7c83E9+iVOtb5Y1In6CQrF1
|
||||
XZQCb9MkPySbuicwR022CySb+lc7Ru44RdqBgV1e+wphyZCoqCk09i18egV3hNs6
|
||||
iEul3M8dqV27yRKrWIUD5jT2tUszTNJfreiuZl9eDmLkcVWExkWzqWPUFJ48hQiZ
|
||||
89Z4Evn04vZGoeL67K5q93lSRHz109zT/KIJSQMZpbaecGAoiZDM8Mdq3KzawGSG
|
||||
ENQazx6lnGoMccvxFhjrVqfYj3U4S/pnCow5fatvkBQSyysL63UxE5ivcFUHHppB
|
||||
Nu4gAM/vbh0kpEUIaT4P6iTe9qFFM/9IVxiiKPYHdPnCmPJHrug1afLLFrrrpqkd
|
||||
o1NrfYIM9gW6jl5QMCcP5DpzMTppokX0P1Tz1ZeOEtZUVtGeZ7Q2wmL4zftwmG9J
|
||||
qoDjsCd0z6MPDUdU46qc7kjQBhOwGLfHXTfGLXGNZxqj0oLvEoEKpdvFNBvMSyxK
|
||||
oGZRwGsHQcUXKhCPtf6PVtSkHMABzpUAhgS8oqjp4RVurD0lcrPgsx8pSRRarfyE
|
||||
ll1QbFCjftuJfeIEshgRkaLGjIQpZDFA3w2XMqDddFz5H/9Ak+F8/rkNnUrN2x4M
|
||||
amca8s4Sbls6RjyysarIytilCtpaKEI2sgkD2fERao6ayTSnWF45qqh635OLaP5A
|
||||
b7qcru9gO0C3Ik+UuiZMgovxo/+yBYe3+8x8q/uKR4apPAkt/2q28Uilw1WboIEB
|
||||
rIjBr0BN1JeHvkiyljJGcvGf5jHdmOrpQu/L1xuSDjsTnh+U6BshQC8bbkJNsVoL
|
||||
|
||||
-> ssh-ed25519 QovoLQ wgg0cFlYEVafE3rXK4GrID3RTatZdKPYzsjT18WskFM
|
||||
bgv+7an3xgdqf6WaiB1FFkXObcykUnvH6lJmX5gFJkQ
|
||||
-> ssh-rsa OFkEIg
|
||||
IIQbFB6VUwbB+ZtKR7Ayg9Im6vMU1AzqHT8CBagA5fwJ7Vp1GuX1X9SxL9hMPkd3
|
||||
4osEbSu3JJDMwfC6AfFtcEjmxjmRYyiYlzmIjhVEsaTlwyeucAPd+fdj+TPjHidZ
|
||||
dffizNEOiENY49jlmWTjMqYKnBsSP9GfH4ZsKpCaWMm2h9p687weuXFfbYfjYMII
|
||||
a3C4iG8m+mZ4crYTKZu6WPbnHn9g0pMxZBs4v6MnBHk6eEJ0uiJvrzYApoFE5om7
|
||||
9AknL27ra/+A1UQl+1kzLT+IivJa8FCfZ+zF1RYLRvSATlIzCqCiBiayAsVtQg5O
|
||||
girBRnlAJTPisszyoAhsqbECvD6bJfwlTW0STg/M1u3ZPMTGL4V0gJgynANmjb7Y
|
||||
TXd11zuhjRYgOBAj09trQFTmmwIgPvvu8+VXNDNPAp02ffBT8kMUvSEik98/35x1
|
||||
Dwvm38t05O6nqyHUF957CRVTzPQPAnb5Cd+Rw/joID2YPyFN9IZwE4mi2Bf3zdZo
|
||||
roxtqCupmWkpxMNN7GZJrmCE/Lh6YV4DgUd6VNQc7QlGsq5K4XRT7aa+s+17cC8e
|
||||
HCxQfGM8sMe9T6IK+K4p6qTqluyI/X0r95kGfzhNmgzufc44i6X497i3fDSVoLpx
|
||||
Uo7Ao3QRNPyaUXcqTTIg8Kx9YiLQC3tDblVJjIZU89o
|
||||
--- Vb9o/bhuN6XXjfK04haEEUXnuIA02j4GH9PmAh0ayN8
|
||||
óE¬dGs;’ްÀ±��ü
|
||||
ñ,OHˆÿœˆ{²¶>ú*wAÃLÌÄ\©0SQöÖ*{6fô‰+Xš¨.
|
||||
--- GCTLfa/BICL9AWTaqGC13M101Z8sqSqPP4ysJVv5zvg
|
||||
]
|
||||
ý¢Ôÿi¹‡7c·f`b@%X”¿J�)û[<+;x-ÇKmTõ@ãÌ„�ýŸK]7sc*럇¼2Ý®5
|
||||
+17
-7
@@ -1,15 +1,25 @@
|
||||
let
|
||||
users = import ../lib/ssh/keys.nix;
|
||||
inherit (import ../lib)
|
||||
users
|
||||
adminSSHKeys
|
||||
attrsToList
|
||||
getSSHKeys
|
||||
;
|
||||
|
||||
tuxcord-ca = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPxiko5Csyq9UODglYzLBvRfxkhQu9GXP7SH2BpC8G/7";
|
||||
in
|
||||
{
|
||||
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
|
||||
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
|
||||
|
||||
# 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;
|
||||
"dns/tuxcord.net/tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
|
||||
"dns/nix.tuxcord.net/nix.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
|
||||
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
|
||||
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
|
||||
}
|
||||
// builtins.listToAttrs (
|
||||
map (user: {
|
||||
name = "dns/tuxcord.net/${user.name}.tuxcord.net.key.age";
|
||||
value.publicKeys = [ tuxcord-ca ] ++ getSSHKeys user.name;
|
||||
}) (builtins.filter (user: user.value.ddns or false) (attrsToList users))
|
||||
)
|
||||
|
||||
@@ -16,13 +16,19 @@ To test the environment, you can launch a virtualized NixOS system derived from
|
||||
nix run '.#nixosConfigurations.<system>.config.system.build.vm'
|
||||
```
|
||||
|
||||
Here, `<system>` refers to the hostname of the system you want to test (e.g., tuxcord-ca).
|
||||
Here, `<system>` refers to the hostname of the system you want to test (e.g., tuxcord-test).
|
||||
|
||||
Note that this will create a `qcow2` image file in the current directory. Nix will automatically manage changes to the configuration and update the image file accordingly while keeping part of its mutable state (e.g., root bash history).
|
||||
|
||||
> [!WARNING]
|
||||
> Not all changes are applied automatically. Updates such as user passwords changes or modifications to the filesystem layout will require deleting the image file so that Nix can re-create it from scratch.
|
||||
|
||||
# Access
|
||||
|
||||
The initial password for the `root` account is `tuxcord`.
|
||||
|
||||
SSH login is enabled for the configured user keys, if using the VM test configuration, yo will have to use the bridged IP.
|
||||
|
||||
# Tooling
|
||||
|
||||
Tooling used to aid in development.
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ 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, some of this tools might be assumed accross document resources.
|
||||
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 across document resources.
|
||||
|
||||
It might also be useful to read the [installation section](#installation) to learn how to configure your testing environment.
|
||||
|
||||
|
||||
+9
-3
@@ -6,14 +6,20 @@ Secrets are managed with `agenix` in the `agenix/` directory. This allows to dec
|
||||
|
||||
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` commands should run relative to the `agenix/` directory.
|
||||
- `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 -->
|
||||
There is a `ntfy.age` secret file which contents look like:
|
||||
|
||||
```sh
|
||||
NTFY_TOPIC=readable-name_XXXXXXXXXX
|
||||
```
|
||||
|
||||
This secret file is meant to be sources by shells before using [ntfy.sh](<https://ntfy.sh/>) to push important notifications. This topic could contain sensitive information and must be kept secret amongst administrators.
|
||||
|
||||
## DNS TSIG Keys
|
||||
|
||||
@@ -24,5 +30,5 @@ These keys can be generated using `tsig-keygen <key-name>` (historically they we
|
||||
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.
|
||||
- Keys restrained to a specific `${zone}` will only be allowed to edit records of such zone.
|
||||
- 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.`).
|
||||
|
||||
+7
-1
@@ -2,7 +2,13 @@
|
||||
|
||||
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.
|
||||
Setup also heavily relies on the secrets configured, make sure you [understand agenix](./SECRETS.md) good enough.
|
||||
|
||||
# Root Password
|
||||
|
||||
The `root` password is `tuxcord` by default on all system configurations. For security, it's important to remember to change it as soon as an installation is done.
|
||||
|
||||
The root account is intended to be kept active in case there ever is the need to perform a TTY login. But this will be rare so do keep a security complex password saved somewhere and don't share it beyond the necessary amount.
|
||||
|
||||
# SSH Keys
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
formatter = pkgs.nixfmt;
|
||||
};
|
||||
|
||||
flake = {
|
||||
lib = import ./lib;
|
||||
pins = import ./npins;
|
||||
};
|
||||
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
rec {
|
||||
toList = x: if builtins.isList x then x else [ x ];
|
||||
|
||||
nameValuePair = name: value: { inherit name value; };
|
||||
|
||||
mapAttrsToList = f: attrs: builtins.attrValues (builtins.mapAttrs f attrs);
|
||||
|
||||
attrsToList = mapAttrsToList nameValuePair;
|
||||
|
||||
getSSHKeys =
|
||||
username:
|
||||
if (builtins.hasAttr "ssh" users.${username}) then
|
||||
toList users.${username}.ssh
|
||||
else
|
||||
builtins.warn "user ${username} declared without ssh keys" [ ];
|
||||
|
||||
users = import ./users.nix;
|
||||
|
||||
adminSSHKeys = builtins.concatLists (
|
||||
map (user: getSSHKeys user.name) (
|
||||
builtins.filter (user: user.value.admin or false) (attrsToList users)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
error = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzdpxex2GlFVf5G2qsh3Ixa/XCMjnbq4JSTmAev7WYJ error.nointernet@gmail.com";
|
||||
javalsai = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFjavnLqxIzFLIUpUWDOwhlYeoII4Qk1/9e0yWWxD/P";
|
||||
max = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxVfJhzPDZ108UjB3Vj/akzlzYn27kyAw29AuYAr7gvG5vrqhLUYYmK8t+ZVWVpc1g6cK7OF1oUn2E5Qfmy6wqyZQXftAZ4OcRS0MB71W1bAcRq3rGe6KQDm8RSEeygX+zO+2Z6zQmVWgPr/I+JFQZ8wiWdP8X8djqTRdhqUD+SR3ZgTcnY3aLmeB/I56rcZQ3lKIeg/pEsyQ8weptlV0rTWamna6Z7Nw48VwWNSI+6EqfW2/4/edm0Ue8jMNqNZ0yx+kHJbudPgZgSR1SiR2rqlEEUaiQJQQV3VdY4DhGm7143ZSKUxyKlfTuQ7qR1zSIg6f5V71A37ik9YiSbBlOZO86swR4qHESoMNf608IuqRt2NdALHwozFPUCu16qnhu5JTk8twSAzrAhOk5zWQj1LYMoQEBhcFSmwir/1gE71NSjYtqXGVAdfkVmZ4uqG5+a1D7H3VXWOqu/j839M045O1ZBY6X3lKDsEJ1Z1+LCl/NojWnvPtJUHYI6+SdQ6k=";
|
||||
|
||||
vectorum = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwfPaylCSN7ZqB6Trz8CmQlyzf0NUIy06uschdIOkdzjUNe/dPGbyEFZy/4SDBhg585x8hwfhfYjLGrneYq+O42DBDTDKxduWnIdl5zgPRqt7jB59jkukf9WUdpUdZsKCM5K97HCnizNEKGRnYllVPVQSapPhOm5dZlUD9YVv1UqbDuxtWOLvArkL52e9T+yL6FagRg6NPqA70MXPMk+S2H7lotFVxP2Eg//BCaQ0/H1vhNy6P4N6LLq3sVK1DSJyd2v8zHkdb2Zo0/Ygukol10KizSsEcihm8+bXp699uSgWIsaIQgDZlE1yx2iabmzQST1kL9+USnZZBZ+KxwtLCCI8mpCv6sxlhq2Zzim5HvsyMYM+zdHWIn1s2c6mEl4ntBAB4s5wAggS5Gjh/BfJLSvGsTFMC/XYX4gWFXynY5NlcopeENL2Afg4gbQvKkxYkWB/TMZWuqj5c5kCy+7F0881DpYxapq6kQ6IE4gkGiEQdhVFGWEFoV/k9iHrl6aanqvFtvuBHHgkXAGPpHAZDVZdp9lU0tqNQIM/eGINq4Or6wd9XDYyj5ezDEBxx1pPgweUDZrNe9+vKR+3AwbzB/XQPxTCcjd4d7Yx58jPLflFP1dDYT+3bvp+vA7UpHcJnISbVNu0SiSaIqLYhwDj1od5l6JDfRCqnMF1T59nRCQ==";
|
||||
pickzelle = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUYQUWoL8iGc+PSrRrHyNwcOcmgGwPvJAM9HRJkPqcW pixel@DOOM-Machine";
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
error = {
|
||||
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzdpxex2GlFVf5G2qsh3Ixa/XCMjnbq4JSTmAev7WYJ error.nointernet@gmail.com";
|
||||
admin = true;
|
||||
ddns = true;
|
||||
};
|
||||
|
||||
javalsai = {
|
||||
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFjavnLqxIzFLIUpUWDOwhlYeoII4Qk1/9e0yWWxD/P";
|
||||
admin = true;
|
||||
ddns = true;
|
||||
};
|
||||
|
||||
max = {
|
||||
ssh = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxVfJhzPDZ108UjB3Vj/akzlzYn27kyAw29AuYAr7gvG5vrqhLUYYmK8t+ZVWVpc1g6cK7OF1oUn2E5Qfmy6wqyZQXftAZ4OcRS0MB71W1bAcRq3rGe6KQDm8RSEeygX+zO+2Z6zQmVWgPr/I+JFQZ8wiWdP8X8djqTRdhqUD+SR3ZgTcnY3aLmeB/I56rcZQ3lKIeg/pEsyQ8weptlV0rTWamna6Z7Nw48VwWNSI+6EqfW2/4/edm0Ue8jMNqNZ0yx+kHJbudPgZgSR1SiR2rqlEEUaiQJQQV3VdY4DhGm7143ZSKUxyKlfTuQ7qR1zSIg6f5V71A37ik9YiSbBlOZO86swR4qHESoMNf608IuqRt2NdALHwozFPUCu16qnhu5JTk8twSAzrAhOk5zWQj1LYMoQEBhcFSmwir/1gE71NSjYtqXGVAdfkVmZ4uqG5+a1D7H3VXWOqu/j839M045O1ZBY6X3lKDsEJ1Z1+LCl/NojWnvPtJUHYI6+SdQ6k=";
|
||||
admin = true;
|
||||
};
|
||||
|
||||
vectorum = {
|
||||
ssh = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwfPaylCSN7ZqB6Trz8CmQlyzf0NUIy06uschdIOkdzjUNe/dPGbyEFZy/4SDBhg585x8hwfhfYjLGrneYq+O42DBDTDKxduWnIdl5zgPRqt7jB59jkukf9WUdpUdZsKCM5K97HCnizNEKGRnYllVPVQSapPhOm5dZlUD9YVv1UqbDuxtWOLvArkL52e9T+yL6FagRg6NPqA70MXPMk+S2H7lotFVxP2Eg//BCaQ0/H1vhNy6P4N6LLq3sVK1DSJyd2v8zHkdb2Zo0/Ygukol10KizSsEcihm8+bXp699uSgWIsaIQgDZlE1yx2iabmzQST1kL9+USnZZBZ+KxwtLCCI8mpCv6sxlhq2Zzim5HvsyMYM+zdHWIn1s2c6mEl4ntBAB4s5wAggS5Gjh/BfJLSvGsTFMC/XYX4gWFXynY5NlcopeENL2Afg4gbQvKkxYkWB/TMZWuqj5c5kCy+7F0881DpYxapq6kQ6IE4gkGiEQdhVFGWEFoV/k9iHrl6aanqvFtvuBHHgkXAGPpHAZDVZdp9lU0tqNQIM/eGINq4Or6wd9XDYyj5ezDEBxx1pPgweUDZrNe9+vKR+3AwbzB/XQPxTCcjd4d7Yx58jPLflFP1dDYT+3bvp+vA7UpHcJnISbVNu0SiSaIqLYhwDj1od5l6JDfRCqnMF1T59nRCQ==";
|
||||
};
|
||||
|
||||
pickzelle = {
|
||||
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUYQUWoL8iGc+PSrRrHyNwcOcmgGwPvJAM9HRJkPqcW pixel@DOOM-Machine";
|
||||
};
|
||||
}
|
||||
+11
-13
@@ -28,6 +28,8 @@ in
|
||||
./vm.nix
|
||||
];
|
||||
|
||||
age.secrets.ntfy.file = "${self}/agenix/ntfy.age";
|
||||
|
||||
nix = {
|
||||
package = inputs'.nix-super.packages.default;
|
||||
|
||||
@@ -98,21 +100,17 @@ in
|
||||
extraHosts =
|
||||
let
|
||||
subdomains = [
|
||||
""
|
||||
".git"
|
||||
"git"
|
||||
"auth"
|
||||
];
|
||||
|
||||
inherit (config.networking) fqdn;
|
||||
hosts = [ fqdn ] ++ map (sub: "${sub}.${fqdn}") subdomains;
|
||||
in
|
||||
builtins.foldl' (
|
||||
hosts-acc: domain-prefix:
|
||||
let
|
||||
host = "${domain-prefix}${config.networking.fqdn}";
|
||||
in
|
||||
hosts-acc
|
||||
+ ''
|
||||
127.0.0.1 ${host}
|
||||
::1 ${host}
|
||||
''
|
||||
) "" subdomains;
|
||||
lib.concatMapStrings (host: ''
|
||||
127.0.0.1 ${host}
|
||||
::1 ${host}
|
||||
'') hosts;
|
||||
};
|
||||
|
||||
virtualisation.podman.enable = true;
|
||||
|
||||
@@ -33,5 +33,6 @@ in
|
||||
tuxcord-ca = mkSystem "tuxcord-ca" "x86_64-linux";
|
||||
|
||||
tuxcord-test = mkSystem "tuxcord-test" "x86_64-linux";
|
||||
tuxcord-acmetest = mkSystem "tuxcord-acmetest" "x86_64-linux";
|
||||
};
|
||||
}
|
||||
|
||||
+4
-1
@@ -15,7 +15,10 @@
|
||||
"xhci_pci"
|
||||
];
|
||||
|
||||
kernelModules = [ "kvm-intel" ];
|
||||
kernelModules = [
|
||||
"kvm-amd"
|
||||
"kvm-intel"
|
||||
];
|
||||
};
|
||||
|
||||
hardware = {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
imports = [
|
||||
./storage.nix
|
||||
];
|
||||
|
||||
networking.fqdn = "nix.tuxcord.net";
|
||||
|
||||
acme.rfc2136.nameserver = "tuxcord.net";
|
||||
dns.enable = true;
|
||||
|
||||
services.getty.autologinUser = "root";
|
||||
|
||||
time.timeZone = "Europe/Madrid";
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
fileSystems."/" = {
|
||||
device = "/dev/vda";
|
||||
fsType = "ext4";
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,13 @@
|
||||
./storage.nix
|
||||
];
|
||||
|
||||
acme = {
|
||||
enable = true;
|
||||
useSelfDns = true;
|
||||
};
|
||||
|
||||
dns.enable = true;
|
||||
networking.fqdn = "tuxcord.net";
|
||||
|
||||
time.timeZone = "Canada/Eastern";
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
device = "/dev/xvda2";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=@persist" ] ++ defaultOptions;
|
||||
neededForBoot = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
{
|
||||
dns.enable = true;
|
||||
imports = [
|
||||
./storage.nix
|
||||
];
|
||||
|
||||
networking.fqdn = "tuxcord.test";
|
||||
|
||||
acme.enable = false;
|
||||
dns.enable = true;
|
||||
|
||||
services.getty.autologinUser = "root";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
fileSystems."/" = {
|
||||
device = "/dev/vda";
|
||||
fsType = "ext4";
|
||||
};
|
||||
}
|
||||
@@ -55,8 +55,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems."/persist".neededForBoot = true;
|
||||
|
||||
environment.persistence."/persist" = {
|
||||
enable = true;
|
||||
hideMounts = true;
|
||||
@@ -72,10 +70,6 @@
|
||||
];
|
||||
files = [
|
||||
"/etc/machine-id"
|
||||
"/etc/ssh/ssh_host_ed25519_key"
|
||||
"/etc/ssh/ssh_host_ed25519_key.pub"
|
||||
"/etc/ssh/ssh_host_rsa_key"
|
||||
"/etc/ssh/ssh_host_rsa_key.pub"
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.acme;
|
||||
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
inherit (config.networking) fqdn;
|
||||
in
|
||||
{
|
||||
# we'll only support rfc2136 based challenges
|
||||
options.acme = {
|
||||
enable = mkEnableOption "" // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
useSelfDns = mkOption {
|
||||
default = false;
|
||||
description = "Sets values of the self DNS if enabled, otherwise requires manual `rfc2136` nameserver and key values.";
|
||||
};
|
||||
|
||||
rfc2136 = {
|
||||
key = mkOption {
|
||||
type = types.path;
|
||||
default = config.age.secrets."dns/${fqdn}.key.age".path;
|
||||
};
|
||||
|
||||
nameserver = mkOption {
|
||||
type = types.str;
|
||||
default = if cfg.useSelfDns then fqdn else null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = with cfg.rfc2136; nameserver != null && key != null;
|
||||
message = "ACME needs rfc2136 parameters to work, consider using `useSelfDns` option.";
|
||||
}
|
||||
];
|
||||
|
||||
environment.persistence."/persist".directories = [
|
||||
{
|
||||
directory = "/var/lib/acme";
|
||||
group = "acme";
|
||||
user = "acme";
|
||||
}
|
||||
];
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
|
||||
defaults = {
|
||||
email = "error@tuxcord.net";
|
||||
reloadServices = [ "nginx" ];
|
||||
postRun = ''
|
||||
source ${config.age.secrets.ntfy.path}
|
||||
${pkgs.ntfy-sh}/bin/ntfy publish -T recycle -t "${config.host.name}" "HTTPS certificate has been renewed"
|
||||
'';
|
||||
};
|
||||
|
||||
certs."${fqdn}" = {
|
||||
dnsProvider = "rfc2136";
|
||||
environmentFile =
|
||||
with cfg.rfc2136;
|
||||
builtins.toFile "dns-01-challenge.cfg" ''
|
||||
RFC2136_NAMESERVER=${nameserver}
|
||||
RFC2136_TSIG_FILE="${key}"
|
||||
'';
|
||||
extraDomainNames = [
|
||||
"*.${fqdn}"
|
||||
"${fqdn}"
|
||||
];
|
||||
|
||||
inherit (config.services.nginx) group;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (config.networking) fqdn;
|
||||
|
||||
acmeEnabled = config.acme.enable;
|
||||
in
|
||||
{
|
||||
services.authelia.instances.main = {
|
||||
enable = true;
|
||||
|
||||
secrets = {
|
||||
jwtSecretFile = builtins.toFile "authelia-jwtSecret" "QWERTYUIOPASDFGHJKLZXCVBNM1234567890abcdefABCDEFGH";
|
||||
storageEncryptionKeyFile = builtins.toFile "authelia-storageEncryptionKeyFile" "supersecretkeyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
sessionSecretFile = builtins.toFile "aauthelia-sessionSecretFile" "supersecretkey";
|
||||
};
|
||||
|
||||
settings = {
|
||||
theme = "dark";
|
||||
default_redirection_url = "https://${fqdn}"; # HAS to be httpS
|
||||
|
||||
server.address = "127.0.0.1:3001";
|
||||
|
||||
log = {
|
||||
level = "debug";
|
||||
format = "text";
|
||||
};
|
||||
|
||||
authentication_backend = {
|
||||
file = {
|
||||
path = "/var/lib/authelia-main/users_database.yml";
|
||||
};
|
||||
};
|
||||
|
||||
access_control = {
|
||||
default_policy = "deny";
|
||||
rules = [
|
||||
{
|
||||
domain = [ "auth.${fqdn}" ];
|
||||
policy = "bypass";
|
||||
}
|
||||
{
|
||||
domain = [ "*.${fqdn}" ];
|
||||
policy = "one_factor";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
session = {
|
||||
name = "authelia_session";
|
||||
expiration = "12h";
|
||||
inactivity = "45m";
|
||||
remember_me = "1M";
|
||||
domain = "${fqdn}";
|
||||
redis.host = "/run/redis-authelia-main/redis.sock";
|
||||
};
|
||||
|
||||
regulation = {
|
||||
max_retries = 3;
|
||||
find_time = "5m";
|
||||
ban_time = "15m";
|
||||
};
|
||||
|
||||
storage = {
|
||||
local = {
|
||||
path = "/var/lib/authelia-main/db.sqlite3";
|
||||
};
|
||||
};
|
||||
|
||||
notifier = {
|
||||
disable_startup_check = false;
|
||||
filesystem = {
|
||||
filename = "/var/lib/authelia-main/notification.txt";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.redis.servers.authelia-main = {
|
||||
enable = true;
|
||||
user = "authelia-main";
|
||||
port = 0;
|
||||
unixSocket = "/run/redis-authelia-main/redis.sock";
|
||||
unixSocketPerm = 600;
|
||||
};
|
||||
|
||||
# services.openldap = {
|
||||
# enable = true;
|
||||
|
||||
# # enable plain connections only
|
||||
# urlList = [ "ldap:///" ];
|
||||
|
||||
# settings = {
|
||||
# attrs = {
|
||||
# olcLogLevel = "conns config";
|
||||
# };
|
||||
|
||||
# children = {
|
||||
# # "cn=schema".includes = [
|
||||
# # "${pkgs.openldap}/etc/schema/core.ldif"
|
||||
# # "${pkgs.openldap}/etc/schema/cosine.ldif"
|
||||
# # "${pkgs.openldap}/etc/schema/inetorgperson.ldif"
|
||||
# # ];
|
||||
|
||||
# "olcDatabase={1}mdb".attrs = {
|
||||
# objectClass = [
|
||||
# "olcDatabaseConfig"
|
||||
# "olcMdbConfig"
|
||||
# ];
|
||||
|
||||
# olcDatabase = "{1}mdb";
|
||||
# olcDbDirectory = "/var/lib/openldap/data";
|
||||
|
||||
# olcSuffix = "dc=example,dc=com";
|
||||
|
||||
# # your admin account, do not use writeText on a production system
|
||||
# olcRootDN = "cn=admin,dc=example,dc=com";
|
||||
# olcRootPW.path = builtins.roFile "olcRootPW" "pass";
|
||||
|
||||
# olcAccess = [
|
||||
# # custom access rules for userPassword attributes
|
||||
# ''
|
||||
# {0}to attrs=userPassword
|
||||
# by self write
|
||||
# by anonymous auth
|
||||
# by * none''
|
||||
|
||||
# # allow read on anything else
|
||||
# ''
|
||||
# {1}to *
|
||||
# by * read''
|
||||
# ];
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
imports = [
|
||||
./acme.nix
|
||||
./authelia.nix
|
||||
./dns.nix
|
||||
./fail2ban.nix
|
||||
./gitea.nix
|
||||
|
||||
+34
-32
@@ -1,6 +1,21 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
self,
|
||||
...
|
||||
}:
|
||||
let
|
||||
agenixDnsDir = ../../agenix/dns + "/${config.dns.domain}";
|
||||
cfg = config.dns;
|
||||
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkIf
|
||||
strings
|
||||
;
|
||||
|
||||
inherit (config.networking) fqdn;
|
||||
|
||||
agenixDnsDir = "${self}/agenix/dns/${fqdn}";
|
||||
agenixKeys = builtins.attrNames (builtins.readDir agenixDnsDir);
|
||||
|
||||
keys = map (
|
||||
@@ -10,35 +25,23 @@ let
|
||||
subdomain = name: "subdomain ${name}";
|
||||
|
||||
zoneDomain =
|
||||
if lib.strings.hasSuffix ".key.age" filename then
|
||||
lib.strings.removeSuffix ".key.age" filename
|
||||
if strings.hasSuffix ".key.age" filename then
|
||||
strings.removeSuffix ".key.age" filename
|
||||
else
|
||||
throw "${filename} is not a `.key.age` file";
|
||||
in
|
||||
{
|
||||
inherit (config.age.secrets."dns/${filename}") path;
|
||||
name = zoneDomain;
|
||||
path = config.age.secrets."dns/${filename}".path;
|
||||
type = if zoneDomain == config.dns.domain then zonesub else subdomain;
|
||||
type = if zoneDomain == fqdn then zonesub else subdomain;
|
||||
}
|
||||
) agenixKeys;
|
||||
|
||||
cfg = config.dns;
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkOption
|
||||
mkIf
|
||||
;
|
||||
in
|
||||
{
|
||||
options.dns = {
|
||||
enable = mkEnableOption "" // {
|
||||
default = true;
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = with lib.types; str;
|
||||
default = config.networking.fqdn;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
@@ -53,7 +56,8 @@ in
|
||||
value = {
|
||||
file = path;
|
||||
group = "named";
|
||||
owner = "named";
|
||||
owner = if config.acme.enable then "acme" else "named";
|
||||
mode = "440";
|
||||
};
|
||||
}
|
||||
) agenixKeys
|
||||
@@ -64,19 +68,17 @@ in
|
||||
|
||||
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;
|
||||
};
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+26
-13
@@ -1,27 +1,40 @@
|
||||
{ config, lib, ... }:
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (config.networking) fqdn;
|
||||
|
||||
acmeEnabled = config.acme.enable;
|
||||
in
|
||||
{
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
|
||||
appName = "Tuxcord's Gitea";
|
||||
appName = "TuxCord Gitea";
|
||||
database.type = "mysql";
|
||||
|
||||
lfs.enable = true;
|
||||
|
||||
settings.server.DOMAIN = config.networking.fqdn;
|
||||
# settings.server.ROOT_URL = "https://git.tuxcord.net/"; ? would also depend on ssl status
|
||||
settings.server.HTTP_PORT = 3000;
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = fqdn;
|
||||
ROOT_URL = "${if acmeEnabled then "https" else "http"}://${fqdn}/";
|
||||
HTTP_PORT = 3000;
|
||||
};
|
||||
|
||||
settings.service.DISABLE_REGISTRATION = true;
|
||||
settings.service.REQUIRE_SIGNIN_VIEW = false;
|
||||
service = {
|
||||
DISABLE_REGISTRATION = true;
|
||||
REQUIRE_SIGNIN_VIEW = false;
|
||||
};
|
||||
|
||||
settings.repository.ENABLE_PUSH_CREATE_USER = true;
|
||||
settings.repository.ENABLE_PUSH_CREATE_ORG = true;
|
||||
settings.repository.DEFAULT_BRANCH = "main";
|
||||
repository = {
|
||||
ENABLE_PUSH_CREATE_USER = true;
|
||||
ENABLE_PUSH_CREATE_ORG = true;
|
||||
DEFAULT_BRANCH = "main";
|
||||
};
|
||||
|
||||
# settings.ui.DEFAULT_THEME = "...";
|
||||
# ui.DEFAULT_THEME = "...";
|
||||
|
||||
# TODO: once we have email setup this would be nice
|
||||
settings.mailer.ENABLED = true;
|
||||
# TODO: once we have email setup this would be nice
|
||||
mailer.ENABLED = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
+43
-10
@@ -1,17 +1,46 @@
|
||||
{ config, ... }:
|
||||
{ config, self, ... }:
|
||||
let
|
||||
inherit (config.networking) fqdn;
|
||||
|
||||
mkVhost =
|
||||
attrs:
|
||||
attrs: locations:
|
||||
let
|
||||
acmeEnabled = config.acme.enable;
|
||||
in
|
||||
{
|
||||
forceSSL = false; # TODO: tweak per host
|
||||
forceSSL = acmeEnabled;
|
||||
useACMEHost = if acmeEnabled then fqdn else null;
|
||||
|
||||
locations = {
|
||||
"= /robots.txt" = {
|
||||
alias = disallowedRobotsTxt;
|
||||
};
|
||||
}
|
||||
// locations;
|
||||
}
|
||||
// attrs;
|
||||
|
||||
mkProxy = port: {
|
||||
proxyPass = "http://127.0.0.1:${toString port}/";
|
||||
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
'';
|
||||
};
|
||||
|
||||
mkSsi = webRoot: {
|
||||
root = webRoot;
|
||||
|
||||
extraConfig = ''
|
||||
ssi on;
|
||||
'';
|
||||
};
|
||||
|
||||
disallowedRobotsTxt = builtins.toFile "robots.txt" ''
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
'';
|
||||
in
|
||||
{
|
||||
services.nginx = {
|
||||
@@ -23,14 +52,18 @@ in
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
|
||||
# services.nginx.virtualHosts."${fqdn}" = {
|
||||
# addSSL = true;
|
||||
# root = "/var/www/myhost.org";
|
||||
# default = true;
|
||||
# };
|
||||
virtualHosts = {
|
||||
"${fqdn}" = mkVhost { default = true; } {
|
||||
"/" = mkSsi "${self.pins.website}/web-root";
|
||||
};
|
||||
|
||||
virtualHosts."git.${fqdn}" = mkVhost {
|
||||
locations."/" = mkProxy config.services.gitea.settings.server.HTTP_PORT;
|
||||
"git.${fqdn}" = mkVhost { } {
|
||||
"/" = mkProxy config.services.gitea.settings.server.HTTP_PORT;
|
||||
};
|
||||
|
||||
"auth.${fqdn}" = mkVhost { } {
|
||||
"/" = mkProxy 3001;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
settings = {
|
||||
ClientAliveInterval = 300;
|
||||
X11Forwarding = true;
|
||||
|
||||
KbdInteractiveAuthentication = false;
|
||||
PasswordAuthentication = false;
|
||||
|
||||
+37
-61
@@ -1,25 +1,6 @@
|
||||
{ lib, self, ... }:
|
||||
let
|
||||
users = [
|
||||
{
|
||||
name = "error";
|
||||
options.admin = true;
|
||||
}
|
||||
{
|
||||
name = "javalsai";
|
||||
options.admin = true;
|
||||
}
|
||||
{
|
||||
name = "max";
|
||||
options.admin = true;
|
||||
}
|
||||
{
|
||||
name = "vectorum";
|
||||
}
|
||||
{
|
||||
name = "pickzelle";
|
||||
}
|
||||
];
|
||||
inherit (self.lib) users;
|
||||
|
||||
adminGroups = [
|
||||
"adm"
|
||||
@@ -30,60 +11,55 @@ let
|
||||
"wheel"
|
||||
];
|
||||
|
||||
getSSHKeys =
|
||||
username:
|
||||
let
|
||||
sshKeys = import "${self}/lib/ssh/keys.nix";
|
||||
in
|
||||
if (builtins.hasAttr username sshKeys) then
|
||||
lib.lists.toList sshKeys.${username}
|
||||
else
|
||||
lib.warn "user ${username} declared without ssh key" [ ];
|
||||
|
||||
mkUser =
|
||||
name: uid: options:
|
||||
let
|
||||
admin = options.admin or false;
|
||||
|
||||
in
|
||||
{
|
||||
users.users.${name} = {
|
||||
isNormalUser = true;
|
||||
extraGroups = lib.optionals admin adminGroups;
|
||||
inherit uid;
|
||||
|
||||
openssh.authorizedKeys.keys = getSSHKeys name;
|
||||
};
|
||||
|
||||
systemd.slices."user-${builtins.toString uid}".sliceConfig = {
|
||||
CPUQuota = "50%";
|
||||
CPUWeight = "10";
|
||||
IOAccounting = true;
|
||||
IOWeight = "10";
|
||||
MemoryMax = "2G";
|
||||
MemorySwapMax = "1G";
|
||||
TasksMax = "100";
|
||||
};
|
||||
mkUser = name: uid: admin: {
|
||||
users.users.${name} = {
|
||||
inherit uid;
|
||||
isNormalUser = true;
|
||||
extraGroups = lib.optionals admin adminGroups;
|
||||
openssh.authorizedKeys.keys = self.lib.getSSHKeys name;
|
||||
};
|
||||
|
||||
systemd.slices."user-${builtins.toString uid}".sliceConfig = {
|
||||
CPUQuota = "50%";
|
||||
CPUWeight = "10";
|
||||
IOAccounting = true;
|
||||
IOWeight = "10";
|
||||
MemoryMax = "2G";
|
||||
MemorySwapMax = "1G";
|
||||
TasksMax = "100";
|
||||
};
|
||||
};
|
||||
in
|
||||
lib.recursiveUpdate
|
||||
(builtins.foldl'
|
||||
(attrs: user: {
|
||||
options = lib.recursiveUpdate attrs.options (mkUser user.name attrs.uid (user.options or { }));
|
||||
options = lib.recursiveUpdate attrs.options (
|
||||
mkUser user.name attrs.uid (user.value.admin or false)
|
||||
);
|
||||
uid = attrs.uid + 1;
|
||||
})
|
||||
{
|
||||
options = { };
|
||||
uid = 1000;
|
||||
}
|
||||
users
|
||||
(lib.attrsToList users)
|
||||
).options
|
||||
{
|
||||
users.users.root = {
|
||||
initialPassword = "tuxcord";
|
||||
users = {
|
||||
motd = ''
|
||||
__ __ __
|
||||
---------/\ \__ /\ \ /\ \__
|
||||
---------\ \ ,_\ __ __ __ _ ___ ___ _ __ \_\ \ ___ __\ \ ,_\
|
||||
----------\ \ \/ /\ \/\ \/\ \/'\ /'___\ / __`\/\`'__\/'_` \ /'_ `\ /'__`\ \ \/
|
||||
-----------\ \ \_\ \ \_\ \/> <//\ \__//\ \L\ \ \ \//\ \L\ \ __/\ \/\ \/\ __/\ \ \_
|
||||
------------\ \__\\ \____//\_/\_\ \____\ \____/\ \_\\ \___,_\/\_\ \_\ \_\ \____\\ \__\
|
||||
-------------\/__/ \/___/ \//\/_/\/____/\/___/ \/_/ \/__,_ /\/_/\/_/\/_/\/____/ \/__/
|
||||
A friendly Linux community - est. July 2023
|
||||
'';
|
||||
|
||||
openssh.authorizedKeys.keys = lib.lists.concatLists (
|
||||
map (user: getSSHKeys user.name) (builtins.filter (user: user.options.admin or false) users)
|
||||
);
|
||||
users.root = {
|
||||
initialPassword = "tuxcord";
|
||||
openssh.authorizedKeys.keys = self.lib.adminSSHKeys;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
memorySize = 4096;
|
||||
|
||||
qemu.networkingOptions = lib.mkForce [
|
||||
"-net nic,netdev=user.0,model=virtio"
|
||||
"-netdev user,id=user.0,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
|
||||
"-nic bridge,br=virbr0,id=hn0,model=virt-net-pci,helper=\${QEMU_BRIDGE_HELPER_PATH}"
|
||||
"-device virtio-net-pci,netdev=hn0,id=nic1,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
This file is provided under the MIT licence:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
# Generated by npins. Do not modify; will be overwritten regularly
|
||||
let
|
||||
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||
version = data.version;
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
||||
range =
|
||||
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
||||
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
||||
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
||||
concatMapStrings = f: list: concatStrings (map f list);
|
||||
concatStrings = builtins.concatStringsSep "";
|
||||
|
||||
# If the environment variable NPINS_OVERRIDE_${name} is set, then use
|
||||
# the path directly as opposed to the fetched source.
|
||||
# (Taken from Niv for compatibility)
|
||||
mayOverride =
|
||||
name: path:
|
||||
let
|
||||
envVarName = "NPINS_OVERRIDE_${saneName}";
|
||||
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
|
||||
ersatz = builtins.getEnv envVarName;
|
||||
in
|
||||
if ersatz == "" then
|
||||
path
|
||||
else
|
||||
# this turns the string into an actual Nix path (for both absolute and
|
||||
# relative paths)
|
||||
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
|
||||
if builtins.substring 0 1 ersatz == "/" then
|
||||
/. + ersatz
|
||||
else
|
||||
/. + builtins.getEnv "PWD" + "/${ersatz}"
|
||||
);
|
||||
|
||||
mkSource =
|
||||
name: spec:
|
||||
assert spec ? type;
|
||||
let
|
||||
path =
|
||||
if spec.type == "Git" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "GitRelease" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "PyPi" then
|
||||
mkPyPiSource spec
|
||||
else if spec.type == "Channel" then
|
||||
mkChannelSource spec
|
||||
else if spec.type == "Tarball" then
|
||||
mkTarballSource spec
|
||||
else
|
||||
builtins.throw "Unknown source type ${spec.type}";
|
||||
in
|
||||
spec // { outPath = mayOverride name path; };
|
||||
|
||||
mkGitSource =
|
||||
{
|
||||
repository,
|
||||
revision,
|
||||
url ? null,
|
||||
submodules,
|
||||
hash,
|
||||
branch ? null,
|
||||
...
|
||||
}:
|
||||
assert repository ? type;
|
||||
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||
# In the latter case, there we will always be an url to the tarball
|
||||
if url != null && !submodules then
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
||||
}
|
||||
else
|
||||
let
|
||||
url =
|
||||
if repository.type == "Git" then
|
||||
repository.url
|
||||
else if repository.type == "GitHub" then
|
||||
"https://github.com/${repository.owner}/${repository.repo}.git"
|
||||
else if repository.type == "GitLab" then
|
||||
"${repository.server}/${repository.repo_path}.git"
|
||||
else
|
||||
throw "Unrecognized repository type ${repository.type}";
|
||||
urlToName =
|
||||
url: rev:
|
||||
let
|
||||
matched = builtins.match "^.*/([^/]*)(\\.git)?$" url;
|
||||
|
||||
short = builtins.substring 0 7 rev;
|
||||
|
||||
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||
in
|
||||
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||
name = urlToName url revision;
|
||||
in
|
||||
builtins.fetchGit {
|
||||
rev = revision;
|
||||
inherit name;
|
||||
# hash = hash;
|
||||
inherit url submodules;
|
||||
};
|
||||
|
||||
mkPyPiSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchurl {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkChannelSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkTarballSource =
|
||||
{
|
||||
url,
|
||||
locked_url ? url,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
builtins.fetchTarball {
|
||||
url = locked_url;
|
||||
sha256 = hash;
|
||||
};
|
||||
in
|
||||
if version == 5 then
|
||||
builtins.mapAttrs mkSource data.pins
|
||||
else
|
||||
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"pins": {
|
||||
"website": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "Git",
|
||||
"url": "https://git.javalsai.tuxcord.net/tuxcord/website.git"
|
||||
},
|
||||
"branch": "main",
|
||||
"submodules": false,
|
||||
"revision": "b18dd7b863644debb0a843a5b21bb490bfe7d048",
|
||||
"url": null,
|
||||
"hash": "18czfxaldy0zhjprdsqzxnzj3p9qlc4canwigr13iw2wisi4ww5y"
|
||||
}
|
||||
},
|
||||
"version": 5
|
||||
}
|
||||
+18
-1
@@ -5,6 +5,24 @@
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
name = "configuration.nix";
|
||||
|
||||
shellHook = ''
|
||||
for path in \
|
||||
/usr/lib/qemu/qemu-bridge-helper \
|
||||
/run/wrappers/bin/qemu-bridge-helper
|
||||
do
|
||||
if [ -x "$path" ]; then
|
||||
export QEMU_BRIDGE_HELPER_PATH="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$QEMU_BRIDGE_HELPER_PATH" ]; then
|
||||
printf "\033[1;33m%s\033[0m\n" \
|
||||
"WARN: 'qemu-bridge-helper' not found, make sure it is installed and the nix shell hook is looking for it" >&2
|
||||
fi
|
||||
'';
|
||||
|
||||
packages = with pkgs; [
|
||||
bat
|
||||
cachix
|
||||
@@ -13,7 +31,6 @@
|
||||
git
|
||||
inputs.agenix.packages.${stdenv.hostPlatform.system}.default
|
||||
jujutsu
|
||||
neovim
|
||||
nix-output-monitor
|
||||
nixfmt
|
||||
npins
|
||||
|
||||
Reference in New Issue
Block a user