Coder Social home page Coder Social logo

sops-nix's Introduction

sops-nix

sops-nix logo

Atomic, declarative, and reproducible secret provisioning for NixOS based on sops.

How it works

Secrets are decrypted from sops files during activation time. The secrets are stored as one secret per file and access-controlled by full declarative configuration of their users, permissions, and groups. GPG keys or age keys can be used for decryption, and compatibility shims are supported to enable the use of SSH RSA or SSH Ed25519 keys. Sops also supports cloud key management APIs such as AWS KMS, GCP KMS, Azure Key Vault and Hashicorp Vault. While not officially supported by sops-nix yet, these can be controlled using environment variables that can be passed to sops.

Features

  • Compatible with all NixOS deployment frameworks: NixOps, nixos-rebuild, krops, morph, nixus, etc.
  • Version-control friendly: Since all files are encrypted they can be directly committed to version control without worry. Diffs of the secrets are readable, and can be shown in cleartext.
  • CI friendly: Since sops files can be added to the Nix store without leaking secrets, a machine definition can be built as a whole from a repository, without needing to rely on external secrets or services.
  • Home-manager friendly: Provides a home-manager module
  • Works well in teams: sops-nix comes with nix-shell hooks that allows multiple people to quickly import all GPG keys. The cryptography used in sops is designed to be scalable: Secrets are only encrypted once with a master key instead of encrypted per machine/developer key.
  • Atomic upgrades: New secrets are written to a new directory which replaces the old directory atomically.
  • Rollback support: If sops files are added to the Nix store, old secrets can be rolled back. This is optional.
  • Fast time-to-deploy: Unlike solutions implemented by NixOps, krops and morph, no extra steps are required to upload secrets.
  • A variety of storage formats: Secrets can be stored in YAML, dotenv, INI, JSON or binary.
  • Minimizes configuration errors: sops files are checked against the configuration at evaluation time.

Demo

There is a configuration.nix example in the deployment step of our usage example.

Supported encryption methods

sops-nix supports two basic ways of encryption, GPG and age.

GPG is based on GnuPG and encrypts against GPG public keys. Private GPG keys may be used to decrypt the secrets on the target machine. The tool ssh-to-pgp can be used to derive a GPG key from a SSH (host) key in RSA format.

The other method is age which is based on age. The tool (ssh-to-age) can convert SSH host or user keys in Ed25519 format to age keys.

Usage example

If you prefer video over the textual description below, you can also checkout this 6min tutorial by @vimjoyer.

1. Install sops-nix

Choose one of the following methods. When using it non-globally with home-manager, refer to Use with home-manager.

Flakes (current recommendation)

If you use experimental nix flakes support:

{
  inputs.sops-nix.url = "github:Mic92/sops-nix";
  # optional, not necessary for the module
  #inputs.sops-nix.inputs.nixpkgs.follows = "nixpkgs";

  outputs = { self, nixpkgs, sops-nix }: {
    # change `yourhostname` to your actual hostname
    nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
      # customize to your system
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        sops-nix.nixosModules.sops
      ];
    };
  };
}

niv (recommended if not using flakes)

First add it to niv:

$ niv add Mic92/sops-nix

Then add the following to your configuration.nix in the imports list:

{
  imports = [ "${(import ./nix/sources.nix).sops-nix}/modules/sops" ];
}

fetchTarball

Add the following to your configuration.nix:

{
  imports = let
    # replace this with an actual commit id or tag
    commit = "298b235f664f925b433614dc33380f0662adfc3f";
  in [ 
    "${builtins.fetchTarball {
      url = "https://github.com/Mic92/sops-nix/archive/${commit}.tar.gz";
      # replace this with an actual hash
      sha256 = "0000000000000000000000000000000000000000000000000000";
    }}/modules/sops"
  ];
}
2. Generate a key for yourself

This key will be used for you to edit secrets.

You can generate yourself a key:

# for age..
$ mkdir -p ~/.config/sops/age
$ age-keygen -o ~/.config/sops/age/keys.txt
# or to convert an ssh ed25519 key to an age key
$ mkdir -p ~/.config/sops/age
$ nix-shell -p ssh-to-age --run "ssh-to-age -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt"
# for GPG >= version 2.1.17
$ gpg --full-generate-key
# for GPG < 2.1.17
$ gpg --default-new-key-algo rsa4096 --gen-key

Or you can use the ssh-to-pgp tool to get a GPG key from an SSH key:

$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i $HOME/.ssh/id_rsa | gpg --import --quiet"
2504791468b153b8a3963cc97ba53d1919c5dfd4
# This exports the public key
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i $HOME/.ssh/id_rsa -o $USER.asc"
2504791468b153b8a3963cc97ba53d1919c5dfd4

(Note that ssh-to-pgp only supports RSA keys; to use Ed25519 keys, use age.)
If you get the following,

ssh-to-pgp: failed to parse private ssh key: ssh: this private key is passphrase protected

then your SSH key is encrypted with your password and you will need to create an unencrypted copy temporarily.

$ cp $HOME/.ssh/id_rsa /tmp/id_rsa
$ ssh-keygen -p -N "" -f /tmp/id_rsa
$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i /tmp/id_rsa | gpg --import --quiet"
$ rm /tmp/id_rsa
How to find the public key of an `age` key

If you generated an age key, the age public key can be found via age-keygen -y $PATH_TO_KEY:

$ age-keygen -y ~/.config/sops/age/keys.txt
age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl

Otherwise, you can convert an existing SSH key into an age public key:

$ nix-shell -p ssh-to-age --run "ssh-to-age < ~/.ssh/id_ed25519.pub"
# or
$ nix-shell -p ssh-to-age --run "ssh-add -L | ssh-to-age"
How to find the GPG fingerprint of a key

Invoke this command and look for your key:

$ gpg --list-secret-keys
/tmp/tmp.JA07D1aVRD/pubring.kbx
-------------------------------
sec   rsa2048 1970-01-01 [SCE]
      9F89C5F69A10281A835014B09C3DC61F752087EF
uid           [ unknown] root <root@localhost>

The fingerprint here is 9F89C5F69A10281A835014B09C3DC61F752087EF.

Your age public key or GPG fingerprint can be written to your .sops.yaml in the root of your configuration directory or repository:

# This example uses YAML anchors which allows reuse of multiple keys 
# without having to repeat yourself.
# Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml
# for a more complex example.
keys:
  - &admin_alice 2504791468b153b8a3963cc97ba53d1919c5dfd4
  - &admin_bob age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
creation_rules:
  - path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
    key_groups:
    - pgp:
      - *admin_alice
      age:
      - *admin_bob

Note: Be sure to not include a - before subsequent key types under key_groups (i.e. age in the above example should not have a - in front). This will otherwise cause sops to require multiple keys (shamir secret sharing) to decrypt a secret, which breaks normal sops-nix usage.

3. Get a public key for your target machine

The easiest way to add new machines is by using SSH host keys (this requires OpenSSH to be enabled).

If you are using age, the ssh-to-age tool can be used to convert any SSH Ed25519 public key to the age format:

$ nix-shell -p ssh-to-age --run 'ssh-keyscan example.com | ssh-to-age'
age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3
$ nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3

For GPG, since sops does not natively support SSH keys yet, sops-nix supports a conversion tool (ssh-to-pgp) to store them as GPG keys:

$ ssh root@server01 "cat /etc/ssh/ssh_host_rsa_key" | nix-shell -p ssh-to-pgp --run "ssh-to-pgp -o server01.asc"
# or with sudo
$ ssh youruser@server01 "sudo cat /etc/ssh/ssh_host_rsa_key" | nix-shell -p ssh-to-pgp --run "ssh-to-pgp -o server01.asc"
0fd60c8c3b664aceb1796ce02b318df330331003
# or just read them locally/over ssh
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i /etc/ssh/ssh_host_rsa_key -o server01.asc"
0fd60c8c3b664aceb1796ce02b318df330331003

The output of these commands is the identifier for the server's key, which can be added to your .sops.yaml:

keys:
  - &admin_alice 2504791468b153b8a3963cc97ba53d1919c5dfd4
  - &admin_bob age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
  - &server_azmidi 0fd60c8c3b664aceb1796ce02b318df330331003
  - &server_nosaxa age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3
creation_rules:
  - path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
    key_groups:
    - pgp:
      - *admin_alice
      - *server_azmidi
      age:
      - *admin_bob
      - *server_nosaxa
  - path_regex: secrets/azmidi/[^/]+\.(yaml|json|env|ini)$
    key_groups:
    - pgp:
      - *admin_alice
      - *server_azmidi
      age:
      - *admin_bob

If you prefer having a separate GPG key, see Use with GPG instead of SSH keys.

4. Create a sops file

To create a sops file you need write a .sops.yaml as described above.

When using GnuPG you also need to import your personal GPG key (and your colleagues) and your servers into your GPG key chain.

sops-nix can automate the import of GPG keys with a hook for nix-shell, allowing public keys to be shared via version control (i.e. git).
# shell.nix
with import <nixpkgs> {};
let
  sops-nix = builtins.fetchTarball {
    url = "https://github.com/Mic92/sops-nix/archive/master.tar.gz";
  };
in
mkShell {
  # imports all files ending in .asc/.gpg
  sopsPGPKeyDirs = [ 
    "${toString ./.}/keys/hosts"
    "${toString ./.}/keys/users"
  ];
  # Also single files can be imported.
  #sopsPGPKeys = [ 
  #  "${toString ./.}/keys/users/mic92.asc"
  #  "${toString ./.}/keys/hosts/server01.asc"
  #];
  
  # This hook can also import gpg keys into its own seperate
  # gpg keyring instead of using the default one. This allows
  # to isolate otherwise unrelated server keys from the user gpg keychain.
  # By uncommenting the following lines, it will set GNUPGHOME
  # to .git/gnupg. 
  # Storing it inside .git prevents accedentially commiting private keys.
  # After setting this option you will also need to import your own
  # private key into keyring, i.e. using a a command like this 
  # (replacing 0000000000000000000000000000000000000000 with your fingerprint)
  # $ (unset GNUPGHOME; gpg --armor --export-secret-key 0000000000000000000000000000000000000000) | gpg --import
  #sopsCreateGPGHome = true;
  # To use a different directory for gpg dirs set sopsGPGHome
  #sopsGPGHome = "${toString ./.}/../gnupg";
  
  nativeBuildInputs = [
    (pkgs.callPackage sops-nix {}).sops-import-keys-hook
  ];
}

A valid directory structure for this might look like:

$ tree .
.
├── keys
│   ├── hosts
│   │   └── server01.asc
│   └── users
│       └── mic92.asc

After configuring .sops.yaml, you can open a new file with sops:

$ nix-shell -p sops --run "sops secrets/example.yaml"

This will start your configured editor located at the $EDITOR environment variable.
An example secret file might be:

# Files must always have a string value
example-key: example-value
# Nesting the key results in the creation of directories.
# These directories will be owned by root:keys and have permissions 0751.
myservice:
  my_subdir:
    my_secret: password1

An example result when saving this file could be:

example-key: ENC[AES256_GCM,data:AB8XMyid4P7mXdjj+A==,iv:RRsZC+V+3w22pOi/2TCjBYn/0OYsNGCu5CT1ZBSKGi0=,tag:zT5mlujrSuA6KKxLKL8CMQ==,type:str]
#ENC[AES256_GCM,data:59QWbzCQCP7kLdhyjFOZe503MgegN0kv505PBNHwjp6aYztDHwx2N9+A1Bz6G/vWYo+4LpBo8/s=,iv:89q3ZXgM1wBUg5G29ROor3VXrO3QFGCvfwDoA3+G14M=,tag:hOSnEZ6DKycnF37LCXOjzg==,type:comment]
#ENC[AES256_GCM,data:kUuJCkDE9JT9C+kdNe0CSB3c+gmgE4We1OoX4C1dWeoZCw/o9/09CzjRi9eOBUEL0P1lrt+g6V2uXFVq4n+M8UPGUAbRUr3A,iv:nXJS8wqi+ephoLynm9Nxbqan0V5dBstctqP0WxniSOw=,tag:ALx396Z/IPCwnlqH//Hj3g==,type:comment]
myservice:
    my_subdir:
        my_secret: ENC[AES256_GCM,data:hcRk5ERw60G5,iv:3Ur6iH1Yu0eu2otcEv+hGRF5kTaH6HSlrofJ5JXvewA=,tag:hpECXFnMhGNnAxxzuGW5jg==,type:str]
sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    hc_vault: []
    age:
        - recipient: age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1dFYvSTRHa3IwTVpuZjEz
            SDZZQnc5a0dGVGEzNXZmNEY5NlZDbVgyNVU0Clo3ZC9MRGp4SHhLUTVCeWlOUUxS
            MEtPdW4rUHhjdFB6bFhyUXRQTkRpWjAKLS0tIDVTbWU2V3dJNUZrK1A5U0c5bkc0
            S3VINUJYc3VKcjBZbHVqcGJBSlVPZWcKqPXE01ienWDbTwxo+z4dNAizR3t6uTS+
            KbmSOK1v61Ri0bsM5HItiMP+fE3VCyhqMBmPdcrR92+3oBmiSFnXPA==
            -----END AGE ENCRYPTED FILE-----
        - recipient: age18jtffqax5v0t6ehh4ypaefl4mfhcrhn6ek3p80mhfp9psx6pd35qew2ww3
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzT3FxcDEzaFRQOVFpNkg2
            Skw4WEIxZzNTWkNBaDRhcUN2ejY4QTAwTERvCkx2clIzT2wyaFJZcjl0RkFXL2p6
            enhqVEZ3ZkNKUU5jTlUxRC9Lb090TzAKLS0tIDBEaG00RFJDZ3ZVVjBGUWJkRHdQ
            YkpudG43eURPVWJUejd3Znk5Z29lWlkK0cIngn2qdmiOE5rHOHxTRcjfZYuY3Ej7
            Yy7nYxMwTdYsm/V6Lp2xm8hvSzBEIFL+JXnSTSwSHnCIfgle5BRbug==
            -----END AGE ENCRYPTED FILE-----
    lastmodified: "2021-11-20T16:21:10Z"
    mac: ENC[AES256_GCM,data:5ieT/yv1GZfZFr+OAZ/DBF+6DJHijRXpjNI2kfBun3KxDkyjiu/OFmAbsoVFY/y6YCT3ofl4Vwa56Veo3iYj4njgxyLpLuD1B6zkMaNXaPywbAhuMho7bDGEJZHrlYOUNLdBqW2ytTuFA095IncXE8CFGr38A2hfjcputdHk4R4=,iv:UcBXWtaquflQFNDphZUqahADkeege5OjUY38pLIcFkU=,tag:yy+HSMm+xtX+vHO78nej5w==,type:str]
    pgp: []
    unencrypted_suffix: _unencrypted
    version: 3.7.1

If you add a new host to your .sops.yaml file, you will need to update the keys for all secrets that are used by the new host. This can be done like so:

$ nix-shell -p sops --run "sops updatekeys secrets/example.yaml"
5. Deploy

If you derived your server public key from SSH, all you need in your configuration.nix is:

{
  imports = [ <sops-nix/modules/sops> ];
  # This will add secrets.yml to the nix store
  # You can avoid this by adding a string to the full path instead, i.e.
  # sops.defaultSopsFile = "/root/.sops/secrets/example.yaml";
  sops.defaultSopsFile = ./secrets/example.yaml;
  # This will automatically import SSH keys as age keys
  sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
  # This is using an age key that is expected to already be in the filesystem
  sops.age.keyFile = "/var/lib/sops-nix/key.txt";
  # This will generate a new key if the key specified above does not exist
  sops.age.generateKey = true;
  # This is the actual specification of the secrets.
  sops.secrets.example-key = {};
  sops.secrets."myservice/my_subdir/my_secret" = {};
}

On nixos-rebuild switch this will make the keys accessible via /run/secrets/example-key and /run/secrets/myservice/my_subdir/my_secret:

$ cat /run/secrets/example-key
example-value
$ cat /run/secrets/myservice/my_subdir/my_secret
password1

/run/secrets is a symlink to /run/secrets.d/{number}:

$ ls -la /run/secrets
lrwxrwxrwx 16 root 12 Jul  6:23  /run/secrets -> /run/secrets.d/1

Set secret permission/owner and allow services to access it

By default secrets are owned by root:root. Furthermore the parent directory /run/secrets.d is only owned by root and the keys group has read access to it:

$ ls -la /run/secrets.d/1
total 24
drwxr-x--- 2 root keys   0 Jul 12  6:23 .
drwxr-x--- 3 root keys   0 Jul 12  6:23 ..
-r-------- 1 root root  20 Jul 12  6:23 example-secret

The secrets option has further parameter to change secret permission. Consider the following nixos configuration example:

{
  # Permission modes are in octal representation (same as chmod),
  # the digits represent: user|group|others
  # 7 - full (rwx)
  # 6 - read and write (rw-)
  # 5 - read and execute (r-x)
  # 4 - read only (r--)
  # 3 - write and execute (-wx)
  # 2 - write only (-w-)
  # 1 - execute only (--x)
  # 0 - none (---)
  sops.secrets.example-secret.mode = "0440";
  # Either a user id or group name representation of the secret owner
  # It is recommended to get the user name from `config.users.users.<?name>.name` to avoid misconfiguration
  sops.secrets.example-secret.owner = config.users.users.nobody.name;
  # Either the group id or group name representation of the secret group
  # It is recommended to get the group name from `config.users.users.<?name>.group` to avoid misconfiguration
  sops.secrets.example-secret.group = config.users.users.nobody.group;
}
This example configures secrets for buildkite, a CI agent; the service needs a token and a SSH private key to function.
{ pkgs, config, ... }:
{
  services.buildkite-agents.builder = {
    enable = true;
    tokenPath = config.sops.secrets.buildkite-token.path;
    privateSshKeyPath = config.sops.secrets.buildkite-ssh-key.path;

    runtimePackages = [
      pkgs.gnutar
      pkgs.bash
      pkgs.nix
      pkgs.gzip
      pkgs.git
    ];

  };

  sops.secrets.buildkite-token.owner = config.users.buildkite-agent-builder.name;
  sops.secrets.buildkite-ssh-key.owner = config.users.buildkite-agent-builder.name;
}

Restarting/reloading systemd units on secret change

It is possible to restart or reload units when a secret changes or is newly initialized.

This behavior can be configured per-secret:

{
  sops.secrets."home-assistant-secrets.yaml" = {
    restartUnits = [ "home-assistant.service" ];
    # there is also `reloadUnits` which acts like a `reloadTrigger` in a NixOS systemd service
  };
}

Symlinks to other directories

Some services might expect files in certain locations. Using the path option a symlink to this directory can be created:

{
  sops.secrets."home-assistant-secrets.yaml" = {
    owner = "hass";
    path = "/var/lib/hass/secrets.yaml";
  };
}
$ ls -la /var/lib/hass/secrets.yaml
lrwxrwxrwx 1 root root 40 Jul 19 22:36 /var/lib/hass/secrets.yaml -> /run/secrets/home-assistant-secrets.yaml

Setting a user's password

sops-nix has to run after NixOS creates users (in order to specify what users own a secret.) This means that it's not possible to set users.users.<name>.hashedPasswordFile to any secrets managed by sops-nix. To work around this issue, it's possible to set neededForUsers = true in a secret. This will cause the secret to be decrypted to /run/secrets-for-users instead of /run/secrets before NixOS creates users. As users are not created yet, it's not possible to set an owner for these secrets.

The password must be stored as a hash for this to work, which can be created with the command mkpasswd

$ echo "password" | mkpasswd -s
$y$j9T$WFoiErKnEnMcGq0ruQK4K.$4nJAY3LBeBsZBTYSkdTOejKU6KlDmhnfUV3Ll1K/1b.
{ config, ... }: {
  sops.secrets.my-password.neededForUsers = true;

  users.users.mic92 = {
    isNormalUser = true;
    hashedPasswordFile = config.sops.secrets.my-password.path;
  };
}

Note: If you are using Impermanence, you must set sops.age.keyFile to a keyfile inside your persist directory or it will not exist at boot time. For example: /nix/persist/var/lib/sops-nix/key.txt Similarly if ssh host keys are used instead, they also need to be placed inside the persisted storage.

Different file formats

At the moment we support the following file formats: YAML, JSON, INI, dotenv and binary.

sops-nix allows specifying multiple sops files in different file formats:

{
  imports = [ <sops-nix/modules/sops> ];
  # The default sops file used for all secrets can be controlled using `sops.defaultSopsFile`
  sops.defaultSopsFile = ./secrets.yaml;
  # If you use something different from YAML, you can also specify it here:
  #sops.defaultSopsFormat = "yaml";
  sops.secrets.github_token = {
    # The sops file can be also overwritten per secret...
    sopsFile = ./other-secrets.json;
    # ... as well as the format
    format = "json";
  };
}

YAML

Open a new file with sops ending in .yaml:

$ sops secrets.yaml

Then, put in the following content:

github_token: 4a6c73f74928a9c4c4bc47379256b72e598e2bd3
ssh_key: |
  -----BEGIN OPENSSH PRIVATE KEY-----
  b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
  QyNTUxOQAAACDENhLwQI4v/Ecv65iCMZ7aZAL+Sdc0Cqyjkd012XwJzQAAAJht4at6beGr
  egAAAAtzc2gtZWQyNTUxOQAAACDENhLwQI4v/Ecv65iCMZ7aZAL+Sdc0Cqyjkd012XwJzQ
  AAAEBizgX7v+VMZeiCtWRjpl95dxqBWUkbrPsUSYF3DGV0rsQ2EvBAji/8Ry/rmIIxntpk
  Av5J1zQKrKOR3TXZfAnNAAAAE2pvZXJnQHR1cmluZ21hY2hpbmUBAg==
  -----END OPENSSH PRIVATE KEY-----

You can include it like this in your configuration.nix:

{
  sops.defaultSopsFile = ./secrets.yaml;
  # YAML is the default 
  #sops.defaultSopsFormat = "yaml";
  sops.secrets.github_token = {
    format = "yaml";
    # can be also set per secret
    sopsFile = ./secrets.yaml;
  };
}

JSON

Open a new file with sops ending in .json:

$ sops secrets.json

Then, put in the following content:

{
  "github_token": "4a6c73f74928a9c4c4bc47379256b72e598e2bd3",
  "ssh_key": "-----BEGIN OPENSSH PRIVATE KEY-----\\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\\nQyNTUxOQAAACDENhLwQI4v/Ecv65iCMZ7aZAL+Sdc0Cqyjkd012XwJzQAAAJht4at6beGr\\negAAAAtzc2gtZWQyNTUxOQAAACDENhLwQI4v/Ecv65iCMZ7aZAL+Sdc0Cqyjkd012XwJzQ\\nAAAEBizgX7v+VMZeiCtWRjpl95dxqBWUkbrPsUSYF3DGV0rsQ2EvBAji/8Ry/rmIIxntpk\\nAv5J1zQKrKOR3TXZfAnNAAAAE2pvZXJnQHR1cmluZ21hY2hpbmUBAg==\\n-----END OPENSSH PRIVATE KEY-----\\n"
}

You can include it like this in your configuration.nix:

{
  sops.defaultSopsFile = ./secrets.json;
  # YAML is the default 
  sops.defaultSopsFormat = "json";
  sops.secrets.github_token = {
    format = "json";
    # can be also set per secret
    sopsFile = ./secrets.json;
  };
}

Binary

This format allows to encrypt an arbitrary binary format that can't be put into JSON/YAML files. Unlike the other two formats, for binary files, one file corresponds to one secret.

To encrypt an binary file use the following command:

$ cp /etc/krb5/krb5.keytab > krb5.keytab
$ sops -e -o krb5.keytab
# an example of what this might result in:
$ head krb5.keytab
{
        "data": "ENC[AES256_GCM,data:bIsPHrjrl9wxvKMcQzaAbS3RXCI2h8spw2Ee+KYUTsuousUBU6OMIdyY0wqrX3eh/1BUtl8H9EZciCTW29JfEJKfi3ackGufBH+0wp6vLg7r,iv:TlKiOmQUeH3+NEdDUMImg1XuXg/Tv9L6TmPQrraPlCQ=,tag:dVeVvRM567NszsXKK9pZvg==,type:str]",
        "sops": {
                "kms": null,
                "gcp_kms": null,
                "azure_kv": null,
                "lastmodified": "2020-07-06T06:21:06Z",
                "mac": "ENC[AES256_GCM,data:ISjUzaw/5mNiwypmUrOk2DAZnlkbnhURHmTTYA3705NmRsSyUh1PyQvCuwglmaHscwl4GrsnIz4rglvwx1zYa+UUwanR0+VeBqntHwzSNiWhh7qMAQwdUXmdCNiOyeGy6jcSDsXUeQmyIWH6yibr7hhzoQFkZEB7Wbvcw6Sossk=,iv:UilxNvfHN6WkEvfY8ZIJCWijSSpLk7fqSCWh6n8+7lk=,tag:HUTgyL01qfVTCNWCTBfqXw==,type:str]",
                "pgp": [
                        {

It can be decrypted again like this:

$ sops -d krb5.keytab > /tmp/krb5.keytab

This is how it can be included in your configuration.nix:

{
  sops.secrets.krb5-keytab = {
    format = "binary";
    sopsFile = ./krb5.keytab;
  };
}

Use with home manager

sops-nix also provides a home-manager module. This module provides a subset of features provided by the system-wide sops-nix since features like the creation of the ramfs and changing the owner of the secrets are not available for non-root users.

Instead of running as an activation script, sops-nix runs as a systemd user service called sops-nix.service. While the sops-nix system module decrypts secrets to the system non-persistent /run/secrets, the home-manager module places them in the users non-persistent $XDG_RUNTIME_DIR/secrets.d. Additionally secrets are symlinked to the users home at $HOME/.config/sops-nix/secrets which are referenced for the .path value in sops-nix. This requires that the home-manager option home.homeDirectory is set to determine the home-directory on evaluation. It will have to be manually set if home-manager is configured as stand-alone or on non NixOS systems.

Depending on whether you use home-manager system-wide or stand-alone using a home.nix, you have to import it in a different way. This example shows the flake approach from the recommended example Install: Flakes (current recommendation)

{
  # NixOS system-wide home-manager configuration
  home-manager.sharedModules = [
    inputs.sops-nix.homeManagerModules.sops
  ];
}
{
  # Configuration via home.nix
  imports = [
    inputs.sops-nix.homeManagerModules.sops
  ];
}

This example show the channel approach from the example Install: nix-channel. All other methods work as well.

{
  # NixOS system-wide home-manager configuration
  home-manager.sharedModules = [
    <sops-nix/modules/home-manager/sops.nix>
  ];
}
{
  # Configuration via home.nix
  imports = [
    <sops-nix/modules/home-manager/sops.nix>
  ];
}

The actual sops configuration is in the sops namespace in your home.nix (or in the home-manager.users.<name> namespace when using home-manager system-wide):

{
  sops = {
    age.keyFile = "/home/user/.age-key.txt"; # must have no password!
    # It's also possible to use a ssh key, but only when it has no password:
    #age.sshKeyPaths = [ "/home/user/path-to-ssh-key" ];
    defaultSopsFile = ./secrets.yaml;
    secrets.test = {
      # sopsFile = ./secrets.yml.enc; # optionally define per-secret files

      # %r gets replaced with a runtime directory, use %% to specify a '%'
      # sign. Runtime dir is $XDG_RUNTIME_DIR on linux and $(getconf
      # DARWIN_USER_TEMP_DIR) on darwin.
      path = "%r/test.txt"; 
    };
  };
}

The secrets are decrypted in a systemd user service called sops-nix, so other services needing secrets must order after it:

{
  systemd.user.services.mbsync.Unit.After = [ "sops-nix.service" ];
}

Use with GPG instead of SSH keys

If you prefer having a separate GPG key, sops-nix also comes with a helper tool, sops-init-gpg-key:

$ nix run github:Mic92/sops-nix#sops-init-gpg-key -- --hostname server01 --gpghome /tmp/newkey
# You can use the following command to save it to a file:
$ cat > server01.asc <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBF8L/iQBCACroEaUfvPBMMorNepNQmideOtNztALejgEJ5wZmxabck+qC1Gb
NWe3tmvChXVHgL7DzodSUfX1PuIjTTeRr2clMXtISPFIsBlRQb4MiErZfsardITM
n4WScg8sTb4nnqEOJiRknwAhBryIjH8kkCXxKlYK67re281dIK4dKBMIolFADlyv
wyHurJ7NPpHxR2WXHcIqXX1DaT6RvGQvZHMpfctob8k/QD4CyV6QwG5IVACQ/tuC
bEUggrkGw+g+XdeieUfWbRsHM4C4pv8BNwA/EYD5d0eKI+rshSPoTT+hcGn8Uh8w
MVQ8PVs6jWMMOAF1JH/stoPr9Yha+TGbMRi5ABEBAAG0GHNlcnZlcjAxIDxyb290
QHNlcnZlcjAxPokBTgQTAQgAOBYhBOTKhnaPF2rrbAFVQVOvjX8UlhOxBQJfC/4k
AhsvBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEFOvjX8UlhOx1XIH/jUOrSR2
wuoqFiHcqaDPgXmTVJk8QanVkmiP3tk0mz5rRKrDX2eX5GnHqYR4PfpjUYNzedQE
sGyTjl7+DvglWJ2Q8m3yD/9+1agBmeqEVQlKqwL6Sc3bI4WBwHaxwVDo/bNwMs0w
o8ngOs1jPd3LfQdfG/rE1NolpHm4LWqYj0D2zEGqozLXVBx2wiuwmm6OKX4U4EHR
UwKax+VZYA+J9oFDN+kOy/yR+bKnOvg5eyOv2ZrK5BKceSBhDTOclMIWTL2cGxcL
jsq4N7fobs4TbwFPxRUi/T9ldXi0LXeGhTl9stImTtj3bL+4Y734TipvB5UvzCDK
CkjjwEvD5MYdGDE=
=uvIf
-----END PGP PUBLIC KEY BLOCK-----
EOF
# fingerprint: E4CA86768F176AEB6C01554153AF8D7F149613B1

You can choose between a RSA GPG key (default, like in the example above) or a Curve25519 based one by adding --keytype Curve25519 like so:

$ nix run github:Mic92/sops-nix#sops-init-gpg-key -- --hostname server01 --gpghome /tmp/newkey --keytype Curve25519
You can use the following command to save it to a file:
cat > server01.asc <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEY7dJExYJKwYBBAHaRw8BAQdAloRZFyqNh3nIDtyUQKaBSMJOtLkbNeg+4TPg
BG5TduG0OG5peC1hLmhvbWUua3VldGVtZWllci5kZSA8cm9vdEBuaXgtYS5ob21l
Lmt1ZXRlbWVpZXIuZGU+iJMEExYKADsWIQREE2hPxiNijOo+CSmrLxbGte+J7wUC
Y7dJEwIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRCrLxbGte+J79LX
AQDtLfQFDKm04ORIk28DrzTBbMTFQEW21dGBXk7ykBx4jQD/ZOnt1RPnB9mzMc8L
wIS3oI8D9719DjoS9hrHnJ4xvge4OARjt0kTEgorBgEEAZdVAQUBAQdA0t1X35pN
ic+etscIIkHjKUwrXhbTgWrARgXUuEMwwz8DAQgHiHgEGBYKACAWIQREE2hPxiNi
jOo+CSmrLxbGte+J7wUCY7dJEwIbDAAKCRCrLxbGte+J7+0NAQCfj95TSyPEFKz3
eLJ1aCA1bZZV/rkhHd+OwX1MFL3mKQD9GMPgvMzDIoofycDzMY2ttJgkRJfq+zOZ
juXFQdUkMgY=
=pf3V
-----END PGP PUBLIC KEY BLOCK-----
EOF
fingerprint: 4413684FC623628CEA3E0929AB2F16C6B5EF89EF
F0477297E369CD1D189DD901278D1535AB473B9E

In both cases, you must upload the GPG key directory /tmp/newkey onto the server. If you uploaded it to /var/lib/sops than your sops configuration will look like this:

{
  # Make sure that `/var/lib/sops` is owned by root and is not world-readable/writable
  sops.gnupg.home = "/var/lib/sops";
  # disable importing host ssh keys
  sops.gnupg.sshKeyPaths = [];
}

However be aware that this will also run GnuPG on your server including the GnuPG daemon. GnuPG is in general not great software and might break in hilarious ways. If you experience problems, you are on your own. If you want a more stable and predictable solution go with SSH keys or one of the KMS services.

Share secrets between different users

Secrets can be shared between different users by creating different files pointing to the same sops key but with different permissions. In the following example the drone secret is exposed as /run/secrets/drone-server for drone-server and as /run/secrets/drone-agent for drone-agent:

{
  sops.secrets.drone-server = {
    owner = config.systemd.services.drone-server.serviceConfig.User;
    key = "drone";
  };
  sops.secrets.drone-agent = {
    owner = config.systemd.services.drone-agent.serviceConfig.User;
    key = "drone";
  };
}

Migrate from pass/krops

If you have used pass before (e.g. in krops) than you can use the following one-liner to convert all your secrets to a YAML structure:

$ for i in *.gpg; do echo "$(basename $i .gpg): |\n$(pass $(dirname $i)/$(basename $i .gpg)| sed 's/^/  /')"; done

Copy the output to the editor you have opened with sops.

Real-world examples

The nix-community infra makes extensive usage of sops-nix. Each host has a secrets.yaml containing secrets for the host. Also Samuel Leathers explains his personal setup in this blog article.

Known limitations

Initrd secrets

sops-nix does not fully support initrd secrets. This is because nixos-rebuild switch installs the bootloader before running sops-nix's activation hook.
As a workaround, it is possible to run nixos-rebuild test before nixos-rebuild switch to provision initrd secrets before actually using them in the initrd. In the future, we hope to extend NixOS to allow keys to be provisioned in the bootloader install phase.

Using secrets at evaluation time

It is not possible to use secrets at evaluation time of nix code. This is because sops-nix decrypts secrets only in the activation phase of nixos i.e. in nixos-rebuild switch on the target machine. If you rely on this feature for some secrets, you should also include solutions that allow secrets to be stored securely in your version control, e.g. git-agecrypt. These types of solutions can be used together with sops-nix.

Templates

If your setup requires embedding secrets within a configuration file, the template feature of sops-nix provides a seamless way to do this.

Here's how to use it:

  1. Define Your Secret

    Specify the secrets you intend to use. This will be encrypted and managed securely by sops-nix.

    {
      sops.secrets.your-secret = { };
    }
  2. Use Templates for Configuration with Secrets

    Create a template for your configuration file and utilize the placeholder where you'd like the secret to be inserted. During the activation phase, sops-nix will substitute the placeholder with the actual secret content.

    {
      sops.templates."your-config-with-secrets.toml".content = ''
        password = "${config.sops.placeholder.your-secret}"
      '';
    }

    You can also define ownership properties for the configuration file:

    { 
      sops.templates."your-config-with-secrets.toml".owner = "serviceuser";
    }
  3. Reference the Rendered Configuration in Services

    When defining a service (e.g., using systemd), refer to the rendered configuration (with secrets in place) by leveraging the .path attribute.

    {
      systemd.services.myservice = {
        # ... (any other service attributes)
    
        serviceConfig = {
          ExecStart = "${pkgs.myservice}/bin/myservice --config ${config.sops.templates."your-config-with-secrets.toml".path}";
          User = "serviceuser";
        };
      };
    }

Related projects

  • agenix: Similar features as sops-nix but uses age.
  • scalpel: Provides a simple template mechanism to inject secrets into configuration files in the nixos activation phase

Need more commercial support?

We are building sops-nix very much as contributors to the community and are committed to keeping it open source.

That said, many of us that are contributing to sops-nix also work for consultancies. If you want to contact one of those for paid-for support setting up sops-nix in your infrastructure you can do so here:

sops-nix's People

Contributors

anilanar avatar anoadragon453 avatar antifuchs avatar bors[bot] avatar dasj avatar ddosolitary avatar dependabot[bot] avatar emergentmind avatar github-actions[bot] avatar janik-haag avatar kuetemeier avatar ma27 avatar mergify[bot] avatar mic92 avatar milibopp avatar mtoohey31 avatar ncfavier avatar nickcao avatar ninlives avatar pizmovc avatar pogobanane avatar quentinmit avatar sebtm avatar shyim avatar siriobalmelli avatar starcraft66 avatar supersandro2000 avatar tomaszal avatar vergedx avatar virchau13 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sops-nix's Issues

Make permissions for /run/secrets 0751

As discussed on IRC, it would be nice to have the permissions on /run/secrets be 0751 instead of 0750. This would avoid the need to add users or services to the keys group.

How to use ssh-to-pgp

Hi. I'm trying to use ssh-to-pgp and following the instruction here: https://github.com/Mic92/sops-nix#3-get-a-pgp-public-key-for-your-machine

I assume I have to clone this repo and run nix-shell -p ssh-to-pgp in the root of the repo next to shell.nix. However when I do that I get the following error:

error: undefined variable 'ssh-to-pgp' at (string):1:94

It's unclear from the documentation how to get ssh-to-pgp installed on the machine I'm provisioning.
What do I need to add to configuration.nix to get it installed on the remote machines?

Passphrase protecting age keys

I was wondering if it was possible to design a workaround that allows to have age keys be passphrase protected at rest?
It seems that sops does not support this out of the box (see getsops/sops#933 or at least i could not find anything).

Maybe it would be possible to passphrase encrypt the age key on disk and then have a nix shell derivation as part of the flake that prompts the user for the passphrase and makes the key temporarily availble to sops in an unprotected fashion. Perhaps it would be possible to do this by using sops own exec-env or exec-file?

Error if key cant be decrypted

I messed um my .asc files and they couldn't be decrypted by sops which is silently ignored and you cannot edit your secrets file. It should throw an error or at least log such thing.

sops-nix fails when cross-compiling

I'm cross-compiling from x86_64-linux to armv6l-unknown-linux-gnueabihf:

builder for '/nix/store/16ac42gw5z54wz966pcr11a4cschc0y7-checked-manifest.json.drv' failed with exit code 126; last 1 log lines:
  /build/.attr-0l2nkwhif96f51f4amnlf414lhl4rv9vh8iffyp431v6s28gsr90: line 1: /nix/store/vaqv96g948bsj153vfxv03snlmpxj4f5-sops-install-secrets-0.0.1-armv6l-unknown-linux-gnueabihf/bin/sops-install-secrets: cannot execute binary file: Exec format error

PGP Hook not running

The shell I have looks more or less like this

pkgs.mkShell {
  sopsPGPKeyDirs = [
    "./keys/host"
    "./keys/users"
  ];
  inputsFrom = [ projectEnv ];
  nativeBuildInputs = [
    (sops-nix { inherit pkgs; }).sops-pgp-hook
    spago2nix'
  ];
}

but I also have an .envrc which calls use flake at the end. Long story short, I have the correct .asc files in the above mentioned folders, but the hook doesn't seem to run since the environment variable doesn't exist.

Even if I direnv block, followed by sops secrets.yaml I get

config file not found and no keys provided through command line options

Also not sure what to make of this

$ nix-shell -p sops --run "sops secrets.yaml"
/nix/store/npdq5pilrfsklvhx0ws44lykc1rl1i66-stdenv-linux/setup: line 81: sopsPGPHook: command not found
config file not found and no keys provided through command line options

$ sops secrets.yaml
config file not found and no keys provided through command line options

Support mounting yaml and json files as is?

My use case: I'd like to pass a sops encrypted .yaml configuration file to my app after decryption as is, instead of picking a single key from the file. So, sops-nix is a little too clever for my use case and it should focus only on decrypting the file, not parsing it.

In other words, I use this file ./secrets/my-config.yaml in my flake:

my-secret1: ENC[AES256_GCM,data:tkyQPQODC3g=,iv:yHliT2FJ74EtnLIeeQtGbOoqVZnF0q5HiXYMJxYx6HE=,tag:EW5LV4kG4lcENaN2HIFiow==,type:str]
my-secret2: ENC[AES256_GCM,data:tkyQPQODC3g=,iv:yHliT2FJ74EtnLIeeQtGbOoqVZnF0q5HiXYMJxYx6HE=,tag:EW5LV4kG4lcENaN2HIFiow==,type:str]
sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    hc_vault: []
...

It should be mounted as /run/secrets/my-config.yaml:

my-secret1: hello
my-secret2: hello

Then I could pass the /run/secrets/my-config.yaml to my app to read any secrets from.

I could do this using a format=binary file, but then I have to remember to use format=binary everywhere, including when invoking sops. Alternatively, I could use a different file extension, but then I'd lose syntax highlight. Yet another alternative would be to use a literal multi line yaml string, but then again I'd lose highlight.

I wonder if this is already supported, because the README.md mentions home-assistant-secrets.yaml, which is similar to what I'm looking for? But I think that was defined as something like this:

home-assistant-secrets.yaml: |
    my-secret1: hello
    my-secret2: hello

(Notice how the renderer fails to highlight the yaml keys my-secret1 and my-secret2).

Does this make any sense to you?

Switch to another pgp library

Updating go dependencies results in:

pkgs/sops-install-secrets/sshkeys/convert.go:10:2: SA1019: package golang.org/x/crypto/openpgp is deprecated: this package is unmaintained except for security fixes. New applications should consider a more focused, modern alternative to OpenPGP for their specific task. If you are required to interoperate with OpenPGP systems and need a maintained package, consider a community fork. See https://golang.org/issue/44226. (staticcheck)
        "golang.org/x/crypto/openpgp"
        ^
pkgs/sops-install-secrets/sshkeys/convert.go:11:2: SA1019: package golang.org/x/crypto/openpgp/packet is deprecated: this package is unmaintained except for security fixes. New applications should consider a more focused, modern alternative to OpenPGP for their specific task. If you are required to interoperate with OpenPGP systems and need a maintained package, consider a community fork. See https://golang.org/issue/44226. (staticcheck)
        "golang.org/x/crypto/openpgp/packet"
        ^

Secrets needed for users are missing after boot

After setupSecrets, the directory /run/secrets.d/users disappears.

To test, I tried adding two ls command in setupSecrets.

diff --git a/modules/sops/default.nix b/modules/sops/default.nix
index aecf795..e2649de 100644
--- a/modules/sops/default.nix
+++ b/modules/sops/default.nix
@@ -294,7 +294,9 @@ in {
 
       setupSecrets = mkIf (regularSecrets != {}) (stringAfter ([ "specialfs" "users" "groups" ] ++ optional cfg.age.generateKey "generate-age-key") ''
         [ -e /run/current-system ] || echo setting up secrets...
+        ls -al /run/secrets.d
         ${withEnvironment "${sops-install-secrets}/bin/sops-install-secrets ${manifest}"}
+        ls -al /run/secrets.d
       '' // lib.optionalAttrs (config.system ? dryActivationScript) {
         supportsDryActivation = true;
       });

Add found logs like this:

Nov 13 17:41:15 t460p stage-2-init: setting up secrets...
Nov 13 17:41:15 t460p stage-2-init: total 0
Nov 13 17:41:15 t460p stage-2-init: drwxr-x--x  3 root root  60 Nov 13 17:41 .
Nov 13 17:41:15 t460p stage-2-init: drwxr-xr-x 11 root root 240 Nov 13 17:41 ..
Nov 13 17:41:15 t460p stage-2-init: drwxr-x--x  3 root root   0 Nov 13 17:41 users
Nov 13 17:41:15 t460p stage-2-init: total 4
Nov 13 17:41:15 t460p stage-2-init: drwxr-x--x  3 root keys   0 Nov 13 17:41 .
Nov 13 17:41:15 t460p stage-2-init: drwxr-xr-x 11 root root 260 Nov 13 17:41 ..
Nov 13 17:41:15 t460p stage-2-init: drwxr-x--x  7 root keys   0 Nov 13 17:41 1
Nov 13 17:41:15 t460p stage-2-init: -rw-------  1 root root 128 Nov 13 17:41 age-keys.txt

After a manual configuration switch, the users directory will be created again and works fine.

Seems that this is caused by the mountSecretFs function? The function mounts /run/secrets.d when it is not a ramfs, ignoring existing files in this directory.

Provide access to the value key in nix

I know the point of this library is to keep secrets out of the nix store, but would it make sense to provide the option to embed the value directly in nix if you want?

type secret struct {
	Name            string     `json:"name"`
	Key             string     `json:"key"`
	Path            string     `json:"path"`
	Owner           string     `json:"owner"`
	Group           string     `json:"group"`
	SopsFile        string     `json:"sopsFile"`
	Format          FormatType `json:"format"`
	Mode            string     `json:"mode"`
	RestartServices []string   `json:"restartServices"`
	ReloadServices  []string   `json:"reloadServices"`
	value           []byte
	mode            os.FileMode
	owner           int
	group           int
}

it seems that the value is available as a byte array

sops-install-secrets assumes the initial file is always stored as a json (cannot parse json)

Thought I'd document this, I don't expect a fix or anything.

The generated file when using sops on a .env file is not a JSON file, but a valid environment file.
sops-install-secrets then fails reading the manifest "Cannot parse json of /nix/store/....: invalid character blah blah"

KEY_1=ENC[...]
KEY_2=ENC[...]
KEY_3=ENC[...]
sops_pgp__list_1__map_created_at=2021-02-19T23:31:12Z
sops_pgp__list_2__map_fp=public-key-id
sops_pgp__list_0__map_created_at=2021-02-19T23:31:12Z
sops_unencrypted_suffix=_unencrypted
sops_version=3.6.1
sops_mac=ENC[....]
sops_pgp__list_1__map_fp=public-key-id
sops_lastmodified=2021-02-20T00:17:45Z
sops_pgp__list_2__map_created_at=2021-02-19T23:31:12Z
sops_pgp__list_0__map_enc=-----BEGIN PGP MESSAGE-----\n\n
\n-----END PGP MESSAGE-----\n
sops_pgp__list_0__map_fp=public-key-id
sops_pgp__list_2__map_enc=-----BEGIN PGP MESSAGE-----\n\n
\n-----END PGP MESSAGE-----\n
sops_pgp__list_1__map_enc=-----BEGIN PGP MESSAGE-----\n\n
\n-----END PGP MESSAGE-----\n

The fix is simple for the user: recreate the file as a .txt file.

ssh-to-pgp fails to install on macOS Big Sur

Seems the cgo linker is being unhappy, and that causes ssh-to-pgp to fail to test - breaking any shell.nix trying to use it:

error: --- Error --- nix-daemon
builder for '/nix/store/fqphylg3w68pmjb606p6xxg6dgwxpsy3-ssh-to-pgp-0.0.1.drv' failed with exit code 2; last 10 log lines:
  golang.org/x/crypto/ssh
  github.com/Mic92/sops-nix/pkgs/sshkeys
  github.com/Mic92/sops-nix/pkgs/ssh-to-pgp
  running tests
  # runtime/cgo
  ld: warning: passed two min versions (10.12.0, 10.12) for platform macOS. Using 10.12.
  ld: file not found: /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
  clang-7: error: linker command failed with exit code 1 (use -v to see invocation)
  FAIL       github.com/Mic92/sops-nix/pkgs/ssh-to-pgp [build failed]
  FAIL

I can go get the ssh-to-pgp binary just fine, but I suppose it would be good to be able to use it from a nix-shell too...

azure: support setting AZURE_AUTH_MODE

I am still progress on this, but for an ideal Azure setup I'm going to need to set AZURE_AUTH_MODE for the context that sops is executed in. For me, I'll only need to set that env var. Others may want to set AZURE_{TENANT_ID,CLIENT_ID,CLIENT_SECRET} for example.

Or maybe we should just document how to set arbitrary variables for sops's context?

(For the full story, I want to set AZURE_AUTH_MODE="msi" so that sops will use the short-lived authentication tokens provided by the VM-local web service to authenticate to Azure KeyVault instead of some other high-value cred that the user would need to manage.)

Does not work with `users.users.<name>.passwordFile`

If you attempt to do something like this:

{
  sops.secrets.root-password.sopsFile = ./root-password.yaml;
  users.users.root.passwordFile = config.sops.secrets.root-password.path;
}

Where root-password.yaml looks like this:

root-password: $6$rounds=65536$00000000000000$00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 

You end up with no password on boot for the user, looking at /etc/shadow shows root:!:1::::::. If you force reactivation to occur manually after booting by running sudo /run/current-system/bin/switch-to-configuration switch then /etc/shadow is updated and contains the correct password hash.

My guess is this is due to some annoying precedence issue, is there anyway around it?

auto-import gpg keys

Scenario:

  • I want to boot a SBC via netboot
  • I want encrypted secrets at rest (and on the netboot server)
  • There is a Yubikey plugged into the SBC with a configured OpenPGP app with certs/keys

So I'd like to have sops-nix (or something) auto-import the gpg key that corresponds to that computer (and corresponds to the key material on the yubikey).

Doesn't use ssh-agent for caching passphrase

When using ssh with a passphrase, doing nixos-rebuild switch results in an error:

setting up secrets...
/nix/store/6smf5qa87ggmcd85d7ixhw76kx13b018-sops-install-secrets-0.0.1/bin/sops-install-secrets: Error setting up gpg keyring: failed to parse private ssh key: ssh: this private key is passphrase protected
Activation script snippet 'setup-secrets' failed (1)
reloading user units for yoctocell...
setting up tmpfiles
warning: error(s) occurred while switching to the new configuration

This happens even when ssh-agent caches the passphrase, meaning that doing a git push wouldn't ask me for the passphrase. Is there a workaround for this, or do I have to remove the passphrase?

Can not add new machines with respective secrets.yml

I did setup sops for two machines whose file's I can access and edit with sops machine1/secret.yml
Today I added to further machines, and for some peculiar reason if I run
sops laptop1/secret.yml or nix-shell -p sops --run "sops laptop1/secret.yml"
I keep getting config file not found and no keys provided through command line options

The machine's public keys have been exported and the proposed shell.nix is present.

Any ideas?

Cannot unmarshal !!seq into string

I was playing around with sops to get the hang of it and unfortunately I keep getting an unmarshalling error whenever my yaml includes lists. Like in the default provided when running:

> nix-shell --run "sops blubb.yml"
<file_content>
hello: Welcome to SOPS! Edit this file as you please!
example_key: example_value
example_array:
- example_value1
- example_value2
example_number: 1234.5679
example_booleans:
- true
- false
</file_content>

Yields:

hostymchostface> /nix/store/5mr1s98rsxrxiywkhfrn8zir4isf0rqg-sops-install-secrets-0.0.1/bin/sops-install-secrets: Cannot parse yaml of '/nix/store/rcncfxywky46lx9d30ycr896rgmkhykf-bla.yml': yaml: unmarshal errors:
hostymchostface>   line 4: cannot unmarshal !!seq into string
…
hostymchostface>   line 8: cannot unmarshal !!seq into string

Request to document installation of sops-nix utilities

The ssh-to-pgp program and sops-pgp-hook nix-shell hook are essential to follow the documented Usage example. Neither is automatically accessible from importing the NixOS module under modules/sops. For example, #29 and #43 are both related to the accessibility of ssh-to-pgp.

Under the "Create a sops file" section, the example shell.nix uses <sops-nix>, which implies that sops-nix (the expression defined in this repo's default.nix) is in the Nix search path. Simply importing the NixOS module, which is the only documented installation step, leaves users like myself with an error that sops-nix was not found in the Nix search path.

What is the recommended approach to make these utilities accessible on the machine used for setup?

For reference, here are the relevant parts of my config:

{ config, pkgs, ... }:
let
  rev = "b0d764fccdd35588ebda2907911099198f73c89a";
  sops-nix = builtins.fetchTarball {
    url = "https://github.com/Mic92/sops-nix/archive/${rev}.tar.gz";
    sha256 = "0ny2pr3qjmw9jdbr0n2sy3w76f0pxfpjc8qr7x9zmwzlwck5xpc1";
  };
in
{
  imports =
    [
      ./configuration.nix (
      ./hardware-configuration.nix
      "${sops-nix}/modules/sops"
    ];
}

Secrets not showing up in /run/secrets after reboot

I just followed the tutorial and tried setting up wifi for my nixos install using nix-sops and it seems to work just fine when I make a nixos-rebuild switch.

However, when I reboot, for some reason, the /run/secrets directory isn't created. Doing another nixos-rebuild switch (without any changes at all), fixes it again until I reboot.

DanielFabian/.dotfiles@230b4ec

Any idea what I might be doing wrong? Or is it perhaps a bug that it's not setting up the secrets during the boot.

nice to have: ssh-to-gpg available in shell.nix

It would be nice to have ssh-to-gpg exposed easily from shell.nix.

But then again, maybe the goal is to delete it once age is merged into sops and you or someone else adds sshpubkey support to sops?

Would it be possible to use a yubikey as the secret key?

I'm currently using a ssh key for my sops configuration and I'm wondering if it is possible to use a yubikey instead. Does anyone have a example configuration? Will it work? One thing I'm not sure is that whether the yubikey will be usable during boot.

Support changing permissions on secret directories

I have a whole bunch of secrets stored in the /run/secrets/scripts directory. I want to put the directory /run/secrets/scripts into a non-root user's $PATH, but since that user doesn't have permission to read the directory, it doesn't work.

This can be worked around by manually symlinking to the secrets, but it would be great to have this as a normal feature.

error when sopsPGPKeyDirs is not a string

I recently helped a friend to debug why their sops hook was not working. It turned out they used sopsPGPKeyDirs = [ ./keys ] instead of sopsPGPKeyDirs = [ "./keys" ]. It would be nice if this would be a hard error instead of silently failing.

ssh-to-pgp tests fail with long temp dir names: File name too long

I'm trying to use sops-nix on a macOS machine, and it's running into problems running tests:

running tests
82ddc034d5ded2524f701114d96f6e894818c7a5
gpg: directory '/private/var/folders/08/j4g_jn953lngpvgmyg8dygk00000gn/T/nix-build-ssh-to-pgp-0.0.1.drv-0/.gnupg' created
gpg: keybox '/private/var/folders/08/j4g_jn953lngpvgmyg8dygk00000gn/T/nix-build-ssh-to-pgp-0.0.1.drv-0/.gnupg/pubring.kbx' created
pub   rsa3072 1970-01-01 [SCE]
      82DD C034 D5DE D252 4F70  1114 D96F 6E89 4818 C7A5
uid                      root (Imported from SSH) <root@localhost>

82ddc034d5ded2524f701114d96f6e894818c7a5
pub   rsa3072 1970-01-01 [SCE]
      82DD C034 D5DE D252 4F70  1114 D96F 6E89 4818 C7A5
uid                      root (Imported from SSH) <root@localhost>

82ddc034d5ded2524f701114d96f6e894818c7a5
gpg: can't connect to the agent: File name too long
sec#  rsa3072 1970-01-01 [SCE]
      82DD C034 D5DE D252 4F70  1114 D96F 6E89 4818 C7A5
uid                      root (Imported from SSH) <root@localhost>

main_test.go:44: unexpected error: exit status 2

--- FAIL: TestCli (6.49s)
FAIL
FAIL    github.com/Mic92/sops-nix/pkgs/ssh-to-pgp       6.588s
FAIL
builder for '/nix/store/zdqrb4z9zndm852zqvj472c4jc4l93y4-ssh-to-pgp-0.0.1.drv' failed with exit code 1
error: build of '/nix/store/zdqrb4z9zndm852zqvj472c4jc4l93y4-ssh-to-pgp-0.0.1.drv' failed

I suspect that's because the temporary folder is already a fairly long directory name, and adding a longer name to that makes gpg-agent unhappy to the extreme. There's a related issue on the debian BTS, where they suggest making a socket in a directory that's different from the "GNUPGHOME" one.

sops-pgp-hook evaluation fails in a strict shell (set -euo pipefail)

While testing things in a local repository, I discovered with direnv that enabling the strict_env option, which executes the hook with set -euo pipefail, would fail to evaluate the hook and exit.

I didn't have the variable below exposed so the script would exit with $VARIABLE_NAME: unbound variable

for key in $sopsPGPKeys; do

for dir in $sopsPGPKeyDirs; do

Changing the logic to "${VARIABLE_NAME-}" would prevent errors and only assign the empty string if the variable is undefined.

Replace sops-pgp-hook with sops-import-gpg-hook

SOPS_PGP_FP is not very flexible especially with multiple hosts.
The recommend solution is to use .sops.yaml which allows to specify different keys per sops file or directory.
That's I want to deprecate sops-pgp-hook with sops-import-gpg-hook, which only import keys and do not set SOPS_PGP_FP.

Not sure how to use gnupgHome?

{
sops.gnupgHome = "/home/cole/.gnupg";
}

But it fails to decrypt during activate. I can can confirm that running sops -d is using PGP and decrypting successfully: Is there something I have to do to make my user's gnupghome available to it during activation?

sops --input-type binary --output-type binary --verbose --output ../unencrypted/wg-server.key -d wg-server.key
[PGP]	 INFO[0000] Decryption succeeded                          fingerprint=...

"/nix/store/... is not in the nix store"

I'm doing something like

{
  sops.secrets.foo.sopsFile = "${secretsPath}/foo"; # where secretsPath = "/nix/store/..."
}

but this fails because of this check:

assertion = cfg.validateSopsFiles -> builtins.isPath sopsFile;

I could use secretsPath + "/foo" instead, but I feel like I shouldn't have to. Is there a better way to check whether a path is in the Nix store?

This runs too early in the boot process if included in an image

Rather than deploying this to an already running NixOS system, I was hoping to be able to build this into a pre-baked image that I could then deploy and boot.

Unfortunately, this doesn't seem to work, since this runs right at the beginning of stage2. At this point, SSH has never run, so there's no host key, the network is not even available to be able to reach Azure KeyVault, etc.

What do you think of having another version of this module that accepts similar config and instead creates a systemd service that can then be sequenced as part of the boot?

99] stage-1-init: resize2fs 1.45.5 (07-Jan-2020)
[  232.432835] stage-1-init: Resizing the filesystem on /dev/disk/by-label/nixos to 134152187 (4k) blocks.
[  232.432994] stage-1-init: The filesystem on /dev/disk/by-label/nixos is now 134152187 (4k) blocks long.
[  232.433343] stage-1-init: mounting /dev/disk/by-label/nixos on /...
[  232.491454] EXT4-fs (sda2): mounted filesystem with ordered data mode. Opts: (null)
[  233.555253] EXT4-fs (sda2): re-mounted. Opts: (null)
[  233.555685] booting system configuration /nix/store/jy2c5crwl63miv0k106fffldb90sccpv-nixos-system-unnamed-20.09.20200720.dirty
[  234.045090] stage-2-init: running activation script...
[  235.601159] stage-2-init: setting up /etc...
[  235.883966] stage-2-init: setting up secrets...
[  237.981769] stage-2-init: /nix/store/14lb4jzdf2j3k9a57niqzv2wi6z49yr9-sops-install-secrets-0.0.1/bin/sops-install-secrets: Error setting up gpg keyring: Cannot read ssh key '/etc/ssh/ssh_host_rsa_key': open /etc/ssh/ssh_host_rsa_key: no such file or directory
[  237.981874] stage-2-init: Activation script snippet 'setup-secrets' failed (1)
[  239.726445] systemd[1]: Inserted module 'autofs4'
[  239.872676] NET: Registered protocol family 10
[  239.873489] Segment Routing with IPv6
[  240.072141] systemd[1]: systemd 245 running in system mode. (+PAM +AUDIT -SELINUX +IMA +

sops.secrets."testFile" => owner does not propogate to the path symlink

The owner I marked for a given secret is not applied to the symlink:

{
 sops.secrets."cachix.dhall" = {
      owner = "cole";
      path = "/home/cole/.config/cachix/cachix.dhall";
      format = "binary";
      sopsFile = ./cachix.dhall.sops;
    };
}
> ls -al ~/.config/cachix/cachix.dhall
lrwxrwxrwx 1 root root 25 Aug  7 01:40 /home/cole/.config/cachix/cachix.dhall -> /run/secrets/cachix.dhall

Unable to install

Hey there. I'm trying to install sops-secrets. I'm following the niv install version (using master HEAD).

This is the error I'm getting:

error: anonymous function at /nix/store/a6xf442xypwmxcvg8glawp8qsjgyp617-82b54d490663b6d87b7b34b9cfc0985df8b49c7d.tar.gz/pkgs/development/go-modules/generic/default.nix:3:1 called without required argument 'modSha256', at /nix/store/rxa8b97sr75xfknlp670wg9kxkp9qz54-source/pkgs/sops-install-secrets/default.nix:2:1

this is what my nix/source.json file looks like:

{
    "niv": {
        "branch": "master",
        "description": "Easy dependency management for Nix projects",
        "homepage": "https://github.com/nmattia/niv",
        "owner": "nmattia",
        "repo":   ##"niv",
        "rev": "f2e2502412a661bc371c7390d86de278c4b9ef97",
        "sha256": "01z6dsc2dlm7nf3x35hcq6d3qhh75786c36am3y9x98a3xn1q4jm",
        "type": "tarball",
        "url": "https://github.com/nmattia/niv/archive/f2e2502412a661bc371c7390d86de278c4b9ef97.tar.gz",
        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
    },
    "nixpkgs": {
        "branch": "nixos-unstable",
        "description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
        "homepage": "https://github.com/NixOS/nixpkgs",
        "owner": "NixOS",
        "repo": "nixpkgs-channels",
        "rev": "82b54d490663b6d87b7b34b9cfc0985df8b49c7d",
        "sha256": "12gpsif48g5b4ys45x36g4vdf0srgal4c96351m7gd2jsgvdllyf",
        "type": "tarball",
        "url": "https://github.com/NixOS/nixpkgs-channels/archive/82b54d490663b6d87b7b34b9cfc0985df8b49c7d.tar.gz",
        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
    },
    "sops-nix": {
        "branch": "master",
        "description": "Atomic secret provisioning for NixOS based on sops",
        "homepage": "",
        "owner": "Mic92",
        "repo": "sops-nix",
        "rev": "b67ae45dc7459e10f390b2c5d24822599b564974",
        "sha256": "02y1590s905zdhw68qqsls1ah6ysj1hyfhcqg0fanv0029lk4agz",
        "type": "tarball",
        "url": "https://github.com/Mic92/sops-nix/archive/b67ae45dc7459e10f390b2c5d24822599b564974.tar.gz",
        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
    }
}

I'm using nixops and I've added the following to my configuration.nix

{ config, lib, pkgs, ... }:

{

  imports =
    [ # include the results of the hardware scan.
      ./hardware-configuration.nix
      "${(import ../../nix/sources.nix).sops-nix}/modules/sops"
    ];

I should probably note the nixops database has nixpkgs pinned as such:

## Updates the pinned nixpkgs in the nixops database
pin-nixpkgs:
	@nixops modify -d server1 deployment/server1.nix -I nixpkgs=https://github.com/nixos/nixpkgs/archive/`cat nix/sources.json | jq -r '.["nixpkgs"]["rev"]'`.tar.gz
	@nixops modify -d server2 deployment/server2.nix -I nixpkgs=https://github.com/nixos/nixpkgs/archive/`cat nix/sources.json | jq -r '.["nixpkgs"]["rev"]'`.tar.gz

I've never built golang with nix so I'm really not sure what the cause might be. Appreciate any guidance.

Simplify installation of needed utilities a lot

Hello,
I am trying to use sops-nix and after reading through the guide and the issues I still can't get it to work because I can't manage to install the needed utilities.
Similar to what is stated in issue #50 I suggest that the installation process for the needed utilities is not only documented but also very much simplified.
I suggest to create an overlay that can be added so that users can then just add ssh-to-pgp and sops-pgp-hook to the list of packages to be installed.
Unfortunately I don't know nix well enough yet, otherwise I would create a PR.

gpg does not work even with correct gnupg.home set

I created a directory: /var/lib/gnupg

drwxr-xr-x 4 root root 4096 Feb 11 16:42 gnupg

sudo GNUPGHOME=/var/lib/gnupg gpg --list-keys works

my config includes:

  sops.gnupg.home = "/var/lib/gnupg";
  sops.gnupg.sshKeyPaths = [];
  sops.defaultSopsFile = ../../secrets/example.yaml;
  sops.secrets.secret = {};

and yet when running nixos-rebuild switch it errors out:

Failed to decrypt '/nix/store/kyygj6xkax7qziizh8lhlh00s69jhgbf-example.yaml': Error getting data key: 0 successful groups required, got 0
Activation script snippet 'setupSecrets' failed (1)

Any ideas?

Some SSH RSA keys cannot be used for decryption...

I'm trying this out for the first time, deploying just a single secret to a single host with deploy-rs, but I'm getting the following error:

⭐ ❓ [activate] [DEBUG] Running activation script
updating GRUB 2 menu...
activating the configuration...
setting up /etc...
setting up secrets...
sops-install-secrets: Imported /etc/ssh/ssh_host_rsa_key with fingerprint e2083f651825666614144c58e6d961dca7ddf0c4
Activation script snippet 'setup-secrets' failed (1)
/nix/store/n6b7y2hj7ymd11xnigkhpyysx3zk83jn-sops-install-secrets-0.0.1/bin/sops-install-secrets: Failed to decrypt '/nix/store/iv09rddx0hfs6bk6262vacwly3g28cw8-secrets.yaml': Error getting data key: 0 successful groups required, got 0
reloading user units for root...
reloading user units for dhess...
setting up tmpfiles
⭐ ⚠️ [activate] [WARN] De-activating due to error

The machine GPG key was imported from its SSH host RSA key as explained in the README. The other key I'm using to encrypt this particular secret is my own personal GPG key. I can edit (decrypt) and encrypt the secrets.yaml file on my local machine fine.

On the server, when I try to run the sops-install-secrets command on the manifest, I get the same error as above:

/nix/store/n6b7y2hj7ymd11xnigkhpyysx3zk83jn-sops-install-secrets-0.0.1/bin/sops-install-secrets /nix/store/mzs4sqzkawwp995jv8svf247rwzpz3iy-checked-manifest.json
sops-install-secrets: Imported /etc/ssh/ssh_host_rsa_key with fingerprint e2083f651825666614144c58e6d961dca7ddf0c4
/nix/store/n6b7y2hj7ymd11xnigkhpyysx3zk83jn-sops-install-secrets-0.0.1/bin/sops-install-secrets: Failed to decrypt '/nix/store/iv09rddx0hfs6bk6262vacwly3g28cw8-secrets.yaml': Error getting data key: 0 successful groups required, got 0

Here are the secrets.yaml file and the manifest:

https://gist.github.com/dhess/74ec4eaa364369420e4121fa8ecbdd92
https://gist.github.com/dhess/a792710fbc263f899f75b2b3879e3e71

ssh-to-pgp: Support generating a public GPG key from a public SSH key

Currently, the readme suggests doing something like:

ssh youruser@server01 "sudo cat /etc/ssh/ssh_host_rsa_key" | ssh-to-pgp -o server01.asc

Which means reading the secret material from the server.

Is it possible to produce the same PGP public key from the SSH public key string, i.e. the string ssh-rsa [some base64] user@host?

This feels safer, and might be easier for users to understand (I was certainly confused by this process...)

sops-pgp-hook generates wrong format if pubkey has public subkeys

I tried importing a gpg key that lives on my yubikey, which looks like this:

$ gpg --list-keys FC88E425C10ECF1A5E433FFA65601C50F5081157
pub   rsa4096/3A9D5EAC405E4511 2017-11-26 [SC]
      Key fingerprint = CB4B 55B7 8759 274A 5AA7  3C4E 3A9D 5EAC 405E 4511
uid                 [ultimate] Andreas Fuchs (backup) <[email protected]>
sub   rsa4096/1A84E17CABE4374E 2017-11-26 [A]
sub   rsa4096/65601C50F5081157 2017-11-26 [E]

and has the following raw fpr output:

$ gpg --fingerprint --with-colons FC88E425C10ECF1A5E433FFA65601C50F5081157
tru::1:1595424541:0:3:1:5
pub:u:4096:1:3A9D5EAC405E4511:1511662807:::u:::scESCA::::::23::0:
fpr:::::::::CB4B55B78759274A5AA73C4E3A9D5EAC405E4511:
uid:u::::1511662807::9311483F59DB5EBC15D55766FD7872E63E6EC3E2::Andreas Fuchs (backup) <[email protected]>::::::::::0:
sub:u:4096:1:1A84E17CABE4374E:1511662807::::::a::::::23:
fpr:::::::::972208FDF991C3B906F714691A84E17CABE4374E:
sub:u:4096:1:65601C50F5081157:1511662807::::::e::::::23:
fpr:::::::::FC88E425C10ECF1A5E433FFA65601C50F5081157:

As you can tell, it has multiple public subkeys, which all get their own fingerprint. The sops-pgp-hook seems to expect only one fingerprint (removed my other keys, so that it appears more clearly):

$ echo $SOPS_PGP_FP
CB4B55B78759274A5AA73C4E3A9D5EAC405E4511 972208FDF991C3B906F714691A84E17CABE4374E FC88E425C10ECF1A5E433FFA65601C50F5081157
$ sops secret.yaml
Error encrypting the data key with one or more master keys: [failed to encrypt new data key with master key "CB4B55B78759274A5AA73C4E3A9D5EAC405E4511\n972208FDF991C3B906F714691A84E17CABE4374E\nFC88E425C10ECF1A5E433FFA65601C50F5081157": could not encrypt data key with PGP key: golang.org/x/crypto/openpgp error: key with fingerprint CB4B55B78759274A5AA73C4E3A9D5EAC405E4511
972208FDF991C3B906F714691A84E17CABE4374E
FC88E425C10ECF1A5E433FFA65601C50F5081157 is not available in keyring and could not be retrieved from keyserver; GPG binary error: exit status 2]

I suspect the awk in https://github.com/Mic92/sops-nix/blob/master/pkgs/sops-pgp-hook/sops-pgp-hook.bash#L5 needs adjusting so that the output of awk is considered to maybe contain multiple fingerprints.

Can't build ssh-to-pgp

During the build:

...
github.com/Mic92/sops-nix/pkgs/sshkeys
github.com/Mic92/sops-nix/pkgs/ssh-to-pgp
running tests
main_test.go:53: unexpected error: error reading github.com/Mic92/sops-nix/pkgs/ssh-to-pgp/test-assets/id_rsa: open github.com/Mic92/sops-nix/pkgs/ssh-to-pgp/test-assets/id_rsa: no such file or directory

--- FAIL: TestCli (0.00s)
FAIL
FAIL    github.com/Mic92/sops-nix/pkgs/ssh-to-pgp       0.002s
FAIL
builder for '/nix/store/vnbay3ri2nlf3qharnymn5fbcy39i9qh-ssh-to-pgp-0.0.1.drv' failed with exit code 1

This is on nixos-unstable-small

Cannot decrypt secret file

When I do nixos-rebuild switch, I get the following error:

...
setting up secrets...
/nix/store/4s57247wv7h4p77kn4isi9idgzwhsb7w-sops-install-secrets-0.0.1/bin/sops-install-secrets: Failed to decrypt '/nix/store/swrk0ywakisy6wqys1ahh80zmymwb37x-secrets.yaml': Error getting data key: 0 successful groups required, got 0
Activation script snippet 'setup-secrets' failed (1)
reloading user units for yoctocell...
setting up tmpfiles
warning: error(s) occurred while switching to the new configuration

I have the following in my nixos config:

{
  sops.gnupgHome = "/home/yoctocell/.gnupg";

  sops.secrets.example-key = {
    owner = "yoctocell";
    group = "yoctocell";
    sopsFile = ./secrets/secrets.yaml;
  };
}

Where the contents of secrets/secrets.yaml is:

example-key: example-value
another-key: another-value

If I run sops secrets/secrets.yaml from the terminal, it decrypts the file and opens it in my $EDITOR. Is there something I am missing from the documentation?

Use a secret as a nixos option value

Hello,
I’d like to know if there is a way to use a nix sops secret as a value of a nixos option ? Some module don’t have things like « passwordFile » options but only « password ». In these kind of cases I never know what to do.

Keeping flakes pure with home-manager and sops

Hello,

I'm using home-manager, flakes and sops and I've integrated sops into my configuration file like so:

{ nixosConfig, ...}:
{
  programs.awscli2 = {
    enable = true;
    config = nixosConfig.sops.secrets.awscli2-config.path;
    credentials = nixosConfig.sops.secrets.awscli2-credentials.path;
  };
}

however, this results in:

error: access to absolute path '/run/secrets/awscli2-config' is forbidden in pure eval mode (use '--impure' to override

This does not occur when using sops secrets outside of home-manager, in my case inside configuration.nix.

Is this unavoidable when using flakes or am I doing something wrong?

How do you use the sops module with niv?

Hi again, I'm getting so close to being able to use sops-nix to keep secrets on my host (Thanks for the fixing those last two issues so quickly)! - unfortunately, my luck has run out as I'm pulling sops-nix in with niv, and I don't understand how importing a sub-module of a niv-managed package should work. Using imports = [ <sops-nix/modules/sops> ]; in my nix files fails with error: file 'sops-nix/modules/sops' was not found in the Nix search path (add it using $NIX_PATH or -I), at /Users/asf/Mess/current/sops-sobs/configuration.nix:3:15.

I tried getting at the submodule in various other ways, but none of them work; the sops attribute remains inaccessible.

I asked the same question on the niv bug tracker as it seems like a documentation problem on their end also, but maybe you know of a quick solution?

Can we add to the current shellHook instead of dying silently?

if [ -z "${shellHook-}" ]; then

My current shellHook is

  shellHook = ''
    export NIX_PATH=nixpkgs=${src.nixpkgs}
    nix build -f deployments.nix one-runner -o deploy-one-runner
    nix build -f deployments.nix canary-runner -o deploy-canary-runner
  '';

which is quite useful. I did not understand at first why the SOPS_PGP_FP env var was not automatically set. May I suggest that we concatenate the current shellHook with the pgpHook? I'll try to write a PR for this.

Use during evaluation?

Would there be a way to encrypt a file that gets decrypted during nix evaluation? The idea would be to store semi-secrets that change the nix configuration like the contents of /etc/hosts - I'd like to keep that out of git but it's fine in the nix store.

How to read secret file after it's declared

I might be fundamentally misunderstanding how to use this tool so please bear with. I have worked through the examples, I'm using a flake based setup and in my configuration.nix have set sops.secrets.mysecret = {}; and can see that at /run/secrets/mysecret exists with the correct value. Later in my configuration, I'm trying to read the contents of the secret file with builtins.readFile "${config.sops.secrets.mysecret.path}" but I get the error access to path /run/secrets/myexample is forbidden in restricted mode. I'm trying to read the file because I want to use it's contents in some string interpolation but maybe that's not the correct usage of sops-nix? I also tried neededForUsers with the same result. Is sops-nix limited to just passing the value of secret paths into path options/configs strings rather than decrypting exposing the secrets during build time?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.