feat: initial commit

This commit is contained in:
Katharina Heidenreich 2026-04-08 20:53:49 +02:00
commit a28c2b5563
19 changed files with 314 additions and 0 deletions

6
.sops.yaml Normal file
View file

@ -0,0 +1,6 @@
creation_rules:
- path_regex: ^secrets/.*(?:$|\.(ya?ml|json|env|txt|key|pub))$
key_groups:
- age:
- age1g5q3hwnpgsas682jkq0zmee3zqggucfe0v5ec0a6pv7wzexadehqne66cj
- age1z7ee2jgwvnrx6dg96rqzhc7gncuancrhm8zaehkelwqkeh4dze7qlsajes

7
config/openssh.nix Normal file
View file

@ -0,0 +1,7 @@
let
secrets = import ../intermediate/secrets.nix;
users = builtins.attrNames secrets.source.openssh.users;
in
rec {
ssh_users = users;
}

15
config/secrets.nix Normal file
View file

@ -0,0 +1,15 @@
{
openssh = {
users = {
nudelerde = {
pub_keys = {
file = ../secrets/openssh/nudelerde/pub_keys;
path = "/home/nudelerde/.ssh/authorized_keys";
owner = "nudelerde";
group = "users";
mode = "0600";
};
};
};
};
}

6
config/services.nix Normal file
View file

@ -0,0 +1,6 @@
rec {
git = {
port = 3000;
domain = "git.nudelerde.de";
};
}

18
configuration.nix Normal file
View file

@ -0,0 +1,18 @@
{ pkgs, ... }:
let
sopsNixVersion = "8f093d0d2f08f37317778bd94db5951d6cce6c46";
in
{
imports = [
"${builtins.fetchTarball "https://github.com/Mic92/sops-nix/archive/${sopsNixVersion}.tar.gz"}/modules/sops"
./hardware-configuration.nix
./system
./services
./programs
];
environment.systemPackages = with pkgs; [ wget tree ];
system.stateVersion = "25.11";
}

View file

@ -0,0 +1,25 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" "rtsx_usb_sdmmc" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/be213f84-29a2-400e-b239-c339eddb6107";
fsType = "ext4";
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

79
intermediate/secrets.nix Normal file
View file

@ -0,0 +1,79 @@
let
lib = import <nixpkgs/lib>;
secretsConfig = (import ../validation/secrets.nix).getSecretsConfig (import ../config/secrets.nix);
getRuntimePath = path:
"/run/secrets/${builtins.concatStringsSep "_" path}";
defaultMetadata = {
path = null;
owner = null;
group = null;
mode = null;
};
normalizeLeaf = path: node:
if builtins.isString node || builtins.isPath node then
{
file = node;
metadata = defaultMetadata;
}
else if builtins.isAttrs node && node ? file then
{
file = node.file;
metadata = {
path = node.path or null;
owner = node.owner or null;
group = node.group or null;
mode = node.mode or null;
};
}
else
throw "Invalid secret leaf at ${builtins.concatStringsSep "." path}: must be string, path, or attrset with 'file'";
flattenTree = path: node:
if builtins.isAttrs node && !(node ? file) then
lib.concatMap (name:
flattenTree (path ++ [ name ]) node.${name}
) (builtins.attrNames node)
else
let
normalized = normalizeLeaf path node;
in
[ {
inherit path;
file = normalized.file;
metadata = normalized.metadata;
} ];
entries = flattenTree [] secretsConfig;
isReady = entry:
builtins.pathExists entry.file;
readyEntries = builtins.filter isReady entries;
missingEntries = builtins.filter (entry: !(isReady entry)) entries;
mkSopsSecrets = sourceEntries:
builtins.listToAttrs (map (entry:
let
secretName = builtins.concatStringsSep "_" entry.path;
in
{
name = secretName;
value = {
sopsFile = entry.file;
format = "binary";
path = if entry.metadata.path != null then entry.metadata.path else getRuntimePath entry.path;
owner = if entry.metadata.owner != null then entry.metadata.owner else "root";
group = if entry.metadata.group != null then entry.metadata.group else "root";
mode = if entry.metadata.mode != null then entry.metadata.mode else "0400";
};
}
) sourceEntries);
in
{
source = secretsConfig;
byName = mkSopsSecrets readyEntries;
missing = missingEntries;
}

6
programs/default.nix Normal file
View file

@ -0,0 +1,6 @@
{ ... }:
{
imports = [
./git.nix
];
}

16
programs/git.nix Normal file
View file

@ -0,0 +1,16 @@
{ config, pkgs, lib, ... }:
{
programs.git = {
enable = true;
config = {
user = {
name = "Katharina Heidenreich";
email = "katharina.heidenreich02@gmail.com";
};
init.defaultBranch = "main";
pull.rebase = false;
core.editor = "nano";
safe.directory = ["/etc/nixos"];
};
};
}

View file

@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:D+pLLrpjFljWBUJ4qZ8qo62Ff+nRPw8IVohCMqY7m6BcBlK90AH2AN0I34ci6rPh3F2XenmL51kMReAHlV8BuuXCDxDB37lIvzVagvfla9sBMx1i8wINFV+DnpL0w78=,iv:0+11qTje7wLSDlCOsTyjKQ0d6Drt1zYkDxL8T2bxvg4=,tag:QD/LxHmPjnZo1XS6/0zLmA==,type:str]",
"sops": {
"age": [
{
"recipient": "age1g5q3hwnpgsas682jkq0zmee3zqggucfe0v5ec0a6pv7wzexadehqne66cj",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3WER1bnJiMDNpK2hTOXhV\nV2g2TEFWTzBtMDFLOGtMb2doV3Q2eENlaHpVCktOa25QU1pNMStGVGtoZ04wZXB6\nVnBncTNURktYTFZUczBoRlhacFRYcUkKLS0tIG5FR3gvWmg4ZWtuUDRYZDBRU3lL\nU3NLeEVwQi9xdWF3MFYwTkZvcURMWmcKqtxEB+rHGQ7/RKd2CVTuJl/eDrGc9xrG\nou/4lCYVQL62EE/iOEsyTrzQhu3kKIhRdqICRz0R2b5fr0RLVRymWw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1z7ee2jgwvnrx6dg96rqzhc7gncuancrhm8zaehkelwqkeh4dze7qlsajes",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGMk1DUFpjdzF0RFhXR0NU\nV293cUY5RlhFYzZhWjJNaFZvbXExRUVtRWkwCjVBMWlnVzdyTTVBZDE0U0g2SXhV\nK2pCK0dJVWZmN0QwUkpqUE44QjdOTGcKLS0tIHR5bUxlS0R3VUVTZzN4bSs0NVp3\nQkVxMjdQNnBOaUtKUTAzWElvb3V3RjAKQYSjLzdGqHoCjyQfgHdR+knIAFS/LY7a\nZLOMKJXjPcdEDALnRQJS0ys7dkDebCABizWeJX1fCERkzVANv1UhyQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-04-08T18:01:44Z",
"mac": "ENC[AES256_GCM,data:NlhzAXFHEVcXukSNRLAIJxWQ8GtYf0w/U3zkiDpH64fQs1yHjeRvF4BvQp83938jR5jkjVVdHwwXjPacztv+6zMzaMchUGglbc5dEx7OeLFmbM3gL8Q69pDrFjKo9g379pHH76JM3RWJLg+EaN2TDEU72fD9VtR9ak9V2/X4xfM=,iv:lwClzYes6Zu0aK8qVLgZ9qHgX+k/j3sNPqMamOnd7dg=,tag:BwIE4TBJEQpyBHN+Ivg0Dw==,type:str]",
"version": "3.12.1"
}
}

7
services/default.nix Normal file
View file

@ -0,0 +1,7 @@
{ ... }:
{
imports = [
./openssh.nix
./forgejo.nix
];
}

22
services/forgejo.nix Normal file
View file

@ -0,0 +1,22 @@
{...}:
let
serv = import ../config/services.nix;
git = serv.git;
in
{
services.forgejo = {
enable = true;
database.type = "postgres";
lfs.enable = true;
settings = {
server = {
DOMAIN = git.domain;
ROOT_URL = "https://${git.domain}/";
HTTP_PORT = git.port;
};
service.DISABLE_REGISTRATION = true;
};
};
networking.firewall.allowedTCPPorts = [ git.port ];
}

17
services/openssh.nix Normal file
View file

@ -0,0 +1,17 @@
{ ... }:
let
opensshConfig = import ../config/openssh.nix;
usersWithKeys = opensshConfig.ssh_users;
in
{
services.openssh = {
enable = true;
settings = {
PasswordAuthentication = true;
PermitRootLogin = "no";
AllowUsers = usersWithKeys;
};
};
networking.firewall.allowedTCPPorts = [ 22 ];
}

5
system/boot.nix Normal file
View file

@ -0,0 +1,5 @@
{ ... }:
{
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";
}

9
system/default.nix Normal file
View file

@ -0,0 +1,9 @@
{ ... }:
{
imports = [
./sops.nix
./users.nix
./network.nix
./boot.nix
];
}

5
system/network.nix Normal file
View file

@ -0,0 +1,5 @@
{ ... }:
{
networking.hostName = "tuserver";
networking.networkmanager.enable = true;
}

14
system/sops.nix Normal file
View file

@ -0,0 +1,14 @@
{ lib, ... }:
let
secretData = import ../intermediate/secrets.nix;
in
{
sops = {
age.keyFile = "/var/lib/sops-nix/key.txt";
secrets = secretData.byName;
};
warnings = lib.optional (secretData.missing != [])
"Some SOPS source files are missing or not yet encrypted; no runtime secrets will be provisioned for: ${builtins.concatStringsSep ", " (map (item: builtins.concatStringsSep "_" item.path) secretData.missing)}";
}

10
system/users.nix Normal file
View file

@ -0,0 +1,10 @@
{ ... }:
{
users.mutableUsers = false;
users.users.nudelerde = {
isNormalUser = true;
extraGroups = [ "wheel" ];
hashedPassword = "$y$j9T$nWURcrCMWKPzj1xAydtNU/$qbOuwWcLSWQBiDTw8WJ2sRZYtP7qnGShQDA2USRC/C0";
};
}

29
validation/secrets.nix Normal file
View file

@ -0,0 +1,29 @@
let
lib = import <nixpkgs/lib>;
helperNames = [ "getSecretsConfig" ];
validateTree = context: node:
if builtins.isAttrs node then
lib.mapAttrs (name: value:
if lib.elem name helperNames then
value
else
validateTree "${context}.${name}" value
) node
else
throw "${context} must be an attrset at non-leaf level.";
getSecretsConfig = secretsConfig:
let
_ =
if builtins.isAttrs secretsConfig then
null
else
throw "config/secrets.nix must evaluate to an attrset.";
__ = validateTree "config/secrets.nix" secretsConfig;
in
secretsConfig;
in
rec {
inherit getSecretsConfig validateTree;
}