Hi! Here are some notes about how to use secrets in NixOS configuration securely. As of now I use sops-nix with simple age keys (not generated from ssh keys).
Concept
We will generate a file with all our secrets (e.g. secrets.yaml). For example:
my_secret_auth: <plain-text secret>
secrets.yaml is stored encrypted. We can edit it with sops secrets.yaml which decrypts it and opens your editor from the $EDITOR environment variable.
For this encryption / decryption sops uses an age public and private keys - we generate those too.
For those secrets to be picked up by nixos we register them in nixos config (we can set secret's owner to allow access for needed service):
sops.secrets = {
  my_secret_auth = {
    owner = "nginx";
  };
};
In the nixos configuration we now can use those secrets like so (an example for nginx basic auth):
basicAuthFile = config.sops.secrets.my_secret_auth.path;
That's basically it. Below are some details on how to setup all of this.
  
  
  Local secrets with nixos-rebuild
For use on a local machine. We will use niv to install sops-nix.
1) Go to your configuration directory, init a niv project with sops-nix:
# where `configuration.nix` is located, adjust if needed
cd /etc/nixos
# init `niv` with `sops-nix` before installing anything
nix-shell -p niv --run "niv init && niv add Mic92/sops-nix"
2) Create the directory for age keys:
mkdir -p ~/.config/sops/age
3) Configure sops and other stuff in secrets.nix (you can choose another name, don't forget to import this file from your configuration), replace YOUR_USER:
{ pkgs, config, ... }:
{
  imports = [ "${(import ./nix/sources.nix).sops-nix}/modules/sops" ];
  environment.systemPackages = with pkgs; [
    age sops
  ];
  sops = {
    defaultSopsFile = ./secrets/secrets.yaml;
    defaultSopsFormat = "yaml";
    age.keyFile = "/home/${config.users.users.YOUR_USER.name}/.config/sops/age/keys.txt";
  };
}
4) Apply configuration above:
sudo nixos-rebuild switch
5) Generate an age key:
age-keygen -o ~/.config/sops/age/keys.txt
6) Create .sops.yaml and paste public key printed on the previous step (replace capslocked text), use arbitrarily username:
keys:
  - &USERNAME PUBLIC_KEY
creation_rules:
  - path_regex: secrets/secrets.yaml$
    key_groups:
    - age:
      - *USERNAME
7) Register secrets to secrets.nix from step 3:
...
sops = {
  # ...
  secrets = {
    my_secret_auth = {
      owner = "nginx";
    };
  };
}
8) Use your secrets in nixos configuration (where the option expects a file path to the secret):
# ...
basicAuthFile = config.sops.secrets.my_secret_auth.path;
# ...
  
  
  Remote secrets with flake
For use on a remote machine.
DISCLAIMER: I keep remote's configs locally and send them via scp when updating it.
1) Add this to your flake:
{
  inputs = {
    # ...
    sops-nix.url = "github:Mic92/sops-nix";  # <--
  };
  outputs = {
    # ...
    sops-nix,  # <--
    ...
  }@inputs:  # <--
  {
    nixosConfigurations.your_flake_name = nixpkgs.lib.nixosSystem {
      # ...
      specialArgs = { inherit inputs; };  # <--
      modules = [
        # ...
        sops-nix.nixosModules.sops  # <--
      ];
    };
  };
}
2) Create the directory for age keys:
mkdir -p ~/.config/sops/age
3) Configure sops and other stuff in secrets.nix (you can choose another name, don't forget to import this file from your configuration), replace YOUR_USER:
{ pkgs, config, inputs, ... }:
{
  imports = [ inputs.sops-nix.nixosModules.sops ];  # <-- differs from the local setup
  environment.systemPackages = with pkgs; [
    age sops
  ];
  sops = {
    defaultSopsFile = ./secrets/secrets.yaml;
    defaultSopsFormat = "yaml";
    age.keyFile = "/home/${config.users.users.YOUR_USER.name}/.config/sops/age/keys.txt";
  };
}
4) Apply configuration above:
# I'm copying the configuration via ssh and running update on a remote - you do you
nixos-rebuild switch --flake .#update
5) Generate an age key:
age-keygen -o ~/.config/sops/age/keys.txt
6) Create .sops.yaml and paste public key printed on the previous step (replace capslocked text), use arbitrarily username:
keys:
  - &USERNAME PUBLIC_KEY
creation_rules:
  - path_regex: secrets/secrets.yaml$
    key_groups:
    - age:
      - *USERNAME
7) Register secrets to secrets.nix from step 3:
...
sops = {
  ...
  secrets = {
    my_secret_auth = {
      owner = "nginx";
    };
  };
  ...
8) Use your secrets in nixos configuration (where the option expects a file path to the secret):
...
basicAuthFile = config.sops.secrets.my_secret_auth.path;
...
9) If you use sops on both local and remote, it's useful to copy age private key from the remote machine to your home keys.txt (so you'll have two keys there) - this way you can edit remote's secrets.yaml locally.
Resources
- sops-nix repo
- short tutorial from vimjoyer
- commands from tutorial above
- nice article from dade about this topic and some more
 


 
    
Top comments (0)