diff --git a/README.md b/README.md
index 5da95fc..bfb3edf 100644
--- a/README.md
+++ b/README.md
@@ -2,60 +2,87 @@

-Atomic secret provisioning for NixOS based on [sops](https://github.com/mozilla/sops).
+Atomic, declarative, and reproducible secret provisioning for NixOS based on [sops](https://github.com/mozilla/sops).
## How it works
-Sops-nix decrypts secrets [sops files](https://github.com/mozilla/sops#2usage)
-on the target machine to files specified in the NixOS configuration at
-activation time. It also adjusts file permissions/owner/group. It uses either
-age or GPG keys for decryption, where both types can be derived from ssh host
-keys. In future we will also support cloud key management APIs such as AWS
-KMS, GCP KMS, Azure Key Vault or Hashicorp's vault.
+Secrets are decrypted from [`sops` files](https://github.com/mozilla/sops#2usage) 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](https://github.com/NixOS/nixops), nixos-rebuild, [krops](https://github.com/krebs/krops/), [morph](https://github.com/DBCDK/morph), [nixus](https://github.com/Infinisil/nixus)
-- Version-control friendly: Since all files are encrypted they can directly committed to version control. The format is readable in diffs and there are also ways of showing [git diffs in cleartext](https://github.com/mozilla/sops#showing-diffs-in-cleartext-in-git)
-- Works well in teams: sops-nix comes with nix-shell hooks that allows quickly import multiple people to import all used keys.
+- Compatible with all NixOS deployment frameworks: [NixOps](https://github.com/NixOS/nixops), nixos-rebuild, [krops](https://github.com/krebs/krops/), [morph](https://github.com/DBCDK/morph), [nixus](https://github.com/Infinisil/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](https://github.com/mozilla/sops#showing-diffs-in-cleartext-in-git).
+- 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.
+- 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 each machine/developer key.
-- CI friendly: Since sops files can be added to the Nix store without leaking secrets, a machine definition can be built as a whole.
-- Atomic upgrades: New secrets are written to a new directory which replaces the old directory in an atomic step.
-- Rollback support: If sops files are added to Nix store, old secrets can be rolled back. This is optional.
-- Fast: Unlike solutions implemented by NixOps, krops and morph there is no extra step required to upload secrets
-- Different storage formats: Secrets can be stored in YAML, JSON or binary.
-- Minimize configuration errors: sops files are checked against the configuration at evaluation time.
+ 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, 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](#5-deploy) of our usage example.
+There is a `configuration.nix` example in the [deployment step](#deploy-example) of our usage example.
## Supported encryption methods
-sops-nix supports two basic ways of encryption, gnupg and age. Gnupg is based
-on gnupg (duh) and encrypts against gnupg public keys. Private gnupg keys may
-be used to decrypt the secrets on the target machine. The tool `ssh-to-pgp` can
-be used to derive a gnupg key from a ssh (host) key in RSA format.
+sops-nix supports two basic ways of encryption, GPG and `age`.
-The other method is age which is based on [age](https://github.com/FiloSottile/age).
-A tool is provided with sops-nix that can convert ssh host or user keys in ed25519
-format to age keys.
+GPG is based on [GnuPG](https://gnupg.org/) 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`](https://github.com/Mic92/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`](https://github.com/FiloSottile/age).
+The tool ([`ssh-to-age`](https://github.com/Mic92/ssh-to-age)) can convert SSH host or user keys in Ed25519
+format to `age` keys.
## Usage example
-### 1. Install nix-sops
+
+1. Install sops-nix
Choose one of the following methods:
-#### [niv](https://github.com/nmattia/niv) (Current recommendation)
+#### Flakes (current recommendation)
+
+If you use experimental nix flakes support:
+
+``` nix
+{
+ 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`](https://github.com/nmattia/niv) (recommended if not using flakes)
First add it to niv:
```console
$ niv add Mic92/sops-nix
```
- Then add the following to your configuration.nix in the `imports` list:
+ Then add the following to your `configuration.nix` in the `imports` list:
```nix
{
@@ -63,7 +90,7 @@ $ niv add Mic92/sops-nix
}
```
-#### nix-channel
+#### `nix-channel`
As root run:
@@ -72,7 +99,7 @@ $ nix-channel --add https://github.com/Mic92/sops-nix/archive/master.tar.gz sops
$ nix-channel --update
```
- Then add the following to your configuration.nix in the `imports` list:
+ Then add the following to your `configuration.nix` in the `imports` list:
```nix
{
@@ -80,9 +107,9 @@ $ nix-channel --update
}
```
-#### fetchTarball
+#### `fetchTarball`
- Add the following to your configuration.nix:
+ Add the following to your `configuration.nix`:
``` nix
{
@@ -90,7 +117,7 @@ $ nix-channel --update
}
```
- or with pinning:
+or with pinning:
```nix
{
@@ -107,38 +134,28 @@ $ nix-channel --update
}
```
-#### Flakes
+
-If you use experimental nix flakes support:
+
+2. Generate a key for yourself
-``` nix
-{
- 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 {
- # change to your system:
- system = "x86_64-linux";
- modules = [
- ./configuration.nix
- sops-nix.nixosModules.sops
- ];
- };
- };
-}
+This key will be used for you to edit secrets.
+
+You can generate yourself a key:
+```console
+# for age
+$ mkdir -p ~/.config/sops/age
+$ age-keygen -o ~/.config/sops/age/keys.txt
+# 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
```
-### 2a. Generate a GPG key for yourself
-
-This is only needed when you plan to use the gnupg encryption.
-When using age, you can skip to step 2b instead.
-
-First generate yourself [a GPG key](https://docs.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key) or use nix-sops
-conversion tool to convert an existing ssh key (we only support RSA keys right now):
-
+Or you can use the `ssh-to-pgp` tool to get a GPG key from an SSH key:
```console
$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i $HOME/.ssh/id_rsa | gpg --import --quiet"
2504791468b153b8a3963cc97ba53d1919c5dfd4
@@ -146,39 +163,57 @@ $ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i $HOME/.ssh/
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i $HOME/.ssh/id_rsa -o $USER.asc"
2504791468b153b8a3963cc97ba53d1919c5dfd4
```
-
-If you get:
-
+(Note that `ssh-to-pgp` only supports RSA keys; to use Ed25519 keys, use `age`.)
+If you get the following,
```console
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 need to create an unencrypted copy temporarily:
-
+then your SSH key is encrypted with your password and you will need to create an unencrypted copy temporarily.
```console
$ 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
```
-The hex string printed here is your GPG fingerprint that can written to your [`.sops.yaml`](https://github.com/mozilla/sops#using-sops-yaml-conf-to-select-kms-pgp-for-new-files) in the root of your configuration directory or repository.
+You can also use an existing SSH Ed25519 key as an `age` key; to do so, see the following.
-```yaml
-# This example uses yaml anchors which allows to name keys
-# and re-use for multiple keys in a flexible way.
-# Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml
-# for a more complex example
-keys:
- - &admin 2504791468b153b8a3963cc97ba53d1919c5dfd4
-creation_rules:
- - path_regex: secrets/[^/]+\.yaml$
- key_groups:
- - pgp:
- - *admin
+
+ 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`:
+```console
+$ age-keygen -y ~/.config/sops/age/keys.txt
+age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
```
-If you have generated a GnuPG key directly you can get your fingerprint like this:
+Otherwise, you can convert an existing SSH key into an `age` public key:
+```console
+$ 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"
+```
+If you get this,
+
+```console
+failed to parse ssh private key: ssh: this private key is passphrase protected
+```
+
+then your SSH key is encrypted with your password and you need to create an unencrypted copy temporarily:
+
+```console
+$ cp $HOME/.ssh/id_ed25519 /tmp/id_ed25519
+$ ssh-keygen -p -N "" -f /tmp/id_ed25519
+$ nix-shell -p ssh-to-age --run "ssh-to-age -private-key -i /tmp/id_ed25519 > ~/.config/sops/age/keys.txt"
+```
+
+
+
+
+ How to find the GPG fingerprint of a key
+
+Invoke this command and look for your key:
```console
$ gpg --list-secret-keys
/tmp/tmp.JA07D1aVRD/pubring.kbx
@@ -189,103 +224,94 @@ uid [ unknown] root
```
The fingerprint here is `9F89C5F69A10281A835014B09C3DC61F752087EF`.
+
-
-### 2b. Generate a SSH and age key for yourself
-
-This is only needed when you plan to use the age encryption.
-When using gnupg, you need to go back to step 2a.
-
-sops-nix in age mode requires you to have an age key.
-You can generate one like this:
-
-``` console
-$ mkdir -p ~/.config/sops/age
-$ age-keygen -o ~/.config/sops/age/keys.txt
+Your `age` public key or GPG fingerprint can written to your [`.sops.yaml`](https://github.com/mozilla/sops#using-sops-YAML-conf-to-select-kms-pgp-for-new-files) in the root of your configuration directory or repository:
+```yaml
+# 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$
+ key_groups:
+ - pgp:
+ - *admin_alice
+ - age:
+ - *admin_bob
```
-If you have an ssh key in `ed25519` format (i.e. if it was generated `ssh-keygen -t ed25519`)
-you can also convert to an age key:
+
+
+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:
```console
-$ 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"
+$ nix-shell -p ssh-to-age --run 'ssh-keyscan my-server.com | ssh-to-age'
+age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3
+$ nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
+age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3
```
-Converting the public key to the age format works like this:
-```console
-$ nix-shell -p ssh-to-age --run " ssh-to-age < ~/.ssh/id_ed25519.pub "
-```
-
-or like this
-
-``` console
-$ nix-shell -p ssh-to-age --run "ssh-add -L | ssh-to-age"
-```
-
-If you get:
-
-```console
-failed to parse ssh private key: ssh: this private key is passphrase protected
-```
-
-then your ssh key is encrypted with your password and you need to create an unencrypted copy temporarily:
-
-```console
-$ cp $HOME/.ssh/id_ed25519 /tmp/id_ed25519
-$ ssh-keygen -p -N "" -f /tmp/id_ed25519
-$ nix-shell -p ssh-to-age --run "ssh-to-age -private-key -i /tmp/id_ed25519 > ~/.config/sops/age/keys.txt"
-```
-
-### 3a. Get a PGP Public key for your machine
-
-The easiest way to add new hosts is using ssh host keys (requires openssh to be enabled).
-Since sops does not natively supports ssh keys yet, nix-sops supports a conversion tool
-to store them as gpg keys.
+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:
```console
$ 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 (or in a ssh session)
+# 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
```
-Also the hex string here is the fingerprint of your server's gpg key that can be exported append to `.sops.yaml`:
+The output of these commands is the identifier for the server's key, which can be added to your `.sops.yaml`:
```yaml
keys:
- - &admin 2504791468b153b8a3963cc97ba53d1919c5dfd4
- - &server 0fd60c8c3b664aceb1796ce02b318df330331003
+ - &admin_alice 2504791468b153b8a3963cc97ba53d1919c5dfd4
+ - &admin_bob age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
+ - &server_azmidi 0fd60c8c3b664aceb1796ce02b318df330331003
+ - &server_nosaxa age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3
creation_rules:
- path_regex: secrets/[^/]+\.yaml$
key_groups:
- pgp:
- - *admin
- - *server
+ - *admin_alice
+ - *server_azmidi
+ - age:
+ - *admin_bob
+ - *server_nosaxa
+ - path_regex: secrets/azmidi/[^/]+\.yaml$
+ key_groups:
+ - pgp:
+ - *admin_alice
+ - *server_azmidi
+ - age:
+ - *admin_bob
```
-If you prefer having a separate GnuPG key, see [Use with GnuPG instead of ssh keys](#use-with-gnupg-instead-of-ssh-keys).
+If you prefer having a separate GPG key, see [Use with GPG instead of SSH keys](#use-with-GPG-instead-of-SSH-keys).
-### 3b. Get a age Public key for your machine
+
-The `ssh-to-age` tool is used to convert any ssh public key to the age format.
-This way you can convert any key:
-```console
-$ nix-shell -p ssh-to-age --run 'ssh-keyscan my-server.com | ssh-to-age'
-$ nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
-```
-
-### 4. Create a sops file
+
+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 automates importing gpg keys with a hook for nix-shell allowing public
-keys to be shared via version control (i.e. git):
+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).
```nix
# shell.nix
@@ -327,7 +353,7 @@ mkShell {
}
```
-Our directory structure looks like this:
+A valid directory structure for this might look like:
```console
$ tree .
@@ -339,134 +365,111 @@ $ tree .
│ └── mic92.asc
```
-After that you can open a new file with sops
+
+
+After configuring `.sops.yaml`, you can open a new file with sops:
```console
-$ nix-shell -p sops --run "sops secrets.yaml"
+$ nix-shell -p sops --run "sops secrets/example.yaml"
```
-This will start your configured editor
-In our example we put the following content in it:
-
-```
-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.
+This will start your configured editor located at the `$EDITOR` environment variable.
+An example secret file might be:
```yaml
+# 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: example value
+ my_secret: password1
```
-As a result when saving the file the following content will be in it:
+An example result when saving this file could be:
```
-example-key: ENC[AES256_GCM,data:7QIOMLd2kZkeVVpH0Q==,iv:ROh+J59ZM6BtjZLhRj1Ylk6ROEvsiX6/UR8obHX8YcQ=,tag:QOiFoHKyGFBkhr9lcWBB3Q==,type:str]
+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: []
- lastmodified: '2020-07-13T09:09:14Z'
- mac: ENC[AES256_GCM,data:BCwTBxaW6qINVfixC32EEYrlqPvGz47wF+o/vNPqcwed1HPwZezlNy7Z4NFLbRcCLAELyeMqkJ+fi9XCWvnT3UvfwB45COpz/xZphURt3gyCVOyd9mT/s9cJ1O9vNy5iKblqCae2X0CTKee/GxJ0G725LDOL4r+oHM1+WWEInWo=,iv:S43qegidSqcaUaDjvQpEQj/qvF/OZcW32Yo05CfyTUs=,tag:npj5auJXZrg7jQwYSjC6Vg==,type:str]
- pgp:
- - created_at: '2020-07-13T08:34:30Z'
- enc: |
- -----BEGIN PGP MESSAGE-----
-
- hQIMAysxjfMwMxADAQ//SyBLvbpyuoTGCZCtoJyaFzZ+vCKWZaD7dCZEURRyNKFV
- 87wZyNO/rwtA1jP64Smqy0q2R8iZfoN0v5oVvtj2y5wFECs8Q5nONCVP4rs9nTRK
- n46w0v2UE2GqIWStFE7Mpv11qdZaMDoNGXq+n6s/uA2mwSYIVvzcWwhKvyKrMNrd
- iOlfCKl4QTaGgGupZqmT2S00AEMJzY5lohvtzAC1TlnXGXhetDyCHtkoN/NKZDU7
- m7j1/pvlIwxTQKeA3FKuxDJDYk+p3+W/EgwEchYDzjo+5A529J/tuIfXWBOF7BAV
- ZiVVWISTahky/ioOMatNBAttu0lBGlSkovkbqIVsbTG7nF1wzGdToCxZmwQveEj7
- 0N8ZzocDkOXqS71LW+X2HYSeywxNUbg/S6MrHrZN8MOp5qnGztm8yrKW2gDDe+Nl
- nqJJ4lGg5CbODoDmhbPPof9tmWkykFmQSqmkjs4pcomcNthmcQvPVy75pnXEN9Wo
- 0cDRnHtgROCJLqfv1AsXWkSxtmZRMMQ1yKJIPVFUHSPodgAoTyA81sHi66RypDOV
- KezX6sW8UuTZ7q1oPcJFpaaHrpIHDn+bqPGMfhu4NVXFusdb7MPxtxlKflhTdc8B
- xzlrB6+LdnCaeN+KqB6DOvmiPP3nC91zflO1SpMY3yUOnTFDKZG7wnVjidyIuMvS
- UAHk6rhsBEJleAn5f4AuBVWtWLuvS4t1g9Lhci3833f7XNp+GFNy05UOsmUo9upr
- cgqaa2teuy2cbUtzS6gLBbcMA7SEs5MDYHjq6le/pwKv
- =ZYPM
- -----END PGP MESSAGE-----
- fp: 0FD60C8C3B664ACEB1796CE02B318DF330331003
- - created_at: '2020-07-13T08:34:30Z'
- enc: |
- -----BEGIN PGP MESSAGE-----
-
- hQIMAysxjfMwMxADARAAqbkG7+WZIDDHNjFp4mcabdGcKaTenJmAQKJjk4vnAWZD
- 5Y6yInTldxldsFNvPcVmjZp/nM1otyH0MEHrurl5LX+BuUj8hRIE0ZFnNU0hNmyd
- toiwTE4GF1/otYFOPb9WnhDt+g6Y0ORuV/ZMSvP8PIu5/UnTeCkbZR/VudOvUq/m
- qF013M3q7UKssW4aReO2goFEhLjm8GfWksCuiGYKoHdJKzFAPYNhoxnxU3n43Oxp
- wz7QYFI0aA7RLZph70WjUNBun5+y4UyEJ8uNZ+cgVBeHQLqVdFUuejdzWK0d79Mr
- 5D9fxgSsPMz7yUMMdPl0T4rrAsZ977pftI9+JofqMN+u9UzUJwfTjnbCxlob39/t
- bfORkanzU8BNUCxpHyyqau921AUtfcqV9Y9Hf+qwxgVRVKgfETOqN376A1nhrYsf
- Mhvmcsk/rDssiRSIu11/mZwifcpALnS8WgO5tK+e/454ANqsiEdSRVogWBTzcIIs
- trm/6kwsTl7COzK0ThUKIb6aOfb910JQKaYq93qWqF1fceIf49Ubz9NVZc80J0an
- OiAaVGS0IOGI1ua8zciY7m+rr1BlrqJFtUm7hd8C9fMaF8YdB2SXgW8/HPGL8uTd
- f9ASg9TMSxhr7wjdqWp4EXXxdB6p4FXai9XBbgAJ2tKcS6AV6QmRVMoITZ7uZpvS
- UAG4nIgey9A57C8DSnt5zVPtxAsjDNiMubLUnHzTEJEJyQH5j2E41teujycOOAye
- I/UHMfpxSgrFfS8JJHYrJO0JQq/maBZi/VzZCl/G3IMn
- =Xls9
- -----END PGP MESSAGE-----
- fp: 0FD60C8C3B664ACEB1796CE02B318DF330331003
- - created_at: '2020-07-13T08:34:30Z'
- enc: |
- -----BEGIN PGP MESSAGE-----
-
- hQEMA5w9xh91IIfvAQf+I1FDo7rglcA6EF7jmQ0pq9FwYR/Dd9+4pu4mxUofQawj
- YsXPToVvyOKFrs1BZzW3Idyn5U/oXnkPN0qNK30DKir/wCt9OBqHHuhlo80OR2nS
- G2ZvHOJKEW3W5Hs2yT1e1MQxznI1lGFrsj6xgZAnKtK3Y6iy48XZ9pTw4Fxjkixw
- NppHtYrMj30mwV9XFAer0EfGlV2AIi70xBZ2inYAzPU2SpLEEoGyztjIeSS4VfhQ
- fnKSx3UjlVIix65s2ky0JqbL1wI+FPKNt2hWupW+M7en8BJ5VfAcbU7n0ZuQnaFx
- YPErw3agfhw1bNnqXh0y5aZ9sswt/Jy+IRkMJHLcqNJQAREdKgGmkW8wO2dngYYL
- IwLyChHJfcSnixboVcW5CIbfmIbOdgfEk2tdSiX1tJIA6qeeJz+D8UbR47nIdIw2
- ZoID5dEUiDgikopjdqWk+zk=
- =43hf
- -----END PGP MESSAGE-----
- fp: 9F89C5F69A10281A835014B09C3DC61F752087EF
+ 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.5.0
+ version: 3.7.1
```
-### 5. Deploy
+
-If you derived your server public key from ssh, all you need in your configuration.nix is:
+
+5. Deploy
+
+If you derived your server public key from SSH, all you need in your `configuration.nix` is:
```nix
{
imports = [ ];
# 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.yaml";
- sops.defaultSopsFile = ./secrets.yaml;
- sops.secrets.example-key = {};
- # This is using ssh keys in the age format:
+ # 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 key accessible
-via `/run/secrets/example-key`:
+On `nixos-rebuild switch` this will make the keys accessible
+via `/run/secrets/example-key` and `/run/secrets/myservice/my_subdir/my_secret`:
```console
$ cat /run/secrets/example-key
example-value
+$ cat /run/secrets/myservice/my_subdir/my_secret
+password1
```
-`/run/secrets` is a symlink to `/etc/secret.d/1`:
+`/run/secrets` is a symlink to `/run/secrets.d/{number}`:
```console
$ 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
@@ -476,9 +479,9 @@ the parent directory `/run/secrets.d` is only owned by
``` console
$ ls -la /run/secrets.d/1
total 24
-drwxr-x--- 2 root keys 0 Jul 18 15:35 .
-drwxr-x--- 3 root keys 0 Jul 18 15:35 ..
--r-------- 1 root root 20 Jul 18 15:35 borgbackup
+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.
@@ -486,8 +489,8 @@ Consider the following nixos configuration example:
```nix
{
- # Permission modes are in octal representation,
- # the digits reprsent: user|group|owner
+ # Permission modes are in octal representation (same as chmod),
+ # the digits represent: user|group|owner
# 7 - full (rwx)
# 6 - read and write (rw-)
# 5 - read and execute (r-x)
@@ -525,8 +528,9 @@ For login or system users this can be done like this:
}
```
-The following example configures secrets for buildkite, a CI agent
-the service needs a token and a ssh private key to function:
+
+This example configures secrets for buildkite, a CI agent;
+the service needs a token and a SSH private key to function.
```nix
{ pkgs, config, ... }:
@@ -555,7 +559,9 @@ the service needs a token and a ssh private key to function:
}
```
-## Restarting/reloading systemd units
+
+
+## Restarting/reloading systemd units on secret change
**With NixOS 21.11**, it is possible to restart or reload units when a secret changes or is newly initialized.
This behaviour can be configured per-secret:
@@ -572,7 +578,7 @@ This logic respects units that prefer to be reloaded or not to be restarted at a
## Symlinks to other directories
Some services might expect files in certain locations.
-Using the `path` option as symlink to this directory can
+Using the `path` option a symlink to this directory can
be created:
```nix
@@ -591,10 +597,10 @@ lrwxrwxrwx 1 root root 40 Jul 19 22:36 /var/lib/hass/secrets.yaml -> /run/secret
## Setting a user's password
-sops-nix has to run after users were created by NixOS.
+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..passwordFile` 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 the users.
+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.
```nix
@@ -610,32 +616,16 @@ As users are not created yet, it's not possible to set an owner for these secret
## Different file formats
-At the moment we support the following file formats: YAML, JSON, binary
+At the moment we support the following file formats: YAML, JSON, and binary.
-NOTE: At the moment we do not support nested data structures that
-sops support. This might change in the future:
-
-We support the following yaml:
-
-```yaml
-key: 1
-```
-
-but not:
-
-```yaml
-nested:
- key: 1
-```
-
-nix-sops allows to specify multiple sops files in different file formats:
+sops-nix allows specifying multiple sops files in different file formats:
```nix
{
imports = [ ];
# 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:
+ # 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...
@@ -654,11 +644,10 @@ Open a new file with sops ending in `.yaml`:
$ sops secrets.yaml
```
-Than put in the following content:
+Then, put in the following content:
```yaml
github_token: 4a6c73f74928a9c4c4bc47379256b72e598e2bd3
-# multi-line strings in yaml start with an |
ssh_key: |
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
@@ -674,7 +663,7 @@ You can include it like this in your `configuration.nix`:
```nix
{
sops.defaultSopsFile = ./secrets.yaml;
- # yaml is the default
+ # YAML is the default
#sops.defaultSopsFormat = "yaml";
sops.secrets.github_token = {
format = "yaml";
@@ -692,7 +681,7 @@ Open a new file with sops ending in `.json`:
$ sops secrets.json
```
-Than put in the following content:
+Then, put in the following content:
``` json
{
@@ -706,7 +695,7 @@ You can include it like this in your `configuration.nix`:
```nix
{
sops.defaultSopsFile = ./secrets.json;
- # yaml is the default
+ # YAML is the default
sops.defaultSopsFormat = "json";
sops.secrets.github_token = {
format = "json";
@@ -718,14 +707,14 @@ You can include it like this in your `configuration.nix`:
### Binary
-Unlike the other two formats for binaries one file correspond to one secret.
This format allows to encrypt an arbitrary binary format that can't be put into
-JSON/YAML files.
+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:
``` console
$ sops -e /tmp/krb5.keytab > 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]",
@@ -746,7 +735,7 @@ 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:
+This is how it can be included in your `configuration.nix`:
```nix
{
@@ -757,15 +746,15 @@ This is how it can be included in your configuration.nix:
}
```
-## Use with GnuPG instead of ssh keys
+## Use with GPG instead of SSH keys
-If you prefer having a separate GnuPG key, sops-nix also comes with a helper tool:
+If you prefer having a separate GPG key, sops-nix also comes with a helper tool, `sops-init-gpg-key`:
```console
$ nix-shell -p sops-init-gpg-key
$ sops-init-gpg-key --hostname server01 --gpghome /tmp/newkey
-You can use the following command to save it to a file:
-cat > server01.asc < server01.asc <