diff --git a/secrets/README.md b/secrets/README.md index 0c93f6de..edab334d 100644 --- a/secrets/README.md +++ b/secrets/README.md @@ -4,6 +4,9 @@ All my secrets are safely encrypted via agenix, and stored in a separate private GitHub repository and referenced as a flake input in this flake. +The encryption is done by using all my host's public keys(`/etc/ssh/ssh_host_ed25519_key`), so that they can only be decrypted on any of my configured hosts. +The host keys are generated locally on each host by openssh without passphrase, and are only readable by `root`, and will never leave the host. + In this way, all secrets is still encrypted when transmitted over the network and written to `/nix/store`, they are decrypted only when they are finally used. @@ -34,18 +37,24 @@ Suppose you want to add a new secret file `xxx.age`. Follow these steps: # and users can decrypt the secrets by any of the corresponding private keys. let - # get user's ssh public key by command: - # cat ~/.ssh/id_ed25519.pub - # if you do not have one, you can generate it by command: - # ssh-keygen -t ed25519 - ryan = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJx3Sk20pLL1b2PPKZey2oTyioODrErq83xG78YpFBoj"; - users = [ ryan ]; - - # get system's ssh public key by command: + # Get system's ssh public key by command: # cat /etc/ssh/ssh_host_ed25519_key.pub - ai = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICGeXNCazqiqxn8TmbCRjA+pLWrxwenn+CFhizBMP6en root@ai"; - systems = [ ai ]; -in + # If you do not have this file, you can generate all the host keys by command: + # sudo ssh-keygen -A + idol_ai = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINHZtzeaQyXwuRMLzoOAuTu8P9bu5yc5MBwo5LI3iWBV root@ai"; + harmonica = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINT7Pgy/Yl+t6UkHp5+8zfeyJqeJ8EndyR1Vjf/XBe5f root@harmonica"; + fern = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMokXUYcUy7tysH4tRR6pevFjyOP4cXMjpBSgBZggm9X root@fern"; + + # A key for recovery purpose, generated by `ssh-keygen -t ed25519 -a 256 -C "ryan@agenix-recovery"` with a strong passphrase + # and keeped it offline in a safe place. + recovery_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHnIGH+653Oe+GQaA8zjjj7HWMWp7bWXed4q5KqY4nqG ryan@agenix-recovery"; + systems = [ + idol_ai + harmonica + fern + + recovery_key + ]; { "./xxx.age".publicKeys = users ++ systems; } @@ -63,7 +72,7 @@ Alternatively, you can encrypt an existing file to `xxx.age` using the following cat /path/to/xxx | agenix -e ./xxx.age ``` -`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, +`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, so all the users and systems defined in `secrets.nix` can decrypt it with their private keys. ## Deploying Secrets @@ -83,7 +92,7 @@ First, add your own private `nix-secrets` repository and `agenix` as a flake inp # my private secrets, it's a private repository, you need to replace it with your own. mysecrets = { url = "github:ryan4yin/nix-secrets"; flake = false; }; }; - + outputs = inputs@{ self, nixpkgs, ... }: { nixosConfigurations = { nixos-test = nixpkgs.lib.nixosSystem { @@ -116,8 +125,10 @@ Then, create `./secrets/default.nix` with the following content: ]; # if you changed this key, you need to regenerate all encrypt files from the decrypt contents! - age.identityPaths = [ - "/home/ryan/.ssh/juliet-age" + age.identityPaths = [ + # using the host key for decryption + # the host key is generated on every host locally by openssh, and will never leave the host. + "/etc/ssh/ssh_host_ed25519_key" ]; age.secrets."xxx" = { @@ -134,16 +145,25 @@ Then, create `./secrets/default.nix` with the following content: } ``` -From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the private keys defined in `age.identityPaths`. +From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the private keys defined in `age.identityPaths`. It will then symlink the secrets to the path defined by the `age.secrets..path` argument, which defaults to `/etc/secrets`. -NOTE: By default, `age.identityPaths` is set to `~/.ssh/id_ed25519` and `~/.ssh/id_rsa`, +NOTE: By default, `age.identityPaths` is set to `~/.ssh/id_ed25519` and `~/.ssh/id_rsa`, so make sure to place your decryption keys there. If you're deploying to the same machine from which you encrypted the secrets, it should work out of the box. +## Adding a new host + +1. `cat` the public key of the new host, send it to an old host. +2. On the old host: + 1. Add the public key to `secrets.nix`, and rekey all the secrets via `sudo agenix -r -i /etc/ssh/ssh_host_ed25519_key`. + 2. Commit and push the changes to `nix-secrets`. +3. On the new host: + 1. Clone this repo and run `nixos-rebuild switch` to deploy it, all the secrets will be decrypted automatically via the host private key. + + ## Other Replacements - [ragenix](https://github.com/yaxitech/ragenix): A Rust reimplementation of agenix. - agenix is mainly written in bash, and it's error message is quite obscure, a little typo may cause some errors no one can understand. - with a type-safe language like Rust, we can get a better error message and less bugs. -