diff --git a/.sops.yaml b/.sops.yaml index fd76726..31d03aa 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,38 +1,11 @@ -# SOPS configuration for StuRa HTW Dresden infrastructure -# -# This file defines which keys can decrypt which secrets. -# Add GPG public keys (.asc files) or age keys to keys/hosts/ and keys/users/ -# to grant decryption access to hosts and users respectively. - keys: - # Admin/user keys - add GPG public keys here - # Example: - # - &user_admin_key age1... or pgp fingerprint - - # Host keys - add host-specific keys here - # Example: - # - &host_proxy_key age1... or pgp fingerprint - # - &host_git_key age1... or pgp fingerprint - -# Define which keys can access which files -creation_rules: - # Default rule: all secrets can be decrypted by admin keys - - path_regex: secrets/.*\.yaml$ - # key_groups: - # - pgp: - # - *user_admin_key - # - age: - # - *user_admin_key + - &goeranh age16m8vvvpw4azfy6gygtstyyj6nd2sf848f7f7argaghwhct38muxsgxpeek + - &gradient age1kfxhahmxprheer63shv68slpmk5qz29nyx3kp4q6n879zz9ha34q04n50x # Host-specific secrets (example) - # - path_regex: secrets/proxy/.*\.yaml$ - # key_groups: - # - pgp: - # - *user_admin_key - # - *host_proxy_key - - # - path_regex: secrets/git/.*\.yaml$ - # key_groups: - # - pgp: - # - *user_admin_key - # - *host_git_key +creation_rules: + - path_regex: hosts/gradient/secrets.sops.yaml$ + key_groups: + - age: + - *gradient + - *goeranh diff --git a/default.nix b/default.nix index 1a1f679..17b85ef 100644 --- a/default.nix +++ b/default.nix @@ -37,9 +37,16 @@ in experimental-features = [ "nix-command" "flakes" + "blake3-hashes" ]; # trusted-users = [ "administration" ]; auto-optimise-store = true; + trusted-substituters = [ + "https://gradient.adm.htw.stura-dresden.de/cache/stura" + ]; + trusted-public-keys = [ + "gradient.adm.htw.stura-dresden.de-stura:rVy7JDos8CTvKJsrotP2/y/ICbCNv69HKy0Dfsgrafs=" + ]; }; optimise.automatic = true; gc = { diff --git a/flake.lock b/flake.lock index 4e0f8b8..0a573e0 100644 --- a/flake.lock +++ b/flake.lock @@ -8,7 +8,9 @@ "flake-parts": "flake-parts", "flake-utils": "flake-utils", "napalm": "napalm", - "nixpkgs": "nixpkgs", + "nixpkgs": [ + "nixpkgs" + ], "pyproject-build-systems": "pyproject-build-systems", "pyproject-nix": "pyproject-nix", "systems": "systems", @@ -77,6 +79,21 @@ "type": "gitlab" } }, + "crane": { + "locked": { + "lastModified": 1777335812, + "narHash": "sha256-bEg5xoAxAwsyfnGhkEX7RJViTIBIYPd8ISg4O1c0HFc=", + "owner": "ipetkov", + "repo": "crane", + "rev": "5e0fb2f64edff2822249f21293b8304dedaaf676", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "disko": { "inputs": { "nixpkgs": [ @@ -168,6 +185,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "git-hooks": { "inputs": { "flake-compat": [ @@ -216,12 +251,34 @@ "type": "github" } }, + "gradient": { + "inputs": { + "crane": "crane", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1777807825, + "narHash": "sha256-LIHC5ayGLbEXY7wBrd71EE12xZDBltYqeE4qdEvWbC0=", + "owner": "wavelens", + "repo": "gradient", + "rev": "0f5779845044d2a39e5f599f781d6cfb9248a219", + "type": "github" + }, + "original": { + "owner": "wavelens", + "repo": "gradient", + "type": "github" + } + }, "mailserver": { "inputs": { "blobs": "blobs", "flake-compat": "flake-compat_2", "git-hooks": "git-hooks", - "nixpkgs": "nixpkgs_2" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { "lastModified": 1773912645, @@ -266,11 +323,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1771848320, - "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", + "lastModified": 1777268161, + "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2fc6539b481e1d2569f25f8799236694180c0993", + "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76", "type": "github" }, "original": { @@ -295,29 +352,29 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs-unstable": { "locked": { - "lastModified": 1773831496, - "narHash": "sha256-JW2/QPyCVzmouqEp1H9kNa8JXd7xEhlam9sy3TYfhDY=", - "owner": "NixOS", + "lastModified": 1777268161, + "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=", + "owner": "nixos", "repo": "nixpkgs", - "rev": "826430a188181a750ffa5948daff334039c5d741", + "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "nixos-25.11-small", + "owner": "nixos", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_2": { "locked": { - "lastModified": 1776734388, - "narHash": "sha256-vl3dkhlE5gzsItuHoEMVe+DlonsK+0836LIRDnm6MXQ=", + "lastModified": 1777077449, + "narHash": "sha256-AIiMJiqvGrN4HyLEbKAoCSRRYn0rnlW5VbKNIMIYqm4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "10e7ad5bbcb421fe07e3a4ad53a634b0cd57ffac", + "rev": "a4bf06618f0b5ee50f14ed8f0da77d34ecc19160", "type": "github" }, "original": { @@ -381,8 +438,10 @@ "inputs": { "authentik": "authentik", "disko": "disko", + "gradient": "gradient", "mailserver": "mailserver", - "nixpkgs": "nixpkgs_3", + "nixpkgs": "nixpkgs_2", + "nixpkgs-unstable": "nixpkgs-unstable", "sops": "sops" } }, @@ -393,11 +452,11 @@ ] }, "locked": { - "lastModified": 1776771786, - "narHash": "sha256-DRFGPfFV6hbrfO9a1PH1FkCi7qR5FgjSqsQGGvk1rdI=", + "lastModified": 1777338324, + "narHash": "sha256-bc+ZZCmOTNq86/svGnw0tVpH7vJaLYvGLLKFYP08Q8E=", "owner": "Mic92", "repo": "sops-nix", - "rev": "bef289e2248991f7afeb95965c82fbcd8ff72598", + "rev": "8eaee5c45428b28b8c47a83e4c09dccec5f279b5", "type": "github" }, "original": { @@ -421,6 +480,21 @@ "type": "github" } }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "uv2nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index f0f177e..dd25bed 100644 --- a/flake.nix +++ b/flake.nix @@ -4,11 +4,14 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; authentik = { url = "github:nix-community/authentik-nix"; + inputs.nixpkgs.follows = "nixpkgs"; }; mailserver = { url = "git+https://gitlab.com/simple-nixos-mailserver/nixos-mailserver?ref=nixos-25.11"; + inputs.nixpkgs.follows = "nixpkgs"; }; sops = { url = "github:Mic92/sops-nix"; @@ -18,17 +21,22 @@ url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; + gradient = { + url = "github:wavelens/gradient"; + }; }; outputs = { self, nixpkgs, + nixpkgs-unstable, authentik, mailserver, disko, sops, - }: + gradient + }@inputs: let sshkeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINABEf0jBjtDdezDDtvl1v27l0DbHP2XUgMARTZXC+MR goeranh@node5" @@ -44,15 +52,6 @@ pkgs = nixpkgs.legacyPackages.x86_64-linux; in pkgs.mkShell { - # Import GPG keys from keys directory - sopsPGPKeyDirs = [ - "${toString ./.}/keys/hosts" - "${toString ./.}/keys/users" - ]; - - # Isolate sops GPG keys to .git/gnupg (optional) - # sopsCreateGPGHome = true; - nativeBuildInputs = [ sops.packages.x86_64-linux.sops-import-keys-hook ]; @@ -184,7 +183,7 @@ result: input: result // { - "${input}" = nixpkgs.lib.nixosSystem { + "${input}" = nixpkgs-unstable.lib.nixosSystem { system = "x86_64-linux"; modules = let @@ -197,8 +196,10 @@ disko.nixosModules.disko authentik.nixosModules.default mailserver.nixosModules.mailserver + gradient.nixosModules.default + sops.nixosModules.sops { - _module.args = { inherit self modulesPath; }; + _module.args = { inherit self inputs modulesPath; }; } ]; }; diff --git a/hosts/gradient/README.md b/hosts/gradient/README.md new file mode 100644 index 0000000..d8116f3 --- /dev/null +++ b/hosts/gradient/README.md @@ -0,0 +1,210 @@ +# Git Host - Forgejo + +Forgejo git server at 141.56.51.7 running in an LXC container. + +## Overview + +- **Hostname**: git +- **FQDN**: git.adm.htw.stura-dresden.de +- **IP Address**: 141.56.51.7 +- **Type**: Proxmox LXC Container +- **Services**: Forgejo, Nginx (reverse proxy), OpenSSH + +## Services + +### Forgejo + +Forgejo is a self-hosted Git service (fork of Gitea) providing: +- Git repository hosting +- Web interface for repository management +- Issue tracking +- Pull requests +- OAuth2 integration support + +**Configuration**: +- **Socket**: `/run/forgejo/forgejo.sock` (Unix socket) +- **Root URL**: https://git.adm.htw.stura-dresden.de +- **Protocol**: HTTP over Unix socket (Nginx handles TLS) + +### Nginx + +Nginx acts as a reverse proxy between the network and Forgejo: +- Receives HTTPS requests (TLS termination) +- Forwards to Forgejo via Unix socket +- Manages ACME/Let's Encrypt certificates +- WebSocket support enabled for live updates + +### OAuth2 Auto-Registration + +OAuth2 client auto-registration is enabled: +- `ENABLE_AUTO_REGISTRATION = true` +- `REGISTER_EMAIL_CONFIRM = false` +- Username field: email + +This allows users to register automatically via OAuth2 providers without manual approval. + +## Deployment + +See the [main README](../../README.md) for deployment methods. + +### Initial Installation + +**Using nixos-anywhere:** +```bash +nix run github:nix-community/nixos-anywhere -- --flake .#git --target-host root@141.56.51.7 +``` + +**Using container tarball:** +```bash +nix build .#containers-git +scp result/tarball/nixos-system-x86_64-linux.tar.xz root@proxmox-host:/var/lib/vz/template/cache/ +pct create 107 /var/lib/vz/template/cache/nixos-system-x86_64-linux.tar.xz \ + --hostname git \ + --net0 name=eth0,bridge=vmbr0,ip=141.56.51.7/24,gw=141.56.51.254 \ + --memory 2048 \ + --cores 2 \ + --rootfs local-lvm:8 \ + --unprivileged 1 \ + --features nesting=1 +pct start 107 +``` + +### Updates + +```bash +# From local machine +nixos-rebuild switch --flake .#git --target-host root@141.56.51.7 + +# Or use auto-generated script +nix run .#git-update +``` + +## Post-Deployment Steps + +After deploying for the first time: + +1. **Access the web interface:** + ``` + https://git.adm.htw.stura-dresden.de + ``` + +2. **Complete initial setup:** + - Create the first admin account via web UI + - Configure any additional settings + - Set up SSH keys for git access + +3. **Configure OAuth2 (optional):** + - If using an external identity provider (e.g., authentik) + - Add OAuth2 application in the provider + - Configure OAuth2 settings in Forgejo admin panel + - Auto-registration is already enabled in configuration + +4. **Set up repositories:** + - Create organizations + - Create repositories + - Configure access permissions + +## Integration with Proxy + +The central proxy at 141.56.51.1 handles: +- **SNI routing**: Inspects TLS handshake and routes HTTPS traffic for git.adm.htw.stura-dresden.de +- **HTTP routing**: Routes HTTP traffic based on Host header +- **ACME challenges**: Forwards `/.well-known/acme-challenge/` requests to this host for Let's Encrypt verification +- **Auto-redirect**: Redirects HTTP to HTTPS (except ACME challenges) + +This host handles its own TLS certificates via ACME. The proxy passes through encrypted traffic without decryption. + +## Troubleshooting + +### Forgejo socket permissions + +If Forgejo fails to start or Nginx cannot connect: + +```bash +# Check socket exists +ls -l /run/forgejo/forgejo.sock + +# Check Forgejo service status +systemctl status forgejo + +# Check Nginx service status +systemctl status nginx + +# View Forgejo logs +journalctl -u forgejo -f +``` + +**Solution**: Ensure the Forgejo user has proper permissions and the socket path is correct in both Forgejo and Nginx configurations. + +### Nginx proxy configuration + +If the web interface is unreachable: + +```bash +# Check Nginx configuration +nginx -t + +# View Nginx error logs +journalctl -u nginx -f + +# Test socket connection +curl --unix-socket /run/forgejo/forgejo.sock http://localhost/ +``` + +**Solution**: Verify the `proxyPass` directive in Nginx configuration points to the correct Unix socket. + +### SSH access issues + +If git operations over SSH fail: + +```bash +# Check SSH service +systemctl status sshd + +# Test SSH connection +ssh -T git@git.adm.htw.stura-dresden.de + +# Check Forgejo SSH settings +cat /var/lib/forgejo/custom/conf/app.ini | grep -A 5 "\[server\]" +``` + +**Solution**: Ensure SSH keys are properly added to user accounts and SSH daemon is running. + +### ACME certificate issues + +If HTTPS is not working: + +```bash +# Check ACME certificate status +systemctl status acme-git.adm.htw.stura-dresden.de + +# View ACME logs +journalctl -u acme-git.adm.htw.stura-dresden.de -f + +# Manually trigger certificate renewal +systemctl start acme-git.adm.htw.stura-dresden.de +``` + +**Solution**: Verify DNS points to proxy (141.56.51.1) and proxy is forwarding ACME challenges correctly. + +## Files and Directories + +- **Configuration**: `/nix/store/.../forgejo/` (managed by Nix) +- **Data directory**: `/var/lib/forgejo/` +- **Custom config**: `/var/lib/forgejo/custom/conf/app.ini` +- **Repositories**: `/var/lib/forgejo/data/gitea-repositories/` +- **Socket**: `/run/forgejo/forgejo.sock` + +## Network + +- **Interface**: eth0 (LXC container) +- **IP**: 141.56.51.7/24 +- **Gateway**: 141.56.51.254 +- **Firewall**: Ports 22, 80, 443 allowed + +## See Also + +- [Main README](../../README.md) - Deployment methods and architecture +- [Proxy README](../proxy/README.md) - How the central proxy routes traffic +- [Forgejo Documentation](https://forgejo.org/docs/latest/) +- [NixOS Forgejo Options](https://search.nixos.org/options?query=services.forgejo) diff --git a/hosts/gradient/default.nix b/hosts/gradient/default.nix new file mode 100644 index 0000000..09cadee --- /dev/null +++ b/hosts/gradient/default.nix @@ -0,0 +1,95 @@ +{ + config, + inputs, + lib, + pkgs, + modulesPath, + ... +}: +{ + imports = [ + "${modulesPath}/virtualisation/proxmox-lxc.nix" + ]; + + sops = { + defaultSopsFile = ./secrets.sops.yaml; + secrets = { + "gradient-jwt".owner = "gradient"; + "gradient-crypt".owner = "gradient"; + "gradient-worker".owner = "gradient-worker"; + }; + }; + + networking = { + hostName = "gradient"; + fqdn = "gradient.adm.htw.stura-dresden.de"; + interfaces.eth0.ipv4.addresses = [ + { + address = "141.56.51.127"; + prefixLength = 24; + } + ]; + + defaultGateway = { + address = "141.56.51.254"; + interface = "eth0"; + }; + firewall.allowedTCPPorts = [ + 80 + 443 + ]; + }; + + services = { + openssh.enable = true; + + gradient = { + enable = true; + frontend.enable = true; + domain = "${config.networking.fqdn}"; + jwtSecretFile = "/run/secrets/gradient-jwt"; + cryptSecretFile = "/run/secrets/gradient-crypt"; + configurePostgres = true; + configureNginx = true; + # serveCache = true; + reportErrors = true; + + worker = { + enable = true; + serverUrl = "ws://127.0.0.1:3000/proto"; + workerId = "8f56dd3a-5698-4512-8bf7-ab8dcfaed46c"; + peersFile = "/run/secrets/gradient-worker-peers"; + capabilities = { + fetch = true; + eval = true; + build = true; + }; + packages.nix = inputs.nixpkgs-unstable.legacyPackages.x86_64-linux.nix; + settings = { + logLevel = { + default = "debug"; + }; + }; + }; + }; + + nginx.commonHttpConfig = '' + real_ip_header proxy_protocol; + set_real_ip_from 141.56.51.1/32; + ''; + nginx.virtualHosts."${config.networking.fqdn}".listen = [ + { + port = 80; + addr = "0.0.0.0"; + } + { + port = 443; + addr = "0.0.0.0"; + ssl = true; + proxyProtocol = true; + } + ]; + }; + + system.stateVersion = "25.11"; +} diff --git a/hosts/gradient/secrets.sops.yaml b/hosts/gradient/secrets.sops.yaml new file mode 100644 index 0000000..6e4f9fa --- /dev/null +++ b/hosts/gradient/secrets.sops.yaml @@ -0,0 +1,27 @@ +gradient-jwt: ENC[AES256_GCM,data:0RgUOHbz5qtBOE1+wldyhzE6b4275JTkzdjgQBbVUnHtNVvqmQUs94JGfB2HRteVJS2pRmRxyh+YYUpuErkmaw==,iv:C6AqWjVs6MGjTJ/QEFq9kz7kSglMXi+rtlmkEK0i4r0=,tag:HvmCN947JveYFDITZfAEMA==,type:str] +gradient-crypt: ENC[AES256_GCM,data:j6KRaxQItKtolZXPxN1Rp4NalX5rYnHvQzL/R0naobgM2nMUiOJJeKiZ5yooXbaNC1wrwWNfMrNDYkm8bxVJeA==,iv:2wiiyJu3u9cEwwos0DhgKiwp0qYSw1z6MdOvpWsf+Is=,tag:GOfN78rlovnPXgiCAE9diA==,type:str] +gradient-worker: ENC[AES256_GCM,data:IktOl14QzBee16ZxZZMmseMomlyF+teJoxsNmqDXcPHq4ZZv7QWDQAjIct4hz1CHofaBfXzVM372WSLTX51/zw==,iv:OZsC9EX4fRUv7Q9AbnXBaskX9hS/wgFctOepz39NyDU=,tag:GHPx4yXb7ta5pj4+yI2PRQ==,type:str] +sops: + age: + - recipient: age1kfxhahmxprheer63shv68slpmk5qz29nyx3kp4q6n879zz9ha34q04n50x + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2OHc0aWRocmx2QkUzcnFa + T3Z5MWp3U2I1c2RZMytnU1hkd0p4ZHNWSW5vCmFuZHBJYjMrSUwranVDNHR1RmFr + dVhSVmdPUGd1czFjM3p3dlBLcTU0T1UKLS0tIDl1eHBkL1lBUWh0ckhya1dJTjdY + WmhPVEl3ZytOdmdaQ3pkN2lLTnRPMzAKCKj7VvRPTBXfsqa6FnJi3ZkWNUXN8JG8 + NlcK9QL/pMoExpoLHfw8ram4Y2i9up4oONeA2iKR12Dh86Y8RUUJfg== + -----END AGE ENCRYPTED FILE----- + - recipient: age16m8vvvpw4azfy6gygtstyyj6nd2sf848f7f7argaghwhct38muxsgxpeek + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVXNoVktTL0VvdVIrVWx6 + cFpLMnhJcmFWYlVKWWZIVUR1NGMzRWhOWngwClVRZ092dDFEMHJ3d3JkdFkwVVI2 + YW9BK0hBNnB6UmM0bzBYYVNqS0QxcFEKLS0tIHljSm03TTRjTVlSam4xN2NhMUJ6 + aDNFUi9SL1BhZHMxVUFkTzR6bk16cWsKeS3Y8b/WlvdgmY5yLjTfTHJwBZoZ7RU8 + GPLB8ezNB3U7XxO05hwlUQJbTkMVhSzu+nKfEavdS1KMoXaxfxhrwA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-04-22T08:34:30Z" + mac: ENC[AES256_GCM,data:74FyYHQ/bMZ3wxodMlvAXYl2UWNkv8arWSDeJwCEfRWz05bzXWy6UaMLWc+dSoqJsVvT3SRVuBMrtilsckVqCVQ4C96c730IVWB/b5juIXtEsp1JiWgS+F3yC992HDGmoGnAkSE/vzZBu3DRA8/eMwkoTtGscpDhnAzUVrkCNUk=,iv:BzhopR3jxZyKZhwRxh1lKaIaGgE5IbIe/AG35D1juZA=,tag:frnRzapbiU49TpkISZ4GEQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/hosts/proxy/default.nix b/hosts/proxy/default.nix index e688417..7fa2238 100644 --- a/hosts/proxy/default.nix +++ b/hosts/proxy/default.nix @@ -43,7 +43,6 @@ iif "lo" accept ct state established,related accept - ip saddr 141.56.51.0/24 accept ip saddr @blacklist4 drop ip6 saddr @blacklist6 drop diff --git a/keys/.gitignore b/keys/.gitignore deleted file mode 100644 index ce29a38..0000000 --- a/keys/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -# Prevent accidental commit of private keys -*.key -*.priv -*.private -*_priv -*-priv -*.sec -*secret* - -# Only allow public keys -!*.asc -!*.gpg -!*.pub -!*.age - -# Allow this gitignore and README -!.gitignore -!README.md diff --git a/keys/README.md b/keys/README.md deleted file mode 100644 index 587f370..0000000 --- a/keys/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Keys Directory - -This directory contains GPG/age public keys for sops encryption. - -## Structure - -- `hosts/` - Host-specific public keys (for servers to decrypt their own secrets) -- `users/` - User/admin public keys (for team members to decrypt secrets) - -## Adding Keys - -### GPG Keys - -Export your GPG public key: -```bash -gpg --export --armor YOUR_KEY_ID > keys/users/yourname.asc -``` - -Export a host's public key: -```bash -gpg --export --armor HOST_KEY_ID > keys/hosts/hostname.asc -``` - -### Age Keys - -For age keys, save the public key to a file: -```bash -echo "age1..." > keys/users/yourname.age -echo "age1..." > keys/hosts/hostname.age -``` - -## Usage - -When you enter the dev shell (`nix develop`), all keys in these directories will be automatically imported into your GPG keyring via the sops-import-keys-hook. - -## Important - -- Only commit **public** keys (.asc, .age files with public keys) -- Never commit private keys -- Update `.sops.yaml` to reference the fingerprints/keys for access control diff --git a/keys/hosts/.gitkeep b/keys/hosts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/keys/users/.gitkeep b/keys/users/.gitkeep deleted file mode 100644 index e69de29..0000000