Agenix: Difference between revisions

From NixOS Wiki
imported>Onny
Add tips and tricks
imported>Onny
mNo edit summary
Line 77: Line 77:
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
age.secrets.nextcloud = {
age.secrets.nextcloud = {
   file = /etc/nixos/secrets/secret1.age;
   file = ./secrets/secret1.age;
   owner = "nextcloud";
   owner = "nextcloud";
   group = "nextcloud";
   group = "nextcloud";

Revision as of 11:02, 29 March 2023

agenix is a commandline tool for managing secrets in your Nix configuration, encrypted with your existing SSH keys. The project also includes the NixOS module age for adding encrypted secrets into the Nix store and decrypting them.

Installation

The following example describes an installation via Flakes. For further installation methods see the upstream documentation.

{
  inputs.agenix.url = "github:ryantm/agenix";
  # optional, not necessary for the module
  #inputs.agenix.inputs.nixpkgs.follows = "nixpkgs";

  outputs = { self, nixpkgs, agenix }: {
    nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        agenix.nixosModules.default
      ];
    };
  };
}

Change yourhostname to your actual hostname and x86_64-linux to your system architecture.

After that installing the agenix client application can be achieved like this

{ config, pkgs, lib, inputs, ... }:{
  environment.systemPackages = [
    inputs.agenix.packages."${system}".default
  ];
}

Configuration

First create a directory where secrets are going to be stored. In this example we're creating the directory secrets inside the NixOS system configuration path /etc/nixos

# mkdir /etc/nixos/secrets

Inside the secrets directory we create a secrets.nix file which will be used by the agenix client as a rule file to encrypt secrets for specific users and parts of the system. The following example configures access to secrets stored in secret1.age for the SSH public keys of user1 and system1.

/etc/nixos/secrets/secrets.nix
let
  user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH";
  users = [ user1 ];

  system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE";
  systems = [ system1 ];
in
{
  "secret1.age".publicKeys = [ user1 system1 ];
}

SSH public keys for a specific user or system can be generated with ssh-keygen, see this page for more information. Usually the public key of your user can be found in ~/.ssh/id_rsa.pub and the system one in /etc/ssh/ssh_host_rsa_key.pub.

Usage

Creating a secret file, which contents will be encrypted

# cd /etc/nixos/secrets
# agenix -e secret1.age

The agenix command will open your default terminal editor. Write in your secret, for example password123.

The filename secret1.age is specified above in the agenix secrets.nix configuration. So agenix will know which keys to use for a specific user or system.

To use and reference the secret inside your Nix configuration, an example would look like this

age.secrets.nextcloud = {
  file = ./secrets/secret1.age;
  owner = "nextcloud";
  group = "nextcloud";
};
services.nextcloud = {
  enable = true;
  package = pkgs.nextcloud25;
  hostName = "localhost";
  config.adminpassFile = config.age.secrets.nextcloud.path;
};

Here, the service Nextcloud requires a password for the administrator account. In this case, the password is stored in an age-encrypted file, so no plaintext passwords will be copied into your world-readable Nix-store. We configure owner and group names to nextcloud so that the webservice has the permissions to read the password wile.

Secrets can be also deployed as file with specific permissions to a target path. In this example the secret is sourced to /home/myuser/.netrc and permissions are set that only myuser is able to read and write the file

age.secrets = {
  netrc = {
    file = ./secrets/netrc.age;
    path = "/home/myuser/.netrc";
    owner = "myuser";
    group = "users";
    mode = "600";
  };
};

Tips and tricks

Replace inplace strings with secrets

Considering that there still might be some modules which doesn't support reading secrets from a file, you could provide a placeholder string instead of a clear-text password and replace this placeholder with the secret provided by Agenix.

In the following example, the Dex module creates the config file /run/dex/config.yaml containing the placeholder string @dex-user-password@. The acitvation script will read the Agenix secret from config.age.secret.dex-user-password.path and replace the placeholder string with the actual secret.

system.activationScripts."dex-user-secret" = ''
  secret=$(cat "${config.age.secrets.dex-user-password.path}")
  configFile=/run/dex/config.yaml
  ${pkgs.gnused}/bin/sed -i "s#@dex-user-password@#$secret#" "$configFile"
'';


See also