diff options
85 files changed, 4900 insertions, 1711 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6418298 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "makefile.configureOnOpen": false +} \ No newline at end of file diff --git a/Makefile b/Makefile index a9d041e..5a10aec 100644 --- a/Makefile +++ b/Makefile @@ -8,30 +8,30 @@ help: @echo "dry-activate - build and show different" corrino: - deploy .#corrino --skip-checks -- --show-trace -L + time deploy .#corrino --skip-checks -- --show-trace -L build: - nix run nixpkgs#nix-output-monitor build ".#nixosConfigurations.${HOSTNAME}.config.system.build.toplevel" + time nix run nixpkgs#nix-output-monitor build ".#nixosConfigurations.${HOSTNAME}.config.system.build.toplevel" update: - nix flake update --commit-lock-file + time nix flake update --commit-lock-file switch-caladan: - nix run https://github.com/LnL7/nix-darwin/archive/master.tar.gz -- switch --flake .#caladan + time sudo nix run https://github.com/LnL7/nix-darwin/archive/master.tar.gz -- switch --flake .#caladan build-corrino: - nix run nixpkgs#nix-output-monitor build .#nixosConfigurations.${HOSTNAME}.config.system.build.toplevel + time nix run nixpkgs#nix-output-monitor build .#nixosConfigurations.${HOSTNAME}.config.system.build.toplevel -deploy: build - nix run -- nixpkgs#nixos-rebuild switch \ +deploy: # build + time nix run -- nixpkgs#nixos-rebuild switch \ --fast \ --build-host root@${BUILDHOST} \ --target-host root@${HOSTNAME} \ --flake ".#${HOSTNAME}" check: - nix flake check + time nix flake check dry-activate: - nix run -- nixpkgs#nixos-rebuild dry-activate --target-host root@${HOSTNAME} --flake ".#corrino" + time nix run -- nixpkgs#nixos-rebuild dry-activate --target-host root@${HOSTNAME} --flake ".#corrino" diff --git a/README.md b/README.md index a925db3..5ae3fda 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ # hefe +## Buildhosts + +[hydra](https://hydra.emile.space) builds the packages, templates and hosts continously. + +- x86_64-linux: corrino (Hetzner AX41) +- x86_64-darwin: kaitain (Mac Mini) +- aarch64-linux: pi4 +- aarch64-darwin: caladan (m1 macbook air) + ## Secrets - Managed using agenix @@ -31,3 +40,7 @@ Print the generated secrets file as follows: ; make switch-caladan ``` +## Troubleshooting + +Weird `lock` issues? Try `sudo pkill -9 nix-daemon` on the build machine + diff --git a/flake.lock b/flake.lock index 7b65192..8462510 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1736955230, - "narHash": "sha256-uenf8fv2eG5bKM8C/UvFaiJMZ4IpUFaQxk9OH5t/1gA=", + "lastModified": 1750173260, + "narHash": "sha256-9P1FziAwl5+3edkfFcr5HeGtQUtrSdk/MksX39GieoA=", "ref": "refs/heads/main", - "rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c", - "revCount": 320, + "rev": "531beac616433bac6f9e2a19feb8e99a22a66baf", + "revCount": 331, "type": "git", "url": "https://github.com/ryantm/agenix" }, @@ -31,11 +31,11 @@ ] }, "locked": { - "lastModified": 1700795494, - "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=", + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", "type": "github" }, "original": { @@ -52,16 +52,16 @@ ] }, "locked": { - "lastModified": 1739302249, - "narHash": "sha256-C2vkThXQfsV7Ub0NP+rmm0iLLNjN9MvDjrbeZw2ZxCQ=", - "ref": "nix-darwin-24.11", - "rev": "f81c16138a6d047dcd257952688114898f5f7878", - "revCount": 1996, + "lastModified": 1749744770, + "narHash": "sha256-MEM9XXHgBF/Cyv1RES1t6gqAX7/tvayBC1r/KPyK1ls=", + "ref": "nix-darwin-25.05", + "rev": "536f951efb1ccda9b968e3c9dee39fbeb6d3fdeb", + "revCount": 2185, "type": "git", "url": "https://github.com/lnl7/nix-darwin" }, "original": { - "ref": "nix-darwin-24.11", + "ref": "nix-darwin-25.05", "type": "git", "url": "https://github.com/lnl7/nix-darwin" } @@ -75,11 +75,11 @@ "utils": "utils" }, "locked": { - "lastModified": 1727447169, - "narHash": "sha256-3KyjMPUKHkiWhwR91J1YchF6zb6gvckCAY1jOE+ne0U=", + "lastModified": 1749105467, + "narHash": "sha256-hXh76y/wDl15almBcqvjryB50B0BaiXJKk20f314RoE=", "ref": "master", - "rev": "aa07eb05537d4cd025e2310397a6adcedfe72c76", - "revCount": 328, + "rev": "6bc76b872374845ba9d645a2f012b764fecd765f", + "revCount": 340, "type": "git", "url": "https://github.com/serokell/deploy-rs" }, @@ -92,11 +92,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", "type": "github" }, "original": { @@ -123,6 +123,21 @@ "url": "https://github.com/numtide/flake-utils" } }, + "hefe-internal": { + "locked": { + "lastModified": 1750711567, + "narHash": "sha256-nQzCB2k8YQrU+nMpo6Vvea/EZQ6mAu8EmxqXtsiwNAg=", + "ref": "refs/heads/main", + "rev": "3b86571ad3fe8da0c6c3a48c38b04f11c1ab3d8c", + "revCount": 150, + "type": "git", + "url": "file:///Users/emile/hefe-internal" + }, + "original": { + "type": "git", + "url": "file:///Users/emile/hefe-internal" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -131,11 +146,11 @@ ] }, "locked": { - "lastModified": 1703113217, - "narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=", + "lastModified": 1745494811, + "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", "owner": "nix-community", "repo": "home-manager", - "rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1", + "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", "type": "github" }, "original": { @@ -151,16 +166,16 @@ ] }, "locked": { - "lastModified": 1736373539, - "narHash": "sha256-dinzAqCjenWDxuy+MqUQq0I4zUSfaCvN9rzuCmgMZJY=", - "ref": "release-24.11", - "rev": "bd65bc3cde04c16755955630b344bc9e35272c56", - "revCount": 3879, + "lastModified": 1749154018, + "narHash": "sha256-gjN3j7joRvT3a8Zgcylnd4NFsnXeDBumqiu4HmY1RIg=", + "ref": "release-25.05", + "rev": "7aae0ee71a17b19708b93b3ed448a1a0952bf111", + "revCount": 4770, "type": "git", "url": "https://github.com/nix-community/home-manager" }, "original": { - "ref": "release-24.11", + "ref": "release-25.05", "type": "git", "url": "https://github.com/nix-community/home-manager" } @@ -172,11 +187,11 @@ ] }, "locked": { - "lastModified": 1736429655, - "narHash": "sha256-BwMekRuVlSB9C0QgwKMICiJ5EVbLGjfe4qyueyNQyGI=", + "lastModified": 1745925850, + "narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=", "ref": "refs/heads/master", - "rev": "0621e47bd95542b8e1ce2ee2d65d6a1f887a13ce", - "revCount": 352, + "rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f", + "revCount": 359, "type": "git", "url": "https://github.com/nix-community/naersk" }, @@ -187,16 +202,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1739206421, - "narHash": "sha256-PwQASeL2cGVmrtQYlrBur0U20Xy07uSWVnFup2PHnDs=", - "ref": "nixos-24.11", - "rev": "44534bc021b85c8d78e465021e21f33b856e2540", + "lastModified": 1752620740, + "narHash": "sha256-f3pO+9lg66mV7IMmmIqG4PL3223TYMlnlw+pnpelbss=", + "ref": "nixos-25.05", + "rev": "32a4e87942101f1c9f9865e04dc3ddb175f5f32e", "shallow": true, "type": "git", "url": "ssh://git@github.com/nixos/nixpkgs.git" }, "original": { - "ref": "nixos-24.11", + "ref": "nixos-25.05", "shallow": true, "type": "git", "url": "ssh://git@github.com/nixos/nixpkgs.git" @@ -204,11 +219,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1739138025, - "narHash": "sha256-M4ilIfGxzbBZuURokv24aqJTbdjPA9K+DtKUzrJaES4=", + "lastModified": 1748856973, + "narHash": "sha256-RlTsJUvvr8ErjPBsiwrGbbHYW8XbB/oek0Gi78XdWKg=", "ref": "nixpkgs-unstable", - "rev": "b2243f41e860ac85c0b446eadc6930359b294e79", - "revCount": 751383, + "rev": "e4b09e47ace7d87de083786b404bf232eb6c89d8", + "revCount": 809757, "type": "git", "url": "https://github.com/nixos/nixpkgs" }, @@ -218,16 +233,105 @@ "url": "https://github.com/nixos/nixpkgs" } }, + "nixpkgs_2": { + "locked": { + "lastModified": 1743259260, + "narHash": "sha256-ArWLUgRm1tKHiqlhnymyVqi5kLNCK5ghvm06mfCl4QY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "eb0e0f21f15c559d2ac7633dc81d079d1caf5f5f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pwndbg": { + "inputs": { + "nixpkgs": "nixpkgs_2", + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": "pyproject-nix", + "uv2nix": "uv2nix" + }, + "locked": { + "lastModified": 1750271240, + "narHash": "sha256-mDT83XFhJaAQA7l1/t3TrjsiHzyW4BCWb5lXfe6Qlb8=", + "ref": "refs/heads/dev", + "rev": "1de6e8e2723f3d89952ca47fd4c8dab78af574b5", + "revCount": 2497, + "type": "git", + "url": "ssh://git@github.com/pwndbg/pwndbg" + }, + "original": { + "type": "git", + "url": "ssh://git@github.com/pwndbg/pwndbg" + } + }, + "pyproject-build-systems": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ], + "pyproject-nix": [ + "pwndbg", + "pyproject-nix" + ], + "uv2nix": [ + "pwndbg", + "uv2nix" + ] + }, + "locked": { + "lastModified": 1742689179, + "narHash": "sha256-kDXV6r6pQp6sxBKKxXqcTGPdiH63m8WA+IvzHhdZlEg=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "5c2a1faadc4015d50eb9919a8e20c112f3765fc2", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "type": "github" + } + }, + "pyproject-nix": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1743085397, + "narHash": "sha256-mCJgxAltNx9uzYTpaSNr6yQtDMXnRykXL87L2bLmsPo=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "af4c3ccf8cffcd49626b0455defb0f6b22cc1910", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "type": "github" + } + }, "root": { "inputs": { "agenix": "agenix", "darwin": "darwin_2", "deploy-rs": "deploy-rs", "flake-utils": "flake-utils", + "hefe-internal": "hefe-internal", "home-manager": "home-manager_2", "naersk": "naersk", "nixpkgs": "nixpkgs", - "nixpkgs-unstable": "nixpkgs-unstable" + "nixpkgs-unstable": "nixpkgs-unstable", + "pwndbg": "pwndbg" } }, "systems": { @@ -280,11 +384,11 @@ "systems": "systems_2" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -292,6 +396,31 @@ "repo": "flake-utils", "type": "github" } + }, + "uv2nix": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ], + "pyproject-nix": [ + "pwndbg", + "pyproject-nix" + ] + }, + "locked": { + "lastModified": 1743267007, + "narHash": "sha256-A5lFzCjO3kBnpUewPaHoM1f6qgubDqw7bgIGSi5i0JE=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "ede084fd69a0b656acb1ac20e6609385a3f967ba", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "uv2nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 51e0093..c755d26 100644 --- a/flake.nix +++ b/flake.nix @@ -1,13 +1,14 @@ { inputs = { - nixpkgs.url = "git+ssh://git@github.com/nixos/nixpkgs.git?shallow=1&ref=nixos-24.11"; + # nixpkgs.url = "git+ssh://git@github.com/nixos/nixpkgs.git?shallow=1&ref=nixos-24.11"; + nixpkgs.url = "git+ssh://git@github.com/nixos/nixpkgs.git?shallow=1&ref=nixos-25.05"; nixpkgs-unstable.url = "git+https://github.com/nixos/nixpkgs?ref=nixpkgs-unstable"; # nix darwin version must match nixpkgs version: # nixpkgs: nixos-xx.yy - # nix-darwin: nix-darwin-xx.yy + # darwin: nix-darwin-xx.yy # with xx.yy being the same - darwin.url = "git+https://github.com/lnl7/nix-darwin?ref=nix-darwin-24.11"; + darwin.url = "git+https://github.com/lnl7/nix-darwin?ref=nix-darwin-25.05"; darwin.inputs.nixpkgs.follows = "nixpkgs"; deploy-rs.url = "git+https://github.com/serokell/deploy-rs?ref=master"; @@ -16,7 +17,7 @@ agenix.url = "git+https://github.com/ryantm/agenix"; agenix.inputs.nixpkgs.follows = "nixpkgs"; - home-manager.url = "git+https://github.com/nix-community/home-manager?ref=release-24.11"; + home-manager.url = "git+https://github.com/nix-community/home-manager?ref=release-25.05"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; naersk.url = "git+https://github.com/nix-community/naersk"; @@ -24,7 +25,9 @@ flake-utils.url = "git+https://github.com/numtide/flake-utils"; - # hefe-internal.url = "git+file:///Users/emile/hefe-internal"; + pwndbg.url = "git+ssh://git@github.com/pwndbg/pwndbg"; + + hefe-internal.url = "git+file:///Users/emile/hefe-internal"; # hefe-internal.url = "git+ssh://git@git.emile.space/hefe-internal"; # nix registry add flake:mylocalrepo git+file:///path/to/local/repo @@ -35,15 +38,16 @@ outputs = { self, - nixpkgs, # packages + nixpkgs, # packages nixpkgs-unstable, # unstable branch - darwin, # darwin related stuff - deploy-rs, # deploy the hosts - agenix, # store secrets crypted using age - home-manager, # manage my home envs - naersk, # build rust stuff - flake-utils, # common flake utils - # hefe-internal, # internal tooling + darwin, # darwin related stuff + deploy-rs, # deploy the hosts + agenix, # store secrets crypted using age + home-manager, # manage my home envs + naersk, # build rust stuff + flake-utils, # common flake utils + pwndbg, # fancy gdbinit + hefe-internal, # internal tooling ... }@inputs: let @@ -63,15 +67,15 @@ }; # main vm host - # + # # in case of broken config, reboot into recovery, then: - # + # # cryptsetup luksOpen /dev/md1 luks0 # mount /dev/disk/by-label/root /mnt # mkdir /mnt/boot # mount /dev/disk/by-label/root /mnt # grub-reboot --boot-directory /mnt/boot "Ni" <- press tab and choose wisely - # + # # also see # //nix/hosts/corrino/hetzner-dedicated-wipe-and-install-nixos-luks-raid-lvm.sh corrino = { @@ -79,7 +83,17 @@ ip = "corrino"; description = "Hetzner AX41 dual 512GB NVME"; modules = [ - # hefe-internal.nixosModules.corrino + hefe-internal.nixosModules.corrino + ( + { self, ... }: + { + nixpkgs.overlays = [ + (final: prev: { + inherit (self.packages.x86_64-linux) goapp-frontend; + }) + ]; + } + ) ]; }; chusuk = { @@ -120,14 +134,22 @@ # lankiveil = { # system = "x86_64-linux"; # ???, ???, RTX A2000 - # description = ""; + # description = "Router"; # }; # poritrin = { # description = "lankiveil bmc"; # }; - # kaitain = {}; - # ecaz = {}; + # kaitain = { + # system = "x86_64-darwin"; + # description = "mac mini"; + # }; + + # ecaz = { + # system = "x86_64-linux"; + # description = "pi4"; + # }; + # gamont = {}; # futher names: https://neoencyclopedia.fandom.com/wiki/List_of_Dune_planets @@ -155,13 +177,11 @@ }; overlays = { - emile = import ./nix/pkgs/overlay.nix; + default = self.overlays.x86_64-linux; x86_64-linux = import ./nix/pkgs/x86_64-linux.nix; aarch64-darwin = import ./nix/pkgs/aarch64-darwin.nix; - default = self.overlays.x86_64-linux; - unstable = final: prev: { unstable = import nixpkgs-unstable { system = "x86_64-linux"; @@ -169,14 +189,13 @@ }; }; - # no clue why, but when rebuilding corrino and this not being commented, something in the - # hardware.bluetooth module breaks - # + # no clue why, but when rebuilding corrino and this not being commented, + # something in the hardware.bluetooth module breaks # unstable-darwin = final: prev: { - # unstable-darwin = import nixpkgs-unstable { - # system = "aarch64-darwin"; - # config.allowUnfree = true; - # }; + unstable-darwin = import nixpkgs-unstable { + system = "aarch64-darwin"; + config.allowUnfree = true; + }; # }; }; @@ -195,44 +214,43 @@ pkgs = import nixpkgs { inherit system; overlays = [ - ( - if system == "x86_64-linux" then - self.overlays.x86_64-linux - else if system == "aarch64-darwin" then - self.overlays.aarch64-darwin - else - null + self.overlays.${system} + # if system == "x86_64-linux" then + # self.overlays.x86_64-linux + # else if system == "aarch64-darwin" then + # self.overlays.aarch64-darwin + # else + # null ) - # self.overlays.emile - # some arguments for packages (_: _: { inherit naersk; }) ]; }; in + # take all the packages exposed from templates and add them to + # the packages exposed by this flake + + # TODO(emile): templates + #helper.merged-template-packages system + # // { - inherit (pkgs) vokobe r2wars-web remarvin; + inherit (pkgs) + vokobe + r2wars-web + # remarvin + # glibc-all-in-one + ; } ); - hydraJobs = let - # A function taking an attribute set of flake templates, importing their flake.nix and returning an attribute ste of their packages (if the template has one or more) - template-packages = templ: - (builtins.mapAttrs - (name: value: - ( - ( - (import ./nix/templates/${name}/flake.nix).outputs) { - inherit nixpkgs flake-utils; - }).packages or {}) - templ); - in { + hydraJobs = { inherit (self) packages; - nixosConfigurations = helper.buildHosts self.nixosConfigurations; - templates = template-packages self.templates; + # nixosConfigurations = helper.buildHosts self.nixosConfigurations; + templates = helper.template-packages self.templates; }; + # TODO(emile): templates templates = { # ; nix nix registry add hefe /Users/emile/Documents/hefe # ; nix flake init -t hefe#ctf @@ -240,14 +258,11 @@ description = "A basic ctf env with pwn, rev, ... tools"; path = ./nix/templates/ctf; welcomeText = '' - # A basic CTF env - ## Intended usage - The intended usage of this flake is... - - ## More info - - [Rust language](https://www.rust-lang.org/) - - [Rust on the NixOS Wiki](https://nixos.wiki/wiki/Rust) - - ... + # CTF flake template + + Run `nix develop` to get a shell with pwntools, pwndbg, pycryptodome, ... + + Add packages in the flake as you like. ''; }; goapp = { @@ -255,12 +270,13 @@ path = ./nix/templates/goapp; welcomeText = '' # A basic golang service - + - using gorilla/mux ''; }; - # checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib; + # checks = builtins.mapAttrs (system: deployLib: + # deployLib.deployChecks self.deploy) deploy-rs.lib; + }; }; - }; } diff --git a/nix/hosts/caladan/aliases.nix b/nix/hosts/caladan/aliases.nix index d65bc14..6738589 100644 --- a/nix/hosts/caladan/aliases.nix +++ b/nix/hosts/caladan/aliases.nix @@ -4,6 +4,7 @@ # short forms tf = "terraform"; + m = "multipass"; r2help = ''r2 -qq -c "?*~..." --''; mosh = "mosh --no-init"; diff --git a/nix/hosts/caladan/darwin-configuration.nix b/nix/hosts/caladan/darwin-configuration.nix index ef18642..e581cb8 100644 --- a/nix/hosts/caladan/darwin-configuration.nix +++ b/nix/hosts/caladan/darwin-configuration.nix @@ -1,7 +1,9 @@ { pkgs, lib, ... }: { - imports = [ ./overlay.nix ]; + imports = [ + ./overlay.nix + ]; system.stateVersion = 5; @@ -27,9 +29,17 @@ # users.users."_nixbld3".uid = 307; # users.users."_nixbld4".uid = 308; # users.users."_nixbld5".uid = 309; + + # virtualisation.multipass = { + # enable = true; + # package = pkgs.multipass; + # logLevel = "debug"; + # }; + + ids.gids.nixbld = 30000; nix = { - useDaemon = true; + # useDaemon = true; # package = pkgs.nixFlakes; extraOptions = '' @@ -85,10 +95,10 @@ { hostName = "corrino.emile.space"; system = "x86_64-linux"; - maxJobs = 16; + maxJobs = 10; speedFactor = 2; - # Feature | Derivations requiring it + # Feature | Derivations requiring it # ----------------|----------------------------------------------------- # kvm | Everything which builds inside a vm, like NixOS tests # nixos-test | Machine can run NixOS tests @@ -110,14 +120,16 @@ ]; }; - nixpkgs = { - config.allowUnfree = true; + nixpkgs.config = { + allowUnfree = true; + allowUnsupportedSystem = true; }; - services.nix-daemon.enable = true; + # services.nix-daemon.enable = true; # <3 - security.pam.enableSudoTouchIdAuth = true; + # security.pam.enableSudoTouchIdAuth = true; + security.pam.services.sudo_local.touchIdAuth = true; environment = { systemPackages = [ ]; # set via home-manager diff --git a/nix/hosts/caladan/emacs_config.el b/nix/hosts/caladan/emacs_config.el index 0ed5786..01cf5bd 100644 --- a/nix/hosts/caladan/emacs_config.el +++ b/nix/hosts/caladan/emacs_config.el @@ -17,10 +17,7 @@ (unless (package-installed-p package) (package-install package))) -(when (display-graphic-p) - (tool-bar-mode 0) - (scroll-bar-mode 'left)) - +(scroll-bar-mode -1) (load-theme 'leuven) ;; light theme (setq pixel-scroll-precision-mode 1) (xterm-mouse-mode 1) @@ -42,9 +39,6 @@ (display-buffer-no-window) (allow-no-window . t))) -(when (not (display-graphic-p)) - (menu-bar-mode -1)) - ;; general purpose emacs settings (use-package emacs :init @@ -148,7 +142,6 @@ completion-category-overrides '((file (styles partial-completion))))) - ;; markdown mode ;; https://jblevins.org/projects/markdown-mode/ (defvar markdown-command) @@ -181,7 +174,7 @@ :ensure nil ; no need to install it as it is built-in, but needs to be activated :hook (after-init . delete-selection-mode)) -;; Configure the Lisp program for SLIME +;; Configure the Lisp program for SLY (add-to-list 'exec-path "/Users/emile/.nix-profile/bin") (defvar inferior-lisp-program "sbcl") @@ -206,14 +199,5 @@ (use-package breadcrumb :ensure t) -;(setq circe-network-options -; '(("Libera Chat" -; :tls t -; :tls-keylist (("/Users/emile/libera.crt" -; "/Users/emile/libera.key")) -; :sasl-external t -; :nick "hanemile" -; :channels ("#test")))) - (provide '.emacs) ;;; emacs_config.el ends here diff --git a/nix/hosts/caladan/home_emile.nix b/nix/hosts/caladan/home_emile.nix index 86d6965..704b73b 100644 --- a/nix/hosts/caladan/home_emile.nix +++ b/nix/hosts/caladan/home_emile.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: { home = { @@ -50,7 +50,7 @@ fi ''; - initExtraBeforeCompInit = '' + initContent = lib.mkOrder 550 '' ${builtins.readFile ./session_variables.zsh} ${builtins.readFile ./functions.zsh} @@ -60,6 +60,18 @@ ''; }; + neovim = let + custom_plugins = pkgs.callPackage ./nvim_plugins.nix { }; + in { + enable = true; + plugins = with pkgs.vimPlugins // custom_plugins; [ + neovim-ayu + lisp.vlime + ]; + extraConfig = '' + ''; + }; + emacs = { enable = true; package = pkgs.emacs; @@ -76,10 +88,8 @@ kitty = { enable = true; - # package = pkgs.kitty; - font = { - name = "Iosevka Nerd Font"; + name = "Berkeley Mono"; size = 13; }; @@ -92,9 +102,6 @@ tab_bar_edge = "top"; tab_bar_style = "slant"; tab_bar_min_tabs = 1; - - # tab_title_template = "{index}[{layout_name[0:2]}]: {title.replace('emile', 'e')[title.rfind('/')+1:]}"; - # tab_title_template = "{index}[{layout_name[0:2]}]: {title.replace('emile', 'e')}"; tab_title_template = "{index} {title.replace('emile', 'e')}"; editor = "/Users/emile/.cargo/bin/hx"; @@ -182,9 +189,9 @@ ## language server # nodePackages_latest.typescript-language-server # js / typescript nil # nix - nodePackages.yaml-language-server # yaml + # nodePackages.yaml-language-server # yaml python312Packages.python-lsp-server # python - gopls # golang + # gopls # golang # binary foo radare2 @@ -199,7 +206,8 @@ # go foo go - delve + # delve + # gotools # c foo cmake @@ -247,9 +255,23 @@ taskwarrior3 - drawio + # drawio + + # cargo rustup + cargo + + utm + + #nmap ffuf + #typst + #age + #ffmpeg + #exiftool + + # custom + # libc-database - libc-database + # unstable.duckdb # blender diff --git a/nix/hosts/caladan/nvim_plugins.nix b/nix/hosts/caladan/nvim_plugins.nix new file mode 100644 index 0000000..7f07816 --- /dev/null +++ b/nix/hosts/caladan/nvim_plugins.nix @@ -0,0 +1,21 @@ +{ vimUtils, fetchgit, ... }: + +let + build = ({name, owner, rev, sha256}: vimUtils.buildVimPlugin { + inherit name; + src = fetchgit { + inherit rev sha256; + url = "https://github.com/${owner}/${name}"; + }; + dependencies = []; + }); +in { + lisp = { + vlime = build { + name = "vlime"; + owner = "l04m33"; + rev = "065b95f3ac7a455314c2bdefeb2b792f290034df"; + sha256 = "1bmmskdwvbl6lvbnjp9lls86rz0vzmk73y644bjb9ix9ygmjbia4"; + }; + }; +} diff --git a/nix/hosts/caladan/overlay.nix b/nix/hosts/caladan/overlay.nix index c9bdd79..8295339 100644 --- a/nix/hosts/caladan/overlay.nix +++ b/nix/hosts/caladan/overlay.nix @@ -3,42 +3,37 @@ { nixpkgs = { overlays = [ - (self: super: { - kitty = super.kitty.overrideAttrs (old: { - preCheck = '' - # skip failing tests due to darwin sandbox - substituteInPlace kitty_tests/file_transmission.py \ - --replace test_file_get dont_test_file_get \ - --replace test_path_mapping_receive dont_test_path_mapping_receive \ - --replace test_transfer_send dont_test_transfer_send - substituteInPlace kitty_tests/shell_integration.py \ - --replace test_fish_integration dont_test_fish_integration - substituteInPlace kitty_tests/shell_integration.py \ - --replace test_bash_integration dont_test_bash_integration - substituteInPlace kitty_tests/open_actions.py \ - --replace test_parsing_of_open_actions dont_test_parsing_of_open_actions - substituteInPlace kitty_tests/ssh.py \ - --replace test_ssh_connection_data dont_test_ssh_connection_data - substituteInPlace kitty_tests/fonts.py \ - --replace 'class Rendering(BaseTest)' 'class Rendering' + #(self: super: { + # kitty = super.kitty.overrideAttrs (old: { + # preCheck = '' + # # skip failing tests due to darwin sandbox + # substituteInPlace kitty_tests/file_transmission.py \ + # --replace test_file_get dont_test_file_get \ + # --replace test_path_mapping_receive dont_test_path_mapping_receive \ + # --replace test_transfer_send dont_test_transfer_send + # substituteInPlace kitty_tests/shell_integration.py \ + # --replace test_fish_integration dont_test_fish_integration + # substituteInPlace kitty_tests/shell_integration.py \ + # --replace test_bash_integration dont_test_bash_integration + # substituteInPlace kitty_tests/open_actions.py \ + # --replace test_parsing_of_open_actions dont_test_parsing_of_open_actions + # substituteInPlace kitty_tests/ssh.py \ + # --replace test_ssh_connection_data dont_test_ssh_connection_data + # substituteInPlace kitty_tests/fonts.py \ + # --replace 'class Rendering(BaseTest)' 'class Rendering' - # TODO(emile): figure out why this test is failing and activate it - # again. - substituteInPlace kittens/hyperlinked_grep/main_test.go \ - --replace TestRgArgParsing DontTestRgArgParsing \ + # # TODO(emile): figure out why this test is failing and activate it + # # again. + # substituteInPlace kittens/hyperlinked_grep/main_test.go \ + # --replace TestRgArgParsing DontTestRgArgParsing \ - # theme collection test starts an http server - rm tools/themes/collection_test.go - # passwd_test tries to exec /usr/bin/dscl - rm tools/utils/passwd_test.go - ''; - }); - - # helix-2303 = self.callPackage ../../pkgs/helix-2303 { }; - # r2 = self.callPackage ../../pkgs/radare2-5.8.4 { }; - # ansel = self.callPackage ../../pkgs/ansel { }; - # typst = self.callPackage ../pkgs/radare2-5.8.4 { }; - }) + # # theme collection test starts an http server + # rm tools/themes/collection_test.go + # # passwd_test tries to exec /usr/bin/dscl + # rm tools/utils/passwd_test.go + # ''; + # }); + #}) ]; config = { allowUnfree = true; diff --git a/nix/hosts/corrino/configuration.nix b/nix/hosts/corrino/configuration.nix index d453b34..7683630 100644 --- a/nix/hosts/corrino/configuration.nix +++ b/nix/hosts/corrino/configuration.nix @@ -25,7 +25,11 @@ in # ./vm.nix ./www/git - ./www/nix-cache + #./www/nix-cache + + # doesn't find the goapp-frontend package, some issue with the overlay being applied, at least + # thats what I think the problem is + # ./www/goapp.emile.space.nix # screego @@ -33,36 +37,38 @@ in ./www/emile.space.nix ./www/tmp.emile.space.nix ./www/hydra.emile.space.nix - ./www/netbox.emile.space.nix + # ./www/netbox.emile.space.nix ./www/stats.emile.space.nix - # ./www/grafana.emile.space.nix + ./www/grafana.emile.space.nix # ./www/prometheus.emile.space.nix - # ./www/loki.emile.space.nix - # ./www/promtail.emile.space.nix ./www/photo - # ./www/tickets.emile.space.nix + ./www/tickets.emile.space.nix # ./www/talks.emile.space.nix + ./www/miniflux.emile.space.nix # ./www/stream.emile.space.nix ./www/md.emile.space.nix ./www/social.emile.space.nix ./www/sso.emile.space.nix - ./www/s3.emile.space.nix + # ./www/s3.emile.space.nix # ./www/cs.emile.space.nix - ./www/irc.emile.space.nix + # ./www/irc.emile.space.nix + # ./www/cl.emile.space.nix # ./www/db.emile.space.nix - # ./www/ctf.emile.space.nix + #./www/ctf.emile.space.nix # ./www/magic-hash.emile.space.nix + # ./www/mc.emile.space.nix + # gemini - ./gemini/emile.space.nix + # ./gemini/emile.space.nix # general purpose modules # r2wars - ./www/r2wa.rs.nix + # ./www/r2wa.rs.nix # milliways # ./remarvin.nix @@ -157,9 +163,7 @@ in ''; }; - supportedFilesystems = { - "cifs" = true; - }; + supportedFilesystems = [ "cifs" ]; }; time.timeZone = "Europe/Berlin"; @@ -218,40 +222,40 @@ in }; # create a oneshot job to authenticate to Tailscale - systemd.services.tailscale-autoconnect = { - description = "Automatic connection to Tailscale"; - - # make sure tailscale is running before trying to connect to tailscale - after = [ - "network-pre.target" - "tailscale.service" - ]; - wants = [ - "network-pre.target" - "tailscale.service" - ]; - wantedBy = [ "multi-user.target" ]; - - # set this service as a oneshot job - serviceConfig.Type = "oneshot"; - - # have the job run this shell script - script = with pkgs; '' - # wait for tailscaled to settle - sleep 2 - - # check if we are already authenticated to tailscale - status="$(${tailscale}/bin/tailscale status -json | ${jq}/bin/jq -r .BackendState)" - if [ $status = "Running" ]; then # if so, then do nothing - exit 0 - fi - - # otherwise authenticate with tailscale - ${tailscale}/bin/tailscale up \ - --advertise-exit-node --exit-node - ''; - # -authkey ${config.age.secrets.tailscale_authkey} - }; + # systemd.services.tailscale-autoconnect = { + # description = "Automatic connection to Tailscale"; + + # # make sure tailscale is running before trying to connect to tailscale + # after = [ + # "network-pre.target" + # "tailscale.service" + # ]; + # wants = [ + # "network-pre.target" + # "tailscale.service" + # ]; + # wantedBy = [ "multi-user.target" ]; + + # # set this service as a oneshot job + # serviceConfig.Type = "oneshot"; + + # # have the job run this shell script + # script = with pkgs; '' + # # wait for tailscaled to settle + # sleep 2 + + # # check if we are already authenticated to tailscale + # status="$(${tailscale}/bin/tailscale status -json | ${jq}/bin/jq -r .BackendState)" + # if [ $status = "Running" ]; then # if so, then do nothing + # exit 0 + # fi + + # # otherwise authenticate with tailscale + # ${tailscale}/bin/tailscale up \ + # --advertise-exit-node --exit-node + # ''; + # # -authkey ${config.age.secrets.tailscale_authkey} + # }; networking = { hostName = "corrino"; @@ -312,6 +316,7 @@ in 80 443 # normal web config.emile.ports.gitDaemon + 8085 ]; allowedUDPPorts = [ # 51820 # wireguard @@ -403,6 +408,9 @@ in "docker" "libvirtd" ]; + packages = with pkgs; [ + docker + ]; }; tmpuser1 = { @@ -438,6 +446,27 @@ in # use corrino as a subnet router and an exit node useRoutingFeatures = "both"; }; + + restic.backups."corrino" = { + repository = "/mnt/storagebox-bx11/corrino"; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; + # restic.server = { + # enable = true; + # prometheus = true; + # package = pkgs.restic-rest-server; + # extraFlags = [ "--no-auth" ]; + # listenAddress = "127.0.0.1:${toString config.emile.ports.restic}"; + # dataDir = "/var/lib/restic"; + # appendOnly = true; + # }; }; nix = { @@ -467,38 +496,38 @@ in allowed-uris = https://github.com/ https://git.emile.space/ git+https://github.com/ ''; - buildMachines = [ - { - hostName = "localhost"; - system = "x86_64-linux"; - protocol = "ssh-ng"; - maxJobs = 8; - supportedFeatures = [ - "nixos-test" - "benchmark" - "big-parallel" - "kvm" - ]; - } - { - hostName = "caladan.pinto-pike.ts.net"; - sshUser = "hydra"; - sshKey = "/var/lib/hydra/.ssh/id_ed25519"; - system = "aarch64-darwin"; - protocol = "ssh-ng"; - maxJobs = 1; - speedFactor = 2; - supportedFeatures = [ - "nixos-test" - "benchmark" - "big-parallel" - "kvm" - ]; - mandatoryFeatures = [ ]; - } - ]; + # buildMachines = [ + # { + # hostName = "localhost"; + # system = "x86_64-linux"; + # protocol = "ssh-ng"; + # maxJobs = 8; + # supportedFeatures = [ + # "nixos-test" + # "benchmark" + # "big-parallel" + # "kvm" + # ]; + # } + # { + # hostName = "caladan.pinto-pike.ts.net"; + # sshUser = "hydra"; + # sshKey = "/var/lib/hydra/.ssh/id_ed25519"; + # system = "aarch64-darwin"; + # protocol = "ssh-ng"; + # maxJobs = 1; + # speedFactor = 2; + # supportedFeatures = [ + # "nixos-test" + # "benchmark" + # "big-parallel" + # "kvm" + # ]; + # mandatoryFeatures = [ ]; + # } + # ]; - distributedBuilds = true; + # distributedBuilds = true; }; nixpkgs.config = { @@ -516,7 +545,7 @@ in }; virtualisation = { - # docker.enable = true; + docker.enable = true; libvirtd = { enable = true; qemu = { @@ -524,12 +553,14 @@ in runAsRoot = true; swtpm.enable = true; ovmf = { - enable = true; - packages = [ - (pkgs.unstable.OVMF.override { + enable = true; + packages = [ + ( + pkgs.OVMF.override { secureBoot = true; tpmSupport = true; - }).fd + } + ).fd ]; }; }; @@ -554,13 +585,25 @@ in }; "/mnt/storagebox-bx11" = { - device = "//u331921.your-storagebox.de/backup"; - fsType = "cifs"; - options = - let - automount_opts = "_netdev,x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s"; - in - [ "${automount_opts},credentials=${config.age.secrets.storage_box_bx11_password.path}" ]; + device = "u331921@u331921.your-storagebox.de:/home/backup"; + fsType = "sshfs"; + options = [ # Filesystem options + "allow_other" # for non-root access + "_netdev" # this is a network fs + + # We don't mount on demand, as that will cause services like navidrome to fail + # as the share doesn't yet exist. + #"x-systemd.automount" # mount on demand, rather than boot + + #"debug" # print debug logging + # warning: this causes the one-shot service to never exit + + # SSH options + "StrictHostKeyChecking=no" # prevent the connection from failing if the host's key hasn't been trusted yet + "ServerAliveInterval=15" # keep connections alive + "Port=23" + "IdentityFile=/root/.ssh/id_ed25519" + ]; }; }; diff --git a/nix/hosts/corrino/ports.nix b/nix/hosts/corrino/ports.nix index 10ae593..483ab7f 100644 --- a/nix/hosts/corrino/ports.nix +++ b/nix/hosts/corrino/ports.nix @@ -5,16 +5,24 @@ photo = { photoprism = 2342; immich = 2343; + immich-public-proxy = 2344; }; git = 3000; hydra = 3001; grafana = 3002; md = 3003; gotosocial = 3004; - immich = 3005; monica = 3006; + miniflux = 3007; harmonia = 5000; + garage = { + s3 = 6001; + web = 6002; + rpc = 6003; + admin = 6004; + }; irc = { + bouncer = 6666; clear = 6667; ssl = 6697; }; @@ -24,6 +32,7 @@ restic = 8002; nocodb = 8003; goatcounter = 8004; + goapp = 8005; r2wars-web = 8089; ctf = 8338; magic-hash = 8339; @@ -33,8 +42,6 @@ s3 = 9000; web = 9001; }; - promtail = 9033; - loki = 9034; authelia = 9091; gitDaemon = 9418; prometheus = { @@ -44,6 +51,7 @@ nginx = 9913; systemd = 9558; smartctl = 9633; + restic = 9634; }; }; }; diff --git a/nix/hosts/corrino/secrets/garage_admin_metrics_secret.age b/nix/hosts/corrino/secrets/garage_admin_metrics_secret.age new file mode 100644 index 0000000..e1af7da --- /dev/null +++ b/nix/hosts/corrino/secrets/garage_admin_metrics_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q 7QkcpYGeeMsbW0GcXzNGPTc0jUf4ydpMiTO6ZxEIKGY +OOxq2hMORsmUzBuoqOIPNJeLqJB0seve9PhorS6PKNs +-> ssh-ed25519 m8VklA pF7mWG6tviFC6qD88dxoQRnXGfR0AuanVyY+bh8XgV0 +mrk4HgEs3i8y5P+BSGM1psweXpY/xO+8vK/DsXyhyiY +--- zqEl/ZN/3jEgMZ/IbPbyTHGZJDDENLOnoQezaACeoSs +íóõÃ÷ÔþlÉé…”,±ÿ‚W`£…\6éyh†Ž. ÏéÞoVÐ(€?äEmå¶,Ü;Á(@¬0dVƒ£A=4©v¡É \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/garage_admin_token_secret.age b/nix/hosts/corrino/secrets/garage_admin_token_secret.age new file mode 100644 index 0000000..2a18a6b --- /dev/null +++ b/nix/hosts/corrino/secrets/garage_admin_token_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q hcMMVkZSsObrOFjetml2z4eH+EfnuSsna+GaXEeMUA4 +y6lFBj49cMhOGuJBpILHsykpBMpKDHZpFXR4E4zZEbg +-> ssh-ed25519 m8VklA Z6zLilTWlGWG17Q6jBx13m3KYs3gE93TPLq0CidHeTA +eqMN5mDMasi/Nw2y5Kgwy2COna+3zbbFTTUrD/O26ls +--- QdVyqrTLmEcGSB37Ft3Ur0Ry9Jk9DyHFI6fo88tnsgI +X`w•YšÙ,ç<ˆçùŸA›Á$XeêDGe´ ;±àµ†¿Âô>ü1n¥s€ª’‰±äÁNr_Y\µ`¬Á„)ü„F#{çãß´<Œ \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/garage_env.age b/nix/hosts/corrino/secrets/garage_env.age new file mode 100644 index 0000000..becb511 --- /dev/null +++ b/nix/hosts/corrino/secrets/garage_env.age Binary files differdiff --git a/nix/hosts/corrino/secrets/garage_rpc_secret.age b/nix/hosts/corrino/secrets/garage_rpc_secret.age index e228d0d..ce8a65a 100644 --- a/nix/hosts/corrino/secrets/garage_rpc_secret.age +++ b/nix/hosts/corrino/secrets/garage_rpc_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/goapp_oidc_client_secret.age b/nix/hosts/corrino/secrets/goapp_oidc_client_secret.age new file mode 100644 index 0000000..1477d56 --- /dev/null +++ b/nix/hosts/corrino/secrets/goapp_oidc_client_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q wi3/W2UnB/8kCTeJ8shGpBQ21uvSQlbtZBAbocbQ+zY +6RQGQss6B6uvq4yFXGVQtbHgDKGzMVO2xDgUDlBV5Es +-> ssh-ed25519 m8VklA oFBut6nQ5Er9YQWpCb+2j3JKsNIjBRjwuQ7ERVekVyM +ccR/5J5g1D11iNieF/BXtzxcusF1Zaq04iifOFk6Q/U +--- r2E/KdtXa9/j5ecWhjzLsztBG8W+if2MeOPya6KJDxY +êCª7p}ôÞÿVjíàüÍ4|³EWëá].kÊ~ìÒÎXŠe:ñ(r¯õ2:ù‹”$}®Ñ~wÒÎ0Æ»Pð`+ ¡X¨g@¸PFXÁ/iú%Š;˜!$Ï ƒ"ªIÔúi¹ñ_Î#¬*Ó|Oà„Œ†d;ZÓò£twDº F»¶l–Ðd„¨F¦6дÎJøä©a4®ýq2ây 8¿ÞT \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/goapp_oidc_secret.age b/nix/hosts/corrino/secrets/goapp_oidc_secret.age new file mode 100644 index 0000000..4ca657b --- /dev/null +++ b/nix/hosts/corrino/secrets/goapp_oidc_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/goapp_oidc_session_key.age b/nix/hosts/corrino/secrets/goapp_oidc_session_key.age new file mode 100644 index 0000000..938f97f --- /dev/null +++ b/nix/hosts/corrino/secrets/goapp_oidc_session_key.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q BAvDdIEUEgmo963+9Wd5VLJgrp3MBISvWR3+27bfJW8 +NOEj2ObYe/cM2CaqzmbgexSEUNZIEo1ZmvlamJaSOjo +-> ssh-ed25519 m8VklA d/hwd3rGkPD3GDdlOP2XUsi687VH+tfKrAsKnImk+kI +gFAyyMZT5DK7da7YXOf/5gUd4Bi9cEe3ddMKUMuctMU +--- 9tVE+AAvptrlMZe5+UGJGzH9usnxa+ZICbikcRT0PYI +g!X+/šØ0P ;™*{ª«V p!¶êÙ4£sÌöãa ÎI+À/\Iœ‚Ô–,Äéo½p‡Î웘DP7"ŠíØÀ¦ä;p·„PÀpÍ +%ÈcÒUÚœ8 \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/gotosocial_environment_file.age b/nix/hosts/corrino/secrets/gotosocial_environment_file.age index 7211c12..d2b6b90 100644 --- a/nix/hosts/corrino/secrets/gotosocial_environment_file.age +++ b/nix/hosts/corrino/secrets/gotosocial_environment_file.age Binary files differdiff --git a/nix/hosts/corrino/secrets/gotosocial_oidc_client_secret.age b/nix/hosts/corrino/secrets/gotosocial_oidc_client_secret.age new file mode 100644 index 0000000..bd6a14a --- /dev/null +++ b/nix/hosts/corrino/secrets/gotosocial_oidc_client_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q PoCUbJ4Pg2ZCYy3HCI4w7J/vu5gh6d257Q/PlOBEEG4 +Hisdtymy8i3cN0LVuXpY8duCBMLlTT8QoOEYVmLy+n8 +-> ssh-ed25519 m8VklA i01UwKFor55UM6dL7glsMP6PQM9fcoa9EV3RRXPwRnE +9fJ9nWhhwyEXclzaYAszUTLTNH/xkM3u9uw0BgY8FOg +--- 8MUr5xLS5Rt1yXNPfIQwfF6ZGJwNOe/RVtlX0MaGMZ8 +ãYéòàì^쌛 ¯ôØhÅ#®‡üÿÂß2¿¢ñ·ÎN°‚tغ¢BêFÖX“Æoˆ“.eœ¼Cv%‘·1/•ýÌO%.‰GíÌþ×Ϥ%fÛÿ·¨šô]žä_2²ªeo~p ÇÜ{ýëbÝšý ðSH±Ó݆RÃnkôßcŽ‘jm‡º<?Ëk’%ÑnÙÈ:ˆFBJ#‰÷& \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/grafana_env_vars.age b/nix/hosts/corrino/secrets/grafana_env_vars.age index 0365676..7ad889e 100644 --- a/nix/hosts/corrino/secrets/grafana_env_vars.age +++ b/nix/hosts/corrino/secrets/grafana_env_vars.age Binary files differdiff --git a/nix/hosts/corrino/secrets/grafana_oidc_client_secret.age b/nix/hosts/corrino/secrets/grafana_oidc_client_secret.age new file mode 100644 index 0000000..91d87e8 --- /dev/null +++ b/nix/hosts/corrino/secrets/grafana_oidc_client_secret.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q YdFGe2zYgdQDdW9tZG/VPlV6ZnWCv1u2hIg3AiBVwU0 +7PXZNJR5HszD2IqVJX3Rw2VfI1Anf3fuOQTFNq58raU +-> ssh-ed25519 m8VklA LP+D7xz1SbSPT+6lEfaRjxNPSsBfyN7pE2LAe7ErVCA +wQeekB+chF01SCX8+BNcKk7o6jN8sT5uic+Oe/od9yc +--- ZG36Lj4tUALxjMb1+86Y3tdH1KMEw+Teeks0UbB2Zvk +¼.² „öií0èÓ.X®¬âúýðNÝâ)¡Â`ÁçuPˆ&4ÌÒÊôšpHTDöžþB‹¾aCŽ—µ>}q…”Q’–QÐã“´¤˜ÅŠ“·‘>T¡È<„þÙ‡+'€zeÞ{©ÅÊÁS؃› IØxîÆˆŸ$mO…Ö¨‹÷¹yÄPÛþvyAš´íUg¦f4$oW¾gýˆ³× \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age b/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age index cf3cac2..a5fe67e 100644 --- a/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age +++ b/nix/hosts/corrino/secrets/hedgedoc_environment_variables.age Binary files differdiff --git a/nix/hosts/corrino/secrets/hedgedoc_oidc_client_secret.age b/nix/hosts/corrino/secrets/hedgedoc_oidc_client_secret.age new file mode 100644 index 0000000..46d39fd --- /dev/null +++ b/nix/hosts/corrino/secrets/hedgedoc_oidc_client_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/immich_oidc_client_secret.age b/nix/hosts/corrino/secrets/immich_oidc_client_secret.age new file mode 100644 index 0000000..be7429d --- /dev/null +++ b/nix/hosts/corrino/secrets/immich_oidc_client_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/miniflux_admin_file.age b/nix/hosts/corrino/secrets/miniflux_admin_file.age new file mode 100644 index 0000000..3e00b9b --- /dev/null +++ b/nix/hosts/corrino/secrets/miniflux_admin_file.age @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q OGds4NLmRiMmVjPTORP3jLe3iEkqrDyTqW4V7ceFfRk +FFdZcsT9ZruNhpY5cb674qpQpK0qzHNwRPCfHvYaKcE +-> ssh-ed25519 m8VklA 84XSPja8dzJEUVR5olwNONVzNn5QrsX+R+WeBHqxXDo +5CVpnTDcO0EG3NsHdFsSABWNBIe3Xe16me13JIOlfos +--- rlIUU/0gYwxIXmpRI5/3mmZXJ+JrG/tE/3IBtpo4uT4 +²Ý-9J¬N™ÌVŸëªG.l‚.eÈ?Á©&¾§rõ;V˜#®ahSJWjh‰ôèv˜Ñ³t;3è¸É‚ϫk Ž(^QU ‹ö*ºcz·ßF°bwPZ¼uqãšÄ‰Û \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/miniflux_oidc_client_secret.age b/nix/hosts/corrino/secrets/miniflux_oidc_client_secret.age new file mode 100644 index 0000000..85879a9 --- /dev/null +++ b/nix/hosts/corrino/secrets/miniflux_oidc_client_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/miniflux_oidc_secret.age b/nix/hosts/corrino/secrets/miniflux_oidc_secret.age new file mode 100644 index 0000000..668c429 --- /dev/null +++ b/nix/hosts/corrino/secrets/miniflux_oidc_secret.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q Xjrf8ip0AwW6b77m4XJupjfszP3echG2XQULubcQO14 +A2RZ+dWnrbS83yw5krGr3QuHzdxUo8RLbqstO7PqdzY +-> ssh-ed25519 m8VklA RHSeMlhwrnG433aw1Hggck8kaVlSL94TVvn68PIS3W8 +ymqenUy96rBZnCaLzrgcAW67s4WkHUv/xRPLw3Viy9g +--- iJRJrTP0vx6h7/uHO09JlKmq5Z/IfcrYxlIe+ZGFFlI +-SàJ¢%·îÄ1ÃdÙZŒÛ"ž5xˆZâ5gsŒ%ã{}uÄnôÅö/›p¶Ûw¦Â€Jò(É3…!Å1nE2„QQMJ™Œs[Ao{t½®¾rð‰Ñëç/Ä +‰vK`Šã¨rúœD» \ No newline at end of file diff --git a/nix/hosts/corrino/secrets/tailscale-corrino-cert.age b/nix/hosts/corrino/secrets/tailscale-corrino-cert.age new file mode 100644 index 0000000..ecb9e6e --- /dev/null +++ b/nix/hosts/corrino/secrets/tailscale-corrino-cert.age Binary files differdiff --git a/nix/hosts/corrino/secrets/tailscale-corrino-key.age b/nix/hosts/corrino/secrets/tailscale-corrino-key.age new file mode 100644 index 0000000..5226883 --- /dev/null +++ b/nix/hosts/corrino/secrets/tailscale-corrino-key.age Binary files differdiff --git a/nix/hosts/corrino/vm.nix b/nix/hosts/corrino/vm.nix index 37d1356..78d818f 100644 --- a/nix/hosts/corrino/vm.nix +++ b/nix/hosts/corrino/vm.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ pkgs, ... }: { services.emile.libvirtnix = { @@ -15,6 +15,19 @@ uuid = "E34DE478-1402-45BB-B3FD-FC960549258E"; genid = "CA1E2462-1E9D-404C-8DDB-19EEF9D9651B"; + os = { + nvram = { + type = "network"; + source = { + mirror = { + abi = "copy"; + ready = "yes"; + type = "network"; + }; + }; + }; + }; + packages = { libvirt = pkgs.libvirt; qemu = pkgs.qemu; diff --git a/nix/hosts/corrino/www/ctf.emile.space.nix b/nix/hosts/corrino/www/ctf.emile.space.nix index 28c9419..a6ebd05 100644 --- a/nix/hosts/corrino/www/ctf.emile.space.nix +++ b/nix/hosts/corrino/www/ctf.emile.space.nix @@ -7,18 +7,19 @@ locations = { "/" = { - proxyPass = "http://127.0.0.1:${toString config.emile.ports.ctf}"; + # proxyPass = "http://127.0.0.1:${toString config.emile.ports.ctf}"; + proxyPass = "http://138.199.213.51"; }; }; }; - virtualisation.oci-containers = { - # backend = "docker"; - containers = { - "ctfd" = { - image = "ctfd/ctfd"; - ports = [ "${toString config.emile.ports.ctf}:8000" ]; - }; - }; - }; + # virtualisation.oci-containers = { + # # backend = "docker"; + # containers = { + # "ctfd" = { + # image = "ctfd/ctfd"; + # ports = [ "${toString config.emile.ports.ctf}:8000" ]; + # }; + # }; + # }; } diff --git a/nix/hosts/corrino/www/git/cgit.nix b/nix/hosts/corrino/www/git/cgit.nix index 68304db..44f5996 100644 --- a/nix/hosts/corrino/www/git/cgit.nix +++ b/nix/hosts/corrino/www/git/cgit.nix @@ -630,7 +630,13 @@ in extraGroups = [ "gitea" ]; home = "/var/lib/git"; uid = lib.mkForce 127; + # shell = "${pkgs.git}/bin/git-shell"; + # openssh.authorizedKeys.keys = [ + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPZi43zHEsoWaQomLGaftPE5k0RqVrZyiTtGqZlpWsew emile@caladan + # " + # ]; }; + users.groups.git = { gid = lib.mkForce 127; }; diff --git a/nix/hosts/corrino/www/git/git.nix b/nix/hosts/corrino/www/git/git.nix deleted file mode 100644 index 3a2b9da..0000000 --- a/nix/hosts/corrino/www/git/git.nix +++ /dev/null @@ -1,106 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: - -let - cfg = config.services.gitea; -in -{ - services.nginx.virtualHosts."git.emile.space" = { - forceSSL = true; - enableACME = true; - - # TODO(emile): figure out why this doesn't work when enabled, has to do with authelia - # extraConfig = authelia-location; - - locations = { - "/" = { - # proxyPass = "http://127.0.0.1:3000"; - proxyPass = "http://127.0.0.1:${toString config.services.gitea.settings.server.HTTP_PORT}"; - - # TODO(emile): figure out why this doesn't work when enabled, has to do with authelia - # extraConfig = authelia-authrequest; - }; - }; - }; - - # auth via authelia - services.authelia.instances.main.settings.identity_providers.oidc.clients = [ - { - id = "git"; - - # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$4bi9wRkfcqnjbdmgt7rU.g$pQ2mC6GW4.BQwanGKKFhFyIx6Y.WY80xd/YpmlYOPnlnGBWpp0dSOTv6a/2yqSA5D.EuRkGCyeexSE5FdCK2TA"; - public = false; - authorization_policy = "two_factor"; - redirect_uris = [ "https://git.emile.space/user/oauth2/authelia/callback" ]; - scopes = [ - "openid" - "email" - "profile" - ]; - } - ]; - - services.gitea = rec { - enable = true; - - appName = "git.emile.space"; - - # unstable in order to use the 1.20... version - #package = pkgs.forgejo; - package = pkgs.unstable.forgejo; - - stateDir = "/var/lib/gitea"; - repositoryRoot = "${stateDir}/repositories"; - - settings = { - service.DISABLE_REGISTRATION = true; - - DEFAULT = { - WORK_PATH = "/var/lib/gitea"; - }; - - server = { - DOMAIN = pkgs.lib.mkForce "git.emile.space"; - ROOT_URL = pkgs.lib.mkForce "https://git.emile.space"; - HTTP_PORT = config.emile.ports.git; - - #START_SSH_SERVER = true; - BUILTIN_SSH_SERVER_USER = "git"; - SSH_USER = "gitea"; - SSH_DOMAIN = "git.emile.space"; - - REPO_INDEXER_ENABLED = true; - }; - - indexer = { - REPO_INDEXER_ENABLED = true; - ISSUE_INDEXER_PATH = "${stateDir}/indexers/issues.bleve"; - REPO_INDEXER_PATH = "${stateDir}/indexers/repos.bleve"; - MAX_FILE_SIZE = 1048576; - REPO_INDEXER_INCLUDE = ""; - REPO_INDEXER_EXCLUDE = "resources/bin/**"; - }; - - #federation = { - # enable = true; - # share_user_statistics = true; - # max_size = 4; - #}; - }; - }; - - users.users.git = { - isSystemUser = true; - useDefaultShell = true; - group = "git"; - extraGroups = [ "gitea" ]; - home = cfg.stateDir; - uid = 127; - }; - users.groups.git = { }; -} diff --git a/nix/hosts/corrino/www/goapp.emile.space.nix b/nix/hosts/corrino/www/goapp.emile.space.nix new file mode 100644 index 0000000..e31079e --- /dev/null +++ b/nix/hosts/corrino/www/goapp.emile.space.nix @@ -0,0 +1,93 @@ +{ config, pkgs, ... }: + +{ + services.nginx.virtualHosts."goapp.emile.space" = { + forceSSL = true; + enableACME = true; + + locations = { + "/" = { + proxyPass = "http://${config.services.emile.goapp-frontend.host}:${toString config.services.emile.goapp-frontend.port}"; + }; + }; + }; + + age.secrets.goapp_oidc_client_secret.owner = "authelia-main"; + age.secrets.goapp_oidc_client_secret.group = "authelia-main"; + + services.authelia.instances.main.settings.identity_providers.oidc.clients = [ + { + client_id = "goapp"; + + # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + client_secret = "{{ secret \"${config.age.secrets.goapp_oidc_client_secret.path}\" }}"; + + public = false; + authorization_policy = "two_factor"; + redirect_uris = [ + "https://goapp.emile.space/oauth2/callback" + ]; + scopes = [ + "openid" + "email" + "profile" + "groups" + ]; + grant_types = [ + "refresh_token" + "authorization_code" + ]; + response_types = [ "code" ]; + response_modes = [ + "form_post" + "query" + "fragment" + ]; + token_endpoint_auth_method = "client_secret_post"; + } + ]; + + environment.systemPackages = with pkgs; [ goapp-frontend ]; + + # deploy: + # - push code + # - build in order to get the new hash (nix build .#goapp-frontend-pkg) + # - update hash in the package (//nix/templates/goapp/frontent/default.nix) + # - deploy + # + # https://goapp.emile.space/oauth2/callback?code=authelia_ac_iZKCXtRMnj2yjUAmiSkg_LBWjiME2-ghE6KMkxdb6Zw.nDLgCVpu9ctH1llEKUml5rr8szd3bkZYaGa_MAOtNLI&iss=https%3A%2F%2Fsso.emile.space&scope=openid+profile+email+groups&state=random-string-here + # + # Unable to exchange authorization code for tokens + # + # unable to exchange authorization code for tokens: oauth2: "invalid_client" "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)." + + services.emile.goapp-frontend = { + enable = true; + package = pkgs.goapp-frontend; + + host = "127.0.0.1"; + port = config.emile.ports.goapp; + public-url = "https://goapp.emile.space/"; + + oidc = { + id = "goapp"; + issuer = "https://sso.emile.space"; + cookie-name = "oidc-client"; + scopes = [ + "openid" + "profile" + "email" + "groups" + ]; + # secret-path = "/run/goapp-frontend_oidc_secret"; + secret-path = config.age.secrets.goapp_oidc_secret.path; + }; + + # TODO(emile): change these when going live + session-key-path = config.age.secrets.goapp_oidc_secret.path; + + logfile-path = "/var/log/goapp-frontend.log"; + database-path = "/var/lib/goapp-frontend/main.db"; + sessiondb-path = "/var/lib/goapp-frontend/session.db"; + }; +} diff --git a/nix/hosts/corrino/www/grafana.emile.space.nix b/nix/hosts/corrino/www/grafana.emile.space.nix index 22b444f..2caa4d4 100644 --- a/nix/hosts/corrino/www/grafana.emile.space.nix +++ b/nix/hosts/corrino/www/grafana.emile.space.nix @@ -3,134 +3,143 @@ { systemd.services.grafana.serviceConfig.EnvironmentFile = config.age.secrets.grafana_env_vars.path; - services = { - nginx.virtualHosts = { - "grafana.emile.space" = { - addSSL = true; - enableACME = true; - locations."/" = { - proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}/"; - proxyWebsockets = true; - }; + + services.nginx.virtualHosts = { + "grafana.emile.space" = { + addSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://${toString config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}/"; + proxyWebsockets = true; }; }; + }; - authelia.instances.main.settings.identity_providers.oidc.clients = [ - { - id = "Grafana"; - - # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$S.RE0jcmr7Sn/tjJDNxV/A$1tsYhQ/YEcVfE4JyzszHemrcUqy.84Fb6xVSmz87if5C9N46Mz2lRWB5l8s4EIrLsiumPnt4HQMkYZ4MoovJzA"; - public = false; - authorization_policy = "two_factor"; - redirect_uris = [ "https://grafana.emile.space/login/generic_oauth" ]; - scopes = [ - "openid" - "email" - "profile" - "groups" - ]; - grant_types = [ - "refresh_token" - "authorization_code" - ]; - response_types = [ "code" ]; - response_modes = [ - "form_post" - "query" - "fragment" - ]; - } - ]; - - grafana = { - enable = true; - settings = { - server = { - http_addr = "127.0.0.1"; - http_port = config.emile.ports.grafana; - domain = "grafana.emile.space"; - root_url = "https://grafana.emile.space/"; - }; + age.secrets.grafana_oidc_client_secret.owner = "authelia-main"; + age.secrets.grafana_oidc_client_secret.group = "authelia-main"; - "auth.generic_oauth" = - let - sso = "https://sso.emile.space/api/oidc"; - in - { - enabled = true; - client_id = "Grafana"; - - # [auth.generic_oauth] - # client_secret = ... - # set in env var as - # GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET - client_secret = "set in env var this is just a placeholder"; - - use_refresh_token = true; - token_url = "${sso}/token"; - auth_url = "${sso}/authorization"; - api_url = "${sso}/userinfo"; - - scopes = [ - "openid" - "email" - "profile" - "groups" - ]; - - email_attribute_path = "email"; - login_attribute_path = "preferred_username"; - name_attribute_path = "name"; - - role_attribute_path = "contains(groups[*], 'grafana_server_admin') && 'GrafanaAdmin' || contains(groups[*], 'grafana_admin') && 'Admin' || contains(groups[*], 'grafana_editor') && 'Editor' || 'Viewer'"; - - }; + services.authelia.instances.main.settings.identity_providers.oidc.clients = [ + { + client_id = "Grafana"; + + # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + client_secret = "{{ secret \"${config.age.secrets.grafana_oidc_client_secret.path}\" }}"; + + public = false; + authorization_policy = "two_factor"; + redirect_uris = [ "https://grafana.emile.space/login/generic_oauth" ]; + scopes = [ + "openid" + "email" + "profile" + "groups" + ]; + grant_types = [ + "refresh_token" + "authorization_code" + ]; + response_types = [ "code" ]; + response_modes = [ + "form_post" + "query" + "fragment" + ]; + } + ]; + + services.grafana = { + enable = true; + settings = { + server = { + http_addr = "127.0.0.1"; + http_port = config.emile.ports.grafana; + domain = "grafana.emile.space"; + root_url = "https://grafana.emile.space/"; }; - provision = { - dashboards.settings = { }; - datasources.settings = { - datasources = [ - { - url = "http://localhost:${toString config.services.prometheus.port}"; - type = "prometheus"; - name = "Prometheus"; - editable = false; - access = "proxy"; # server = "proxy", browser = "direct" - } - { - name = "loki"; - url = "http://${config.services.loki.configuration.common.instance_addr}:${toString config.services.loki.configuration.server.http_listen_port}"; - type = "loki"; - } + "auth.generic_oauth" = + let + sso = "https://sso.emile.space/api/oidc"; + in + { + enabled = true; + client_id = "Grafana"; + + # [auth.generic_oauth] + # client_secret = ... + # set in env var as + # GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET + client_secret = "set in env var this is just a placeholder"; + + use_refresh_token = true; + token_url = "${sso}/token"; + auth_url = "${sso}/authorization"; + api_url = "${sso}/userinfo"; + + scopes = [ + "openid" + "email" + "profile" + "groups" ]; + + email_attribute_path = "email"; + login_attribute_path = "preferred_username"; + name_attribute_path = "name"; + + role_attribute_path = "contains(groups[*], 'grafana_server_admin') && 'GrafanaAdmin' || contains(groups[*], 'grafana_admin') && 'Admin' || contains(groups[*], 'grafana_editor') && 'Editor' || 'Viewer'"; + }; + }; - # TODO(emile): finish setting up the grafana notifier filling out the settings section - # notifiers = [ - # { - # uid = "2ad1c1d1-bcd9-4cb8-8897-c89c5820ffb1"; - # type = "email"; - # settings = {}; - # org_name = "Main Org."; - # org_id = 1; - # name = "email"; - # id_default = true; - # frequency = "5m"; - # disable_resolve_message = false; - # } - # ]; - - # TODO(emile): finish setting up the alerting stuff within here - # alerting = { - # templates.settings = { }; - # rules.settings = {}; - # policies.settings = {}; - # muteTimings.settings = {}; - # contactPoints.settings = {}; - # }; + provision = { + dashboards.settings = { }; + datasources.settings = { + deleteDatasources = [ + { name = "Prometheus"; orgId = 1; } + { name = "Lampadas"; orgId = 1; } + ]; + datasources = [ + { + url = "http://localhost:${toString config.services.prometheus.port}"; + type = "prometheus"; + name = "Prometheus Corrino"; + editable = false; + access = "proxy"; # server = "proxy", browser = "direct" + } + { + url = "http://lampadas:9009"; + type = "prometheus"; + name = "Prometheus Lampadas"; + editable = false; + access = "proxy"; # server = "proxy", browser = "direct" + } + ]; }; + + # TODO(emile): finish setting up the grafana notifier filling out the settings section + # notifiers = [ + # { + # uid = "2ad1c1d1-bcd9-4cb8-8897-c89c5820ffb1"; + # type = "email"; + # settings = {}; + # org_name = "Main Org."; + # org_id = 1; + # name = "email"; + # id_default = true; + # frequency = "5m"; + # disable_resolve_message = false; + # } + # ]; + + # TODO(emile): finish setting up the alerting stuff within here + # alerting = { + # templates.settings = { }; + # rules.settings = {}; + # policies.settings = {}; + # muteTimings.settings = {}; + # contactPoints.settings = {}; + # }; }; }; } diff --git a/nix/hosts/corrino/www/hydra.emile.space.nix b/nix/hosts/corrino/www/hydra.emile.space.nix index a5cdb53..fe70bf4 100644 --- a/nix/hosts/corrino/www/hydra.emile.space.nix +++ b/nix/hosts/corrino/www/hydra.emile.space.nix @@ -21,9 +21,10 @@ services.hydra = { enable = true; - package = pkgs.hydra_unstable.overrideAttrs (old: { - patches = (if old ? patches then old.patches else [ ]) ++ [ ./hydra.patch ]; - }); + #package = pkgs.hydra_unstable.overrideAttrs (old: { + # patches = (if old ? patches then old.patches else [ ]) ++ [ ./hydra.patch ]; + #}); + package = pkgs.hydra; listenHost = "*"; port = config.emile.ports.hydra; diff --git a/nix/hosts/corrino/www/irc.emile.space.nix b/nix/hosts/corrino/www/irc.emile.space.nix index ac00445..7653cb4 100644 --- a/nix/hosts/corrino/www/irc.emile.space.nix +++ b/nix/hosts/corrino/www/irc.emile.space.nix @@ -1,155 +1,198 @@ -{ config, ... }: +{ config, pkgs, ... }: { + ############################################################################## + # Client + ############################################################################## + # gamja web client + # https://codeberg.org/emersion/gamja + # + # nah, let's just use the commaond line "senpai" client, from the same person + + ############################################################################## + # Bouncer + ############################################################################## + # soju bouncer + # https://soju.im + + # services.soju = { + # enable = true; + # listen = [ "127.0.0.1:${toString config.emile.ports.irc.bouncer}" ]; + + # hostName = "irc.emile.space"; + # httpOrigins = [ "127.0.0.1" "irc.emile.space" ]; + + # # tlsCertificateKey = "/var/lib/acme/irc.emile.space/key.pem"; + # # tlsCertificate = "/var/lib/acme/irc.emile.space/cert.pem"; + # }; + + # services.soju = { + # enable = true; + # package = pkgs.soju; + # listen = [ "127.0.0.1:${toString config.emile.ports.irc.bouncer}" ]; + # adminSocket.enable = true; + # # tlsCertificateKey = "/var/lib/acme/irc.emile.space/key.pem"; + # # tlsCertificate = "/var/lib/acme/irc.emile.space/cert.pem"; + # httpOrigins = [ "127.0.0.1" "irc.emile.space" ]; + # hostName = "irc.emile.space"; + # extraConfig = ""; + # enableMessageLogging = true; + # acceptProxyIP = []; + # }; + + ############################################################################## + # Server + ############################################################################## + # Create a tls cert for the irc server - security.acme.certs = { - "irc.emile.space" = { - webroot = "/var/lib/acme/acme-challenge/"; - email = "acme@emile.space"; - postRun = "cp fullchain.pem /home/ergo/ && cp key.pem /home/ergo && chown ergo:ergo /home/ergo/*.pem && systemctl reload ergo.service"; - }; - }; - - # Allow ergo to access the created cert - # The systemd server runs using a dynamic user, so the below inserts the .pem files - # into "/run/credentials/ergochat.service/key.pem" - systemd.services.ergochat.serviceConfig = { - LoadCredential = [ - "fullchain.pem:/var/lib/acme/irc.emile.space/fullchain.pem" - "key.pem:/var/lib/acme/irc.emile.space/key.pem" - ]; - }; - - # allow connections to the port from the "outside" - networking.firewall.allowedTCPPorts = [ config.emile.ports.irc.ssl ]; - - services.ergochat = { - enable = true; - - # https://raw.githubusercontent.com/ergochat/ergo/master/default.yaml - settings = { - accounts = { - authentication-enabled = true; - multiclient = { - allowed-by-default = true; - always-on = "opt-out"; - auto-away = "opt-out"; - enabled = true; - }; - registration = { - enabled = true; - allow-before-connect = true; - bcrypt-cost = 4; - email-verification = { - enabled = false; - }; - throttling = { - duration = "10m"; - enabled = true; - max-attempts = 30; - }; - }; - }; - channels = { - default-modes = "+ntC"; - registration = { - enabled = true; - }; - }; - datastore = { - autoupgrade = true; - path = "/var/lib/ergo/ircd.db"; - }; - history = { - enabled = true; - autoreplay-on-join = 0; - autoresize-window = "3d"; - channel-length = 2048; - chathistory-maxmessages = 100; - client-length = 256; - restrictions = { - expire-time = "1w"; - grace-period = "1h"; - query-cutoff = "none"; - }; - retention = { - allow-individual-delete = false; - enable-account-indexing = false; - }; - tagmsg-storage = { - default = false; - whitelist = [ - "+draft/react" - "+react" - ]; - }; - znc-maxmessages = 2048; - }; - limits = { - awaylen = 390; - channellen = 64; - identlen = 20; - kicklen = 390; - nicklen = 32; - topiclen = 390; - }; - network = { - name = "emilespace"; - }; - server = { - casemapping = "permissive"; - check-ident = false; - enforce-utf = true; - forward-confirm-hostnames = false; - ip-cloaking = { - enabled = false; - }; - ip-limits = { - count = false; - throttle = false; - }; - listeners = { - # sts only port - ":6667".sts-only = true; - - # loopback listeners - # "127.0.0.1:6668" = {}; - # "[::]:6668" = {}; - - ":${toString config.emile.ports.irc.ssl}" = { - tls = { - cert = "/run/credentials/ergochat.service/fullchain.pem"; - key = "/run/credentials/ergochat.service/key.pem"; - }; - - # for cloud load balancers setting a PROXY header, NOT reverse proxies... - proxy = false; - - min-tls-version = 1.2; - }; - }; - lookup-hostnames = false; - max-sendq = "1M"; - name = "emile.space"; - relaymsg = { - enabled = false; - }; - sts = { - enabled = true; # redirect from plain to tls if supported - - # how long clients should be forced to use TLS for. - # (Emile): no clue why, can I set something like \infty here? - duration = "12m"; - - }; - }; - logging = [ - { - method = "stderr"; - type = "* -userinput -useroutput"; - level = "debug"; - } - ]; - }; - }; + # security.acme.certs = { + # "irc.emile.space" = { + # webroot = "/var/lib/acme/acme-challenge/"; + # email = "acme@emile.space"; + # # postRun = "cp fullchain.pem /home/ergo/ && cp key.pem /home/ergo && chown ergo:ergo /home/ergo/*.pem && systemctl reload ergo.service"; + # }; + # }; + + # # Allow ergo to access the created cert + # # The systemd server runs using a dynamic user, so the below inserts the .pem files + # # into "/run/credentials/ergochat.service/key.pem" + # systemd.services.ergochat.serviceConfig = { + # LoadCredential = [ + # "fullchain.pem:/var/lib/acme/irc.emile.space/fullchain.pem" + # "key.pem:/var/lib/acme/irc.emile.space/key.pem" + # ]; + # }; + + # # allow connections to the port from the "outside" + # networking.firewall.allowedTCPPorts = [ config.emile.ports.irc.ssl ]; + + # services.ergochat = { + # enable = true; + + # # https://raw.githubusercontent.com/ergochat/ergo/master/default.yaml + # settings = { + # accounts = { + # authentication-enabled = true; + # multiclient = { + # allowed-by-default = true; + # always-on = "opt-out"; + # auto-away = "opt-out"; + # enabled = true; + # }; + # registration = { + # enabled = true; + # allow-before-connect = true; + # bcrypt-cost = 4; + # email-verification = { + # enabled = false; + # }; + # throttling = { + # duration = "10m"; + # enabled = true; + # max-attempts = 30; + # }; + # }; + # }; + # channels = { + # default-modes = "+ntC"; + # registration = { + # enabled = true; + # }; + # }; + # datastore = { + # autoupgrade = true; + # path = "/var/lib/ergo/ircd.db"; + # }; + # history = { + # enabled = true; + # autoreplay-on-join = 0; + # autoresize-window = "3d"; + # channel-length = 2048; + # chathistory-maxmessages = 100; + # client-length = 256; + # restrictions = { + # expire-time = "1w"; + # grace-period = "1h"; + # query-cutoff = "none"; + # }; + # retention = { + # allow-individual-delete = false; + # enable-account-indexing = false; + # }; + # tagmsg-storage = { + # default = false; + # whitelist = [ + # "+draft/react" + # "+react" + # ]; + # }; + # znc-maxmessages = 2048; + # }; + # limits = { + # awaylen = 390; + # channellen = 64; + # identlen = 20; + # kicklen = 390; + # nicklen = 32; + # topiclen = 390; + # }; + # network = { + # name = "emilespace"; + # }; + # server = { + # casemapping = "permissive"; + # check-ident = false; + # enforce-utf = true; + # forward-confirm-hostnames = false; + # ip-cloaking = { + # enabled = false; + # }; + # ip-limits = { + # count = false; + # throttle = false; + # }; + # listeners = { + # # sts only port + # ":6667".sts-only = true; + + # # loopback listeners + # # "127.0.0.1:6668" = {}; + # # "[::]:6668" = {}; + + # ":${toString config.emile.ports.irc.ssl}" = { + # tls = { + # cert = "/run/credentials/ergochat.service/fullchain.pem"; + # key = "/run/credentials/ergochat.service/key.pem"; + # }; + + # # for cloud load balancers setting a PROXY header, NOT reverse proxies... + # proxy = false; + + # min-tls-version = 1.2; + # }; + # }; + # lookup-hostnames = false; + # max-sendq = "1M"; + # name = "emile.space"; + # relaymsg = { + # enabled = false; + # }; + # sts = { + # enabled = true; # redirect from plain to tls if supported + + # # how long clients should be forced to use TLS for. + # # (Emile): no clue why, can I set something like \infty here? + # duration = "12m"; + + # }; + # }; + # logging = [ + # { + # method = "stderr"; + # type = "* -userinput -useroutput"; + # level = "debug"; + # } + # ]; + # }; + # }; } diff --git a/nix/hosts/corrino/www/loki.emile.space.nix b/nix/hosts/corrino/www/loki.emile.space.nix deleted file mode 100644 index e5bfe24..0000000 --- a/nix/hosts/corrino/www/loki.emile.space.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ config, ... }: - -{ - services = { - loki = { - enable = false; - configuration = { - auth_enabled = false; - server = { - http_listen_port = config.emile.ports.loki; - }; - - limits_config = { - reject_old_samples = false; - reject_old_samples_max_age = "7d"; - max_global_streams_per_user = 100000; - max_streams_per_user = 100000; - - retention_period = "10m"; - }; - - compactor = { - retention_enabled = true; - delete_request_store = "tsdb"; - }; - - common = { - instance_addr = "127.0.0.1"; - ring = { - instance_addr = "127.0.0.1"; - kvstore.store = "inmemory"; - }; - replication_factor = 1; - path_prefix = "/tmp/loki"; - }; - - # limits_config.allow_structured_metadata = false; - - schema_config.configs = [ - { - from = "2023-05-09"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - { - from = "2024-10-18"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - ]; - }; - }; - }; -} diff --git a/nix/hosts/corrino/www/mc.emile.space.nix b/nix/hosts/corrino/www/mc.emile.space.nix new file mode 100644 index 0000000..1a081bc --- /dev/null +++ b/nix/hosts/corrino/www/mc.emile.space.nix @@ -0,0 +1,153 @@ +{ config, pkgs, ... }: + +{ + services.minecraft-server = { + package = pkgs.minecraft-server; + serverProperties = { + server-port = 43000; + + # 0 peaceful + # 1 easy + # 2 normal + # 3 hard + difficulty = 1; + + # 0 survival + # 1 creative + # 2 adventure + # 5 default + # "spectator" spectator + # gamemode = "survival"; + gamemode = 0; + + max-players = 10; + motd = "Neurodivergenter Hexenzirkel"; + enable-rcon = true; + "rcon.password" = "hunter2"; + enable-command-block = false; + enable-query = false; + spawn-protection = 0; + + white-list = true; + }; + openFirewall = true; + + whitelist = { + "emileemail" = "a7614a53-b8b8-47b7-91cf-860e7c7f325f"; + "dodonator23" = "f93506b6-76e8-437d-927d-dceeb833a33f"; + "ChaosAyumi" = "223040ec-ca30-4238-8b58-c81597c30426"; + "xerunala" = "962e41c8-1da8-4592-9a2f-e36cdb20d5a6"; + "rappet" = "588377a5-362f-4ea1-8195-9cf97dd7a884"; + }; + + jvmOpts = "-Xms4092M -Xmx4092M"; + eula = true; + enable = true; + declarative = true; + dataDir = "/var/lib/minecraft"; + }; + + services.nginx.virtualHosts."mc.emile.space" = { + forceSSL = true; + enableACME = true; + }; + + services.bluemap = { + enable = true; + + enableNginx = true; + host = "mc.emile.space"; + + webappSettings = { + enabled = true; + webroot = config.services.bluemap.webRoot; + }; + + # webserverSettings = {}; + webserverSettings.enabled = false; # using nginx; + webRoot = "/var/lib/bluemap/web"; + + # coreSettings = {}; + coreSettings.data = "/var/lib/bluemap"; + coreSettings.metrics = false; # don't send data to the devs + + storage = { + "file" = { + root = "${config.services.bluemap.webRoot}/maps"; + }; + }; + # storage.<name>.storage-type + + maps = let + worldpath = "/var/lib/minecraft/world"; + in { + "overworld" = { + world = "${worldpath}"; + ambient-light = 0.1; + cave-detection-ocean-floor = -5; + dimension = "minecraft:overworld"; + }; + + "nether" = { + world = "${worldpath}/DIM-1"; + sorting = 100; + sky-color = "#290000"; + void-color = "#150000"; + ambient-light = 0.6; + world-sky-light = 0; + remove-caves-below-y = -10000; + cave-detection-ocean-floor = -5; + cave-detection-uses-block-light = true; + max-y = 90; + dimension = "minecraft:the_nether"; + }; + + "end" = { + world = "${worldpath}/DIM1"; + sorting = 200; + sky-color = "#080010"; + void-color = "#080010"; + ambient-light = 0.6; + world-sky-light = 0; + remove-caves-below-y = -10000; + cave-detection-ocean-floor = -5; + dimension = "minecraft:the_end"; + }; + }; + + # A set of resourcepacks, datapacks, and mods to extract resources from, loaded in alphabetical order. + packs = {}; + + # How often to trigger rendering the map, in the format of a systemd timer onCalendar configuration. See systemd.timer(5). + # + # This one means "every three hours": + # *-*-* */3:00:00 + onCalendar = "*-*-* *:00:00"; + + eula = true; + + enableRender = true; + + # The world used by the default map ruleset. If you configure your own maps you do not need to set this. + # defaultWorld = "${config.services.minecraft.dataDir}/world"; + + addons = {}; + }; + + services.restic.backups."corrino" = { + paths = [ "/var/lib/minecraft" ]; + }; + + services.restic.backups."minecraft" = { + repository = "/mnt/storagebox-bx11/minecraft"; + paths = [ "/var/lib/minecraft" ]; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; +} diff --git a/nix/hosts/corrino/www/md.emile.space.nix b/nix/hosts/corrino/www/md.emile.space.nix index 6088ea0..1ee46fd 100644 --- a/nix/hosts/corrino/www/md.emile.space.nix +++ b/nix/hosts/corrino/www/md.emile.space.nix @@ -6,18 +6,21 @@ enableACME = true; locations = { "/" = { - proxyPass = "http://127.0.0.1:${toString config.services.hedgedoc.settings.port}"; + proxyPass = "http://[${config.services.hedgedoc.settings.host}]:${toString config.services.hedgedoc.settings.port}"; }; }; }; + age.secrets.hedgedoc_oidc_client_secret.owner = "authelia-main"; + age.secrets.hedgedoc_oidc_client_secret.group = "authelia-main"; + # auth via authelia services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "HedgeDoc"; + client_id = "HedgeDoc"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$l4Kyec7Q9oY2GAhWA/xMig$P/MYFmulfgsDNyyiclUzd6le0oSiOvqCIvl4op5DkXtVTxLWlMA3ZwhJ6Z7u.OfIREuEM2htH6asxWPhBhkpNQ"; + client_secret = "{{ secret \"${config.age.secrets.hedgedoc_oidc_client_secret.path}\" }}"; public = false; authorization_policy = "two_factor"; redirect_uris = [ "https://md.emile.space/auth/oauth2/callback" ]; @@ -47,7 +50,7 @@ environmentFile = config.age.secrets.hedgedoc_environment_variables.path; settings = { - host = "127.0.0.1"; + host = "::1"; port = config.emile.ports.md; domain = "md.emile.space"; @@ -85,28 +88,20 @@ }; }; - # backups - # services.restic.backups."hedgedoc" = { - # user = "u331921"; - # timerConfig = { - # OnCalendar = "daily"; - # Persistent = true; - # }; - # # repository = "stfp:u331921@u331921.your-storagebox-de:23/restic"; - # repository = "/mnt/storagebox-bx11/backup/hedgedoc"; - # initialize = true; # initializes the repo, don't set if you want manual control - # passwordFile = config.age.secrets.restic_password.path; - # paths = [ "/var/lib/hedgedoc/" ]; - # pruneOpts = [ - # "--keep-daily 7" - # "--keep-weekly 5" - # "--keep-monthly 12" - # "--keep-yearly 75" - # ]; - - # # extraOpts = [ - # # "sftp.command='ssh backup@192.168.1.100 -i /home/user/.ssh/id_rsa -s sftp'" - # # ]; - # }; + services.restic.backups."corrino" = { + paths = [ "/var/lib/hedgedoc" ]; + }; + services.restic.backups."hedgedoc" = { + repository = "/mnt/storagebox-bx11/hedgedoc"; + paths = [ "/var/lib/hedgedoc" ]; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; } diff --git a/nix/hosts/corrino/www/miniflux.emile.space.nix b/nix/hosts/corrino/www/miniflux.emile.space.nix new file mode 100644 index 0000000..90cb8f2 --- /dev/null +++ b/nix/hosts/corrino/www/miniflux.emile.space.nix @@ -0,0 +1,81 @@ +{ config, pkgs, ... }: + +{ + services.nginx.virtualHosts."miniflux.emile.space" = { + forceSSL = true; + enableACME = true; + locations = { + "/" = { + proxyPass = "http://${config.services.miniflux.config.LISTEN_ADDR}"; + }; + }; + }; + + # oidc not working and I can't bother to continue debugging it now + # + # Apr 12 15:37:38 corrino authelia[3693799]: {"level":"error","method":"POST","msg":"Access Request failed with error: Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The request was determined to be using 'token_endpoint_auth_method' method 'none', however the OAuth 2.0 client registration does not allow this method. The registered client with id 'miniflux' is configured to only support 'token_endpoint_auth_method' method 'client_secret_basic'. Either the Authorization Server client registration will need to have the 'token_endpoint_auth_method' updated to 'none' or the Relying Party will need to be configured to use 'client_secret_basic'. + # + # age.secrets.miniflux_oidc_client_secret.owner = "authelia-main"; + # age.secrets.miniflux_oidc_client_secret.group = "authelia-main"; + # + # auth via authelia + # services.authelia.instances.main.settings.identity_providers.oidc.clients = [ + # { + # client_id = "miniflux"; + + # # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + # client_secret = "{{ secret \"${config.age.secrets.miniflux_oidc_client_secret.path}\" }}"; + # public = false; + # authorization_policy = "two_factor"; + # redirect_uris = [ "https://miniflux.emile.space/oauth2/oidc/callback" ]; + # scopes = [ + # "openid" + # "email" + # "profile" + # ]; + # # grant_types = [ + # # "refresh_token" + # # "authorization_code" + # # ]; + # # response_types = [ "code" ]; + # # response_modes = [ + # # "form_post" + # # "query" + # # "fragment" + # # ]; + # # token_endpoint_auth_method = "client_secret_post"; + # # token_endpoint_auth_method = "none"; + # } + # ]; + + services.miniflux = { + enable = true; + package = pkgs.miniflux; + config = { + LISTEN_ADDR = "[::1]:${toString config.emile.ports.miniflux}"; + BASE_URL = "https://miniflux.emile.space"; + + # Cleanup job frequency to remove old sessions and archive entries. + CLEANUP_FREQUENCY = 48; + + # Set to 1 to enable maintenance mode. Maintenance mode disables the web ui and show a text message to the users. + # MAINTENANCE_MODE = 1; + # MAINTENANCE_MESSAGE = "updating foo"; + + # DISABLE_LOCAL_AUTH = "true"; + # OAUTH2_CLIENT_ID = "miniflux"; + # OAUTH2_USER_CREATION = 1; + # OAUTH2_CLIENT_SECRET_FILE = config.age.secrets.miniflux_oidc_secret.path; + # OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://sso.emile.space"; + # OAUTH2_OIDC_PROVIDER_NAME = "authelia"; + # OAUTH2_PROVIDER = "oidc"; + # OAUTH2_REDIRECT_URL = "https://miniflux.emile.space/oauth2/oidc/callback"; + + LOG_LEVEL = "debug"; + }; + createDatabaseLocally = true; + + # File containing the ADMIN_USERNAME and ADMIN_PASSWORD (length >= 6) in the format of an EnvironmentFile=, as described by systemd.exec(5). + adminCredentialsFile = config.age.secrets.miniflux_admin_file.path; + }; +} diff --git a/nix/hosts/corrino/www/photo/immich.nix b/nix/hosts/corrino/www/photo/immich.nix index 92a3a64..3e1bf48 100644 --- a/nix/hosts/corrino/www/photo/immich.nix +++ b/nix/hosts/corrino/www/photo/immich.nix @@ -6,6 +6,15 @@ forceSSL = true; enableACME = true; locations = { + # # immich private proxy + # "/share" = { + # proxyPass = "http://${config.services.immich.host}:${toString config.services.immich-public-proxy.port}"; + # }; + # "/share/*" = { + # proxyPass = "http://${config.services.immich.host}:${toString config.services.immich-public-proxy.port}"; + # }; + + # immich "/" = { proxyPass = "http://${config.services.immich.host}:${toString config.services.immich.port}"; proxyWebsockets = true; @@ -13,13 +22,17 @@ }; }; + age.secrets.immich_oidc_client_secret.owner = "authelia-main"; + age.secrets.immich_oidc_client_secret.group = "authelia-main"; + # auth via authelia services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "Immich"; + client_id = "Immich"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$iCgyAKjoYH9UKADProvbgw$LjrYkX1MjjtSXWDkxDjyp3NkLLuLVvKVwy3o8/Rw.8Z8b6yCkPWdBCothuCMlaGcgfG/zLWM6lRV4BrXVZpkig"; + client_secret = "{{ secret \"${config.age.secrets.immich_oidc_client_secret.path}\" }}"; + public = false; authorization_policy = "two_factor"; redirect_uris = [ @@ -43,15 +56,14 @@ # "fragment" #]; - token_endpoint_auth_method = "client_secret_basic"; + # token_endpoint_auth_method = "client_secret_basic"; # might be needed since the upgrade to nixos-24.11 and the resulting # 4.37.5 -> 4.38.17 upgrade - # token_endpoint_auth_method = "client_secret_post"; + token_endpoint_auth_method = "client_secret_post"; } ]; - services.immich = { enable = true; package = pkgs.immich; @@ -59,7 +71,7 @@ secretsFile = config.age.secrets.immich_secrets_file.path; host = "127.0.0.1"; - port = config.emile.ports.immich; + port = config.emile.ports.photo.immich; machine-learning = { enable = false; @@ -68,4 +80,19 @@ }; }; }; + + # services.immich-public-proxy = { + # enable = true; + # package = pkgs.immich-public-proxy; + # settings = { + # downloadOriginalPhoto = true; + # showGalleryTitle = true; + # allowDownloadAll = 1; + # showHomePage = true; + # showMetadata = true; + # }; + # port = config.emile.ports.photo.immich-public-proxy; + # openFirewall = false; + # immichUrl = "photo.emile.space"; + # }; } diff --git a/nix/hosts/corrino/www/prometheus.emile.space.nix b/nix/hosts/corrino/www/prometheus.emile.space.nix index 898f3b2..ec13dfa 100644 --- a/nix/hosts/corrino/www/prometheus.emile.space.nix +++ b/nix/hosts/corrino/www/prometheus.emile.space.nix @@ -38,15 +38,43 @@ enable = true; port = config.emile.ports.prometheus.exporter.nginx; }; + restic = { + enable = true; + # repository = "sftp:u331921@u331921.your-storagebox.de:/home/backup"; + repository = "/mnt/storagebox-bx11/corrino"; + port = config.emile.ports.prometheus.exporter.restic; + passwordFile = config.age.secrets.restic_password.path; + }; }; scrapeConfigs = [ { job_name = "corrino"; static_configs = [ - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" ]; } - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.systemd.port}" ]; } - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.smartctl.port}" ]; } - { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" ]; } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.systemd.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.smartctl.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" + ]; + } + { + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.restic.port}" + ]; + } ]; } { diff --git a/nix/hosts/corrino/www/promtail.emile.space.nix b/nix/hosts/corrino/www/promtail.emile.space.nix deleted file mode 100644 index 654414c..0000000 --- a/nix/hosts/corrino/www/promtail.emile.space.nix +++ /dev/null @@ -1,114 +0,0 @@ -{ config, ... }: - -{ - # allow the promtail user to read the nginx access files - users.users.promtail.extraGroups = [ "nginx" ]; - - services = { - promtail = { - enable = true; - configuration = { - server = { - http_listen_port = config.emile.ports.promtail; - grpc_listen_port = 0; - }; - positions.filename = "/tmp/positions.yml"; - clients = [{ - url = "http://localhost:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push"; - }]; - scrape_configs = [ - - # systemd - { - job_name = "journal"; - journal = { - max_age = "12h"; - labels = { - job = "systemd-journal"; - host = config.networking.hostName; - }; - }; - relabel_configs = [ - { - source_labels = [ "__journal__systemd_unit" ]; - target_label = "unit"; - } - ]; - } - - # nginx error log - { - job_name = "nginx-error-logs"; - static_configs = [{ - targets = [ "localhost" ]; - labels = { - job = "nginx-error-logs"; - host = "corrino"; - __path__ = "/var/log/nginx/*error.log"; - }; - }]; - } - - # nginx - { - job_name = "nginx"; - static_configs = [ - { - targets = [ "localhost" ]; - labels = { - job = "nginx"; - host = "corrino"; - __path__ = "/var/log/nginx/*access.log"; - }; - } - ]; - pipeline_stages = [ - # { - # regex = { - # expression = "(?:[0-9]{1,3}\.){3}([0-9]{1,3})"; - # replace = "***"; - # }; - # } - { - regex = { - expression = ''(?P<remote_addr>.+) - - \[(?P<time_local>.+)\] "(?P<method>.+) (?P<url>.+) (HTTP\/(?P<version>\d.\d))" (?P<status>\d{3}) (?P<body_bytes_sent>\d+) (["](?P<http_referer>(\-)|(.+))["]) (["](?P<http_user_agent>.+)["])''; - }; - } - { - labels = { - remote_addr = null; - time_local = null; - method = null; - url = null; - status = null; - body_bytes_sent = null; - http_referer = null; - http_user_agent = null; - }; - } - { - timestamp = { - source = "time_local"; - format = "02/Jan/2006:15:04:05 -0700"; - }; - } - { - drop = { - source = "url"; - expression = ''/(_matrix|.well-known|notifications|api|identity).*''; - }; - } - { - drop = { - source = "url"; - expression = ''grafana.*''; - }; - } - ]; - } - - ]; - }; - }; - }; -} diff --git a/nix/hosts/corrino/www/s3.emile.space.nix b/nix/hosts/corrino/www/s3.emile.space.nix index b4646ad..ae33542 100644 --- a/nix/hosts/corrino/www/s3.emile.space.nix +++ b/nix/hosts/corrino/www/s3.emile.space.nix @@ -1,12 +1,21 @@ -{ config, ... }: +{ config, pkgs, ... }: { + security.acme.certs."s3.emile.space" = { + group = "nginx"; + domain = "s3.emile.space"; + extraDomainNames = [ + "*.s3.emile.space" + "*.s3-web.emile.space" + ]; + }; + services.nginx.virtualHosts."s3.emile.space" = { forceSSL = true; enableACME = true; locations = { "/" = { - proxyPass = "http://[::1]:${toString config.emile.ports.minio.s3}"; + proxyPass = "http://[::1]:${toString config.emile.ports.garage.s3}"; }; }; }; @@ -16,24 +25,96 @@ enableACME = true; locations = { "/" = { - proxyPass = "http://[::1]:${toString config.emile.ports.minio.web}"; + proxyPass = "http://[::1]:${toString config.emile.ports.garage.web}"; }; }; }; - services.minio = { + services.garage = { enable = true; - region = "eu-north-1-hel-1a"; # corrino is in the helsinki hetzner dc + package = pkgs.garage_1_x; + settings = { + data_dir = [ + { capacity = "50G"; path = "/var/lib/garage/data"; } + ]; - listenAddress = "[::1]:${toString config.emile.ports.minio.s3}"; + db_engine = "sqlite"; + replication_factor = 3; - browser = true; - consoleAddress = "[::1]:${toString config.emile.ports.minio.web}"; + s3_api = { + s3_region = "garage"; + api_bind_addr = "[::]:${toString config.emile.ports.garage.s3}"; + root_domain = "s3.emile.space"; + }; + s3_web = { + bind_addr = "[::]:${toString config.emile.ports.garage.web}"; + root_domain = "s3-web.emile.space"; + index = "index.html"; + }; + admin = { + api_bind_addr = "[::]:${toString config.emile.ports.garage.admin}"; + # metrics_token = config.age.secrets.garage_admin_metrics_secret.path; + # admin_token = config.age.secrets.garage_admin_token_secret.path; + }; - dataDir = [ "/minio/data" ]; - configDir = "/minio/config"; + # rpc_secret_file = config.age.secrets.garage_rpc_secret.path; + rpc_bind_addr = "[::]:${toString config.emile.ports.garage.rpc}"; + rpc_bind_outgoing = false; + rpc_public_addr = "[fc00:1::1]:${toString config.emile.ports.garage.rpc}"; + }; - rootCredentialsFile = config.age.secrets.minio_root_credz.path; - # accessKey + environmentFile = config.age.secrets.garage_env.path; }; +# metrics_token = config.age.secrets.garage_admin_metrics_secret.path; +# admin_token = config.age.secrets.garage_admin_token_secret.path; +# rpc_secret_file = config.age.secrets.garage_rpc_secret.path; + +# nix/hosts/corrino/secrets/garage_admin_metrics_secret.age +# nix/hosts/corrino/secrets/garage_admin_token_secret.age +# nix/hosts/corrino/secrets/garage_admin_token.age +# nix/hosts/corrino/secrets/garage_metrics_token.age +# nix/hosts/corrino/secrets/garage_rpc_secret.age + + # services.garage = { + # enable = true; + # package = pkgs.garage_1_x; + # settings = { + # db_engine = "sqlite"; + # replication_factor = 2; + + # data_dir = [ + # { capacity = "50G"; path = dataDir; } + # ]; + + # compression_level = 1; + + # rpc_secret_file = config.age.secrets.garage_rpc_secret.path; + # rpc_bind_addr = "[::]:${toString config.emile.ports.garage.rpc}"; + # rpc_bind_outgoing = false; + # rpc_public_addr = "[fc00:1::1]:${toString config.emile.ports.garage.rpc}"; + + # allow_world_readable_secrets = false; + + # s3_api = { + # api_bind_addr = "[::]:${toString config.emile.ports.garage.s3}"; + # s3_region = "garage"; + # root_domain = "s3.emile.space"; + # }; + + # s3_web = { + # bind_addr = "[::]:${toString config.emile.ports.garage.web}"; + # root_domain = "s3-web.emile.space"; + # add_host_to_metrics = true; + # }; + + # admin = { + # api_bind_addr = "[::]:${toString config.emile.ports.garage.admin}"; + # metrics_token = config.age.secrets.garage_admin_metrics_secret.path; + # admin_token = config.age.secrets.garage_admin_token_secret.path; + # trace_sink = "http://localhost:4317"; + # }; + + # }; + # logLevel = "trace"; # info + # }; } diff --git a/nix/hosts/corrino/www/social.emile.space.nix b/nix/hosts/corrino/www/social.emile.space.nix index 210f0be..d9d30f7 100644 --- a/nix/hosts/corrino/www/social.emile.space.nix +++ b/nix/hosts/corrino/www/social.emile.space.nix @@ -38,13 +38,17 @@ }; }; + age.secrets.gotosocial_oidc_client_secret.owner = "authelia-main"; + age.secrets.gotosocial_oidc_client_secret.group = "authelia-main"; + # auth via authelia services.authelia.instances.main.settings.identity_providers.oidc.clients = [ { - id = "gotosocial"; + client_id = "gotosocial"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$oDpZ5FuO965TbjPoophJXw$dbkAwWFvLN1h1Zh9US2ZOE5ilPRdEHMdGF/x0uorou2UqURrXF0KQmXxsV38F2yYMS7u/ecramKlvfMwsqHOcg"; + client_secret = "{{ secret \"${config.age.secrets.gotosocial_oidc_client_secret.path}\" }}"; + public = false; authorization_policy = "two_factor"; redirect_uris = [ "https://social.emile.space/auth/callback" ]; @@ -93,4 +97,21 @@ Restart = "on-failure"; }; }; + + services.restic.backups."corrino" = { + paths = [ "/var/lib/gotosocial" ]; + }; + + services.restic.backups."gotosocial" = { + repository = "/mnt/storagebox-bx11/gotosocial"; + paths = [ "/var/lib/gotosocial" ]; + passwordFile = config.age.secrets.restic_password.path; + initialize = true; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; } diff --git a/nix/hosts/corrino/www/sso.emile.space.nix b/nix/hosts/corrino/www/sso.emile.space.nix index 44e30bb..6ffff80 100644 --- a/nix/hosts/corrino/www/sso.emile.space.nix +++ b/nix/hosts/corrino/www/sso.emile.space.nix @@ -141,9 +141,22 @@ in storage.local.path = "/var/lib/authelia-main/db.sqlite"; session = { - domain = "sso.emile.space"; - expiration = 3600; # 1 hour - inactivity = 300; # 5 minutes + # domain = "sso.emile.space"; + # expiration = 3600; # 1 hour + # inactivity = 300; # 5 minutes + + cookies = [ + { + domain = "emile.space"; + authelia_url = "https://sso.emile.space"; + # The period of time the user can be inactive for until the session is destroyed. Useful if you want long session timers but don’t want unused devices to be vulnerable. + inactivity = "1h"; + # The period of time before the cookie expires and the session is destroyed. This is overridden by remember_me when the remember me box is checked. + expiration = "1d"; + # The period of time before the cookie expires and the session is destroyed when the remember me box is checked. Setting this to -1 disables this feature entirely for this session cookie domain + remember_me = "3M"; + } + ]; }; notifier = { @@ -196,6 +209,16 @@ in default_policy = "deny"; rules = [ { + # silverbullet needs access to these without auth + domain = "sb.emile.space"; + policy = "bypass"; + resources = [ + "/.client/manifest.json$" + "/.client/[a-zA-Z0-9_-]+.png$" + "/service_worker.js$" + ]; + } + { domain = "*.emile.space"; policy = "two_factor"; } diff --git a/nix/hosts/corrino/www/templates/goapp/default.nix b/nix/hosts/corrino/www/templates/goapp/default.nix deleted file mode 100644 index 716d6ab..0000000 --- a/nix/hosts/corrino/www/templates/goapp/default.nix +++ /dev/null @@ -1,30 +0,0 @@ - -{ - services.authelia.instances.main.settings.identity_providers.oidc.clients = [ - { - id = "goapp"; - - # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$WUai4pp1ZVJDrJ8j6ICLiQ$NOMMaCZ3gt.x.a09MWatMkJWQIaH0QeWgRXSbuD2iWRwR.N6MWmJA6QO.LIKcxn6l.zHZN4bO1Ztsrbo9010Tw"; - public = false; - authorization_policy = "two_factor"; - redirect_uris = [ "https://127.0.0.1:8080/auth/oauth2/callback" ]; - scopes = [ - "openid" - "email" - "profile" - ]; - grant_types = [ - "refresh_token" - "authorization_code" - ]; - response_types = [ "code" ]; - response_modes = [ - "form_post" - "query" - "fragment" - ]; - token_endpoint_auth_method = "client_secret_post"; - } - ]; -} diff --git a/nix/hosts/corrino/www/tickets.emile.space.nix b/nix/hosts/corrino/www/tickets.emile.space.nix index fb12961..08f23d3 100644 --- a/nix/hosts/corrino/www/tickets.emile.space.nix +++ b/nix/hosts/corrino/www/tickets.emile.space.nix @@ -18,7 +18,7 @@ enable = true; package = pkgs.pretix; plugins = with config.services.pretix.package.plugins; [ - passbook + # passbook pages ]; user = "pretix"; diff --git a/nix/hosts/lampadas/configuration.nix b/nix/hosts/lampadas/configuration.nix index cc829d8..d2630a8 100644 --- a/nix/hosts/lampadas/configuration.nix +++ b/nix/hosts/lampadas/configuration.nix @@ -2,7 +2,7 @@ # your system. Help is available in the configuration.nix(5) man page, on # https://search.nixos.org/options and in the NixOS manual (`nixos-help`). -{ pkgs, lib, ... }: +{ config, pkgs, lib, ... }: let emile_keys = [ @@ -17,12 +17,34 @@ in ./hardware-configuration.nix ]; + hardware.fancontrol = { + enable = true; + config = '' + # Configuration file generated by pwmconfig, changes will be lost + INTERVAL=10 + DEVPATH=hwmon0=devices/platform/coretemp.0 hwmon1=devices/platform/nct6775.672 + DEVNAME=hwmon0=coretemp hwmon1=nct6798 + FCTEMPS=hwmon1/pwm3=hwmon0/temp2_input hwmon1/pwm2=hwmon1/temp2_input + FCFANS=hwmon1/pwm3=hwmon1/fan3_input hwmon1/pwm2=hwmon1/fan2_input + MINTEMP=hwmon1/pwm3=35 hwmon1/pwm2=35 + MAXTEMP=hwmon1/pwm3=75 hwmon1/pwm2=75 + MINSTART=hwmon1/pwm3=255 hwmon1/pwm2=255 + MINSTOP=hwmon1/pwm3=30 hwmon1/pwm2=30 + MINPWM=hwmon1/pwm3=30 hwmon1/pwm2=30 + MAXPWM=hwmon1/pwm3=255 hwmon1/pwm2=255 + ''; + }; + boot = { loader = { systemd-boot.enable = true; efi.canTouchEfiVariables = true; }; kernelParams = [ "ip=dhcp" ]; + kernelModules = [ + # fan speed modules, detected using `sensors-detect` + "coretemp" "nct6775" + ]; initrd = { availableKernelModules = [ "r8169" ]; systemd.users.root.shell = "/bin/cryptsetup-askpass"; @@ -159,10 +181,41 @@ in }; # metric exporters - prometheus.exporters = { - node.enable = true; # port 9100 - systemd.enable = true; # port 9558 - smartctl.enable = true; # port 9633 + prometheus = { + enable = true; + port = 9090; + listenAddress = "100.87.209.97"; + scrapeConfigs = [ + { + job_name = "node"; + static_configs = [{ + targets = [ + "localhost:${toString config.services.prometheus.exporters.node.port}" + ]; + }]; + } + { + job_name = "systemd"; + static_configs = [{ + targets = [ + "localhost:${toString config.services.prometheus.exporters.systemd.port}" + ]; + }]; + } + { + job_name = "smartctl"; + static_configs = [{ + targets = [ + "localhost:${toString config.services.prometheus.exporters.smartctl.port}" + ]; + }]; + } + ]; + exporters = { + node.enable = true; # port 9100 + systemd.enable = true; # port 9558 + smartctl.enable = true; # port 9633 + }; }; # shares @@ -177,7 +230,6 @@ in openFirewall = true; settings = { global = { - ## Browsing/Identification ### "workgroup" = "Pacific"; "server string" = "lampadas"; @@ -269,18 +321,6 @@ in "force user" = "emile"; "guest ok" = "no"; "read only" = "no"; - - # "fruit:aapl" = "yes"; - # "fruit:copyfile" = "yes"; - # "fruit:delete_empty_adfiles" = "yes"; - # "fruit:metadata" = "stream"; - # "fruit:posix_rename" = "yes"; - # "fruit:time machine" = "yes"; - # "fruit:veto_appledouble" = "no"; - # "fruit:wipe_intentionally_left_blank_rfork" = "yes"; - # "fruit:nfs_aces" = "no"; - # "fruit:zero_file_id" = "yes"; - # "fruit:encoding" = "native"; }; public = { diff --git a/nix/lib/flake-helper.nix b/nix/lib/flake-helper.nix index ddace97..e58e8b1 100644 --- a/nix/lib/flake-helper.nix +++ b/nix/lib/flake-helper.nix @@ -6,6 +6,8 @@ deploy-rs, home-manager, darwin, + flake-utils, + pwndbg, ... }@inputs: @@ -65,7 +67,7 @@ rec { if system == "x86_64-linux" then self.nixosModules.x86_64-linux else if system == "aarch64-darwin" then - ({ }) + { } else null ) @@ -83,17 +85,24 @@ rec { { ... }: { nixpkgs.overlays = [ - self.overlays.emile - ( if system == "x86_64-linux" then self.overlays.x86_64-linux else if system == "aarch64-darwin" then self.overlays.aarch64-darwin + # // self.overlays.unstable-darwin + # {} else null ) + # no clue why, but when rebuilding corrino and this not being commented, + # something in the hardware.bluetooth module breaks + # + # (if system == "aarch64-darwin" + # then self.overlays.unstable-darwin + # else null) + (_: _: { inherit (agenix.packages."x86_64-linux") agenix; }) (_: _: { @@ -197,8 +206,12 @@ rec { user = "root"; # user to install as sshUser = sshUser; # user to ssh to as - # make sure people can use sudo - sshOpts = ["-A" "-t" "-S"]; + # make sure people can use sudo + sshOpts = [ + "-A" + "-t" + "-S" + ]; # sshOpts = [ "-o" "ProxyCommand=none" ]; # make sure to add the nix foo on the darwin hosts to ~/.zshenv @@ -233,4 +246,35 @@ rec { # don't build hosts that start with an underscore (nixpkgs.lib.filterAttrs (name: host: (builtins.substring 0 1 name) != "_") hosts); + + # A function taking an attribute set of flake templates, importing their + # flake.nix/output/packages (if there are any) and returning an attribute set + # of their packages (if the template has one or more) + template-packages = + builtins.mapAttrs (name: value: + (((import ../../nix/templates/${name}/flake.nix).outputs) + { inherit nixpkgs flake-utils pwndbg; }) + .packages or { } + ); + + # TODO(emile): templates + # apply the above function to the templates + # templates = template-packages self.templates; + + # TODO(emile): templates + # Merge template packages into root packages with template prefix + # merged-template-packages = + # system: + # let + # lib = nixpkgs.lib; + # in + # lib.foldl ( + # acc: tplName: + # let + # tplPkgs = templates.${tplName}.${system} or { }; + # prefixed = lib.mapAttrs' (pkgName: pkg: lib.nameValuePair "${tplName}-${pkgName}" pkg) tplPkgs; + # in + # acc // prefixed + # ) { } (builtins.attrNames templates); + } diff --git a/nix/modules/goapp-frontend/default.nix b/nix/modules/goapp-frontend/default.nix new file mode 100644 index 0000000..c5f62aa --- /dev/null +++ b/nix/modules/goapp-frontend/default.nix @@ -0,0 +1,134 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.emile.goapp-frontend; +in +with lib; +{ + options.services.emile.goapp-frontend = { + enable = mkEnableOption "Enable goapp-frontend"; + package = mkPackageOption pkgs "goapp-frontend" { }; + + # ip, port and external host to listen on + host = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "0.0.0.0"; + description = "The host the service listens on"; + }; + port = mkOption { + type = types.int; + default = 8080; + example = 8080; + description = "The port the service listens on"; + }; + public-url = mkOption { + type = types.str; + default = "http://localhost:8080/"; + example = "https://goapp.emile.space/"; + description = '' + The domain that the service can be reached from externally. This is used by oidc for redirects and thus should be set, as you'll probably be running this behind some kind of reverse proxy. + ''; + }; + + # the oidc config + oidc = mkOption { + type = types.submodule { + options = { + id = mkOption { + type = types.str; + default = ""; + example = "AiliavahweiweeG5"; + description = "The oidc id"; + }; + issuer = mkOption { + type = types.str; + default = ""; + example = "https://sso.emile.space"; + description = "The oidc identity provider"; + }; + cookie-name = mkOption { + type = types.str; + default = "oidc-client"; + example = "CookieMcCookieface"; + description = "The oidc cookie name"; + }; + scopes = mkOption { + type = types.listOf types.str; + default = [ "openid" "profile" "email" "groups" ]; + example = [ "openid" "profile" "email" ]; + description = "The openid scopes to request"; + }; + secret-path = mkOption { + type = types.str; + default = ""; + example = "/run/goapp_oidc_secret"; + description = "The path to the oidc secret"; + }; + }; + }; + }; + + # paths to files + session-key-path = mkOption { + type = types.str; + default = ""; + example = "/run/sesionkey"; + description = "The path to a file containing the sessionKey"; + }; + logfile-path = mkOption { + type = types.str; + default = "/var/log/goapp-frontend.log"; + example = "/var/log/goapp-frontend.log"; + description = "The path to where the logfile should be written"; + }; + + database-path = mkOption { + type = types.str; + default = "/var/lib/goapp-frontend/main.db"; + example = "/var/lib/goapp-frontend/main.db"; + description = "The path to the main database"; + }; + sessiondb-path = mkOption { + type = types.str; + default = "/var/lib/goapp-frontend/sessions.db"; + example = "/var/lib/goapp-frontend/sessions.db"; + description = "The path to the sessions database"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.goapp-frontend = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + RestartSec = 5; + Restart = "on-failure"; + }; + environment = { + VERSION = pkgs.goapp-frontend.version; + }; + path = [ pkgs.goapp-frontend ]; + serviceConfig.ExecStart = '' + ${pkgs.goapp-frontend}/bin/frontend \ + --host ${cfg.host} \ + --port ${toString cfg.port} \ + --public-url ${cfg.public-url} \ + --id ${cfg.oidc.id} \ + --issuer ${cfg.oidc.issuer} \ + --cookie-name ${cfg.oidc.cookie-name} \ + --scopes ${concatStringsSep "," cfg.oidc.scopes} \ + --oidc-secret-path ${cfg.oidc.secret-path} \ + --logfilepath ${cfg.logfile-path} \ + --databasepath ${cfg.database-path} \ + --sessiondbpath ${cfg.sessiondb-path} \ + --sessionkeypath ${cfg.session-key-path} \ + --templatespath ${pkgs.goapp-frontend}/templates + ''; + }; + }; +} diff --git a/nix/modules/libvirtnix/a.xml b/nix/modules/libvirtnix/a.xml new file mode 100644 index 0000000..1255ad4 --- /dev/null +++ b/nix/modules/libvirtnix/a.xml @@ -0,0 +1,259 @@ +<domain type='kvm' id='5'> + <name>fileserver2</name> + <uuid>d62e0276-d474-452b-80f4-c951c39bcf74</uuid> + <metadata> + <libosinfo:libosinfo xmlns:libosinfo='http://libosinfo.org/xmlns/libvirt/domain/1.0'> + <libosinfo:os id='http://nixos.org/nixos/unknown'/> + </libosinfo:libosinfo> + </metadata> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static'>3</vcpu> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch='x86_64' machine='pc-q35-3.1'>hvm</type> + <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> + <nvram>/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd</nvram> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + <vmport state='off'/> + </features> + <cpu mode='host-passthrough' check='none' migratable='on'/> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <pm> + <suspend-to-mem enabled='no'/> + <suspend-to-disk enabled='no'/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='block' device='disk'> + <driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/> + <source dev='/dev/vmstorage/fileserver2' index='3'/> + <backingStore/> + <target dev='vda' bus='virtio'/> + <alias name='virtio-disk0'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </disk> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/mapper/storage1' index='2'/> + <backingStore/> + <target dev='vdb' bus='virtio'/> + <alias name='virtio-disk1'/> + <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/> + </disk> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/mapper/storage2' index='1'/> + <backingStore/> + <target dev='vdc' bus='virtio'/> + <alias name='virtio-disk2'/> + <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/> + </disk> + <controller type='usb' index='0' model='qemu-xhci' ports='15'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='0' model='pcie-root'> + <alias name='pcie.0'/> + </controller> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <alias name='pci.1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x11'/> + <alias name='pci.2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0x12'/> + <alias name='pci.3'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='4' port='0x13'/> + <alias name='pci.4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='5' port='0x14'/> + <alias name='pci.5'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='6' port='0x15'/> + <alias name='pci.6'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/> + </controller> + <controller type='pci' index='7' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='7' port='0x16'/> + <alias name='pci.7'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x6'/> + </controller> + <controller type='pci' index='8' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='8' port='0x17'/> + <alias name='pci.8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x7'/> + </controller> + <controller type='pci' index='9' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='9' port='0x18'/> + <alias name='pci.9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='10' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='10' port='0x19'/> + <alias name='pci.10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x1'/> + </controller> + <controller type='pci' index='11' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='11' port='0x1a'/> + <alias name='pci.11'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x2'/> + </controller> + <controller type='pci' index='12' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='12' port='0x1b'/> + <alias name='pci.12'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x3'/> + </controller> + <controller type='pci' index='13' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='13' port='0x1c'/> + <alias name='pci.13'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x4'/> + </controller> + <controller type='pci' index='14' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='14' port='0x1d'/> + <alias name='pci.14'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x5'/> + </controller> + <controller type='pci' index='15' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='15' port='0x1e'/> + <alias name='pci.15'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x6'/> + </controller> + <controller type='pci' index='16' model='pcie-to-pci-bridge'> + <model name='pcie-pci-bridge'/> + <alias name='pci.16'/> + <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <alias name='ide'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='virtio-serial' index='0'> + <alias name='virtio-serial0'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </controller> + <controller type='scsi' index='0' model='lsilogic'> + <alias name='scsi0'/> + <address type='pci' domain='0x0000' bus='0x10' slot='0x01' function='0x0'/> + </controller> + <interface type='bridge'> + <mac address='52:54:00:bf:ba:88'/> + <source network='services' portid='6c3a3512-d823-4521-9043-3a91a65682f5' bridge='br7'/> + <target dev='vnet2'/> + <model type='virtio'/> + <alias name='net0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </interface> + <serial type='pty'> + <source path='/dev/pts/3'/> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + <alias name='serial0'/> + </serial> + <console type='pty' tty='/dev/pts/3'> + <source path='/dev/pts/3'/> + <target type='serial' port='0'/> + <alias name='serial0'/> + </console> + <channel type='unix'> + <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/domain-5-fileserver2/org.qemu.guest_agent.0'/> + <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/> + <alias name='channel0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0' state='disconnected'/> + <alias name='channel1'/> + <address type='virtio-serial' controller='0' bus='0' port='2'/> + </channel> + <input type='tablet' bus='usb'> + <alias name='input0'/> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='ps2'> + <alias name='input1'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input2'/> + </input> + <graphics type='spice' port='5901' autoport='yes' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <sound model='ich9'> + <alias name='sound0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + </sound> + <audio id='1' type='spice'/> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> + <alias name='video0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </video> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir0'/> + <address type='usb' bus='0' port='2'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir1'/> + <address type='usb' bus='0' port='3'/> + </redirdev> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <backend model='random'>/dev/urandom</backend> + <alias name='rng0'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/> + </rng> + </devices> + <seclabel type='dynamic' model='apparmor' relabel='yes'> + <label>libvirt-d62e0276-d474-452b-80f4-c951c39bcf74</label> + <imagelabel>libvirt-d62e0276-d474-452b-80f4-c951c39bcf74</imagelabel> + </seclabel> + <seclabel type='dynamic' model='dac' relabel='yes'> + <label>+109:+115</label> + <imagelabel>+109:+115</imagelabel> + </seclabel> +</domain> diff --git a/nix/modules/libvirtnix/b.xml b/nix/modules/libvirtnix/b.xml new file mode 100644 index 0000000..311e7d5 --- /dev/null +++ b/nix/modules/libvirtnix/b.xml @@ -0,0 +1,183 @@ +<domain type="kvm" id="1337"> + <name>blub</name> + <uuid>cafebabe-d474-452b-80f4-c951c39bcf74</uuid> + <metadata> + <libosinfo:libosinfo xmlns:libosinfo="https://libosinfo.org/xmlns/libvirt/domain/1.0"> + <libosinfo:os id="https://nixos.org/nixos/unknown"/> + </libosinfo:libosinfo> + </metadata> + <memory unit="KiB">2097152</memory> + <currentMemory unit="KiB">2097152</currentMemory> + <vcpu placement="static">3</vcpu> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch="x86_64" machine="pc-q35-3.1">hvm</type> + <loader readonly="yes" pflash="pflash">/usr/share/OVMF/OVMF_CODE.fd</loader> + <nvram>/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd</nvram> + <type dev="hd"/> + </os> + <features> + <acpi/> + <apic/> + <vmport state="off"/> + </features> + <cpu mode="host-passthrough" check="none" migratable="on"/> + <clock offset="utc"> + <timer name="rtc" tickpolicy="catchup"/> + <timer name="pit" tickpolicy="delay"/> + <timer name="hpet" present="no"/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <pm> + <suspend-to-mem enabled="no"/> + <suspend-to-disk enabled="no"/> + </pm> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type="block" device="disk">block + <driver name="qemu" type="raw" cache="none" io="native" discard="unmap"/> + <source dev="/dev/vmstorage/fileserver2" index="3"/> + <backingStore/> + <target dev="vda" bus="virtio"/> + <alias name="virtio-disk0"/> + <address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/> + </disk> + <disk type="block" device="disk">block + <driver name="qemu" type="raw"/> + <source dev="/dev/mapper/storage1" index="2"/> + <backingStore/> + <target dev="vdb" bus="virtio"/> + <alias name="virtio-disk1"/> + <address type="pci" domain="0x0000" bus="0x08" slot="0x00" function="0x0"/> + </disk> + <disk type="block" device="disk">block + <driver name="qemu" type="raw"/> + <source dev="/dev/maper/storage2" index="1"/> + <backingStore/> + <target dev="vdc" bus="virtio"/> + <alias name="virtio-disk2"/> + <address type="pci" domain="0x0000" bus="0x09" slot="0x00" function="0x0"/> + </disk> + <controller type="usb" index="0" model="qemu-xhci" ports="15"> + <model name="qemu-xhci"/> + <alias name="usb"/> + <address type="pci" domain="0x0000" bus="0x02" slot="0x00" function="0x0"/> + </controller> + <controller type="pci" index="0" model="pci-root"> + <model name="pci-root"/> + <alias name="pcie.0"/> + </controller> + <controller type="pci" index="1" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="1" port="0x10"/> + <alias name="pci.1"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0"/> + </controller> + <controller type="pci" index="2" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="2" port="0x11"/> + <alias name="pci.2"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0"/> + </controller> + <controller type="pci" index="3" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="3" port="0x12"/> + <alias name="pci.3"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x2"/> + </controller> + <controller type="pci" index="4" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="4" port="0x13"/> + <alias name="pci.4"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x3"/> + </controller> + <controller type="pci" index="5" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="5" port="0x14"/> + <alias name="pci.5"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x4"/> + </controller> + <controller type="pci" index="6" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="6" port="0x15"/> + <alias name="pci.6"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x5"/> + </controller> + <controller type="pci" index="7" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="7" port="0x16"/> + <alias name="pci.7"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x6"/> + </controller> + <controller type="pci" index="8" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="8" port="0x17"/> + <alias name="pci.8"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x7"/> + </controller> + <controller type="pci" index="9" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="9" port="0x18"/> + <alias name="pci.9"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x0"/> + </controller> + <controller type="pci" index="10" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="10" port="0x19"/> + <alias name="pci.10"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x1"/> + </controller> + <controller type="pci" index="11" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="11" port="0x1a"/> + <alias name="pci.11"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x2"/> + </controller> + <controller type="pci" index="12" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="12" port="0x1b"/> + <alias name="pci.12"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x3"/> + </controller> + <controller type="pci" index="13" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="13" port="0x1c"/> + <alias name="pci.13"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x4"/> + </controller> + <controller type="pci" index="14" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="14" port="0x1d"/> + <alias name="pci.14"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x5"/> + </controller> + <controller type="pci" index="15" model="pcie-root-port"> + <model name="pcie-root-port"/> + <target chassis="15" port="0x1e"/> + <alias name="pci.15"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x6"/> + </controller> + <controller type="pci" index="16" model="pcie-root-port"> + <model name="pcie-root-port"/> + <alias name="pci.16"/> + <address type="pci" domain="0x0000" bus="0x07" slot="0x00" function="0x0"/> + </controller> + <controller type="sata" index="0"> + <alias name="ide"/> + <address type="pci" domain="0x0000" bus="0x00" slot="0x1f" function="0x02"/> + </controller> + <controller type="virtio-serial" index="0"> + <alias name="virtio-serial0"/> + <address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/> + </controller> + <controller type="scsi" index="0" model="lsilogic"> + <model name="lsilogic"/> + <alias name="scsi0"/> + <address type="pci" domain="0x0000" bus="0x10" slot="0x01" function="0x0"/> + </controller> + </devices> +</domain> diff --git a/nix/modules/libvirtnix/config.nix b/nix/modules/libvirtnix/config.nix new file mode 100644 index 0000000..5272ce2 --- /dev/null +++ b/nix/modules/libvirtnix/config.nix @@ -0,0 +1,583 @@ +{ + services.emile.libvirtnix = { + enable = true; + vm = { + "alan" = { + vm_type = "kvm"; + id = "1337"; + name = "blub"; + uuid = "cafebabe-d474-452b-80f4-c951c39bcf74"; + + metadata.libosinfo = "https://libosinfo.org/xmlns/libvirt/domain/1.0"; + metadata.libosinfo_os = "https://nixos.org/nixos/unknown"; + + memory.unit = "KiB"; + memory.value = 2097152; + + currentMemory.unit = "KiB"; + currentMemory.value = 2097152; + + vcpu.placement = "static"; + vcpu.count = 3; + + resource.partition = "/machine"; + + os = { + type = { + arch = "x86_64"; + machine = "pc-q35-3.1"; + value = "hvm"; + }; + + loader = { + readonly = "yes"; + type = "pflash"; + value = "/usr/share/OVMF/OVMF_CODE.fd"; + }; + + nvram.value = "/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd"; + + boot.dev = "hd"; + }; + + features = { + acpi = true; + apic = true; + vmport = { + state = "off"; + }; + }; + + cpu = { + mode = "host-passthrough"; + check = "none"; + migratable = "on"; + }; + + clock = { + offset = "utc"; + timer = [ + { + name = "rtc"; + tickpolicy = "catchup"; + } + { + name = "pit"; + tickpolicy = "delay"; + } + { + name = "hpet"; + present = "no"; + } + ]; + }; + + on_poweroff = "destroy"; + on_reboot = "restart"; + on_crash = "destroy"; + + pm = { + suspend-to-mem = "no"; + suspend-to-disk = "no"; + }; + + devices = { + emulators = [ + { + value = "/usr/bin/qemu-system-x86_64"; + } + ]; + + disks = [ + { + type = "block"; + device = "disk"; + driver = { + name = "qemu"; + type = "raw"; + cache = "none"; + io = "native"; + discard = "unmap"; + }; + source = { + dev = "/dev/vmstorage/fileserver2"; + index = 3; + }; + backingStore = true; + target = { + dev = "vda"; + bus = "virtio"; + }; + alias = { + name = "virtio-disk0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x04"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "block"; + device = "disk"; + driver = { + name = "qemu"; + type = "raw"; + }; + source = { + dev = "/dev/mapper/storage1"; + index = 2; + }; + backingStore = true; + target = { + dev = "vdb"; + bus = "virtio"; + }; + alias = { + name = "virtio-disk1"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x08"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "block"; + device = "disk"; + driver = { + name = "qemu"; + type = "raw"; + }; + source = { + dev = "/dev/maper/storage2"; + index = 1; + }; + backingStore = true; + target = { + dev = "vdc"; + bus = "virtio"; + }; + alias = { + name = "virtio-disk2"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x09"; + slot = "0x00"; + function = "0x0"; + }; + } + ]; + + controllers = [ + { + type = "usb"; + index = 0; + model = "qemu-xhci"; + ports = 15; + alias = { + name = "usb"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x02"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "pci"; + index = 0; + model = "pci-root"; + alias = { + name = "pcie.0"; + }; + } + { + type = "pci"; + index = 1; + model = "pcie-root-port"; + target = { + chassis = 1; + port = "0x10"; + }; + alias = { + name = "pci.1"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x0"; + multifunction = "on"; + }; + } + { + type = "pci"; + index = 2; + model = "pcie-root-port"; + target = { + chassis = 2; + port = "0x11"; + }; + alias = { + name = "pci.2"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x0"; + multifunction = "on"; + }; + } + { + type = "pci"; + index = 3; + model = "pcie-root-port"; + target = { + chassis = 3; + port = "0x12"; + }; + alias = { + name = "pci.3"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x2"; + }; + } + { + type = "pci"; + index = 4; + model = "pcie-root-port"; + target = { + chassis = 4; + port = "0x13"; + }; + alias = { + name = "pci.4"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x3"; + }; + } + { + type = "pci"; + index = 5; + model = "pcie-root-port"; + target = { + chassis = 5; + port = "0x14"; + }; + alias = { + name = "pci.5"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x4"; + }; + } + { + type = "pci"; + index = 6; + model = "pcie-root-port"; + target = { + chassis = 6; + port = "0x15"; + }; + alias = { + name = "pci.6"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x5"; + }; + } + { + type = "pci"; + index = 7; + model = "pcie-root-port"; + target = { + chassis = 7; + port = "0x16"; + }; + alias = { + name = "pci.7"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x6"; + }; + } + { + type = "pci"; + index = 8; + model = "pcie-root-port"; + target = { + chassis = 8; + port = "0x17"; + }; + alias = { + name = "pci.8"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x02"; + function = "0x7"; + }; + } + { + type = "pci"; + index = 9; + model = "pcie-root-port"; + target = { + chassis = 9; + port = "0x18"; + }; + alias = { + name = "pci.9"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x0"; + multifunction = "on"; + }; + } + { + type = "pci"; + index = 10; + model = "pcie-root-port"; + target = { + chassis = 10; + port = "0x19"; + }; + alias = { + name = "pci.10"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x1"; + }; + } + { + type = "pci"; + index = 11; + model = "pcie-root-port"; + target = { + chassis = 11; + port = "0x1a"; + }; + alias = { + name = "pci.11"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x2"; + }; + } + { + type = "pci"; + index = 12; + model = "pcie-root-port"; + target = { + chassis = 12; + port = "0x1b"; + }; + alias = { + name = "pci.12"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x3"; + }; + } + { + type = "pci"; + index = 13; + model = "pcie-root-port"; + target = { + chassis = 13; + port = "0x1c"; + }; + alias = { + name = "pci.13"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x4"; + }; + } + { + type = "pci"; + index = 14; + model = "pcie-root-port"; + target = { + chassis = 14; + port = "0x1d"; + }; + alias = { + name = "pci.14"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x5"; + }; + } + { + type = "pci"; + index = 15; + model = "pcie-root-port"; + target = { + chassis = 15; + port = "0x1e"; + }; + alias = { + name = "pci.15"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x03"; + function = "0x6"; + }; + } + { + type = "pci"; + index = 16; + model = "pcie-root-port"; + alias = { + name = "pci.16"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x07"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "sata"; + index = 0; + alias = { + name = "ide"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x00"; + slot = "0x1f"; + function = "0x02"; + }; + } + { + type = "virtio-serial"; + index = 0; + alias = { + name = "virtio-serial0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x03"; + slot = "0x00"; + function = "0x0"; + }; + } + { + type = "scsi"; + index = 0; + model = "lsilogic"; + alias = { + name = "scsi0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x10"; + slot = "0x01"; + function = "0x0"; + }; + } + ]; + interfaces = [ + { + type = "bridge"; + mac = { + address = "52:54:00:bf:ba:88"; + }; + source = { + network = "services"; + portid = "6c3a3512-d823-4521-9043-3a91a65682f5"; + bridge = "br7"; + }; + target = { + dev = "vnet2"; + }; + model = { + type = "virtio"; + }; + alias = { + name = "net0"; + }; + address = { + type = "pci"; + domain = "0x0000"; + bus = "0x01"; + slot = "0x00"; + function = "0x0"; + }; + } + ]; + }; + }; + }; + }; +} diff --git a/nix/modules/libvirtnix/domain.nix b/nix/modules/libvirtnix/domain.nix index a028c7d..d1a5b9c 100644 --- a/nix/modules/libvirtnix/domain.nix +++ b/nix/modules/libvirtnix/domain.nix @@ -1,701 +1,1443 @@ -{ pkgs, lib, ... }: - -{ - options = with lib; { - - # meta, this allows defining the package used for each vm individually, defaults should be sane - packages = mkOption { - type = types.submodule { - options = { - libvirt = mkPackageOption pkgs "libvirt" { }; - qemu = mkPackageOption pkgs "qemu" { }; - }; - }; +{ config, lib, ... }: + +let + mkTag = import ./xml.nix { inherit lib; }; + pkgs = import <nixpkgs> { }; + + stringOption = + { + default ? "", + }: + lib.mkOption { + type = lib.types.str; + default = "${default}"; }; - # attributs for the root `<domain ...>` node - type = mkOption { - type = types.enum [ - "xen" - "hvm" - "kvm" - "qemu" - "lxc" - ]; - default = "kvm"; - example = "qemu"; - description = '' - hypervisor used for running the domain - - allowed values are driver specific, if missing, plz send PR - - hvm since since 8.1.0 and QEMU 2.12 - ''; - }; - - id = mkOption { - type = types.int; - default = 0; - example = 42; - }; - - # General metadata - name = mkOption { - type = types.str; - example = "MyGuest"; - }; - - uuid = mkOption { - type = types.str; - example = "3e3fce45-4f53-4fa7-bb32-11f34168b82b"; - }; - - genid = mkOption { - type = types.str; - example = "43dc0cf8-809b-4adb-9bea-a9abb5f3d90e"; - }; - - title = mkOption { - type = types.str; - example = "A short description - title - of the domain"; + # shorthand for an option with an enum, no default value + enumOpt = + options: + lib.mkOption { + type = lib.types.nullOr (lib.types.enum options); + default = null; }; +in +{ + options = { + services.emile.libvirtnix = + let + + address = lib.mkOption { + default = null; + type = lib.types.nullOr ( + lib.types.submodule { + options = { + type = enumOpt [ "pci" ]; + domain = lib.mkOption { + type = lib.types.str; + example = "0x0000"; + }; + bus = lib.mkOption { + type = lib.types.str; + example = "0x4"; + }; + slot = lib.mkOption { + type = lib.types.str; + example = "0x00"; + }; + function = lib.mkOption { + type = lib.types.str; + example = "0x00"; + }; + multifunction = lib.mkOption { + type = lib.types.enum [ + "on" + "off" + ]; + example = "on"; + default = "off"; + }; + }; + } + ); + }; - description = mkOption { - type = types.str; - example = "Some human readable description"; - }; + interface = lib.mkOption { + type = lib.types.submodule { + options = { + type = enumOpt [ "bridge" ]; + mac = lib.mkOption { + type = lib.types.submodule { + options = { + address = lib.types.mkOption { + type = lib.types.str; + }; + }; + }; + }; + source = lib.mkOption { + type = lib.types.submodule { + options = { + network = lib.types.mkOption { + type = lib.types.str; + }; + portid = lib.types.mkOption { + type = lib.types.str; + }; + bridge = lib.types.mkOption { + type = lib.types.str; + }; + }; + }; + }; + target = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.types.mkOption { + type = lib.types.str; + }; + }; + }; + }; + model = lib.mkOption { + type = lib.types.submodule { + options = { + type = lib.types.mkOption { + type = enumOpt [ "virtio" ]; + }; + }; + }; + }; + alias = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.types.mkOption { + name = lib.types.str; + }; + }; + }; + }; + inherit address; + }; + }; + }; - metadata = mkOption { - type = types.str; - default = ""; - example = '' - <metadata> - <app1:foo xmlns:app1="http://app1.org/app1/">..</app1:foo> - <app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar> - </metadata> - ''; - }; - os = mkOption { - type = types.submodule { - options = { - firmware = mkOption { - type = types.enum [ - "bios" - "efi" + controller = lib.types.submodule { + options = { + type = enumOpt [ + "usb" + "pci" + "sata" + "virtio-serial" + "scsi" ]; - default = "efi"; - example = "bios"; + index = lib.mkOption { type = lib.types.int; }; + model = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + ports = lib.mkOption { + type = lib.types.nullOr lib.types.int; + default = null; + }; + alias = lib.mkOption { + type = lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; + }; + }; + }; + target = lib.mkOption { + type = lib.types.nullOr ( + lib.types.submodule { + options = { + chassis = lib.mkOption { type = lib.types.int; }; + port = lib.mkOption { type = lib.types.str; }; + }; + } + ); + default = null; + }; + inherit address; }; - type = mkOption { - type = types.enum [ - "hvm" - "linux" - ]; - default = "hvm"; - example = "linux"; - }; - arch = mkOption { type = types.str; }; - machine = mkOption { type = types.str; }; - - # TODO(emile): features - # Search for the following... - # > When using firmware auto-selection there are different features enabled in the firmwares - # ... here: https://libvirt.org/formatdomain.html - # can't bother to implement this now - - # features = mkOption { - # type = types.submodule { - # options = { - # enabled = { - # type = types.enum [ "yes" "no" ]; - # }; - # name = {}; - # }; - # }; - # }; - - # such as: - # <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> - loader = mkOption { - type = types.submodule { - options = { - readonly = mkOption { - type = types.enum [ - "yes" - "no" - ]; + }; + + emulator = lib.types.submodule { + options = { + value = lib.mkOption { type = lib.types.str; }; + }; + }; + + disk = lib.types.submodule { + options = { + type = enumOpt [ "block" ]; + device = enumOpt [ "disk" ]; + driver = lib.mkOption { + type = lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; + type = enumOpt [ "raw" ]; + cache = enumOpt [ "none" ]; + io = enumOpt [ "native" ]; + discard = enumOpt [ "unmap" ]; }; - type = mkOption { - type = types.enum [ - "rom" - "pflash" - ]; + }; + }; + source = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { type = lib.types.str; }; + index = lib.mkOption { type = lib.types.int; }; + }; + }; + }; + backingStore = lib.mkOption { type = lib.types.bool; }; + target = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { type = lib.types.str; }; + bus = enumOpt [ "virtio" ]; + }; + }; + }; + alias = lib.mkOption { + type = lib.types.submodule { + options = { + name = lib.mkOption { type = lib.types.str; }; }; - secure = mkOption { - type = types.enum [ + }; + }; + inherit address; + }; + }; + + devices = lib.mkOption { + type = lib.types.submodule { + options = { + emulators = lib.mkOption { + type = lib.types.listOf emulator; + }; + disks = lib.mkOption { + type = lib.types.listOf disk; + }; + controllers = lib.mkOption { + type = lib.types.listOf controller; + }; + interfaces = lib.mkOption { + type = lib.types.listOf interface; + }; + }; + }; + }; + + pm = lib.mkOption { + type = lib.types.submodule { + options = { + suspend-to-mem = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ "yes" "no" - ]; - }; - stateless = mkOption { - type = types.enum [ + ] + ); + default = null; + example = "yes"; + }; + suspend-to-disk = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ "yes" "no" - ]; - }; - format = mkOption { - type = types.enum [ - "raw" - "qcow2" - ]; - }; - value = mkOption { - type = types.str; - example = "/usr/share/OVMF/OVMF_CODE.fd"; - }; + ] + ); + default = null; + example = "yes"; }; }; }; + }; - # <nvram type='network'> - # <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'> - # <host name='example.com' port='6000'/> - # <auth username='myname'> - # <secret type='iscsi' usage='mycluster_myname'/> - # </auth> - # </source> - # </nvram> - - # nvram = { - # type = "network"; - # source = { - # protocol = "iscsi"; - # name = "iqn.2013-07.com.example:iscsi-nopool/0"; - # }; - # }; - - nvram = mkOption { - type = types.submodule { - options = { - type = mkOption { - type = types.enum [ - "file" - "block" - "dir" - "network" - "volume" - "nvme" - "vhostuser" - "vhostvdpa" - ]; - default = ""; - }; + on_handle = lib.mkOption { + type = lib.types.enum [ + "destroy" + "restart" + "preserve" + "rename-restart" + ]; + }; - source = mkOption { - type = types.submodule { + on_poweroff = on_handle; + on_reboot = on_handle; + on_crash = on_handle; + + clock = lib.mkOption { + type = lib.types.submodule { + options = { + offset = lib.mkOption { + type = lib.types.str; + example = "utc"; + default = "utc"; + }; + timer = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule { options = { - # TODO(emile): figure out how to conditionally allow setting the options below - # if the type defined above has been set - - # if type == file - file = mkOption { type = types.str; }; - fdgroup = mkOption { type = types.str; }; - - # if type == block - dev = mkOption { type = types.str; }; - - # if type == dir - dir = mkOption { type = types.str; }; - - # if type == network - protocol = mkOption { - type = types.enum [ - "nbd" - "iscsi" - "rbd" - "sheepdog" - "gluster" - "vxhs" - "nfs" - "http" - "https" - "ftp" - "ftps" - "tftp" - "ssh" - ]; - }; - name = mkOption { type = types.str; }; - tls = mkOption { - type = types.enum [ - "yes" - "no" + name = lib.mkOption { + type = lib.types.enum [ + # "platform" (currently unsupported) + "hpet" # xen, qemu, lxc + "kvmclock" # qemu + "pit" # qemu + "rtc" # qemu, lxc + "tsc" # xen, qemu - since 3.2.0 + + # The hypervclock timer adds support for the reference time counter and the reference page for iTSC feature for guests running the Microsoft Windows operating system. + "hypervclock" # qemu - since 1.2.2 + + "armvtimer" # qemu - since 6.1.0 ]; + default = ""; + example = ""; }; - tlsHostname = mkOption { type = types.str; }; - query = mkOption { type = types.str; }; - - # if type == volume - pool = mkOption { type = types.str; }; - volume = mkOption { type = types.str; }; - mode = mkOption { - type = types.enum [ - "direct" - "host" + track = lib.mkOption { + # TODO(emile): Only valid for name="rtc" or name="platform". + type = lib.types.enum [ + "boot" + "guest" + "wall" + "realtime" ]; - default = "host"; - }; - - # if type == nvme - type = mkOption { - type = types.enum [ "pci" ]; - default = "pci"; - description = '' - When the type is `nvme`, only `pci` is supported - When the type is `vhostuser`, only `unix` is supported - - (I've got not clue how to model this is nix, it's essentially an attribute that is overloaded based on another value) - ''; + default = ""; + example = ""; }; - managed = mkOption { - type = types.enum [ - "yes" - "no" - ]; + tickpolicy = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ + "catchup" + "delay" + "merge" + "discard" + "catchup" + ] + ); + default = null; + example = ""; }; - namespace = mkOption { - type = types.int; - default = 0; + present = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ + "yes" + "no" + ] + ); + default = null; + example = ""; }; + }; + } + ); + example = [ + { + name = "rtc"; + tickpolicy = "catchup"; + } + { + name = "pit"; + tickpolicy = "delay"; + } + { + name = "hpet"; + present = "no"; + } + ]; + default = [ + { + name = "rtc"; + tickpolicy = "catchup"; + } + { + name = "pit"; + tickpolicy = "delay"; + } + { + name = "hpet"; + present = "no"; + } + ]; + }; + }; + }; + }; - # if type == vhostuser - # type = see the type in the nvme section above - path = mkOption { type = types.str; }; + cpu = lib.mkOption { + type = lib.types.submodule { + options = { + mode = lib.mkOption { + type = lib.types.str; + example = "host-passthrough"; + default = ""; + }; + check = lib.mkOption { + type = lib.types.str; + example = "none"; + default = ""; + }; + migratable = lib.mkOption { + type = lib.types.str; + example = "on"; + default = ""; + }; + }; + }; + }; - # if type == vhostvdpa - # dev = (defined above in the "type == block" section) + features = lib.mkOption { + type = lib.types.submodule { + options = { + acpi = lib.mkEnableOption "enable acpi"; + apic = lib.mkEnableOption "enable apic"; + + vmport = lib.mkOption { + type = lib.types.submodule { + options = { + state = lib.mkOption { + type = lib.types.str; + example = "off"; + default = ""; + }; + }; + }; + }; + }; + }; + }; - # if type == file - # if type == block - # if type == volume - seclabel = mkOption { type = types.str; }; + os_boot = lib.mkOption { + type = lib.types.submodule { + options = { + dev = lib.mkOption { + type = lib.types.str; + example = "hd"; + default = ""; + }; + }; + }; + }; - index = mkOption { - type = types.int; - default = 0; - }; + os_nvram = lib.mkOption { + type = lib.types.submodule { + options = { + value = lib.mkOption { + type = lib.types.str; + example = "/var/lib/libvirt/qemu/nvram/fileserver2_VARS.fd"; + default = ""; + }; + }; + }; + }; - # TODO(emile): implement checks here - # start here and scroll down a bit to the table - # https://libvirt.org/formatdomain.html#hard-drives-floppy-disks-cdroms - # if type == network - host = mkOption { - type = types.submodule { - options = { - name = mkOption { type = types.str; }; - port = mkOption { - type = types.int; - default = 0; - }; - transport = mkOption { type = types.str; }; - socket = mkOption { type = types.str; }; - - }; - }; - }; + os_loader = lib.mkOption { + type = lib.types.submodule { + options = { + readonly = lib.mkOption { + type = lib.types.str; + example = "yes"; + default = ""; + }; + type = lib.mkOption { + type = lib.types.str; + example = "pflash"; + default = ""; + }; + value = lib.mkOption { + type = lib.types.str; + example = "/usr/share/OVMF/OVMF_CODE.fd"; + default = ""; + }; + }; + }; + }; - snapshot = mkOption { - type = types.submodule { - options = { - name = mkOption { type = types.str; }; - }; - }; - }; + os_type = lib.mkOption { + type = lib.types.submodule { + options = { + arch = lib.mkOption { + type = lib.types.str; + example = "x86_64"; + default = ""; + }; + machine = lib.mkOption { + type = lib.types.str; + example = "pc-q35-3.1"; + default = ""; + }; + value = lib.mkOption { + type = lib.types.str; + example = "hvm"; + default = ""; + }; + }; + }; + }; - config = mkOption { - type = types.submodule { - options = { - file = mkOption { type = types.str; }; - }; - }; - }; + os = lib.mkOption { + description = "os"; + type = lib.types.submodule { + options = { + type = os_type; + loader = os_loader; + nvram = os_nvram; + boot = os_boot; + }; + }; + }; - # Since 3.9.0, the auth element is supported for a disk type "network" that is using a source element with the protocol attributes "rbd", "iscsi", or "ssh". - auth = mkOption { - type = types.submodule { - options = { - type = mkOption { - # type = types.enum [ "chap" ]; - # freeform, yet "chap" is one of the allowed options, I don't know others (yet) - type = types.str; - }; - username = mkOption { type = types.str; }; - - # https://libvirt.org/formatsecret.html - secret = mkOption { - type = types.submodule { - options = { - ephemeral = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - }; - private = mkOption { - type = types.enum [ - "yes" - "no" - ]; - default = "no"; - }; - - uuid = types.submodule { - options = { - value = mkOption { - type = types.str; - default = ""; - }; - }; - }; - description = types.submodule { - options = { - value = mkOption { - type = types.str; - default = ""; - }; - }; - }; - - usage = types.submodule { - options = { - type = mkOption { - type = types.enum [ - "volume" - "ceph" - "iscsi" - "tls" - "vtpm" - ]; - default = ""; - }; - value = mkOption { - type = types.str; - default = ""; - }; - - name = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - volume = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - # when using the "iscsi" type - target = mkOption { - type = types.submodule { - options = { - value = mkOption { type = types.str; }; - }; - }; - }; - - }; - }; - - }; - }; - }; # end of secret - - }; - }; - }; # end of auth - - # https://libvirt.org/formatstorageencryption.html - encryption = mkOption { - type = types.submodule { - options = { - type = mkOption { type = types.str; }; - - # mandatory - format = mkOption { - type = types.enum [ - "default" - "qcow" - "luks" - "luks2" - "luks-any" - ]; - }; - - engine = mkOption { - type = types.enum [ - "qemu" - "librbd" - ]; - }; - - secrets = mkOption { - type = types.listOf (mkOption { - type = types.submodule { - options = { - - # mandatory - type = mkOption { type = types.enum [ "volume" ]; }; - - # uuid or usage - uuid = mkOption { type = types.str; }; - usage = mkOption { type = types.str; }; - - }; - }; - }); - }; # end of secrets - - cipher = mkOption { - type = types.submodule { - options = { - name = mkOption { - type = types.str; - example = "'aes', 'des', 'cast5', 'serpent', 'twofish', etc."; - }; - size = mkOption { - type = types.str; - example = "'256', '192', '128', etc."; - }; - mode = mkOption { - type = types.str; - example = "'cbc', 'xts', 'ecb', etc."; - }; - hash = mkOption { - type = types.str; - example = "'md5', 'sha1', 'sha256', etc."; - }; - }; - }; - }; # end of cipher - - ivgen = mkOption { - type = types.submodule { - options = { - name = mkOption { - type = types.str; - example = "'plain', 'plain64', 'essiv', etc."; - }; - hash = mkOption { - type = types.str; - example = "'md5', 'sha1', 'sha256'"; - }; - }; - }; - }; # end of ivygen - }; - }; - }; # end of encryption - - # TODO(emile): reservations - # Looking at the following, it seems like this can use the source element recursively - # Haven't looked into how to define recursive nix options yet... - # https://github.com/virt-manager/virt-manager/blob/5ddd3456a0ca9836a98fc6ca4f0b2eaab268bf47/tests/data/cli/compare/virt-install-many-devices.xml#L398-L400 - - # TODO(emile): initiator - - # Based on this here: - # https://github.com/virt-manager/virt-manager/blob/5ddd3456a0ca9836a98fc6ca4f0b2eaab268bf47/tests/data/cli/compare/virt-install-many-devices.xml#L440 - address = mkOption { - type = types.submodule { - options = { - domain = mkOption { type = types.int; }; - bus = mkOption { type = types.int; }; - slot = mkOption { type = types.int; }; - function = mkOption { type = types.int; }; - }; - }; - }; # end of address - - # TODO(emile): slices - # Didn't find any usage of it, why is there documentation for it then? - - ssl = mkOption { - type = types.submodule { - options = { - verify = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - }; - }; - }; # end of ssl - - # TODO(emile): cookies for http and https - - readahead = mkOption { - type = types.submodule { - options = { - size = mkOption { type = types.int; }; - }; - }; - }; # end of readahead - - timeout = mkOption { - type = types.submodule { - options = { - seconds = mkOption { type = types.int; }; - }; - }; - }; # end of timeout - - identity = mkOption { - type = types.submodule { - options = { - user = mkOption { type = types.str; }; - group = mkOption { type = types.str; }; - - # if ssh - # required - username = mkOption { type = types.str; }; - - # one of these: - agentsock = mkOption { type = types.str; }; - keyfile = mkOption { type = types.str; }; - }; - }; - }; # end of identity - - # disk type "vhostuser" - reconnect = mkOption { - type = types.submodule { - options = { - # mandatory - enabled = mkOption { - type = types.enum [ - "yes" - "no" - ]; - }; - timeout = mkOption { - type = types.int; - description = "seconds"; - }; - - # optional for disk type network and protocol nbd - delay = mkOption { - type = types.int; - default = 0; - description = "seconds"; - }; - }; - }; - }; # end of reconnect - - # disk type "ssh" - knownHosts = mkOption { - type = types.submodule { - options = { - path = mkOption { type = types.str; }; - }; - }; - }; # end of knownHosts - - dataStore = mkOption { - type = types.submodule { - options = { - # TODO(emile): can accept the same types as a `source` element - type = mkOption { type = types.str; }; - - # TODO(emile): can accept format and source subelements - # this is (once again) recursive for the source, stil need to figure - # out how to handle this, just not now - }; - }; - }; # end of dataStore - - startupPolicy = mkOption { - type = types.enum [ - "mandatory" - "requisite" - "optional" - ]; - default = "mandatory"; - }; # end of startupPolicy - - backingStore = mkOption { - type = types.submodule { - options = { - type = mkOption { - # TODO(emile): can accept the same types as a `source` element - type = types.str; - }; - - index = mkOption { - # TODO(emile): figure out if this can just be an int - type = types.str; - }; - - # TODO(emile): can use the following sub elements: - # - format - # - source - # - backingStore - }; - }; - }; # end of backingStore - - mirror = mkOption { - type = types.submodule { - options = { - api = mkOption { - type = types.enum [ - "copy" - "active-commit" - ]; - }; - ready = mkOption { - type = types.enum [ - "yes" - "abort" - "pivot" - ]; - }; - # TODO(emile): can use the following sub elements: - # - type (disk types) - # - format - # - source - # - file - }; - }; - }; # end of mirror + resource = lib.mkOption { + description = "resource"; + type = lib.types.submodule { + options = { + partition = lib.mkOption { + type = lib.types.str; + example = "/machine"; + default = ""; + }; + }; + }; + }; - }; - }; - }; # end of source + vcpu = lib.mkOption { + description = "vcpu"; + type = lib.types.submodule { + options = { + placement = lib.mkOption { + # TODO(emile): fill up + type = lib.types.enum [ "static" ]; + example = "static"; + default = "static"; + }; + count = lib.mkOption { + type = lib.types.int; + example = 4; + default = 1; + }; + }; + }; + }; + + mem = lib.mkOption { + description = "memory"; + type = lib.types.submodule { + options = { + unit = lib.mkOption { + # TODO(emile): fill up + type = lib.types.enum [ + "KiB" + "MiB" + "GiB" + "TiB" + ]; + example = "KiB"; + default = "KiB"; + }; + value = lib.mkOption { + type = lib.types.int; + example = 2097152; + default = 1000; + }; + }; + }; + }; + memory = mem; + currentMemory = mem; + + metadata = lib.mkOption { + description = "metadata submodule"; + type = lib.types.submodule { + options = { + libosinfo = lib.mkOption { + type = lib.types.str; + example = "https://libosinfo.org/xmlns/libvirt/domain/1.0"; + default = ""; + }; + libosinfo_os = lib.mkOption { + type = lib.types.str; + example = "https://nixos.org/nixos/unknown"; + default = ""; }; }; - }; # end of nvram + }; + }; + vm = lib.types.submodule { + options = { + vm_type = stringOption { default = "kvm"; }; + id = stringOption { }; + name = stringOption { }; + uuid = stringOption { }; + + inherit + metadata + memory + currentMemory + vcpu + resource + os + features + cpu + clock + on_poweroff + on_reboot + on_crash + pm + devices + ; + }; + }; + in + { + enable = lib.mkEnableOption "Enable r2wars-web"; + + # Temporary output we write the domain to, in order to inspect the correctness of + # the generated xml + output.domain = lib.mkOption { type = lib.types.path; }; + + # An attrset of VMs + vm = lib.mkOption { + description = "VMs to define"; + type = lib.types.attrsOf vm; }; }; - }; + }; - memory = lib.mkOption { - type = lib.types.int; - default = 1024; - example = 2048; - description = '' - The amount of memory to provide to the VM - ''; - }; + config = lib.mkIf config.services.emile.libvirtnix.enable { + services.emile.libvirtnix = + let + vm = config.services.emile.libvirtnix.vm; + + # try this in a nix repl + # nix-repl> mkTag = import ./xml.nix { lib = (import <nixpkgs> {}).lib; } + # nix-repl> :p let func = (x: mkTag {name=x.variant;}); case = {"emulator" = func; "disk" = func;}; in map (x: case."${x.variant}" x) [ {variant = "emulator"; value = "asd";} {variant = "disk"; type = "block"; } ] + + emulator = + x: + mkTag { + name = "emulator"; + value = x.value; + }; + + interface = + x: + mkTag { + name = "interface"; + args = [ + ( + if x.type != null then + { + key = "type"; + val = x.type; + } + else + "" + ) + ]; + children = [ + # ( + # if x.mac != null then + # (mkTag { + # name = "mac"; + # args = [ + # { + # key = "address"; + # val = x.mac.address; + # } + # ]; + # closing = false; + # }) + # else + # "" + # ) + #( + # if x.source != null then + # (mkTag { + # name = "source"; + # args = [ + # { + # key = "network"; + # val = x.source.network; + # } + # { + # key = "portid"; + # val = x.source.portid; + # } + # { + # key = "bridge"; + # val = x.source.bridge; + # } + # ]; + # closing = false; + # }) + # else + # "" + #) + #( + # if x.target != null then + # (mkTag { + # name = "target"; + # args = [ + # { + # key = "dev"; + # val = x.target.dev; + # } + # ]; + # }) + # else + # "" + #) + #( + # if x.model != null then + # (mkTag { + # name = "model"; + # args = [ + # { + # key = "type"; + # val = x.model.type; + # } + # ]; + # }) + # else + # "" + #) + #( + # if x.alias!= null then + # (mkTag { + # name = "alias"; + # args = [ + # { + # key = "name"; + # val = x.alias.name; + # } + # ]; + # }) + # else + # "" + #) + #( + # if x.address != null then + # mkTag { + # name = "address"; + # args = [ + # ( + # if x.address.type != null then + # { + # key = "type"; + # val = x.address.type; + # } + # else + # "" + # ) + # { + # key = "domain"; + # val = x.address.domain; + # } + # { + # key = "bus"; + # val = x.address.bus; + # } + # { + # key = "slot"; + # val = x.address.slot; + # } + # { + # key = "function"; + # val = x.address.function; + # } + # ]; + # closing = false; + # } + # else + # "" + #) + ]; + }; + + controller = + x: + mkTag { + name = "controller"; + args = [ + ( + if x.type != null then + { + key = "type"; + val = x.type; + } + else + "" + ) + ( + if x.index != null then + { + key = "index"; + val = "${toString x.index}"; + } + else + "" + ) + ( + if x.model != null then + { + key = "model"; + val = x.model; + } + else + "" + ) + ( + if x.ports != null then + { + key = "ports"; + val = "${toString x.ports}"; + } + else + "" + ) + ]; + children = [ + # TODO(emile): figure out if the arg in controller is really the same as the + # one given in model. The configs I've got let it seem so + # <controller type="pci" index="1" model="pcie-root-port"> + # <model name="pcie-root-port"/> + ( + if x.model != null then + (mkTag { + name = "model"; + args = [ + { + key = "name"; + val = x.model; + } + ]; + closing = false; + }) + else + "" + ) + ( + if x.target != null then + (mkTag { + name = "target"; + args = [ + { + key = "chassis"; + val = "${toString x.target.chassis}"; + } + { + key = "port"; + val = x.target.port; + } + ]; + }) + else + "" + ) + (mkTag { + name = "alias"; + args = [ + ( + if x.alias.name != null then + { + key = "name"; + val = x.alias.name; + } + else + "" + ) + ]; + closing = false; + }) + + ( + if x.address != null then + mkTag { + name = "address"; + args = [ + ( + if x.address.type != null then + { + key = "type"; + val = x.address.type; + } + else + "" + ) + { + key = "domain"; + val = x.address.domain; + } + { + key = "bus"; + val = x.address.bus; + } + { + key = "slot"; + val = x.address.slot; + } + { + key = "function"; + val = x.address.function; + } + ]; + closing = false; + } + else + "" + ) + ]; + }; + + disk = + x: + mkTag { + name = "disk"; + args = [ + { + key = "type"; + val = x.type; + } + { + key = "device"; + val = x.device; + } + ]; + children = [ + (mkTag { + name = "driver"; + args = [ + ( + if x.driver.name != null then + { + key = "name"; + val = x.driver.name; + } + else + "" + ) + ( + if x.driver.type != null then + { + key = "type"; + val = x.driver.type; + } + else + "" + ) + ( + if x.driver.cache != null then + { + key = "cache"; + val = x.driver.cache; + } + else + "" + ) + ( + if x.driver.io != null then + { + key = "io"; + val = x.driver.io; + } + else + "" + ) + ( + if x.driver.discard != null then + { + key = "discard"; + val = x.driver.discard; + } + else + "" + ) + ]; + closing = false; + }) + (mkTag { + name = "source"; + args = [ + { + key = "dev"; + val = x.source.dev; + } + { + key = "index"; + val = "${toString x.source.index}"; + } + ]; + closing = false; + }) + ( + if x.backingStore == true then + mkTag { + name = "backingStore"; + closing = false; + } + else + "" + ) + (mkTag { + name = "target"; + args = [ + { + key = "dev"; + val = x.target.dev; + } + { + key = "bus"; + val = x.target.bus; + } + ]; + closing = false; + }) + (mkTag { + name = "alias"; + args = [ + { + key = "name"; + val = x.alias.name; + } + ]; + closing = false; + }) + (mkTag { + name = "address"; + args = [ + { + key = "type"; + val = x.address.type; + } + { + key = "domain"; + val = x.address.domain; + } + { + key = "bus"; + val = x.address.bus; + } + { + key = "slot"; + val = x.address.slot; + } + { + key = "function"; + val = x.address.function; + } + ]; + closing = false; + }) + ]; + value = x.type; + }; + + devices = + vm_name: + mkTag { + name = "devices"; + children = + map (x: emulator x) vm.${vm_name}.devices.emulators + ++ map (x: disk x) vm.${vm_name}.devices.disks + ++ map (x: controller x) vm.${vm_name}.devices.controllers + ++ map (x: interface x) vm.${vm_name}.devices.interfaces; + }; + + pm = + vm_name: + mkTag { + name = "pm"; + children = + let + suspend-to-mem = mkTag { + name = "suspend-to-mem"; + args = [ + { + key = "enabled"; + val = vm.${vm_name}.pm.suspend-to-mem; + } + ]; + closing = false; + }; + + suspend-to-disk = mkTag { + name = "suspend-to-disk"; + args = [ + { + key = "enabled"; + val = vm.${vm_name}.pm.suspend-to-disk; + } + ]; + closing = false; + }; + in + [ + suspend-to-mem + suspend-to-disk + ]; + }; + + on_handler = + { vm_name, tag }: + mkTag { + name = "${tag}"; + value = vm.${vm_name}.${tag}; + }; + + on_poweroff = + vm_name: + on_handler { + inherit vm_name; + tag = "on_poweroff"; + }; + on_reboot = + vm_name: + on_handler { + inherit vm_name; + tag = "on_reboot"; + }; + on_crash = + vm_name: + on_handler { + inherit vm_name; + tag = "on_crash"; + }; + + clock = + vm_name: + mkTag { + name = "clock"; + args = [ + { + key = "offset"; + val = vm.${vm_name}.clock.offset; + } + ]; + children = map ( + x: + mkTag { + name = "timer"; + args = + let + tickpolicy = + if x.tickpolicy != null then + { + key = "tickpolicy"; + val = x.tickpolicy; + } + else + { }; + + present = + if x.present != null then + { + key = "present"; + val = x.present; + } + else + { }; + in + [ + { + key = "name"; + val = x.name; + } + tickpolicy + present + ]; + } + ) vm.${vm_name}.clock.timer; + }; + + cpu = + vm_name: + mkTag { + name = "cpu"; + args = + let + mode = vm.${vm_name}.cpu.mode; + check = vm.${vm_name}.cpu.check; + migratable = vm.${vm_name}.cpu.migratable; + in + [ + ( + if (mode != null) then + { + key = "mode"; + val = mode; + } + else + "" + ) + ( + if (check != null) then + { + key = "check"; + val = check; + } + else + "" + ) + ( + if (migratable != null) then + { + key = "migratable"; + val = migratable; + } + else + "" + ) + ]; + closing = false; + }; + + features = + vm_name: + mkTag { + name = "features"; + children = + let + acpi = + vm_name: + mkTag { + name = "acpi"; + closing = false; + }; + apic = + vm_name: + mkTag { + name = "apic"; + closing = false; + }; + vmport = + vm_name: + mkTag { + name = "vmport"; + args = [ + { + key = "state"; + val = vm.${vm_name}.features.vmport.state; + } + ]; + closing = false; + }; + in + [ + (if (vm.${vm_name}.features.acpi != false) then (acpi vm_name) else "") + (if (vm.${vm_name}.features.apic != false) then (apic vm_name) else "") + (if (vm.${vm_name}.features.vmport != null) then (vmport vm_name) else "") + ]; + }; + + os = + vm_name: + mkTag { + name = "os"; + children = + let + os_type = + vm_name: + mkTag { + name = "type"; + args = [ + { + key = "arch"; + val = vm.${vm_name}.os.type.arch; + } + { + key = "machine"; + val = vm.${vm_name}.os.type.machine; + } + ]; + value = vm.${vm_name}.os.type.value; + }; + os_loader = + vm_name: + mkTag { + name = "loader"; + args = [ + { + key = "readonly"; + val = vm.${vm_name}.os.loader.readonly; + } + { + key = "pflash"; + val = vm.${vm_name}.os.loader.type; + } + ]; + value = vm.${vm_name}.os.loader.value; + }; + os_nvram = + vm_name: + mkTag { + name = "nvram"; + value = vm.${vm_name}.os.nvram.value; + }; + os_boot = + vm_name: + mkTag { + name = "type"; + args = [ + { + key = "dev"; + val = vm.${vm_name}.os.boot.dev; + } + ]; + closing = false; + }; + in + [ + (os_type vm_name) + (os_loader vm_name) + (os_nvram vm_name) + (os_boot vm_name) + ]; + }; + + resource = + vm_name: + mkTag { + name = "resource"; + children = [ + (mkTag { + name = "partition"; + value = "${toString vm.${vm_name}.resource.partition}"; + }) + ]; + }; + + vcpu = + vm_name: + mkTag { + name = "vcpu"; + args = [ + { + key = "placement"; + val = vm.${vm_name}.vcpu.placement; + } + ]; + value = "${toString vm.${vm_name}.vcpu.count}"; + }; + + currentMemory = + vm_name: + mkTag { + name = "currentMemory"; + args = [ + { + key = "unit"; + val = vm.${vm_name}.currentMemory.unit; + } + ]; + value = "${toString vm.${vm_name}.currentMemory.value}"; + }; + memory = + vm_name: + mkTag { + name = "memory"; + args = [ + { + key = "unit"; + val = vm.${vm_name}.memory.unit; + } + ]; + value = "${toString vm.${vm_name}.memory.value}"; + }; + + libosinfo_os = + vm_name: + mkTag { + name = "libosinfo:os"; + args = [ + { + key = "id"; + val = vm.${vm_name}.metadata.libosinfo_os; + } + ]; + closing = false; + }; + + libosinfo_libosinfo = + vm_name: + mkTag { + name = "libosinfo:libosinfo"; + args = [ + { + key = "xmlns:libosinfo"; + val = vm.${vm_name}.metadata.libosinfo; + } + ]; + children = [ + (libosinfo_os vm_name) + ]; + }; + + metadata = + vm_name: + mkTag { + name = "metadata"; + children = [ (libosinfo_libosinfo vm_name) ]; + }; + + uuid = + vm_name: + mkTag { + name = "uuid"; + value = vm.${vm_name}.uuid; + }; + + name = + vm_name: + mkTag { + name = "name"; + value = vm.${vm_name}.name; + }; + + # the vm_name has to be passed in, as we want to accesses the value for the given vm when + # generating the config + domain = + vm_name: + mkTag { + name = "domain"; + args = [ + { + key = "type"; + val = vm.${vm_name}.vm_type; + } + { + key = "id"; + val = vm.${vm_name}.id; + } + ]; + children = [ + (name vm_name) + (uuid vm_name) + (metadata vm_name) + (memory vm_name) + (currentMemory vm_name) + (vcpu vm_name) + (resource vm_name) + (os vm_name) + (features vm_name) + (cpu vm_name) + (clock vm_name) + (on_poweroff vm_name) + (on_reboot vm_name) + (on_crash vm_name) + (pm vm_name) + (devices vm_name) + ]; + }; + in + { + output.domain = pkgs.writeText "libvirt-domain-config.xml" (domain "alan"); + }; }; } diff --git a/nix/modules/libvirtnix/os.nix b/nix/modules/libvirtnix/os.nix new file mode 100644 index 0000000..41f36f3 --- /dev/null +++ b/nix/modules/libvirtnix/os.nix @@ -0,0 +1,119 @@ +{ lib, ... }: + +let + mkOption = lib.mkOption; + submodule = lib.types.submodule; + types = lib.types; + + os = { + firmware = mkOption { + type = types.enum [ + "bios" + "efi" + ]; + default = "efi"; + example = "bios"; + }; + + type = mkOption { + type = types.enum [ + "hvm" + "linux" + ]; + default = "hvm"; + example = "linux"; + }; + + arch = mkOption { type = types.str; }; + machine = mkOption { type = types.str; }; + + # TODO(emile): features + # Search for the following... + # > When using firmware auto-selection there are different features enabled in the firmwares + # ... here: https://libvirt.org/formatdomain.html + # can't bother to implement this now + + # features = mkOption { + # type = types.submodule { + # options = { + # enabled = { + # type = types.enum [ "yes" "no" ]; + # }; + # name = {}; + # }; + # }; + # }; + + # such as: + # <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader> + loader = mkOption { + type = types.submodule { + options = { + readonly = mkOption { + type = types.enum [ + "yes" + "no" + ]; + }; + type = mkOption { + type = types.enum [ + "rom" + "pflash" + ]; + }; + secure = mkOption { + type = types.enum [ + "yes" + "no" + ]; + }; + stateless = mkOption { + type = types.enum [ + "yes" + "no" + ]; + }; + format = mkOption { + type = types.enum [ + "raw" + "qcow2" + ]; + }; + value = mkOption { + type = types.str; + example = "/usr/share/OVMF/OVMF_CODE.fd"; + }; + }; + }; + }; + + # <nvram type='network'> + # <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'> + # <host name='example.com' port='6000'/> + # <auth username='myname'> + # <secret type='iscsi' usage='mycluster_myname'/> + # </auth> + # </source> + # </nvram> + + # nvram = { + # type = "network"; + # source = { + # protocol = "iscsi"; + # name = "iqn.2013-07.com.example:iscsi-nopool/0"; + # }; + # }; + + }; +in +{ + options = { + os = mkOption { + type = submodule { + options = { + inherit (os) firmware type arch machine loader; + }; + }; + }; + }; +} diff --git a/nix/modules/libvirtnix/secret.nix b/nix/modules/libvirtnix/secret.nix new file mode 100644 index 0000000..b597174 --- /dev/null +++ b/nix/modules/libvirtnix/secret.nix @@ -0,0 +1,174 @@ +{ config, lib, ... }: + +# https://libvirt.org/formatsecret.html + +let + pkgs = import <nixpkgs> { }; + + mkOption = lib.mkOption; + submodule = lib.types.submodule; + types = lib.types; + enum = types.enum; + str = types.str; + + yesNoOption = mkOption { + type = enum [ + "yes" + "no" + ]; + default = "no"; + }; + # YesnoOption = mkOption { type = enum [ "yes" "no" ]; default = "yes"; }; + + # takes a few args and creats a valid xml tag pair out of it + # + # testTag = mkTag { + # name = "name"; + # args = [ + # { + # key = "arg1"; + # val = "arg1val"; + # } + # { + # key = "arg2"; + # val = "arg2val"; + # } + # ]; + # value = "qwe"; + # children = [ + # (mkTag { name = "nested"; args = []; value = "qwe"; children = [];}) + # ]; + # }; + # + # <name arg1=arg1val arg2=arg2val> + # value + # {children} + # </name> + mkTag = + { + name, # name of the tag to be used, such as `secret`, `description`, ... + args ? [ ], # args, [ { key="a"; val="b"; } { key="c"; val="d"; } ] + value ? "", # the value to place in the middle + children ? [ ], # the child elements + }: + let + args_str = + " " + lib.strings.concatStrings (lib.strings.intersperse " " (map (x: "${x.key}='${x.val}'") args)); + child_evaled = lib.strings.concatStrings children; + in + "<${name}${lib.optionalString (args != [ ]) args_str}>${value}${child_evaled}</${name}>"; + + strOption = + { + default ? "", + }: + mkOption { + type = str; + default = "${default}"; + }; + + usage = mkOption { + type = submodule { + options = { + type = mkOption { + type = enum [ + "volume" + "ceph" + "iscsi" + "tls" + "vtpm" + ]; + default = ""; + }; + + value = strOption { }; + + name = strOption { }; + volume = strOption { }; + target = strOption { }; + }; + }; + }; + + secret = { + inherit usage; + + ephemeral = yesNoOption; + private = yesNoOption; + + uuid = strOption { }; + description = strOption { }; + }; + +in +{ + options = { + services.emile.libvirtnix = { + enable = lib.mkEnableOption "Enable r2wars-web"; + + secret = mkOption { + type = submodule { + options = { + inherit (secret) + ephemeral + private + uuid + description + usage + ; + }; + }; + }; + + # output = mkOption { type = types.path; }; + }; + }; + + config = lib.mkIf config.services.emile.libvirtnix.enable { + services.emile.libvirtnix = + let + secret = mkTag { + name = "secret"; + args = [ + { + key = "ephemeral"; + val = config.services.emile.libvirtnix.secret.ephemeral; + } + { + key = "private"; + val = config.services.emile.libvirtnix.secret.private; + } + ]; + children = [ + (mkTag { + name = "description"; + value = "Super secret description"; + }) + (mkTag { + name = "uuid"; + value = "0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f"; + }) + (mkTag { + name = "usage"; + args = [ + { + key = "type"; + val = "volume"; + } + ]; + children = [ + (mkTag { + name = "volume"; + value = "/var/lib/libvirt/images/kernel.img"; + }) + ]; + }) + ]; + }; + + in + { + # output = pkgs.writeText "libvirt-secret-config.xml" secret; + }; + }; +} diff --git a/nix/modules/libvirtnix/test.nix b/nix/modules/libvirtnix/test.nix new file mode 100644 index 0000000..8542b7e --- /dev/null +++ b/nix/modules/libvirtnix/test.nix @@ -0,0 +1,10 @@ +let + pkgs = import <nixpkgs> {}; +in + pkgs.lib.evalModules { + modules = [ + # ./secret.nix + ./domain.nix + ./config.nix + ]; + } diff --git a/nix/modules/libvirtnix/xml.nix b/nix/modules/libvirtnix/xml.nix new file mode 100644 index 0000000..10eefa3 --- /dev/null +++ b/nix/modules/libvirtnix/xml.nix @@ -0,0 +1,58 @@ +{ lib, ... }: + +# takes a few args and creats a valid xml tag pair out of it +# +# testTag = mkTag { +# name = "name"; +# args = [ +# { +# key = "arg1"; +# val = "arg1val"; +# } +# { +# key = "arg2"; +# val = "arg2val"; +# } +# ]; +# value = "qwe"; +# children = [ +# (mkTag { name = "nested"; args = []; value = "qwe"; children = [];}) +# ]; +# }; +# +# <name arg1=arg1val arg2=arg2val> +# value +# {children} +# </name> +{ + name, # name of the tag to be used, such as `secret`, `description`, ... + args ? [ ], # args, [ { key="a"; val="b"; } { key="c"; val="d"; } ] + value ? "", # the value to place in the middle + children ? [ ], # the child elements + closing ? true, # add a closing tag +}: +let + + # filter out all values missing a key + # this allows passing empty args such as `{}` which then get discarded + filteredArgs = (builtins.filter (x: x ? key) args); + + # convert the list of attr sets into a list of strings + mappedArgs = (map (x: "${x.key}='${x.val}'") filteredArgs); + + # [ "A" "B" "C" ] => [ "A" " " "B" " " "C" ] + spacedArgs = lib.strings.intersperse "" mappedArgs; + + # [ "A" " " "B" " " "C" ] => "A B C" + joinedArgs = lib.strings.concatStrings spacedArgs; + + # prefix the args with a space when inserting + args_str = lib.optionalString (filteredArgs != [ ]) (" " + joinedArgs); + + child_evaled = lib.strings.concatStrings children; + + cond = condition: value: if condition then value else ""; + + closingTag = if closing == true then "</${name}>" else ""; +in +"<${name}${args_str}${cond (closing == false) "/"}>${value}${child_evaled}${lib.optionalString (closing) closingTag}" diff --git a/nix/modules/x86_64-linux.nix b/nix/modules/x86_64-linux.nix index e5dbc64..62945b3 100644 --- a/nix/modules/x86_64-linux.nix +++ b/nix/modules/x86_64-linux.nix @@ -4,6 +4,7 @@ ./r2wars-web ./remarvin ./filebrowser - ./libvirtnix + # ./libvirtnix + ./goapp-frontend ]; } diff --git a/nix/pkgs/aarch64-darwin.nix b/nix/pkgs/aarch64-darwin.nix index f5e8b60..78d5374 100644 --- a/nix/pkgs/aarch64-darwin.nix +++ b/nix/pkgs/aarch64-darwin.nix @@ -1,6 +1,7 @@ final: prev: { vokobe = final.callPackage ./vokobe { inherit (final) naersk; }; r2wars-web = final.callPackage ./r2wars-web { }; - remarvin = final.callPackage ./remarvin { }; - libc-database = final.callPackage ./libc-database {}; + # remarvin = final.callPackage ./remarvin { }; + # libc-database = final.callPackage ./libc-database {}; + # glibc-all-in-one = final.callPackage ./glibc-all-in-one { }; } diff --git a/nix/pkgs/glibc-all-in-one/default.nix b/nix/pkgs/glibc-all-in-one/default.nix new file mode 100644 index 0000000..896f91e --- /dev/null +++ b/nix/pkgs/glibc-all-in-one/default.nix @@ -0,0 +1,36 @@ +{ pkgs ? import <nixpkgs> {}, lib, fetchFromGitHub }: + +let + python = pkgs.python311.withPackages ( ps: with ps; [ requests ] ); +in pkgs.stdenv.mkDerivation rec { + name = "glibc-all-in-one"; + version = "master"; + + src = fetchFromGitHub { + owner = "fr0ster"; + repo = "glibc-all-in-one"; + rev = version; + sha256 = "sha256-vrh/ol56sNWTjGbwZ1Jrh+Lxz7aROvI6IbkJf/WliNE="; + }; + + buildPhase = ''''; + + installPhase = '' + mkdir -p $out/bin + cp build download extract $out/bin + cp update_list $out/bin/update_list_raw + + echo "${python}/bin/python3 $out/bin/update_list_raw" > $out/bin/update_list + chmod +x $out/bin/update_list + + mkdir -p $out/debs + mkdir -p $out/libs + ''; + + meta = { + description = ""; + homepage = "https://github.com/fr0ster/glibc-all-in-one"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ hanemile ]; + }; + } diff --git a/nix/pkgs/libc-database/default.nix b/nix/pkgs/libc-database/default.nix index b13a167..0bc91b4 100644 --- a/nix/pkgs/libc-database/default.nix +++ b/nix/pkgs/libc-database/default.nix @@ -13,7 +13,7 @@ pkgs.stdenv.mkDerivation rec { owner = "niklasb"; repo = "libc-database"; rev = version; - sha256 = "Zysjhr76TenMarnoKo+M8DrTNbsnaXSoFZO1puPVoxU="; + sha256 = "sha256-Zysjhr76TenMarnoKo+M8DrTNbsnaXSoFZO1puPVoxU="; }; # not building, we just want to download the repo diff --git a/nix/pkgs/overlay.nix b/nix/pkgs/overlay.nix deleted file mode 100644 index e213533..0000000 --- a/nix/pkgs/overlay.nix +++ /dev/null @@ -1,9 +0,0 @@ -final: prev: { - vokobe = final.callPackage ./vokobe { inherit (final) naersk; }; - r2wars-web = final.callPackage ./r2wars-web { }; - remarvin = final.callPackage ./remarvin { }; - - pretalx_old = prev.pretalx.overrideAttrs ( old: { - version = "2024.1.0"; - }); -} diff --git a/nix/pkgs/r2wars-web/default.nix b/nix/pkgs/r2wars-web/default.nix index 1d55de3..01b4a2d 100644 --- a/nix/pkgs/r2wars-web/default.nix +++ b/nix/pkgs/r2wars-web/default.nix @@ -18,7 +18,7 @@ pkgs.buildGoModule rec { vendorHash = null; - CGO_ENABLED = 0; + env.CGO_ENABLED = 0; subPackages = [ "src" ]; postInstall = '' diff --git a/nix/pkgs/x86_64-linux.nix b/nix/pkgs/x86_64-linux.nix index f5e8b60..33f314b 100644 --- a/nix/pkgs/x86_64-linux.nix +++ b/nix/pkgs/x86_64-linux.nix @@ -2,5 +2,6 @@ final: prev: { vokobe = final.callPackage ./vokobe { inherit (final) naersk; }; r2wars-web = final.callPackage ./r2wars-web { }; remarvin = final.callPackage ./remarvin { }; - libc-database = final.callPackage ./libc-database {}; + # glibc-all-in-one = final.callPackage ./glibc-all-in-one { }; + # libc-database = final.callPackage ./libc-database {}; } diff --git a/nix/templates/ctf/flake.lock b/nix/templates/ctf/flake.lock new file mode 100644 index 0000000..b756d8d --- /dev/null +++ b/nix/templates/ctf/flake.lock @@ -0,0 +1,141 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1740603184, + "narHash": "sha256-t+VaahjQAWyA+Ctn2idyo1yxRIYpaDxMgHkgCNiMJa4=", + "ref": "nixos-24.11", + "rev": "f44bd8ca21e026135061a0a57dcf3d0775b67a49", + "shallow": true, + "type": "git", + "url": "ssh://git@github.com/nixos/nixpkgs.git" + }, + "original": { + "ref": "nixos-24.11", + "shallow": true, + "type": "git", + "url": "ssh://git@github.com/nixos/nixpkgs.git" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1736241350, + "narHash": "sha256-CHd7yhaDigUuJyDeX0SADbTM9FXfiWaeNyY34FL1wQU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8c9fd3e564728e90829ee7dbac6edc972971cd0f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pwndbg": { + "inputs": { + "nixpkgs": "nixpkgs_2", + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": "pyproject-nix", + "uv2nix": "uv2nix" + }, + "locked": { + "lastModified": 1740333626, + "narHash": "sha256-OcwULIZcWOC1FNGa0SNGtyMyfbwTsBj17LBPpGOZL78=", + "ref": "refs/heads/dev", + "rev": "ef090ebf5eb75713b1f97c3d9aa3d7be636b0c3a", + "revCount": 2284, + "type": "git", + "url": "ssh://git@github.com/pwndbg/pwndbg" + }, + "original": { + "type": "git", + "url": "ssh://git@github.com/pwndbg/pwndbg" + } + }, + "pyproject-build-systems": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ], + "pyproject-nix": [ + "pwndbg", + "pyproject-nix" + ], + "uv2nix": [ + "pwndbg", + "uv2nix" + ] + }, + "locked": { + "lastModified": 1737338290, + "narHash": "sha256-gnXlfFEHA+/jMH7R+7y3JxrI3WfOjgBhzzJNuFW70UU=", + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "rev": "e1487e5cefda0c7990bdd2e660bee20971680e45", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "build-system-pkgs", + "type": "github" + } + }, + "pyproject-nix": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1738204167, + "narHash": "sha256-J5M2sj3x4ocM93shScT/3Z4XWHZhwwW1NyQK+C+8Mys=", + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "rev": "0d9f4b90cee1b5c5d6c142ef22de1e246e003ccc", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "pyproject.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "pwndbg": "pwndbg" + } + }, + "uv2nix": { + "inputs": { + "nixpkgs": [ + "pwndbg", + "nixpkgs" + ], + "pyproject-nix": [ + "pwndbg", + "pyproject-nix" + ] + }, + "locked": { + "lastModified": 1738653454, + "narHash": "sha256-tAFX8mPZtZ+zVE/+bwPC3U+u5MxjpNP0gG24DG26jVs=", + "owner": "pyproject-nix", + "repo": "uv2nix", + "rev": "05b0c148bc53aebc6a906b6d0ac41dde5954cd47", + "type": "github" + }, + "original": { + "owner": "pyproject-nix", + "repo": "uv2nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/templates/ctf/flake.nix b/nix/templates/ctf/flake.nix index e8b75b9..f185bb7 100644 --- a/nix/templates/ctf/flake.nix +++ b/nix/templates/ctf/flake.nix @@ -1,14 +1,20 @@ { - description = "ctf"; + description = '' + One Flake to rule them all^W^Wcommon CTF problems, namely broken infa. + + Usage: + ; nix flake init -t git+https://github.com/hanemile/hefe\#ctf + ''; nixConfig.bash-prompt = "\[ctf\]; "; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs"; + nixpkgs.url = "git+ssh://git@github.com/nixos/nixpkgs.git?shallow=1&ref=nixos-24.11"; + pwndbg.url = "git+ssh://git@github.com/pwndbg/pwndbg"; }; # Flake outputs outputs = - { nixpkgs, ... }: + { nixpkgs, pwndbg, ... }@inputs: let # Systems supported allSystems = [ @@ -21,30 +27,46 @@ # Helper to provide system-specific attributes nameValuePair = name: value: { inherit name value; }; genAttrs = names: f: builtins.listToAttrs (map (n: nameValuePair n (f n)) names); - forAllSystems = f: genAttrs allSystems (system: f { pkgs = import nixpkgs { inherit system; }; }); + forAllSystems = f: genAttrs allSystems (system: f { + pkgs = import nixpkgs { inherit system; }; + pwndbg = inputs.pwndbg.packages.${system}.default; + }); in { # Development environment output devShells = forAllSystems ( - { pkgs }: + { pkgs, pwndbg }: { default = - let - python = pkgs.python311; # Use Python 3.11 - in pkgs.mkShell { - packages = - with pkgs; - [ qemu ] - ++ [ - # Python plus helper tools - (python.withPackages ( - ps: with ps; [ - pwntools - pycryptodome - ] - )) - ]; + shellHook = '' + cat << EOF > solve.py + from pwn import * + + context.gdbinit="${pwndbg}/share/pwndbg/gdbinit.py" + + # exe = ELF("./a.out") + + p = remote("138.199.213.51", 31335) + #p = gdb.debug(exe.path, gdbscript='''' + # break main + # c + # '''') + + p.sendlineafter(b"> ", b"asd") + + p.interactive() + EOF + ''; + packages = [ + pkgs.gcc + pwndbg + (pkgs.python311.withPackages ( ps: with ps; [ + pwntools + pwndbg + pycryptodome + ])) + ]; }; } ); diff --git a/nix/templates/ctf/solve.py b/nix/templates/ctf/solve.py new file mode 100644 index 0000000..acc4a75 --- /dev/null +++ b/nix/templates/ctf/solve.py @@ -0,0 +1,15 @@ +from pwn import * + +context.gdbinit="/nix/store/jhvjf5drzzqq54xghzz94h0a6wsn1fs1-pwndbg/share/pwndbg/gdbinit.py" + +# exe = ELF("./a.out") + +p = remote("138.199.213.51", 31335) +#p = gdb.debug(exe.path, gdbscript=''' +# break main +# c +# ''') + +p.sendlineafter(b"> ", b"asd") + +p.interactive() diff --git a/nix/templates/goapp/flake.nix b/nix/templates/goapp/flake.nix index 1ca876f..385f1bf 100644 --- a/nix/templates/goapp/flake.nix +++ b/nix/templates/goapp/flake.nix @@ -12,20 +12,26 @@ overlays = [ ]; }; + # take a name and return an attrset with a corresponding package and docker container package-and-docker = name: (let - pkgname = name + "-pkg"; + # define the name for the package and docker container + pkgname = name; dockername = name + "-docker"; + # import the package itself package = import ./${name} { inherit pkgs name; }; + + # define the container + container = pkgs.dockerTools.buildImage { + name = "${name}"; # TODO(emile): this could simply be `inherit name;` iinw + config.Cmd = [ "${package}/bin/${name}" ]; + }; in { # the raw package ${pkgname} = package; # the docker image - ${dockername} = pkgs.dockerTools.buildImage { - name = "${name}"; - config.Cmd = [ "${package}/bin/${name}" ]; - }; + ${dockername} = container; }); in { diff --git a/nix/templates/goapp/frontend/default.nix b/nix/templates/goapp/frontend/default.nix index 42ccb79..7b5caa8 100644 --- a/nix/templates/goapp/frontend/default.nix +++ b/nix/templates/goapp/frontend/default.nix @@ -4,13 +4,20 @@ let version = "0.0.1"; in pkgs.buildGoModule { - name = "${name}-${version}"; pname = "${name}"; version = "${version}"; src = ./.; - subPackages = [ "src" ]; - vendorHash = "sha256-VXuhsXejduIcthawj4qu7hruBEDegj27YY0ym5srMQY="; - doCheck = true; + # use the dependencies directly from the vendor/ folder + # vendorHash = null; + + vendorHash = "sha256-dXWwAP0XM24cAcDV87XHQX9dLg6TDQ7ZVfEFgW/Q+J4="; + + doCheck = false; + + postInstall = '' + cp -r templates $out + mv $out/bin/{src,${name}} + ''; } diff --git a/nix/templates/goapp/frontend/go.mod b/nix/templates/goapp/frontend/go.mod index fecf4ac..a71f5a0 100644 --- a/nix/templates/goapp/frontend/go.mod +++ b/nix/templates/goapp/frontend/go.mod @@ -1,20 +1,20 @@ -module github.com/hanemile/goapp/backend +module github.com/hanemile/goapp/frontend go 1.23.5 require ( + github.com/coreos/go-oidc/v3 v3.12.0 github.com/gorilla/handlers v1.5.2 github.com/gorilla/mux v1.8.1 github.com/gorilla/securecookie v1.1.2 github.com/gorilla/sessions v1.4.0 github.com/mattn/go-sqlite3 v1.14.24 - golang.org/x/crypto v0.33.0 + github.com/spf13/cobra v1.9.1 golang.org/x/oauth2 v0.21.0 modernc.org/sqlite v1.34.5 ) require ( - github.com/coreos/go-oidc/v3 v3.12.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.2 // indirect @@ -23,8 +23,8 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.6 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/sys v0.30.0 // indirect modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/nix/templates/goapp/frontend/go.sum b/nix/templates/goapp/frontend/go.sum index 365e2c5..15bbb6f 100644 --- a/nix/templates/goapp/frontend/go.sum +++ b/nix/templates/goapp/frontend/go.sum @@ -1,6 +1,8 @@ github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo= github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -31,6 +33,8 @@ github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBW github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -38,6 +42,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= @@ -50,6 +56,7 @@ golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= diff --git a/nix/templates/goapp/frontend/run.sh b/nix/templates/goapp/frontend/run.sh index fb3c7b3..b2624f3 100755 --- a/nix/templates/goapp/frontend/run.sh +++ b/nix/templates/goapp/frontend/run.sh @@ -1,3 +1,4 @@ +# these are tests creds that aren't valid, try it :D export CLIENT_ID=goapp export CLIENT_SECRET=KGFO5LQnUxu1Zs.35gOem3MaG8odthg1U0v0.kScVPS6TPTWVRnAdT_nj4PYYSfuU6jdzTM6 export CLIENT_CALLBACK_URL=http://localhost:8080/oauth2/callback @@ -6,4 +7,5 @@ export SESSION_KEY=aes1Itheich4aeQu9Ouz7ahcaiVoogh9 go run ./... \ --id goapp \ --issuer "https://sso.emile.space" \ - --secret "KGFO5LQnUxu1Zs.35gOem3MaG8odthg1U0v0.kScVPS6TPTWVRnAdT_nj4PYYSfuU6jdzTM6" + --secret "KGFO5LQnUxu1Zs.35gOem3MaG8odthg1U0v0.kScVPS6TPTWVRnAdT_nj4PYYSfuU6jdzTM6" \ + $@ diff --git a/nix/templates/goapp/frontend/server.log b/nix/templates/goapp/frontend/server.log index 4b6cff5..6c4d6dc 100644 --- a/nix/templates/goapp/frontend/server.log +++ b/nix/templates/goapp/frontend/server.log @@ -177,3 +177,5 @@ ::1 - - [19/Feb/2025:19:43:29 +0100] "GET /oauth2/callback?code=authelia_ac_8UdV__GJCN9gxJrYa629TC3FToyDDhsbacPbJzhvcJ4.uPw2-_N4jQr7xf7JNZ_IZBNHEq-eeOFoZup7Vwjx1Y0&iss=https%3A%2F%2Fsso.emile.space&scope=openid+profile+email+groups&state=random-string-here HTTP/1.1" 500 142 ::1 - - [19/Feb/2025:19:49:22 +0100] "GET / HTTP/1.1" 200 6587 ::1 - - [19/Feb/2025:19:49:23 +0100] "GET /login HTTP/1.1" 302 242 +::1 - - [19/Feb/2025:19:56:09 +0100] "GET / HTTP/1.1" 200 6587 +::1 - - [19/Feb/2025:19:56:12 +0100] "GET /login HTTP/1.1" 302 242 diff --git a/nix/templates/goapp/frontend/src/handlers.go b/nix/templates/goapp/frontend/src/handlers.go index 8fdd325..2cbacde 100644 --- a/nix/templates/goapp/frontend/src/handlers.go +++ b/nix/templates/goapp/frontend/src/handlers.go @@ -12,7 +12,7 @@ import ( ) func indexHandler(w http.ResponseWriter, r *http.Request) { - session, err := globalState.sessions.Get(r, "session") + session, err := globalState.sessions.Get(r, options.CookieName) if err != nil { log.Println("error getting the session") } @@ -37,9 +37,14 @@ func indexHandler(w http.ResponseWriter, r *http.Request) { }, }, } - tpl.NextLinks = []Link{ - {"Login", "/login"}, - } + + // session.Values["id_token"] = claimsIDToken + // session.Values["userinfo"] = claimsUserInfo + // session.Values["logged"] = true + // + log.Println("logged", session.Values["logged"]) + log.Println("id-token", session.Values["id_token"]) + log.Println("userinfo", session.Values["userinfo"]) if logged, ok := session.Values["logged"].(bool); ok && logged { tpl.LoggedIn = true @@ -68,6 +73,10 @@ func indexHandler(w http.ResponseWriter, r *http.Request) { tpl.Claims.UserInfo.Name = filterText(tpl.Claims.UserInfo.Name, options.Filters) tpl.RawToken = rawTokens[tpl.Claims.IDToken.JWTIdentifier] tpl.AuthorizeCodeURL = acURLs[tpl.Claims.IDToken.JWTIdentifier].String() + + tpl.NextLinks = []Link{{"Logout", "/logout"}} + } else { + tpl.NextLinks = []Link{{"Login", "/login"}} } w.Header().Add("Content-Type", "text/html") @@ -129,12 +138,11 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/", http.StatusFound) } -func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { +func oauthCallbackHandler(w http.ResponseWriter, r *http.Request) { log.Println("hit the oauth callback handler") - if req.FormValue("error") != "" { - log.Printf("got an error from the idp: %s", req.FormValue("error")) - http.Redirect(res, req, fmt.Sprintf("/error?%s", req.Form.Encode()), http.StatusFound) - + if r.FormValue("error") != "" { + log.Printf("got an error from the idp: %s", r.FormValue("error")) + http.Redirect(w, r, fmt.Sprintf("/error?%s", r.Form.Encode()), http.StatusFound) return } @@ -146,24 +154,32 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { ok bool ) + log.Println(r.URL) + // The state should be checked here in production - if token, err = oauth2Config.Exchange(req.Context(), req.URL.Query().Get("code")); err != nil { + if token, err = oauth2Config.Exchange( + r.Context(), + r.URL.Query().Get("code"), + // oauth2.SetAuthURLParam("client_id", oauth2Config.ClientID), + // oauth2.SetAuthURLParam("client_secret", oauth2Config.ClientSecret), + ); err != nil { log.Println("Unable to exchange authorization code for tokens") - writeErr(res, err, "unable to exchange authorization code for tokens", http.StatusInternalServerError) + log.Println(err) + writeErr(w, err, "unable to exchange authorization code for tokens", http.StatusInternalServerError) return } // Extract the ID Token from OAuth2 token. if idTokenRaw, ok = token.Extra("id_token").(string); !ok { log.Println("missing id token") - writeErr(res, nil, "missing id token", http.StatusInternalServerError) + writeErr(w, nil, "missing id token", http.StatusInternalServerError) return } // Parse and verify ID Token payload. - if idToken, err = verifier.Verify(req.Context(), idTokenRaw); err != nil { + if idToken, err = verifier.Verify(r.Context(), idTokenRaw); err != nil { log.Printf("unable to verify id token or token is invalid: %+v", idTokenRaw) - writeErr(res, err, "unable to verify id token or token is invalid", http.StatusInternalServerError) + writeErr(w, err, "unable to verify id token or token is invalid", http.StatusInternalServerError) return } @@ -172,15 +188,15 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { if err = idToken.Claims(&claimsIDToken); err != nil { log.Printf("unable to decode id token claims: %+v", &claimsIDToken) - writeErr(res, err, "unable to decode id token claims", http.StatusInternalServerError) + writeErr(w, err, "unable to decode id token claims", http.StatusInternalServerError) return } var userinfo *oidc.UserInfo - if userinfo, err = provider.UserInfo(req.Context(), oauth2.StaticTokenSource(token)); err != nil { + if userinfo, err = provider.UserInfo(r.Context(), oauth2.StaticTokenSource(token)); err != nil { log.Printf("unable to retreive userinfo claims") - writeErr(res, err, "unable to retrieve userinfo claims", http.StatusInternalServerError) + writeErr(w, err, "unable to retrieve userinfo claims", http.StatusInternalServerError) return } @@ -188,15 +204,15 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { if err = userinfo.Claims(&claimsUserInfo); err != nil { log.Printf("unable to decode userinfo claims") - writeErr(res, err, "unable to decode userinfo claims", http.StatusInternalServerError) + writeErr(w, err, "unable to decode userinfo claims", http.StatusInternalServerError) return } var session *sessions.Session - if session, err = globalState.sessions.Get(req, options.CookieName); err != nil { + if session, err = globalState.sessions.Get(r, options.CookieName); err != nil { log.Printf("unable to get session from cookie") - writeErr(res, err, "unable to get session from cookie", http.StatusInternalServerError) + writeErr(w, err, "unable to get session from cookie", http.StatusInternalServerError) return } @@ -204,11 +220,11 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { session.Values["userinfo"] = claimsUserInfo session.Values["logged"] = true rawTokens[claimsIDToken.JWTIdentifier] = idTokenRaw - acURLs[claimsIDToken.JWTIdentifier] = req.URL + acURLs[claimsIDToken.JWTIdentifier] = r.URL - if err = session.Save(req, res); err != nil { + if err = session.Save(r, w); err != nil { log.Printf("unable to save session") - writeErr(res, err, "unable to save session", http.StatusInternalServerError) + writeErr(w, err, "unable to save session", http.StatusInternalServerError) return } @@ -216,11 +232,11 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { if redirectUrl, ok = session.Values["redirect-url"].(string); ok { log.Printf("all fine!") - http.Redirect(res, req, redirectUrl, http.StatusFound) + http.Redirect(w, r, redirectUrl, http.StatusFound) return } - http.Redirect(res, req, "/", http.StatusFound) + http.Redirect(w, r, "/", http.StatusFound) } func writeErr(w http.ResponseWriter, err error, msg string, statusCode int) { diff --git a/nix/templates/goapp/frontend/src/init.go b/nix/templates/goapp/frontend/src/init.go index 97e58f0..75fd87d 100644 --- a/nix/templates/goapp/frontend/src/init.go +++ b/nix/templates/goapp/frontend/src/init.go @@ -2,8 +2,10 @@ package main import ( "context" + // "crypto/tls" "fmt" "log" + // "net/http" "net/url" "os" "strings" @@ -32,12 +34,17 @@ func dbInit() { func sessionInit() { log.Println("[i] Setting up Session Storage...") + session_key, err := os.ReadFile(options.SessionKeyPath) + if err != nil { + log.Println("Could not read Session key") + panic(err) + } store, err := NewSqliteStore( sessiondbPath, "sessions", "/", 3600, - []byte(os.Getenv("SESSION_KEY"))) + session_key) if err != nil { panic(err) } @@ -60,17 +67,29 @@ func oauth2Init() (err error) { } verifier = provider.Verifier(&oidc.Config{ClientID: options.ClientID}) + + clientSecretBytes, err := os.ReadFile(options.ClientSecretPath) + if err != nil { + panic(err) + } + clientSecret := strings.TrimSpace(string(clientSecretBytes)) + log.Printf("[ ] ClientID: %s", options.ClientID) - log.Printf("[ ] ClientSecret: %s", options.ClientSecret) + log.Printf("[ ] ClientSecret: %s", clientSecret) log.Printf("[ ] redirectURL: %s", redirectURL.String()) log.Printf("[ ] providerEndpoint: %+v", provider.Endpoint()) log.Printf("[ ] Scopes: %s", options.Scopes) + log.Printf("[ ] Endpoint: %+v", provider.Endpoint()) + oauth2Config = oauth2.Config{ ClientID: options.ClientID, - ClientSecret: options.ClientSecret, + ClientSecret: clientSecret, RedirectURL: redirectURL.String(), Endpoint: provider.Endpoint(), Scopes: strings.Split(options.Scopes, ","), } + + oauth2Config.Endpoint.AuthStyle = oauth2.AuthStyleInParams + return nil } diff --git a/nix/templates/goapp/frontend/src/main.go b/nix/templates/goapp/frontend/src/main.go index fcf4224..72ec7ee 100644 --- a/nix/templates/goapp/frontend/src/main.go +++ b/nix/templates/goapp/frontend/src/main.go @@ -38,18 +38,21 @@ func main() { rootCmd := &cobra.Command{Use: "goapp", RunE: root} - rootCmd.Flags().StringVar(&options.Host, "host", "0.0.0.0", "Specifies the tcp host to listen on") + rootCmd.Flags().StringVar(&options.Host, "host", "127.0.0.1", "Specifies the tcp host to listen on") rootCmd.Flags().IntVar(&options.Port, "port", 8080, "Specifies the port to listen on") rootCmd.Flags().StringVar(&options.PublicURL, "public-url", "http://localhost:8080/", "Specifies the root URL to generate the redirect URI") rootCmd.Flags().StringVar(&options.ClientID, "id", "", "Specifies the OpenID Connect Client ID") - rootCmd.Flags().StringVarP(&options.ClientSecret, "secret", "s", "", "Specifies the OpenID Connect Client Secret") + rootCmd.Flags().StringVarP(&options.ClientSecretPath, "oidc-secret-path", "s", "", "Specifies the OpenID Connect Client Secret path") rootCmd.Flags().StringVarP(&options.Issuer, "issuer", "i", "", "Specifies the URL for the OpenID Connect OP") rootCmd.Flags().StringVar(&options.Scopes, "scopes", "openid,profile,email,groups", "Specifies the OpenID Connect scopes to request") rootCmd.Flags().StringVar(&options.CookieName, "cookie-name", "oidc-client", "Specifies the storage cookie name to use") rootCmd.Flags().StringSliceVar(&options.Filters, "filters", []string{}, "If specified filters the specified text from html output (not json) out of the email addresses, display names, audience, etc") rootCmd.Flags().StringSliceVar(&options.GroupsFilter, "groups-filter", []string{}, "If specified only shows the groups in this list") - rootCmd.Flags().StringVar(&options.LogFilePath, "logpath", "./server.log", "Specifies the path to store the server logs at") + rootCmd.Flags().StringVar(&options.LogFilePath, "logfilepath", "./server.log", "Specifies the path to store the server logs at") rootCmd.Flags().StringVar(&options.TemplatesPath, "templatespath", "./templates", "Specifies the path to where the templates are stored") + rootCmd.Flags().StringVar(&options.DatabasePath, "databasepath", "./main.db", "Specifies the path to where the database is stored") + rootCmd.Flags().StringVar(&options.SessionDBPath, "sessiondbpath", "./sessions.db", "Specifies the path to where the session database is stored") + rootCmd.Flags().StringVar(&options.SessionKeyPath, "sessionkeypath", "", "Specifies the path to where the session key is stored") _ = rootCmd.MarkFlagRequired("id") _ = rootCmd.MarkFlagRequired("secret") diff --git a/nix/templates/goapp/frontend/src/types.go b/nix/templates/goapp/frontend/src/types.go index 7efcc70..97e0db5 100644 --- a/nix/templates/goapp/frontend/src/types.go +++ b/nix/templates/goapp/frontend/src/types.go @@ -50,16 +50,19 @@ type ClamsAddress struct { } type Options struct { - Host string - Port int - LogFilePath string - TemplatesPath string - ClientID string - ClientSecret string - Issuer string - PublicURL string - Scopes string - CookieName string - Filters []string - GroupsFilter []string + ClientID string + ClientSecretPath string + CookieName string + DatabasePath string + Filters []string + GroupsFilter []string + Host string + Issuer string + LogFilePath string + Port int + PublicURL string + Scopes string + SessionDBPath string + SessionKeyPath string + TemplatesPath string } diff --git a/nix/templates/goapp/frontend/templates/index.html b/nix/templates/goapp/frontend/templates/index.html index 1d21f3d..e4693af 100644 --- a/nix/templates/goapp/frontend/templates/index.html +++ b/nix/templates/goapp/frontend/templates/index.html @@ -5,6 +5,8 @@ <h1>goapp</h1> +{{ . }} + {{- if .LoggedIn }} <p id="welcome">Logged in as {{ or .Claims.UserInfo.PreferredUsername .Claims.IDToken.Subject "unknown" }}!</p> <p><a href="/logout" id="log-out">Log out</a></p> diff --git a/secret_create.sh b/secret_create.sh index fcd05cb..1f27834 100755 --- a/secret_create.sh +++ b/secret_create.sh @@ -2,6 +2,8 @@ # $1 = hostname # $2 = secretname (with .age suffix) +# set -xe + if [ $# -lt 2 ]; then # TODO: print usage echo "USAGE: ./secret_create.sh <hostname> <secretname>" |