mirror of
https://github.com/Swarsel/.dotfiles.git
synced 2025-12-06 17:17:22 +01:00
feat: new deploy system, allows for in-repo pii
This commit is contained in:
parent
7e11641fe7
commit
a11c7854d1
19 changed files with 1251 additions and 412 deletions
|
|
@ -340,66 +340,74 @@ In this section I am creating some attributes that define general concepts of my
|
|||
They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference.
|
||||
|
||||
#+begin_src nix :tangle no :noweb-ref flakeoutputgeneral
|
||||
inherit lib;
|
||||
inherit lib;
|
||||
|
||||
# nixosModules = import ./modules/nixos { inherit lib; };
|
||||
# homeModules = import ./modules/home { inherit lib; };
|
||||
packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; });
|
||||
formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt);
|
||||
overlays = import ./overlays { inherit self lib inputs; };
|
||||
# nixosModules = import ./modules/nixos { inherit lib; };
|
||||
# homeModules = import ./modules/home { inherit lib; };
|
||||
packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; });
|
||||
formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt);
|
||||
overlays = import ./overlays { inherit self lib inputs; };
|
||||
|
||||
apps = lib.swarselsystems.forAllSystems (system:
|
||||
let
|
||||
appNames = [
|
||||
"swarsel-bootstrap"
|
||||
"swarsel-install"
|
||||
"swarsel-rebuild"
|
||||
"swarsel-postinstall"
|
||||
];
|
||||
appSet = lib.swarselsystems.mkApps system appNames self;
|
||||
in
|
||||
|
||||
appSet // {
|
||||
default = appSet.swarsel-bootstrap;
|
||||
}
|
||||
);
|
||||
|
||||
devShells = lib.swarselsystems.forAllSystems (system:
|
||||
let
|
||||
pkgs = lib.swarselsystems.pkgsFor.${system};
|
||||
checks = self.checks.${system};
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
NIX_CONFIG = "experimental-features = nix-command flakes";
|
||||
inherit (checks.pre-commit-check) shellHook;
|
||||
buildInputs = checks.pre-commit-check.enabledPackages;
|
||||
nativeBuildInputs = [
|
||||
pkgs.nix
|
||||
pkgs.home-manager
|
||||
pkgs.git
|
||||
pkgs.just
|
||||
pkgs.age
|
||||
pkgs.ssh-to-age
|
||||
pkgs.sops
|
||||
pkgs.statix
|
||||
pkgs.deadnix
|
||||
pkgs.nixpkgs-fmt
|
||||
apps = lib.swarselsystems.forAllSystems (system:
|
||||
let
|
||||
appNames = [
|
||||
"swarsel-bootstrap"
|
||||
"swarsel-install"
|
||||
"swarsel-rebuild"
|
||||
"swarsel-postinstall"
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
appSet = lib.swarselsystems.mkApps system appNames self;
|
||||
in
|
||||
|
||||
templates = import ./templates { inherit lib; };
|
||||
appSet // {
|
||||
default = appSet.swarsel-bootstrap;
|
||||
}
|
||||
);
|
||||
|
||||
checks = lib.swarselsystems.forAllSystems (system:
|
||||
let
|
||||
pkgs = lib.swarselsystems.pkgsFor.${system};
|
||||
in
|
||||
import ./checks { inherit self inputs system pkgs; }
|
||||
);
|
||||
devShells = lib.swarselsystems.forAllSystems (system:
|
||||
let
|
||||
pkgs = lib.swarselsystems.pkgsFor.${system};
|
||||
checks = self.checks.${system};
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
NIX_CONFIG = ''
|
||||
plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: {
|
||||
buildInputs = [pkgs.nixVersions.latest pkgs.boost];
|
||||
patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ];
|
||||
})}/lib/nix/plugins
|
||||
extra-builtins-file = ${self + /nix/extra-builtins.nix}
|
||||
'';
|
||||
inherit (checks.pre-commit-check) shellHook;
|
||||
|
||||
diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix;
|
||||
buildInputs = checks.pre-commit-check.enabledPackages;
|
||||
nativeBuildInputs = [
|
||||
# (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions.
|
||||
pkgs.nix
|
||||
pkgs.home-manager
|
||||
pkgs.git
|
||||
pkgs.just
|
||||
pkgs.age
|
||||
pkgs.ssh-to-age
|
||||
pkgs.sops
|
||||
pkgs.statix
|
||||
pkgs.deadnix
|
||||
pkgs.nixpkgs-fmt
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
templates = import ./templates { inherit lib; };
|
||||
|
||||
checks = lib.swarselsystems.forAllSystems (system:
|
||||
let
|
||||
pkgs = lib.swarselsystems.pkgsFor.${system};
|
||||
in
|
||||
import ./checks { inherit self inputs system pkgs; }
|
||||
);
|
||||
|
||||
diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix;
|
||||
#+end_src
|
||||
|
||||
** Pre-commit-hooks (Checks)
|
||||
|
|
@ -849,7 +857,7 @@ My work machine. Built for more security, this is the gold standard of my config
|
|||
sharedOptions;
|
||||
|
||||
home-manager.users."${primaryUser}" = {
|
||||
home.stateVersion = lib.mkForce "23.05";
|
||||
# home.stateVersion = lib.mkForce "23.05";
|
||||
swarselsystems = lib.recursiveUpdate
|
||||
{
|
||||
isLaptop = true;
|
||||
|
|
@ -3685,6 +3693,136 @@ AppImage version of mgba in which the lua scripting works.
|
|||
|
||||
#+end_src
|
||||
|
||||
**** swarsel-deploy
|
||||
|
||||
#+begin_src nix :tangle pkgs/swarsel-deploy/default.nix
|
||||
# heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix
|
||||
{ name, bc, nix-output-monitor, writeShellApplication, ... }:
|
||||
writeShellApplication {
|
||||
runtimeInputs = [ bc nix-output-monitor ];
|
||||
inherit name;
|
||||
text = ''
|
||||
set -euo pipefail
|
||||
shopt -s lastpipe # allow cmd | readarray
|
||||
|
||||
function die() {
|
||||
echo "error: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
function show_help() {
|
||||
echo 'Usage: deploy [OPTIONS] <host,...> [ACTION]'
|
||||
echo "Builds, pushes and activates nixosConfigurations on target systems."
|
||||
echo ""
|
||||
echo 'ACTION:'
|
||||
echo ' switch [default] Switch immediately to the new configuration and make it the boot default'
|
||||
echo ' boot Make the configuration the new boot default'
|
||||
echo " test Activate the configuration but don't make it the boot default"
|
||||
echo " dry-activate Don't activate, just show what would be done"
|
||||
echo ""
|
||||
echo 'OPTIONS: [passed to nix build]'
|
||||
}
|
||||
|
||||
function time_start() {
|
||||
T_START=$(date +%s.%N)
|
||||
}
|
||||
|
||||
function time_next() {
|
||||
T_END=$(date +%s.%N)
|
||||
T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1")
|
||||
T_START="$T_END"
|
||||
}
|
||||
|
||||
cd ~/.dotfiles
|
||||
USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) ||
|
||||
die "Could not determine current working directory. Something went very wrong."
|
||||
[[ -e "$USER_FLAKE_DIR/flake.nix" ]] ||
|
||||
die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix."
|
||||
cd "$USER_FLAKE_DIR"
|
||||
|
||||
[[ $# -gt 0 ]] || {
|
||||
show_help
|
||||
exit 1
|
||||
}
|
||||
|
||||
OPTIONS=()
|
||||
POSITIONAL_ARGS=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
"help" | "--help" | "-help" | "-h")
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
|
||||
-*) OPTIONS+=("$1") ;;
|
||||
,*) POSITIONAL_ARGS+=("$1") ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
[[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] ||
|
||||
die "Missing argument: <hosts...>"
|
||||
[[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] ||
|
||||
die "Too many arguments given."
|
||||
|
||||
tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS
|
||||
ACTION="''${POSITIONAL_ARGS[1]-switch}"
|
||||
|
||||
# Expand flake paths for hosts definitions
|
||||
declare -A TOPLEVEL_FLAKE_PATHS
|
||||
for host in "''${HOSTS[@]}"; do
|
||||
TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel"
|
||||
done
|
||||
|
||||
time_start
|
||||
|
||||
# Get outputs of all derivations (should be cached)
|
||||
declare -A TOPLEVEL_STORE_PATHS
|
||||
for host in "''${HOSTS[@]}"; do
|
||||
toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}"
|
||||
echo "[1;36m Building [m📦 [34m$host[m"
|
||||
nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json ||
|
||||
die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}"
|
||||
TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel")
|
||||
time_next
|
||||
echo "[1;32m Built [m✅ [34m$host[m [33m''${TOPLEVEL_STORE_PATHS["$host"]}[m [90min ''${T_LAST}s[m"
|
||||
done
|
||||
|
||||
current_host=$(hostname)
|
||||
|
||||
for host in "''${HOSTS[@]}"; do
|
||||
store_path="''${TOPLEVEL_STORE_PATHS["$host"]}"
|
||||
|
||||
if [ "$host" = "$current_host" ]; then
|
||||
echo -e "\033[1;36m Running locally for $host... \033[m"
|
||||
ssh_prefix="sudo"
|
||||
else
|
||||
echo -e "\033[1;36m Copying \033[m➡️ \033[34m$host\033[m"
|
||||
nix copy --to "ssh://$host" "$store_path"
|
||||
time_next
|
||||
echo -e "\033[1;32m Copied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m"
|
||||
ssh_prefix="ssh $host --"
|
||||
fi
|
||||
|
||||
echo -e "\033[1;36m Applying \033[m⚙️ \033[34m$host\033[m"
|
||||
prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system)
|
||||
$ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" ||
|
||||
die "Failed to set system profile"
|
||||
$ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" ||
|
||||
echo "Error while activating new system" >&2
|
||||
|
||||
if [[ -n $prev_system ]]; then
|
||||
$ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true
|
||||
fi
|
||||
|
||||
time_next
|
||||
echo -e "\033[1;32m Applied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m"
|
||||
done
|
||||
cd -
|
||||
'';
|
||||
}
|
||||
|
||||
#+end_src
|
||||
|
||||
**** sshrm
|
||||
|
||||
This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually.
|
||||
|
|
@ -3886,6 +4024,10 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a
|
|||
autologin = lib.mkDefault true;
|
||||
nswitch-rcm = lib.mkDefault true;
|
||||
};
|
||||
|
||||
server = {
|
||||
ssh = lib.mkDefault true;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -4490,8 +4632,6 @@ TODO
|
|||
{
|
||||
home-manager.users."${linuxUser}".imports = [
|
||||
# put home-manager imports here that are for all normal hosts
|
||||
inputs.sops-nix.homeManagerModules.sops
|
||||
inputs.nix-index-database.hmModules.nix-index
|
||||
"${self}/modules/home/common"
|
||||
"${self}/modules/home/server"
|
||||
"${self}/modules/home/optional"
|
||||
|
|
@ -4597,6 +4737,83 @@ TODO
|
|||
}
|
||||
#+end_src
|
||||
|
||||
*** Auxiliary files
|
||||
**** extra-builtins
|
||||
|
||||
#+begin_src nix :tangle nix/extra-builtins.nix
|
||||
|
||||
{ exec, ... }:
|
||||
let
|
||||
assertMsg = pred: msg: pred || builtins.throw msg;
|
||||
hasSuffix =
|
||||
suffix: content:
|
||||
let
|
||||
lenContent = builtins.stringLength content;
|
||||
lenSuffix = builtins.stringLength suffix;
|
||||
in
|
||||
lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix;
|
||||
in
|
||||
{
|
||||
# Instead of calling sops directly here, we call a wrapper script that will cache the output
|
||||
# in a predictable path in /tmp, which allows us to only require the password for each encrypted
|
||||
# file once.
|
||||
sopsImportEncrypted =
|
||||
nixFile:
|
||||
assert assertMsg (builtins.isPath nixFile)
|
||||
"The file to decrypt must be given as a path to prevent impurity.";
|
||||
assert assertMsg (hasSuffix ".nix.age" nixFile)
|
||||
"The content of the decrypted file must be a nix expression and should therefore end in .nix.age";
|
||||
exec [
|
||||
./sops-decrypt-and-cache.sh
|
||||
nixFile
|
||||
];
|
||||
}
|
||||
|
||||
#+end_src
|
||||
**** sops-decrypt-and-cache
|
||||
|
||||
#+begin_src shell :tangle nix/sops-decrypt-and-cache.sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
print_out_path=false
|
||||
if [[ $1 == "--print-out-path" ]]; then
|
||||
print_out_path=true
|
||||
shift
|
||||
fi
|
||||
|
||||
file="$1"
|
||||
shift
|
||||
|
||||
basename="$file"
|
||||
# store path prefix or ./ if applicable
|
||||
[[ $file == "/nix/store/"* ]] && basename="${basename#*"-"}"
|
||||
[[ $file == "./"* ]] && basename="${basename#"./"}"
|
||||
|
||||
# Calculate a unique content-based identifier (relocations of
|
||||
# the source file in the nix store should not affect caching)
|
||||
new_name="$(sha512sum "$file")"
|
||||
new_name="${new_name:0:32}-${basename//"/"/"%"}"
|
||||
|
||||
# Derive the path where the decrypted file will be stored
|
||||
out="/var/tmp/nix-import-encrypted/$UID/$new_name"
|
||||
umask 077
|
||||
mkdir -p "$(dirname "$out")"
|
||||
|
||||
# Decrypt only if necessary
|
||||
if [[ ! -e $out ]]; then
|
||||
agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key)
|
||||
SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file"
|
||||
fi
|
||||
|
||||
# Print out path or decrypted content
|
||||
if [[ $print_out_path == true ]]; then
|
||||
echo "$out"
|
||||
else
|
||||
cat "$out"
|
||||
fi
|
||||
#+end_src
|
||||
** NixOS
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: h:6da812f5-358c-49cb-aff2-0a94f20d70b3
|
||||
|
|
@ -4858,6 +5075,14 @@ We enable the use of =home-manager= as a NixoS module. A nice trick here is the
|
|||
home-manager = lib.mkIf config.swarselsystems.withHomeManager {
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
verbose = true;
|
||||
sharedModules = [
|
||||
inputs.nix-index-database.hmModules.nix-index
|
||||
inputs.sops-nix.homeManagerModules.sops
|
||||
{
|
||||
home.stateVersion = lib.mkDefault config.system.stateVersion;
|
||||
}
|
||||
];
|
||||
extraSpecialArgs = { inherit (inputs) self; };
|
||||
};
|
||||
};
|
||||
|
|
@ -6450,7 +6675,7 @@ This dynamically uses systemd boot or Lanzaboote depending on `config.swarselsys
|
|||
lanzaboote = lib.mkIf (!config.swarselsystems.initialSetup && config.swarselsystems.isSecureBoot) {
|
||||
enable = true;
|
||||
pkiBundle = "/var/lib/sbctl";
|
||||
configurationLimit = 3;
|
||||
configurationLimit = 6;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -6555,6 +6780,7 @@ Here we just define some aliases for rebuilding the system, and we allow some in
|
|||
environment.systemPackages = with pkgs; [
|
||||
gnupg
|
||||
nix-index
|
||||
nvd
|
||||
ssh-to-age
|
||||
git
|
||||
emacs
|
||||
|
|
@ -6695,6 +6921,8 @@ Here we just define some aliases for rebuilding the system, and we allow some in
|
|||
:CUSTOM_ID: h:f3db197d-1d03-4bf8-b59f-f9891b358f0b
|
||||
:END:
|
||||
|
||||
Here I am forcing =startWhenNeeded= to false so that the value will not be set to true in containers = this would be a problem because it would delay ssh host key generation.
|
||||
|
||||
#+begin_src nix :tangle modules/nixos/server/ssh.nix
|
||||
{ self, lib, config, ... }:
|
||||
{
|
||||
|
|
@ -6702,6 +6930,18 @@ Here we just define some aliases for rebuilding the system, and we allow some in
|
|||
config = lib.mkIf config.swarselsystems.modules.server.ssh {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
startWhenNeeded = lib.mkForce false;
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
KbdInteractiveAuthentication = false;
|
||||
PermitRootLogin = "yes";
|
||||
};
|
||||
hostKeys = [
|
||||
{
|
||||
path = "/etc/ssh/ssh_host_ed25519_key";
|
||||
type = "ed25519";
|
||||
}
|
||||
];
|
||||
};
|
||||
users.users."${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = [
|
||||
(self + /secrets/keys/ssh/yubikey.pub)
|
||||
|
|
@ -10166,6 +10406,7 @@ This is just a separate container for derivations defined in [[#h:64a5cc16-6b16-
|
|||
fhs
|
||||
swarsel-bootstrap
|
||||
swarsel-displaypower
|
||||
swarsel-deploy
|
||||
swarselzellij
|
||||
sshrm
|
||||
|
||||
|
|
@ -10266,7 +10507,7 @@ It is very convenient to have SSH aliases in place for machines that I use. This
|
|||
};
|
||||
"winters" = {
|
||||
hostname = "192.168.1.2";
|
||||
user = "swarsel";
|
||||
user = "root";
|
||||
};
|
||||
"minecraft" = {
|
||||
hostname = "130.61.119.129";
|
||||
|
|
@ -10943,8 +11184,10 @@ Currently I only use it as before with =initExtra= though.
|
|||
{
|
||||
hg = "history | grep";
|
||||
hmswitch = "home-manager --flake ${flakePath}#$(whoami)@$(hostname) switch |& nom";
|
||||
nswitch = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v switch |& nom --json";
|
||||
nboot = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v boot |& nom --json";
|
||||
# nswitch = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v switch |& nom --json";
|
||||
nswitch = "swarsel-deploy $(hostname) switch";
|
||||
# nboot = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v boot |& nom --json";
|
||||
nboot = "swarsel-deploy $(hostname) boot";
|
||||
magit = "emacsclient -nc -e \"(magit-status)\"";
|
||||
config = "git --git-dir=$HOME/.cfg/ --work-tree=$HOME";
|
||||
g = "git";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue