feat: initial commit
This commit is contained in:
commit
a28c2b5563
19 changed files with 314 additions and 0 deletions
6
.sops.yaml
Normal file
6
.sops.yaml
Normal 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
7
config/openssh.nix
Normal 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
15
config/secrets.nix
Normal 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
6
config/services.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
rec {
|
||||||
|
git = {
|
||||||
|
port = 3000;
|
||||||
|
domain = "git.nudelerde.de";
|
||||||
|
};
|
||||||
|
}
|
||||||
18
configuration.nix
Normal file
18
configuration.nix
Normal 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";
|
||||||
|
}
|
||||||
|
|
||||||
25
hardware-configuration.nix
Normal file
25
hardware-configuration.nix
Normal 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
79
intermediate/secrets.nix
Normal 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
6
programs/default.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./git.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
16
programs/git.nix
Normal file
16
programs/git.nix
Normal 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"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
18
secrets/openssh/nudelerde/pub_keys
Normal file
18
secrets/openssh/nudelerde/pub_keys
Normal 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
7
services/default.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./openssh.nix
|
||||||
|
./forgejo.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
22
services/forgejo.nix
Normal file
22
services/forgejo.nix
Normal 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
17
services/openssh.nix
Normal 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
5
system/boot.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
boot.loader.grub.enable = true;
|
||||||
|
boot.loader.grub.device = "/dev/sda";
|
||||||
|
}
|
||||||
9
system/default.nix
Normal file
9
system/default.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./sops.nix
|
||||||
|
./users.nix
|
||||||
|
./network.nix
|
||||||
|
./boot.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
5
system/network.nix
Normal file
5
system/network.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
networking.hostName = "tuserver";
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
}
|
||||||
14
system/sops.nix
Normal file
14
system/sops.nix
Normal 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
10
system/users.nix
Normal 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
29
validation/secrets.nix
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue