inital config
This commit is contained in:
+26
@@ -0,0 +1,26 @@
|
||||
# Nix build results
|
||||
result
|
||||
result-*
|
||||
|
||||
# direnv
|
||||
.direnv
|
||||
.envrc
|
||||
|
||||
# Secrets / private keys
|
||||
*.key
|
||||
*.pem
|
||||
*.agekey
|
||||
AGE-SECRET-KEY-*
|
||||
*.secret
|
||||
.sops.yaml
|
||||
|
||||
# Local/private hardware information
|
||||
*.local
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Editors
|
||||
.vscode/
|
||||
.idea/
|
||||
.zed/
|
||||
@@ -0,0 +1,14 @@
|
||||
keys:
|
||||
- &yubikey_14321697 age1yubikey1q26trpwnpym6t9m5qlcfm00kddy3tzex7u8r6ck7sqkq39wxc5wwwafuq89
|
||||
- &yubikey_32464919 age1yubikey1qgvu222dwg2gtvc4mq2txk79t4ep5gk9qwgfh520lc3m4kyxjmtgzexyljy
|
||||
- &recovery_bitwarden age1r993gvlratqk5h5seuzrd8fjv356csnrvtdt5ugcfdu3cw66hdls9gtuwd
|
||||
- &host AGE_HOST_D
|
||||
|
||||
creation_rules:
|
||||
- path_regex: secrets/.*\.yaml$
|
||||
key_groups:
|
||||
- age:
|
||||
- *yubikey_14321697
|
||||
- *yubikey_32464919
|
||||
- *recovery_bitwarden
|
||||
- *host
|
||||
@@ -0,0 +1,24 @@
|
||||
# NixOS Config
|
||||
|
||||
TODO...
|
||||
|
||||
|
||||
## Neuinstallation
|
||||
|
||||
### X. Nach der Installation
|
||||
|
||||
#### X.X. Bootstrap-Skript ausführen
|
||||
|
||||
Nach der Installation ist es notwendig das Bootstrap-Skript auszuführen.
|
||||
Dafür muss zunächst der Key ausgewählt werden (Yubikey oder Bitwarden):
|
||||
|
||||
```bash
|
||||
sudo env SOPS_AGE_KEY_FILE=/home/user/nixos-config/age/yubikey-14321697.txt /home/user/nixos-config/scripts/bootstrap-host.sh
|
||||
```
|
||||
```bash
|
||||
sudo env SOPS_AGE_KEY_FILE=/home/user/nixos-config/age/yubikey-32464919.txt /home/user/nixos-config/scripts/bootstrap-host.sh
|
||||
```
|
||||
Für den Recovery-Key aus Bitwarden, muss dieser zunächst exportiert werden und als .txt Datei gespeichert werden.
|
||||
```bash
|
||||
sudo env SOPS_AGE_KEY_FILE=/path/to/recovery-keyfile.txt /home/user/nixos-config/scripts/bootstrap-host.sh
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
# Serial: 14321697, Slot: 1
|
||||
# Name: age identity 34bb9100
|
||||
# Created: Thu, 10 Sep 2026 06:31:58 +0000
|
||||
# PIN policy: Once (A PIN is required once per session, if set)
|
||||
# Touch policy: Always (A physical touch is required for every decryption)
|
||||
# Recipient: age1yubikey1q26trpwnpym6t9m5qlcfm00kddy3tzex7u8r6ck7sqkq39wxc5wwwafuq89
|
||||
AGE-PLUGIN-YUBIKEY-1YXYD5QYZXJAEZQQF8YHJ5
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Serial: 32464919, Slot: 1
|
||||
# Name: age identity 1b6d4f63
|
||||
# Created: Thu, 10 Sep 2026 06:46:10 +0000
|
||||
# PIN policy: Once (A PIN is required once per session, if set)
|
||||
# Touch policy: Always (A physical touch is required for every decryption)
|
||||
# Recipient: age1yubikey1qgvu222dwg2gtvc4mq2txk79t4ep5gk9qwgfh520lc3m4kyxjmtgzexyljy
|
||||
AGE-PLUGIN-YUBIKEY-1ZASW7QVZRDK57CCKHC0YW
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
description = "Declarative NixOS desktop configuration";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
impermanence.url = "github:nix-community/impermanence";
|
||||
|
||||
sops-nix.url = "github:Mic92/sops-nix";
|
||||
|
||||
disko.url = "github:nix-community/disko";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
nixpkgs,
|
||||
home-manager,
|
||||
impermanence,
|
||||
sops-nix,
|
||||
disko,
|
||||
...
|
||||
}:
|
||||
{
|
||||
nixosConfigurations.desktop = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
|
||||
modules = [
|
||||
disko.nixosModules.disko
|
||||
impermanence.nixosModules.impermanence
|
||||
sops-nix.nixosModules.sops
|
||||
home-manager.nixosModules.home-manager
|
||||
|
||||
./hosts/desktop
|
||||
./modules/base.nix
|
||||
./modules/boot.nix
|
||||
./modules/ephemeral-root.nix
|
||||
./modules/impermanence.nix
|
||||
./modules/persistence.nix
|
||||
./modules/secrets.nix
|
||||
./modules/desktop.nix
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
home.stateVersion = "25.11";
|
||||
|
||||
programs.home-manager.enable = true;
|
||||
|
||||
programs.git = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
age
|
||||
sops
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./disko.nix
|
||||
];
|
||||
|
||||
networking.hostName = "desktop";
|
||||
|
||||
users.users.user = {
|
||||
isNormalUser = true;
|
||||
home = "/home/user";
|
||||
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"networkmanager"
|
||||
];
|
||||
};
|
||||
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
|
||||
users.user = import ../../home/user.nix;
|
||||
};
|
||||
|
||||
system.stateVersion = "25.11";
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
disko.devices.disk.main = {
|
||||
type = "disk";
|
||||
device = "/dev/disk/by-id/ata-Vi550_S3_4935445284600580";
|
||||
|
||||
content = {
|
||||
type = "gpt";
|
||||
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "1G";
|
||||
type = "EF00";
|
||||
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
|
||||
luks = {
|
||||
size = "100%";
|
||||
label="luks";
|
||||
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "cryptroot";
|
||||
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
};
|
||||
|
||||
content = {
|
||||
type = "btrfs";
|
||||
|
||||
subvolumes = {
|
||||
"/@nix" = {
|
||||
mountpoint = "/nix";
|
||||
mountOptions = [
|
||||
"compress=zstd"
|
||||
"noatime"
|
||||
];
|
||||
};
|
||||
|
||||
"/@persist" = {
|
||||
mountpoint = "/persist";
|
||||
mountOptions = [
|
||||
"compress=zstd"
|
||||
"noatime"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
time.timeZone = "Europe/Berlin";
|
||||
|
||||
i18n.defaultLocale = "de_DE.UTF-8";
|
||||
|
||||
console.keyMap = "de";
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
git
|
||||
vim
|
||||
curl
|
||||
wget
|
||||
htop
|
||||
tree
|
||||
];
|
||||
|
||||
programs.git.enable = true;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
boot.plymouth.enable = true;
|
||||
|
||||
boot.initrd.systemd.enable = true;
|
||||
|
||||
boot.kernelParams = [
|
||||
"quiet"
|
||||
"splash"
|
||||
];
|
||||
|
||||
boot.consoleLogLevel = 3;
|
||||
boot.initrd.verbose = false;
|
||||
|
||||
boot.initrd.luks.devices."cryptroot" = {
|
||||
device = "/dev/disk/by-partlabel/luks";
|
||||
};
|
||||
|
||||
fileSystems."/".device = "/dev/mapper/cryptroot";
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
fileSystems."/" = {
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
|
||||
options = [
|
||||
"mode=755"
|
||||
"nosuid"
|
||||
"nodev"
|
||||
];
|
||||
|
||||
neededForBoot = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
fileSystems."/persist".neededForBoot = true;
|
||||
|
||||
environment.persistence."/persist" = {
|
||||
hideMounts = true;
|
||||
|
||||
directories = [
|
||||
{
|
||||
directory = "/home/user/nixos-config";
|
||||
user = "user";
|
||||
group = "users";
|
||||
}
|
||||
|
||||
"/var/lib/nixos"
|
||||
];
|
||||
|
||||
files = [
|
||||
"/etc/machine-id"
|
||||
"/etc/ssh/ssh_host_ed25519_key"
|
||||
"/etc/ssh/ssh_host_ed25519_key.pub"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
sops.age.keyFile = "/persist/keys/host-age.key";
|
||||
}
|
||||
Executable
+168
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="/home/user/nixos-config"
|
||||
PERSIST_DIR="/persist"
|
||||
KEY_DIR="${PERSIST_DIR}/keys"
|
||||
HOST_KEY="${KEY_DIR}/host-age.key"
|
||||
|
||||
SOPS_TEMPLATE="${REPO_DIR}/.sops.yaml.template"
|
||||
LOCAL_SOPS="${REPO_DIR}/.sops.yaml"
|
||||
|
||||
echo "==> NixOS host bootstrap"
|
||||
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
echo "ERROR: Dieses Script muss als root ausgeführt werden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v age-keygen >/dev/null 2>&1; then
|
||||
echo "ERROR: age-keygen wurde nicht gefunden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v sops >/dev/null 2>&1; then
|
||||
echo "ERROR: sops wurde nicht gefunden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${SOPS_AGE_KEY_FILE:-}" ]]; then
|
||||
echo "ERROR: SOPS_AGE_KEY_FILE ist nicht gesetzt."
|
||||
echo
|
||||
echo "Beispiel:"
|
||||
echo
|
||||
echo " SOPS_AGE_KEY_FILE=${REPO_DIR}/age/yubikey-a.txt \\"
|
||||
echo " sudo -E ${REPO_DIR}/scripts/bootstrap-host.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${SOPS_AGE_KEY_FILE}" ]]; then
|
||||
echo "ERROR: SOPS_AGE_KEY_FILE existiert nicht:"
|
||||
echo " ${SOPS_AGE_KEY_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "${PERSIST_DIR}"; then
|
||||
echo "ERROR: ${PERSIST_DIR} ist nicht gemountet."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "${REPO_DIR}" ]]; then
|
||||
echo "ERROR: Repository fehlt:"
|
||||
echo " ${REPO_DIR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${SOPS_TEMPLATE}" ]]; then
|
||||
echo "ERROR: SOPS template fehlt:"
|
||||
echo " ${SOPS_TEMPLATE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -e "${HOST_KEY}" ]]; then
|
||||
echo "ERROR: Host-Key existiert bereits:"
|
||||
echo " ${HOST_KEY}"
|
||||
echo
|
||||
echo "Es wird nichts überschrieben."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -e "${LOCAL_SOPS}" ]]; then
|
||||
echo "ERROR: Lokale .sops.yaml existiert bereits:"
|
||||
echo " ${LOCAL_SOPS}"
|
||||
echo
|
||||
echo "Es wird nichts überschrieben."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "==> SOPS identity:"
|
||||
echo " ${SOPS_AGE_KEY_FILE}"
|
||||
|
||||
echo
|
||||
echo "==> Erzeuge Host-age-Key"
|
||||
|
||||
install -d -m 0700 "${KEY_DIR}"
|
||||
|
||||
age-keygen -o "${HOST_KEY}"
|
||||
|
||||
chmod 0600 "${HOST_KEY}"
|
||||
chown root:root "${HOST_KEY}"
|
||||
|
||||
HOST_RECIPIENT="$(age-keygen -y "${HOST_KEY}")"
|
||||
|
||||
echo
|
||||
echo "==> Host recipient:"
|
||||
echo
|
||||
echo " ${HOST_RECIPIENT}"
|
||||
|
||||
echo
|
||||
echo "==> Erzeuge lokale .sops.yaml"
|
||||
|
||||
sed "s/AGE_HOST_D/${HOST_RECIPIENT}/g" \
|
||||
"${SOPS_TEMPLATE}" > "${LOCAL_SOPS}"
|
||||
|
||||
chmod 0600 "${LOCAL_SOPS}"
|
||||
|
||||
echo
|
||||
echo "============================================================"
|
||||
echo "Der Host-Key wurde erzeugt."
|
||||
echo
|
||||
echo "Private Key:"
|
||||
echo " ${HOST_KEY}"
|
||||
echo
|
||||
echo "Lokale SOPS-Konfiguration:"
|
||||
echo " ${LOCAL_SOPS}"
|
||||
echo
|
||||
echo "Jetzt werden die vorhandenen Secrets auf"
|
||||
echo "YubiKey A + YubiKey B + Recovery + Host"
|
||||
echo "rekeyed."
|
||||
echo "============================================================"
|
||||
echo
|
||||
|
||||
read -r -p "Rekeying jetzt durchführen? [y/N] " answer
|
||||
|
||||
if [[ "${answer}" != "y" && "${answer}" != "Y" ]]; then
|
||||
echo
|
||||
echo "Abgebrochen."
|
||||
echo
|
||||
echo "Der Host-Key und .sops.yaml wurden bereits erzeugt."
|
||||
echo "Das Rekeying wurde NICHT durchgeführt."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
shopt -s nullglob
|
||||
secret_files=( "${REPO_DIR}"/secrets/*.yaml )
|
||||
shopt -u nullglob
|
||||
|
||||
if [[ "${#secret_files[@]}" -eq 0 ]]; then
|
||||
echo
|
||||
echo "Keine secrets/*.yaml gefunden."
|
||||
echo "Host-Key wurde erfolgreich erzeugt."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "==> Rekeye Secrets"
|
||||
|
||||
for secret in "${secret_files[@]}"; do
|
||||
echo
|
||||
echo "Updating:"
|
||||
echo " ${secret}"
|
||||
|
||||
SOPS_AGE_KEY_FILE="${SOPS_AGE_KEY_FILE}" \
|
||||
sops updatekeys --yes "${secret}"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "==> Bootstrap abgeschlossen."
|
||||
echo
|
||||
echo "Host recipient:"
|
||||
echo " ${HOST_RECIPIENT}"
|
||||
echo
|
||||
echo "Host key:"
|
||||
echo " ${HOST_KEY}"
|
||||
echo
|
||||
echo "SOPS config:"
|
||||
echo " ${LOCAL_SOPS}"
|
||||
@@ -0,0 +1,38 @@
|
||||
test:
|
||||
message: ENC[AES256_GCM,data:eF4xvJYIkGg1,iv:CVf9AA5hjPBq+wZLpOjmcOZhve2Tsyk/eULXdOp9Q/s=,tag:BrRYXcHOuftG0Vap4bK4ig==,type:str]
|
||||
number: ENC[AES256_GCM,data:M8M=,iv:hgv/5PHEIS1ENu2UGMsKMc+liHMjEafd6ITyZvpGnb8=,tag:Xs/cUc/Ny17Ka8qtQHWMUw==,type:int]
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IE5MdVJBQSBBOStPcWx0
|
||||
YkhRNkFKNmhNeHlvQWFYRDJ2UmNMR2lyTWZEV3MrbldmSWd1Sgp4a0FidVJwZ2tv
|
||||
V2JlZjRQT05xZlpoTEFiVUdKVTRVemx3a0dnTm9MRENjCi0tLSBQMGE0aXVQRFQx
|
||||
NjVEWEtNcldHUWlXbmhQRWxXdzk5bzd1RjNmaFdRS1Z3Crl/J6U3WSvIZRreNIXO
|
||||
aTqjTZaahbHjX4pmkDRmSd2o5x1oNksutIoWO5l32tX8SEU3quDj9bDymZIJBp8X
|
||||
86g=
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1yubikey1q26trpwnpym6t9m5qlcfm00kddy3tzex7u8r6ck7sqkq39wxc5wwwafuq89
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEcyMVBZdyBBdktHQ0px
|
||||
ZVBMNDhteElxVXlUczd5K2I5K25iejNCOEZkTjFDRkwzcUlJWAptRmlpazhsbkY5
|
||||
QnRhamtXR1JObFlTY1FjZ1hIUmxzTTZEYXVrZzlaY2lBCi0tLSBSUlAxOFZlcTFn
|
||||
cEFRR2tIT2liSVAxaHhkcWs4MlQ1cVBTeW9vUm9PcW5VCpQ82CSSMYHMK5Su/An9
|
||||
o6Ybb//z92Xm1fbuCv/1E/yQg12sOClbsJvNPWbwynoWkAmVzureuDzXNgIsv2oA
|
||||
Mt4=
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1yubikey1qgvu222dwg2gtvc4mq2txk79t4ep5gk9qwgfh520lc3m4kyxjmtgzexyljy
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzMWthMjdFTElpbzcvcFFQ
|
||||
UzdzbUtpSkVQQWpWTVpxNUcwamlqOE5Nd2hVCkZNeUdvOVF0eWxwZ2F5WlY0UHNv
|
||||
QlFlNUdRSlh6M0xub1dUNkNTWVdxZzQKLS0tIGNQcGdzazZTRll1MEhuZzlxZUM0
|
||||
UEdvV0xsRzRRRUZxZ0NsUFpUSEpKZ2sKQxxSJOQen+whTB4awc7EGSUJO/CWmlOc
|
||||
Srryah6025tEfH+scMxYJcpSMKrQlQ778yvK92xxSJbFgoQi0sReoA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1r993gvlratqk5h5seuzrd8fjv356csnrvtdt5ugcfdu3cw66hdls9gtuwd
|
||||
lastmodified: "2026-09-10T08:56:29Z"
|
||||
mac: ENC[AES256_GCM,data:YOEymqQFlK/4iaQpcA3e7OtuTnqz/52iS+TAc2sSIdKP2TV9NG6tr32Fn66AQrjFfYmfY81LIYFRnqRNV1IH9rccNTvxxklF6wKCz8p0/ESqpKbDEaNsoRzaTHCNRvDu3t8GvrxudDtRXQtQ94yx/WCk/M7XHQuY0LbagJv0Jm0=,iv:AIyGRpYuAsxaD2Rm/CZMUCLEkHCR3ImvJ/GoRwG9FAk=,tag:Fr5T15lfHUv1cIvJmXwZkA==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.13.3
|
||||
Reference in New Issue
Block a user