diff --git a/.gitattributes b/.gitattributes index 95d2ba0..7806c50 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -shared/secrets/* filter=git-crypt diff=git-crypt +shared/secrets/weather-api-key filter=git-crypt diff=git-crypt diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..52f1cd9 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,7 @@ +keys: + - &primary age1fxr5s6d6ar0xy5pr63kpq93tk7jha5k96jcxnyquj6s2mw8mmcpss8w29w +creation_rules: + - path_regex: shared/secrets/secrets.yaml$ + key_groups: + - age: + - *primary diff --git a/flake.lock b/flake.lock index 59924e3..0e1306d 100644 --- a/flake.lock +++ b/flake.lock @@ -509,10 +509,31 @@ "nixpkgs-stable": "nixpkgs-stable", "nixpkgs-unstable": "nixpkgs-unstable", "nixvim": "nixvim", + "sops-nix": "sops-nix", "spicetify-nix": "spicetify-nix", "zen-browser": "zen-browser" } }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744669848, + "narHash": "sha256-pXyanHLUzLNd3MX9vsWG+6Z2hTU8niyphWstYEP3/GU=", + "owner": "mic92", + "repo": "sops-nix", + "rev": "61154300d945f0b147b30d24ddcafa159148026a", + "type": "github" + }, + "original": { + "owner": "mic92", + "repo": "sops-nix", + "type": "github" + } + }, "spicetify-nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index 4d95af9..40e2cb7 100644 --- a/flake.nix +++ b/flake.nix @@ -23,10 +23,10 @@ # ========= Utilities ========= # # Secrets management - # sops-nix = { - # url = "github:mic92/sops-nix"; - # inputs.nixpkgs.follows = "nixpkgs"; - # }; + sops-nix = { + url = "github:mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; # Catppuccin theming catppuccin = { url = "github:catppuccin/nix"; diff --git a/justfile b/justfile index 0863203..c7609de 100644 --- a/justfile +++ b/justfile @@ -44,3 +44,19 @@ unlock: # Connect to tailnet or sign-in if not registered start-tailscale: tailscale up --login-server https://vpn.martials.no + +# Generate a new age key from an existing ssh key (without passphrase) +@generate-age-from-ssh: + nix run nixpkgs#ssh-to-age -- -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt + +# Get a public age key from an existing age private key +@get-public-age-key: + nix shell nixpkgs#age -c age-keygen -y ~/.config/sops/age/keys.txt + +# Edit the SOPS secrets file +@edit-secrets: + nix run nixpkgs#sops -- shared/secrets/secrets.yaml + +# Hash a string using the mkpasswd command +hash PASS: + echo "{{PASS}}" | mkpasswd -s diff --git a/shared/modules/security/default.nix b/shared/modules/security/default.nix index 8bb4925..c251b0f 100644 --- a/shared/modules/security/default.nix +++ b/shared/modules/security/default.nix @@ -1,5 +1,6 @@ { imports = [ + ./sops.nix ./yubikey.nix ]; diff --git a/shared/modules/security/sops.nix b/shared/modules/security/sops.nix new file mode 100644 index 0000000..7e9a4ba --- /dev/null +++ b/shared/modules/security/sops.nix @@ -0,0 +1,20 @@ +{ + inputs, + lib, + systemConfig, + ... +}: + +{ + imports = [ + inputs.sops-nix.nixosModules.sops + ]; + + sops = { + defaultSopsFile = lib.custom.relativeToRoot "shared/secrets/secrets.yaml"; + defaultSopsFormat = "yaml"; + + age.keyFile = "/home/${systemConfig.user.name}/.config/sops/age/keys.txt"; + secrets.password.neededForUsers = true; + }; +} diff --git a/shared/modules/users.nix b/shared/modules/users.nix index 0fce21a..62a29e9 100644 --- a/shared/modules/users.nix +++ b/shared/modules/users.nix @@ -1,11 +1,11 @@ -{ systemConfig, ... }: +{ config, systemConfig, ... }: let username = systemConfig.user.name; in { - # Define a user without a password, TODO pass in user.password users.users.${username} = { isNormalUser = true; + hashedPasswordFile = config.sops.secrets.password.path; description = username; extraGroups = [ "networkmanager" diff --git a/shared/secrets/secrets.yaml b/shared/secrets/secrets.yaml new file mode 100644 index 0000000..b56d68e --- /dev/null +++ b/shared/secrets/secrets.yaml @@ -0,0 +1,21 @@ +password: ENC[AES256_GCM,data:tEiGH0G57H9yfRr3t9MyPEw3UvKPXJcCQ3xd0Baiz2yzIlFdPAMWl3TUjmGgEolaU2HznIv3DXAtlqQt8mXCMJKE8XD20VTOjw==,iv:OZYO/Ps9JakbvLqJ6QaUQ6YcJRasM0GRSQzs/mhg3eg=,tag:UjzK0vJPHj8UEgDMAlBjZw==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1fxr5s6d6ar0xy5pr63kpq93tk7jha5k96jcxnyquj6s2mw8mmcpss8w29w + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBReCtVUlRYV0hXL1RDa2ta + dDVlRU1FazI1cjA1OGJxNUZ6TGVkWFI2SGxVCm9VdUliTk1CeWRGN3pvOU5ZcGNZ + dGxNMlFRUlcyR1NKNVVscDFPbHRUWjAKLS0tIDhhQjhPWnZXdVZkd1owT0pWQ2dH + aENIaVM4cm1ZWDVOcEFYZEFjTDc1OUkKpRq6R6PYR9lPdX79Kaw+7R3OYLZLVrYh + seVS5wbrjShY2MZGKAOc0mUt5pCDBddt43gGAmI152451l70LZiN7A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-04-16T22:29:18Z" + mac: ENC[AES256_GCM,data:e+OAwJgpRLaCh64dQPOtI7ZmH9NflmyO37HmQFCWEjn65VB0tGfodmmKzzf8D+e7dZLQCO2RA86atSN3GdiB5JSJ7LGJg0XYMDBPi4Kc9iOSgxvnzeZd0YL52aD9qRHx4H5GDPSTHd0ZdqGj1c6DUVaHLxwd3uFh3FzS7nkAlfQ=,iv:r2tIu9xSrT0xv5vJV4OlDj0ogs9LZggucjY1KrI48Fk=,tag:oUavEzaMczLx47ZB6XE8+w==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.4