Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 101 additions & 9 deletions doc/secrets.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,110 @@
# Secrets
Secrets are managed using [git-crypt][git-crypt] so you can keep your flake in
a public repository like GitHub without exposing your password or other
sensitive data.
Secrets are managed using [git-crypt][git-crypt] and [agenix][agenix]
so you can keep your flake in a public repository like GitHub without
exposing your password or other sensitive data.

By default, everything in the secrets folder is automatically encrypted. Just
be sure to run `git-crypt init` before putting anything in here.

## Agenix
Currently, there is [no mechanism][secrets-issue] in nix itself to deploy secrets
within the nix store because it is world-readable.

Most NixOS modules have the ability to set options to files in the system, outside
the nix store, that contain sensitive information. You can use [agenix][agenix]
to easily setup those secret files declaratively.

[agenix][agenix] encrypts secrets and stores them as .age files in your repository.
Age files are encrypted with multiple ssh public keys, so any host or user with a
matching ssh private key can read the data. The [age module][age module] will add those
encrypted files to the nix store and decrypt them on activation to `/run/secrets`.

### Setup
All hosts must have openssh enabled, this is done by default in the core profile.

You need to populate your `secrets/secrets.nix` with the proper ssh public keys.
Be extra careful to make sure you only add public keys, you should never share a
private key!!

secrets/secrets.nix:
```nix
let
system = "<system ssh key>";
user = "<user ssh key>";
allKeys = [ system user ];
in
```

On most systems, you can get your systems ssh public key from `/etc/ssh/ssh_host_ed25519_key.pub`. If
this file doesn't exist you likely need to enable openssh and rebuild your system.

Your users ssh public key is probably stored in `~/.ssh/id_ed25519.pub` or
`~/.ssh/id_rsa.pub`. If you haven't generated a ssh key yet, be sure do so:
```sh
ssh-keygen -t ed25519
```

> ##### _Note:_
> The underlying tool used by agenix, rage, doesn't work well with password protected
> ssh keys. So if you have lots of secrets you might have to type in your password many
> times.


### Secrets
You will need the `agenix` command to create secrets. DevOS conveniently provides that
in the devShell, so just run `nix develop` whenever you want to edit secrets. Make sure
to always run `agenix` while in the `secrets/` folder, so it can pick up your `secrets.nix`.

To create secrets, simply add lines to your `secrets/secrets.nix`:
```
let
...
allKeys = [ system user ];
in
{
"secret.age".publicKeys = allKeys;
}
```
That would tell agenix to create a `secret.age` file that is encrypted with the `system`
and `user` ssh public key.

Then go into the `secrets` folder and run:
```sh
agenix -e secret.age
```
This will create the `secret.age`, if it doesn't already exist, and allow you to edit it.

If you ever change the `publicKeys` entry of any secret make sure to rekey the secrets:
```sh
agenix --rekey
```

### Usage
Once you have your secret file encrypted and ready to use, you can utilize the [age module][age module]
to ensure that your secrets end up in `/run/secrets`.

In any profile that uses a NixOS module that requires a secret you can enable a particular secret like so:

```nix
{ self, ... }:
{
age.secrets.mysecret.file = "${self}/secrets/mysecret.age";
}
```


Then you can just pass the path `/run/secrets/mysecret` to the module.

You can make use of the many options provided by the age module to customize where and how
secrets get decrypted. You can learn about them by looking at the
[age module][age module].


> ##### _Note:_
> Currently, there is [no mechanism][secrets-issue] in nix to deploy secrets
> within the nix/store so, if they end up in the nix/store after deployment, they
> will be world readable on that machine.
>
> The author of devos intends to implement a workaround for this situation in
> the near future, but for the time being, simple be aware of this.
> You can take a look at the [agenix repository][agenix] for more information
> about the tool.

[git-crypt]: https://github.com/AGWA/git-crypt
[agenix]: https://github.com/ryantm/agenix
[age module]: https://github.com/ryantm/agenix/blob/master/modules/age.nix
[secrets-issue]: https://github.com/NixOS/nix/issues/8
21 changes: 21 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,26 @@
home.inputs.nixpkgs.follows = "nixos";
naersk.url = "github:nmattia/naersk";
naersk.inputs.nixpkgs.follows = "latest";
agenix.url = "github:ryantm/agenix";
agenix.inputs.nixpkgs.follows = "latest";
nixos-hardware.url = "github:nixos/nixos-hardware";

pkgs.url = "path:./pkgs";
pkgs.inputs.nixpkgs.follows = "nixos";
};

outputs = inputs@{ self, pkgs, digga, nixos, ci-agent, home, nixos-hardware, nur, ... }:
outputs =
{ self
, pkgs
, digga
, nixos
, ci-agent
, home
, nixos-hardware
, nur
, agenix
, ...
} @ inputs:
digga.lib.mkFlake {
inherit self inputs;

Expand All @@ -36,6 +49,7 @@
./pkgs/default.nix
pkgs.overlay # for `srcs`
nur.overlay
agenix.overlay
];
};
latest = { };
Expand All @@ -60,6 +74,7 @@
{ _module.args.ourLib = self.lib; }
ci-agent.nixosModules.agent-profile
home.nixosModules.home-manager
agenix.nixosModules.age
./modules/customBuilds.nix
];
};
Expand Down
1 change: 1 addition & 0 deletions overlays/overrides.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ channels: final: prev: {
discord
element-desktop
manix
rage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

off topic:

We might want to push for an update to latest release asap: https://github.com/str4d/rage/releases

Because:

Plugin support!

And I see how people want to use https://github.com/str4d/age-plugin-yubikey to seamlessly decrypt with their security key

nixpkgs-fmt
qutebrowser
signal-desktop
Expand Down
6 changes: 6 additions & 0 deletions profiles/core/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ in
'';
};

# For rage encryption, all hosts need a ssh key pair
Copy link
Contributor

@GTrunSec GTrunSec May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The practice of agenix should enable the ed25519 in ssh services by default. like:

  services.openssh.hostKeys = [
    { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
    { type = "ed25519"; bits = 256; path = "/etc/ssh/ssh_host_ed25519_key"; }
  ];

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? Looking at man configuration.nix the default for hostKeys is just what you put except without the bits = 256; part.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Sorry I overlooked the man page. Just ignore this comment.

Copy link
Member Author

@Pacman99 Pacman99 May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice if it was possible to generate these files without enabling the openssh daemon. It would require decoupling the key generation parts from the daemon parts of the nixos sshd module.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about if I write a bash to generate these files by executing remote ssh. It would be an alternative choice for generating keys.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a bad idea, but it doesn't feel declarative. I think this seems to be the best solution for now. We could alternatively generate the hostKeys ourself, but that would conflict with the ssh module.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future reference, perhaps we could just make a more minimal module that generates the keys, but doesn't enable ssh.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimally we could contribute changes to the upstream ssh module to separate host key generation from the daemon itself.

services.openssh = {
enable = true;
openFirewall = lib.mkDefault false;
};

services.earlyoom.enable = true;

}
1 change: 1 addition & 0 deletions secrets/.gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* filter=git-crypt diff=git-crypt
.gitattributes !filter !diff
secrets.nix !filter !diff
README.md !filter !diff
Comment on lines 1 to 4
Copy link
Member Author

@Pacman99 Pacman99 May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git-crypt is a little pointless if your using agenix properly. I also don't really like using it in general, agenix is just a much better solution for nix based setups.

We should probably leave it in the template for backwards compatibility - users might be storing secrets with the assumption that they are going to be encrypted.

But I would be in favor of removing it at some point.

Cool addition if you drop git-crypt: sudo nixos-rebuild switch --flake github:<nix config repo>.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also in favor of dropping it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm late to the party, but it would be good to drop as it actually enourages bad secrets management (putting secrets into Nix store). This was really more of a move of desparation on my part than an actual well thought out secrets strategy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely agree, I'm just more worried about someone not realizing git-crypt usage in secrets is dropped and committing their secrets to a public repo. Which is arguably worse.

9 changes: 9 additions & 0 deletions secrets/secrets.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let
# set ssh public keys here for your system and user
system = "";
user = "";
allKeys = [ system user ];
in
{
"secret.age".publicKeys = allKeys;
}