sops: introduce sops-nix (age), ssh keys from encrypted tarball, .example secrets
This commit is contained in:
parent
8be13b680f
commit
a7ec82579c
9 changed files with 149 additions and 7 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
||||||
modules/usb-devices.nix
|
modules/usb-devices.nix
|
||||||
secrets/
|
# real secrets never enter the repo — only .example structure files are tracked
|
||||||
.sops.yaml
|
secrets/*
|
||||||
|
!secrets/*.example
|
||||||
result
|
result
|
||||||
8
.sops.yaml
Normal file
8
.sops.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
keys:
|
||||||
|
- &asxpi age19xvmm6j3h2u6mc3w6k65ufry4p5aa5lwu96p55h3e42p9wfzwc0qp2w7pk
|
||||||
|
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: secrets/.*
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *asxpi
|
||||||
34
README.md
34
README.md
|
|
@ -1,5 +1,35 @@
|
||||||
# NixOS
|
# NixOS
|
||||||
|
|
||||||
|
Flake-based NixOS configuration for a ThinkPad P14s Gen 6 (AMD), tracking `nixos-unstable`.
|
||||||
|
|
||||||
|
## Highlights
|
||||||
|
|
||||||
|
- **Secure Boot** via [lanzaboote](https://github.com/nix-community/lanzaboote)
|
||||||
|
- **Secrets**: [sops-nix](https://github.com/Mic92/sops-nix) with age — xray config, WireGuard, SSH keys, private routes/hosts; encrypted files stay out of the repo (only `.example` structure files are tracked), decrypted to `/run/secrets` at activation
|
||||||
|
- **Desktop**: GNOME on Wayland, AMD GPU
|
||||||
|
- **Local LLMs**: Ollama with ROCm (gfx1151) + Lemonade for XDNA2 NPU serving via [nix-amd-ai](https://github.com/noamsto/nix-amd-ai)
|
||||||
|
- **Networking**: Xray VLESS+Reality with sing-box TUN, WireGuard, WWAN modem
|
||||||
|
- **Gaming**: Steam with gamescope, declarative Flatpaks via [nix-flatpak](https://github.com/gmodena/nix-flatpak)
|
||||||
|
- **Litecoin Core (MWEB)**: vendored package build, revived after removal from nixpkgs
|
||||||
|
- **Power**: AMD P-State tuning, zram swap ahead of disk swap
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
flake.nix # inputs and host definition
|
||||||
|
configuration.nix # entry point, imports modules
|
||||||
|
modules/ # one module per concern (boot, desktop, ollama, xray, ...)
|
||||||
|
secrets/ # sops-encrypted (age) secrets, gitignored; .example files document structure
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo nixos-rebuild switch --flake /etc/nixos#meow
|
||||||
|
```
|
||||||
|
|
||||||
|
Fresh install: restore `secrets/` and the age key (`/var/lib/sops-nix/key.txt`) from out-of-band backup first.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- [ ] Add secret manager (sops-nix)
|
|
||||||
- [ ] Check nix Home manager
|
- [ ] Evaluate Home Manager
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
./modules/programs.nix
|
./modules/programs.nix
|
||||||
./modules/wireguard.nix
|
./modules/wireguard.nix
|
||||||
./modules/security.nix
|
./modules/security.nix
|
||||||
|
./modules/sops.nix
|
||||||
./modules/power.nix
|
./modules/power.nix
|
||||||
./modules/xray.nix
|
./modules/xray.nix
|
||||||
./modules/ollama.nix
|
./modules/ollama.nix
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@
|
||||||
# A previous wwan-autoconnect oneshot service called `mmcli --simple-connect`
|
# A previous wwan-autoconnect oneshot service called `mmcli --simple-connect`
|
||||||
# with a hardcoded APN and set up routing by hand. It fought NM for the modem
|
# with a hardcoded APN and set up routing by hand. It fought NM for the modem
|
||||||
# (endless "connecting") and its hardcoded APN broke when the SIM changed.
|
# (endless "connecting") and its hardcoded APN broke when the SIM changed.
|
||||||
# Removed: connect via the GNOME network applet using the "narayana" GSM
|
# Removed: connect via the GNOME network applet using the carrier's GSM
|
||||||
# profile (apn=data.narayana). Re-add a service only if headless autoconnect
|
# profile instead. Re-add a service only if headless autoconnect is needed,
|
||||||
# is needed, and if so set the NM profile's autoconnect=no to avoid contention.
|
# and if so set the NM profile's autoconnect=no to avoid contention.
|
||||||
|
|
||||||
# IVPN service — installed but not auto-started at boot.
|
# IVPN service — installed but not auto-started at boot.
|
||||||
# Start manually: `sudo systemctl start ivpn-service`
|
# Start manually: `sudo systemctl start ivpn-service`
|
||||||
|
|
|
||||||
30
modules/sops.nix
Normal file
30
modules/sops.nix
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# sops-nix: decrypt secrets at activation using the root-side age key.
|
||||||
|
# Key installed once via:
|
||||||
|
# sudo install -d -m 700 /var/lib/sops-nix
|
||||||
|
# sudo install -m 600 ~/.config/sops/age/keys.txt /var/lib/sops-nix/key.txt
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
||||||
|
|
||||||
|
# Secret files are gitignored (only .example structure files are tracked),
|
||||||
|
# so they are referenced by absolute path and read at activation, not eval.
|
||||||
|
sops.validateSopsFiles = false;
|
||||||
|
|
||||||
|
# SSH keys travel as one encrypted tarball so filenames stay inside the
|
||||||
|
# encrypted payload. (Re)create with:
|
||||||
|
# tar -C ~/.ssh -cf secrets/ssh-keys.tar <keys...> && sops -e -i secrets/ssh-keys.tar
|
||||||
|
sops.secrets."ssh-keys.tar" = {
|
||||||
|
sopsFile = "/etc/nixos/secrets/ssh-keys.tar";
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
system.activationScripts.ssh-keys = {
|
||||||
|
deps = [ "setupSecrets" "users" ];
|
||||||
|
text = ''
|
||||||
|
mkdir -p /home/asxpi/.ssh
|
||||||
|
${pkgs.gnutar}/bin/tar --unlink-first -C /home/asxpi/.ssh -xf ${config.sops.secrets."ssh-keys.tar".path}
|
||||||
|
chown -R asxpi:users /home/asxpi/.ssh
|
||||||
|
chmod 700 /home/asxpi/.ssh
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
14
secrets/network.yaml.example
Normal file
14
secrets/network.yaml.example
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Encrypt with: sops -e -i secrets/network.yaml
|
||||||
|
# xray-endpoint: xray server IP (spliced into sing-box route rules at runtime)
|
||||||
|
# route-exclude: JSON array of CIDRs excluded from the TUN (sing-box quote=false splice)
|
||||||
|
# ssh-hosts: ssh_config fragment, pulled in via Include /run/secrets/ssh-hosts
|
||||||
|
xray-endpoint: 203.0.113.1
|
||||||
|
route-exclude: '["203.0.113.1/32","198.51.100.7/32","10.20.0.0/24","fd69:69:69::/64"]'
|
||||||
|
ssh-hosts: |
|
||||||
|
Host jump
|
||||||
|
HostName 10.20.0.10
|
||||||
|
AddressFamily inet
|
||||||
|
|
||||||
|
Host myserver.example.com myserver
|
||||||
|
HostName myserver.example.com
|
||||||
|
ProxyJump jump
|
||||||
12
secrets/wg0.conf.example
Normal file
12
secrets/wg0.conf.example
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# wg-quick config, sops-encrypted whole-file (format = "binary").
|
||||||
|
# Same format for wg2.conf. Encrypt with: sops -e -i secrets/wg0.conf
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = <client-private-key>
|
||||||
|
Address = 10.20.0.2/24
|
||||||
|
DNS = 10.20.0.1
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <server-public-key>
|
||||||
|
AllowedIPs = 10.20.0.0/24
|
||||||
|
Endpoint = 198.51.100.7:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
46
secrets/xray-config.json.example
Normal file
46
secrets/xray-config.json.example
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"port": 10808,
|
||||||
|
"protocol": "socks",
|
||||||
|
"settings": {
|
||||||
|
"udp": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"port": 10809,
|
||||||
|
"protocol": "http"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [
|
||||||
|
{
|
||||||
|
"address": "203.0.113.1",
|
||||||
|
"port": 443,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"id": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"encryption": "mlkem768x25519plus.native.0rtt.<base64-client-key>",
|
||||||
|
"flow": "xtls-rprx-vision"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "tcp",
|
||||||
|
"security": "reality",
|
||||||
|
"realitySettings": {
|
||||||
|
"fingerprint": "chrome",
|
||||||
|
"serverName": "www.example.com",
|
||||||
|
"publicKey": "<reality-public-key>",
|
||||||
|
"shortId": "<short-id>",
|
||||||
|
"spiderX": "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue