mirror of
https://github.com/Mic92/sops-nix.git
synced 2025-03-16 13:38:20 +00:00
docs: make README.md clearer
This makes several changes to the README to make reading it clearer. - General grammar, capitalization, and punctuation fixes. - Change the usage example into collapsible sections so the README is navigable. - Merge steps 2a/2b and steps 3a/3b into steps 2 and 3, since they share a lot in common. - Use age examples for .sops.yaml, instead of just GPG fingerprints. - Make sure there is only one consistent example throughout the entirety of the usage example. - Make the age/GPG/SSH trichotomy less confusing. - Adds a source for the "GnuPG is not great software" claim.
This commit is contained in:
parent
3c53d012ac
commit
e6866b54e6
1 changed files with 242 additions and 238 deletions
480
README.md
480
README.md
|
@ -2,49 +2,50 @@
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
## How it works
|
||||||
|
|
||||||
Sops-nix decrypts secrets [sops files](https://github.com/mozilla/sops#2usage)
|
Secrets are decrypted from [`sops` files](https://github.com/mozilla/sops#2usage) during
|
||||||
on the target machine to files specified in the NixOS configuration at
|
activation time. The secrets are access-controlled by by full declarative configuration of their users, permissions, and groups.
|
||||||
activation time. It also adjusts file permissions/owner/group. It uses either
|
It can use `age`, GPG, or SSH keys for decryption.
|
||||||
age or GPG keys for decryption, where both types can be derived from ssh host
|
In the future, we will also support cloud key management APIs such as AWS
|
||||||
keys. In future we will also support cloud key management APIs such as AWS
|
KMS, GCP KMS, Azure Key Vault and Hashicorp Vault.
|
||||||
KMS, GCP KMS, Azure Key Vault or Hashicorp's vault.
|
|
||||||
|
|
||||||
## Features
|
## 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)
|
- 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 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)
|
- Version-control friendly: Since all files are encrypted they can 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).
|
||||||
- Works well in teams: sops-nix comes with nix-shell hooks that allows quickly import multiple people to import all used keys.
|
- 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 keys.
|
||||||
The cryptography used in sops is designed to be scalable: Secrets are only encrypted once with a master key
|
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.
|
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 atomically.
|
||||||
- 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 the Nix store, old secrets can be rolled back. This is optional.
|
||||||
- Rollback support: If sops files are added to 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.
|
||||||
- Fast: Unlike solutions implemented by NixOps, krops and morph there is no extra step required to upload secrets
|
- A variety of storage formats: Secrets can be stored in YAML, JSON or binary.
|
||||||
- Different storage formats: Secrets can be stored in YAML, JSON or binary.
|
- Minimizes configuration errors: sops files are checked against the configuration at evaluation time.
|
||||||
- Minimize configuration errors: sops files are checked against the configuration at evaluation time.
|
|
||||||
|
|
||||||
## Demo
|
## 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
|
## Supported encryption methods
|
||||||
|
|
||||||
sops-nix supports two basic ways of encryption, gnupg and age. Gnupg is based
|
sops-nix supports two basic ways of encryption, GPG and age.
|
||||||
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
|
GPG is based on [GnuPG](https://gnupg.org/) and encrypts against GPG public keys. Private GPG keys may
|
||||||
be used to derive a gnupg key from a ssh (host) key in RSA format.
|
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 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
|
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.
|
format to age keys.
|
||||||
|
|
||||||
## Usage example
|
## Usage example
|
||||||
|
|
||||||
### 1. Install nix-sops
|
<details>
|
||||||
|
<summary><b>1. Install nix-sops</b></summary>
|
||||||
|
|
||||||
Choose one of the following methods:
|
Choose one of the following methods:
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ Choose one of the following methods:
|
||||||
$ niv add Mic92/sops-nix
|
$ 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
|
```nix
|
||||||
{
|
{
|
||||||
|
@ -72,7 +73,7 @@ $ nix-channel --add https://github.com/Mic92/sops-nix/archive/master.tar.gz sops
|
||||||
$ nix-channel --update
|
$ 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
|
```nix
|
||||||
{
|
{
|
||||||
|
@ -82,7 +83,7 @@ $ nix-channel --update
|
||||||
|
|
||||||
#### fetchTarball
|
#### fetchTarball
|
||||||
|
|
||||||
Add the following to your configuration.nix:
|
Add the following to your `configuration.nix`:
|
||||||
|
|
||||||
``` nix
|
``` nix
|
||||||
{
|
{
|
||||||
|
@ -120,7 +121,7 @@ If you use experimental nix flakes support:
|
||||||
outputs = { self, nixpkgs, sops-nix }: {
|
outputs = { self, nixpkgs, sops-nix }: {
|
||||||
# change `yourhostname` to your actual hostname
|
# change `yourhostname` to your actual hostname
|
||||||
nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
|
nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
|
||||||
# change to your system:
|
# customize to your system
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
modules = [
|
modules = [
|
||||||
./configuration.nix
|
./configuration.nix
|
||||||
|
@ -131,14 +132,28 @@ If you use experimental nix flakes support:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2a. Generate a GPG key for yourself
|
</details>
|
||||||
|
|
||||||
This is only needed when you plan to use the gnupg encryption.
|
<details>
|
||||||
When using age, you can skip to step 2b instead.
|
<summary><b>2. Generate a key for yourself</b></summary>
|
||||||
|
|
||||||
First generate yourself [a GPG key](https://docs.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key) or use nix-sops
|
This key will be used for you to edit secrets.
|
||||||
conversion tool to convert an existing ssh key (we only support RSA keys right now):
|
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you can use the `ssh-to-pgp` tool to get a GPG key from an SSH key:
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i $HOME/.ssh/id_rsa | gpg --import --quiet"
|
$ nix-shell -p gnupg -p ssh-to-pgp --run "ssh-to-pgp -private-key -i $HOME/.ssh/id_rsa | gpg --import --quiet"
|
||||||
2504791468b153b8a3963cc97ba53d1919c5dfd4
|
2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||||
|
@ -146,39 +161,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"
|
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i $HOME/.ssh/id_rsa -o $USER.asc"
|
||||||
2504791468b153b8a3963cc97ba53d1919c5dfd4
|
2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||||
```
|
```
|
||||||
|
(Note that `ssh-to-pgp` currently only supports RSA keys.)
|
||||||
If you get:
|
If you get the following,
|
||||||
|
|
||||||
```console
|
```console
|
||||||
ssh-to-pgp: failed to parse private ssh key: ssh: this private key is passphrase protected
|
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.
|
||||||
then your ssh key is encrypted with your password and you need to create an unencrypted copy temporarily:
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ cp $HOME/.ssh/id_rsa /tmp/id_rsa
|
$ cp $HOME/.ssh/id_rsa /tmp/id_rsa
|
||||||
$ ssh-keygen -p -N "" -f /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"
|
$ 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 your existing SSH key as an age key.
|
||||||
|
|
||||||
```yaml
|
<details>
|
||||||
# This example uses yaml anchors which allows to name keys
|
<summary> How to find the age public key </summary>
|
||||||
# and re-use for multiple keys in a flexible way.
|
|
||||||
# Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml
|
If you generated an age key, the age public key can be found via `age-keygen -y $PATH_TO_KEY`:
|
||||||
# for a more complex example
|
```console
|
||||||
keys:
|
$ age-keygen -y ~/.config/sops/age/keys.txt
|
||||||
- &admin 2504791468b153b8a3963cc97ba53d1919c5dfd4
|
age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
|
||||||
creation_rules:
|
|
||||||
- path_regex: secrets/[^/]+\.yaml$
|
|
||||||
key_groups:
|
|
||||||
- pgp:
|
|
||||||
- *admin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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"
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary> How to find the GPG fingerprint of a key </summary>
|
||||||
|
|
||||||
|
Invoke this command and look for your key:
|
||||||
```console
|
```console
|
||||||
$ gpg --list-secret-keys
|
$ gpg --list-secret-keys
|
||||||
/tmp/tmp.JA07D1aVRD/pubring.kbx
|
/tmp/tmp.JA07D1aVRD/pubring.kbx
|
||||||
|
@ -189,103 +222,95 @@ uid [ unknown] root <root@localhost>
|
||||||
```
|
```
|
||||||
|
|
||||||
The fingerprint here is `9F89C5F69A10281A835014B09C3DC61F752087EF`.
|
The fingerprint here is `9F89C5F69A10281A835014B09C3DC61F752087EF`.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
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:
|
||||||
### 2b. Generate a SSH and age key for yourself
|
```yaml
|
||||||
|
# This example uses YAML anchors which allows reuse of multiple keys
|
||||||
This is only needed when you plan to use the age encryption.
|
# without having to repeat yourself.
|
||||||
When using gnupg, you need to go back to step 2a.
|
# Also see https://github.com/Mic92/dotfiles/blob/master/nixos/.sops.yaml
|
||||||
|
# for a more complex example.
|
||||||
sops-nix in age mode requires you to have an age key.
|
keys:
|
||||||
You can generate one like this:
|
- &admin_alice 2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||||
|
- &admin_bob age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
|
||||||
``` console
|
creation_rules:
|
||||||
$ mkdir -p ~/.config/sops/age
|
- path_regex: secrets/[^/]+\.yaml$
|
||||||
$ age-keygen -o ~/.config/sops/age/keys.txt
|
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`)
|
</details>
|
||||||
you can also convert to an age key:
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>3. Get a public key for your target machine</b></summary>
|
||||||
|
|
||||||
|
The easiest way to add new machines is 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 public key to the age format:
|
||||||
```console
|
```console
|
||||||
$ mkdir -p ~/.config/sops/age
|
$ nix-shell -p ssh-to-age --run 'ssh-keyscan my-server.com | ssh-to-age'
|
||||||
$ nix-shell -p ssh-to-age --run "ssh-to-age -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt"
|
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:
|
For GPG, since sops does not natively support SSH keys yet, nix-sops supports a conversion tool (`ssh-to-pgp`)
|
||||||
```console
|
to store them as GPG keys:
|
||||||
$ 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.
|
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ ssh root@server01 "cat /etc/ssh/ssh_host_rsa_key" | nix-shell -p ssh-to-pgp --run "ssh-to-pgp -o server01.asc"
|
$ 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
|
# 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"
|
$ 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
|
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"
|
$ nix-shell -p ssh-to-pgp --run "ssh-to-pgp -i /etc/ssh/ssh_host_rsa_key -o server01.asc"
|
||||||
0fd60c8c3b664aceb1796ce02b318df330331003
|
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
|
```yaml
|
||||||
keys:
|
keys:
|
||||||
- &admin 2504791468b153b8a3963cc97ba53d1919c5dfd4
|
- &admin_alice 2504791468b153b8a3963cc97ba53d1919c5dfd4
|
||||||
- &server 0fd60c8c3b664aceb1796ce02b318df330331003
|
- &admin_bob age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
|
||||||
|
- &server_azmidi 0fd60c8c3b664aceb1796ce02b318df330331003
|
||||||
|
- &server_nosaxa age1rgffpespcyjn0d8jglk7km9kfrfhdyev6camd3rck6pn8y47ze4sug23v3
|
||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: secrets/[^/]+\.yaml$
|
- path_regex: secrets/[^/]+\.yaml$
|
||||||
key_groups:
|
key_groups:
|
||||||
- pgp:
|
- pgp:
|
||||||
- *admin
|
- *admin_alice
|
||||||
- *server
|
- *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
|
</details>
|
||||||
|
|
||||||
The `ssh-to-age` tool is used to convert any ssh public key to the age format.
|
<details>
|
||||||
This way you can convert any key:
|
<summary><b>4. Create a sops file</b></summary>
|
||||||
```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
|
|
||||||
|
|
||||||
To create a sops file you need write a `.sops.yaml` as described above.
|
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
|
When using GnuPG you also need to import your personal GPG key
|
||||||
keys to be shared via version control (i.e. git):
|
(and your colleagues) and your servers into your GPG key chain.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>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).</summary>
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
# shell.nix
|
# shell.nix
|
||||||
|
@ -319,7 +344,7 @@ mkShell {
|
||||||
# $ (unset GNUPGHOME; gpg --armor --export-secret-key 0000000000000000000000000000000000000000) | gpg --import
|
# $ (unset GNUPGHOME; gpg --armor --export-secret-key 0000000000000000000000000000000000000000) | gpg --import
|
||||||
#sopsCreateGPGHome = true;
|
#sopsCreateGPGHome = true;
|
||||||
# To use a different directory for gpg dirs set sopsGPGHome
|
# To use a different directory for gpg dirs set sopsGPGHome
|
||||||
#sopsGPGHome = "${toString ./.}/../gnupg";
|
#sopsGPGHome = "${toString ./.}/../GnuPG";
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
(pkgs.callPackage sops-nix {}).sops-import-keys-hook
|
(pkgs.callPackage sops-nix {}).sops-import-keys-hook
|
||||||
|
@ -327,7 +352,7 @@ mkShell {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Our directory structure looks like this:
|
A valid directory structure for this might look like:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ tree .
|
$ tree .
|
||||||
|
@ -339,134 +364,111 @@ $ tree .
|
||||||
│ └── mic92.asc
|
│ └── mic92.asc
|
||||||
```
|
```
|
||||||
|
|
||||||
After that you can open a new file with sops
|
</details>
|
||||||
|
|
||||||
|
After configuring `.sops.yaml`, you can open a new file with sops:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-shell -p sops --run "sops secrets.yaml"
|
$ nix-shell -p sops --run "sops secrets/example.yaml"
|
||||||
```
|
```
|
||||||
|
|
||||||
This will start your configured editor
|
This will start your configured editor located at the `$EDITOR` environment variable.
|
||||||
In our example we put the following content in it:
|
An example secret file might be:
|
||||||
|
|
||||||
```
|
|
||||||
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.
|
|
||||||
```yaml
|
```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:
|
myservice:
|
||||||
my_subdir:
|
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:
|
sops:
|
||||||
kms: []
|
kms: []
|
||||||
gcp_kms: []
|
gcp_kms: []
|
||||||
azure_kv: []
|
azure_kv: []
|
||||||
lastmodified: '2020-07-13T09:09:14Z'
|
hc_vault: []
|
||||||
mac: ENC[AES256_GCM,data:BCwTBxaW6qINVfixC32EEYrlqPvGz47wF+o/vNPqcwed1HPwZezlNy7Z4NFLbRcCLAELyeMqkJ+fi9XCWvnT3UvfwB45COpz/xZphURt3gyCVOyd9mT/s9cJ1O9vNy5iKblqCae2X0CTKee/GxJ0G725LDOL4r+oHM1+WWEInWo=,iv:S43qegidSqcaUaDjvQpEQj/qvF/OZcW32Yo05CfyTUs=,tag:npj5auJXZrg7jQwYSjC6Vg==,type:str]
|
age:
|
||||||
pgp:
|
- recipient: age12zlz6lvcdk6eqaewfylg35w0syh58sm7gh53q5vvn7hd7c6nngyseftjxl
|
||||||
- created_at: '2020-07-13T08:34:30Z'
|
enc: |
|
||||||
enc: |
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
-----BEGIN PGP MESSAGE-----
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1dFYvSTRHa3IwTVpuZjEz
|
||||||
|
SDZZQnc5a0dGVGEzNXZmNEY5NlZDbVgyNVU0Clo3ZC9MRGp4SHhLUTVCeWlOUUxS
|
||||||
hQIMAysxjfMwMxADAQ//SyBLvbpyuoTGCZCtoJyaFzZ+vCKWZaD7dCZEURRyNKFV
|
MEtPdW4rUHhjdFB6bFhyUXRQTkRpWjAKLS0tIDVTbWU2V3dJNUZrK1A5U0c5bkc0
|
||||||
87wZyNO/rwtA1jP64Smqy0q2R8iZfoN0v5oVvtj2y5wFECs8Q5nONCVP4rs9nTRK
|
S3VINUJYc3VKcjBZbHVqcGJBSlVPZWcKqPXE01ienWDbTwxo+z4dNAizR3t6uTS+
|
||||||
n46w0v2UE2GqIWStFE7Mpv11qdZaMDoNGXq+n6s/uA2mwSYIVvzcWwhKvyKrMNrd
|
KbmSOK1v61Ri0bsM5HItiMP+fE3VCyhqMBmPdcrR92+3oBmiSFnXPA==
|
||||||
iOlfCKl4QTaGgGupZqmT2S00AEMJzY5lohvtzAC1TlnXGXhetDyCHtkoN/NKZDU7
|
-----END AGE ENCRYPTED FILE-----
|
||||||
m7j1/pvlIwxTQKeA3FKuxDJDYk+p3+W/EgwEchYDzjo+5A529J/tuIfXWBOF7BAV
|
- recipient: age18jtffqax5v0t6ehh4ypaefl4mfhcrhn6ek3p80mhfp9psx6pd35qew2ww3
|
||||||
ZiVVWISTahky/ioOMatNBAttu0lBGlSkovkbqIVsbTG7nF1wzGdToCxZmwQveEj7
|
enc: |
|
||||||
0N8ZzocDkOXqS71LW+X2HYSeywxNUbg/S6MrHrZN8MOp5qnGztm8yrKW2gDDe+Nl
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
nqJJ4lGg5CbODoDmhbPPof9tmWkykFmQSqmkjs4pcomcNthmcQvPVy75pnXEN9Wo
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzT3FxcDEzaFRQOVFpNkg2
|
||||||
0cDRnHtgROCJLqfv1AsXWkSxtmZRMMQ1yKJIPVFUHSPodgAoTyA81sHi66RypDOV
|
Skw4WEIxZzNTWkNBaDRhcUN2ejY4QTAwTERvCkx2clIzT2wyaFJZcjl0RkFXL2p6
|
||||||
KezX6sW8UuTZ7q1oPcJFpaaHrpIHDn+bqPGMfhu4NVXFusdb7MPxtxlKflhTdc8B
|
enhqVEZ3ZkNKUU5jTlUxRC9Lb090TzAKLS0tIDBEaG00RFJDZ3ZVVjBGUWJkRHdQ
|
||||||
xzlrB6+LdnCaeN+KqB6DOvmiPP3nC91zflO1SpMY3yUOnTFDKZG7wnVjidyIuMvS
|
YkpudG43eURPVWJUejd3Znk5Z29lWlkK0cIngn2qdmiOE5rHOHxTRcjfZYuY3Ej7
|
||||||
UAHk6rhsBEJleAn5f4AuBVWtWLuvS4t1g9Lhci3833f7XNp+GFNy05UOsmUo9upr
|
Yy7nYxMwTdYsm/V6Lp2xm8hvSzBEIFL+JXnSTSwSHnCIfgle5BRbug==
|
||||||
cgqaa2teuy2cbUtzS6gLBbcMA7SEs5MDYHjq6le/pwKv
|
-----END AGE ENCRYPTED FILE-----
|
||||||
=ZYPM
|
lastmodified: "2021-11-20T16:21:10Z"
|
||||||
-----END PGP MESSAGE-----
|
mac: ENC[AES256_GCM,data:5ieT/yv1GZfZFr+OAZ/DBF+6DJHijRXpjNI2kfBun3KxDkyjiu/OFmAbsoVFY/y6YCT3ofl4Vwa56Veo3iYj4njgxyLpLuD1B6zkMaNXaPywbAhuMho7bDGEJZHrlYOUNLdBqW2ytTuFA095IncXE8CFGr38A2hfjcputdHk4R4=,iv:UcBXWtaquflQFNDphZUqahADkeege5OjUY38pLIcFkU=,tag:yy+HSMm+xtX+vHO78nej5w==,type:str]
|
||||||
fp: 0FD60C8C3B664ACEB1796CE02B318DF330331003
|
pgp: []
|
||||||
- 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
|
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.5.0
|
version: 3.7.1
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. Deploy
|
</details>
|
||||||
|
|
||||||
If you derived your server public key from ssh, all you need in your configuration.nix is:
|
<details>
|
||||||
|
<summary id="deploy-example"><b>5. Deploy</b></summary>
|
||||||
|
|
||||||
|
If you derived your server public key from SSH, all you need in your `configuration.nix` is:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
imports = [ <sops-nix/modules/sops> ];
|
imports = [ <sops-nix/modules/sops> ];
|
||||||
# This will add secrets.yml to the nix store
|
# This will add secrets.yml to the nix store
|
||||||
# You can avoid this by adding a string to the full path instead, i.e.
|
# You can avoid this by adding a string to the full path instead, i.e.
|
||||||
# sops.defaultSopsFile = "/root/.sops/secrets.yaml";
|
# sops.defaultSopsFile = "/root/.sops/secrets/example.yaml";
|
||||||
sops.defaultSopsFile = ./secrets.yaml;
|
sops.defaultSopsFile = ./secrets/example.yaml;
|
||||||
sops.secrets.example-key = {};
|
# This will automatically import SSH keys as age keys
|
||||||
# This is using ssh keys in the age format:
|
|
||||||
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||||
# This is using an age key that is expected to already be in the filesystem
|
# This is using an age key that is expected to already be in the filesystem
|
||||||
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
||||||
# This will generate a new key if the key specified above does not exist
|
# This will generate a new key if the key specified above does not exist
|
||||||
sops.age.generateKey = true;
|
sops.age.generateKey = true;
|
||||||
|
# This is the actual specification of the secrets.
|
||||||
|
sops.secrets.example-key = {};
|
||||||
sops.secrets."myservice/my_subdir/my_secret" = {};
|
sops.secrets."myservice/my_subdir/my_secret" = {};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
On `nixos-rebuild switch` this will make the key accessible
|
On `nixos-rebuild switch` this will make the keys accessible
|
||||||
via `/run/secrets/example-key`:
|
via `/run/secrets/example-key` and `/run/secrets/myservice/my_subdir/my_secret`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ cat /run/secrets/example-key
|
$ cat /run/secrets/example-key
|
||||||
example-value
|
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
|
```console
|
||||||
$ ls -la /run/secrets
|
$ ls -la /run/secrets
|
||||||
lrwxrwxrwx 16 root 12 Jul 6:23 /run/secrets -> /run/secrets.d/1
|
lrwxrwxrwx 16 root 12 Jul 6:23 /run/secrets -> /run/secrets.d/1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## Set secret permission/owner and allow services to access it
|
## Set secret permission/owner and allow services to access it
|
||||||
|
|
||||||
By default secrets are owned by `root:root`. Furthermore
|
By default secrets are owned by `root:root`. Furthermore
|
||||||
|
@ -476,9 +478,9 @@ the parent directory `/run/secrets.d` is only owned by
|
||||||
``` console
|
``` console
|
||||||
$ ls -la /run/secrets.d/1
|
$ ls -la /run/secrets.d/1
|
||||||
total 24
|
total 24
|
||||||
drwxr-x--- 2 root keys 0 Jul 18 15:35 .
|
drwxr-x--- 2 root keys 0 Jul 12 6:23 .
|
||||||
drwxr-x--- 3 root keys 0 Jul 18 15:35 ..
|
drwxr-x--- 3 root keys 0 Jul 12 6:23 ..
|
||||||
-r-------- 1 root root 20 Jul 18 15:35 borgbackup
|
-r-------- 1 root root 20 Jul 12 6:23 example-secret
|
||||||
```
|
```
|
||||||
|
|
||||||
The secrets option has further parameter to change secret permission.
|
The secrets option has further parameter to change secret permission.
|
||||||
|
@ -486,8 +488,8 @@ Consider the following nixos configuration example:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
# Permission modes are in octal representation,
|
# Permission modes are in octal representation (same as chmod),
|
||||||
# the digits reprsent: user|group|owner
|
# the digits represent: user|group|owner
|
||||||
# 7 - full (rwx)
|
# 7 - full (rwx)
|
||||||
# 6 - read and write (rw-)
|
# 6 - read and write (rw-)
|
||||||
# 5 - read and execute (r-x)
|
# 5 - read and execute (r-x)
|
||||||
|
@ -525,8 +527,9 @@ For login or system users this can be done like this:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The following example configures secrets for buildkite, a CI agent
|
<details>
|
||||||
the service needs a token and a ssh private key to function:
|
<summary>This example configures secrets for buildkite, a CI agent;
|
||||||
|
the service needs a token and a SSH private key to function.</summary>
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ pkgs, config, ... }:
|
{ pkgs, config, ... }:
|
||||||
|
@ -555,7 +558,9 @@ the service needs a token and a ssh private key to function:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Restarting/reloading systemd units
|
</details>
|
||||||
|
|
||||||
|
## 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.
|
**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:
|
This behaviour can be configured per-secret:
|
||||||
|
@ -591,10 +596,10 @@ lrwxrwxrwx 1 root root 40 Jul 19 22:36 /var/lib/hass/secrets.yaml -> /run/secret
|
||||||
|
|
||||||
## Setting a user's password
|
## 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.<name>.passwordFile` to any secrets managed by sops-nix.
|
This means that it's not possible to set `users.users.<name>.passwordFile` to any secrets managed by sops-nix.
|
||||||
To work around this issue, it's possible to set `neededForUsers = true` in a secret.
|
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.
|
As users are not created yet, it's not possible to set an owner for these secrets.
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
|
@ -610,12 +615,12 @@ As users are not created yet, it's not possible to set an owner for these secret
|
||||||
|
|
||||||
## Different file formats
|
## 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
|
NOTE: At the moment we do not support nested data structures that
|
||||||
sops support. This might change in the future:
|
sops support. This might change in the future.
|
||||||
|
|
||||||
We support the following yaml:
|
We support the following YAML:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
key: 1
|
key: 1
|
||||||
|
@ -635,8 +640,8 @@ nix-sops allows to specify multiple sops files in different file formats:
|
||||||
imports = [ <sops-nix/modules/sops> ];
|
imports = [ <sops-nix/modules/sops> ];
|
||||||
# The default sops file used for all secrets can be controlled using `sops.defaultSopsFile`
|
# The default sops file used for all secrets can be controlled using `sops.defaultSopsFile`
|
||||||
sops.defaultSopsFile = ./secrets.yaml;
|
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.defaultSopsFormat = "YAML";
|
||||||
sops.secrets.github_token = {
|
sops.secrets.github_token = {
|
||||||
# The sops file can be also overwritten per secret...
|
# The sops file can be also overwritten per secret...
|
||||||
sopsFile = ./other-secrets.json;
|
sopsFile = ./other-secrets.json;
|
||||||
|
@ -658,7 +663,7 @@ Than put in the following content:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
github_token: 4a6c73f74928a9c4c4bc47379256b72e598e2bd3
|
github_token: 4a6c73f74928a9c4c4bc47379256b72e598e2bd3
|
||||||
# multi-line strings in yaml start with an |
|
# multi-line strings in YAML start with an |
|
||||||
ssh_key: |
|
ssh_key: |
|
||||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
@ -674,10 +679,10 @@ You can include it like this in your `configuration.nix`:
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
sops.defaultSopsFile = ./secrets.yaml;
|
sops.defaultSopsFile = ./secrets.yaml;
|
||||||
# yaml is the default
|
# YAML is the default
|
||||||
#sops.defaultSopsFormat = "yaml";
|
#sops.defaultSopsFormat = "YAML";
|
||||||
sops.secrets.github_token = {
|
sops.secrets.github_token = {
|
||||||
format = "yaml";
|
format = "YAML";
|
||||||
# can be also set per secret
|
# can be also set per secret
|
||||||
sopsFile = ./secrets.yaml;
|
sopsFile = ./secrets.yaml;
|
||||||
};
|
};
|
||||||
|
@ -706,7 +711,7 @@ You can include it like this in your `configuration.nix`:
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
sops.defaultSopsFile = ./secrets.json;
|
sops.defaultSopsFile = ./secrets.json;
|
||||||
# yaml is the default
|
# YAML is the default
|
||||||
sops.defaultSopsFormat = "json";
|
sops.defaultSopsFormat = "json";
|
||||||
sops.secrets.github_token = {
|
sops.secrets.github_token = {
|
||||||
format = "json";
|
format = "json";
|
||||||
|
@ -746,7 +751,7 @@ It can be decrypted again like this:
|
||||||
$ sops -d krb5.keytab > /tmp/krb5.keytab
|
$ 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
|
```nix
|
||||||
{
|
{
|
||||||
|
@ -757,9 +762,9 @@ 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
|
```console
|
||||||
$ nix-shell -p sops-init-gpg-key
|
$ nix-shell -p sops-init-gpg-key
|
||||||
|
@ -788,22 +793,22 @@ EOF
|
||||||
fingerprint: E4CA86768F176AEB6C01554153AF8D7F149613B1
|
fingerprint: E4CA86768F176AEB6C01554153AF8D7F149613B1
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case you need to make upload the gpg key directory `/tmp/newkey` to your server.
|
In this case, 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:
|
If you uploaded it to `/var/lib/sops` than your sops configuration will look like this:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
# Make sure that `/var/lib/sops` is owned by root and is not world-readable/writable
|
# Make sure that `/var/lib/sops` is owned by root and is not world-readable/writable
|
||||||
sops.gnupg.home = "/var/lib/sops";
|
sops.gnupg.home = "/var/lib/sops";
|
||||||
# disable import host ssh keys
|
# disable importing host ssh keys
|
||||||
sops.gnupg.sshKeyPaths = [];
|
sops.gnupg.sshKeyPaths = [];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
However be aware that this will also run gnupg on your server including the
|
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
|
GnuPG daemon. [GnuPG is in general not great software](https://latacora.micro.blog/2019/07/16/the-pgp-problem.html) and might break in
|
||||||
hilarious ways. If you experience problems, you are on your own. If you want a
|
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.
|
more stable and predictable solution go with SSH keys or one of the KMS services.
|
||||||
|
|
||||||
|
|
||||||
## Share secrets between different users
|
## Share secrets between different users
|
||||||
|
@ -830,7 +835,7 @@ example the `drone` secret is exposed as `/run/secrets/drone-server` for
|
||||||
|
|
||||||
If you have used [pass](https://www.passwordstore.org) before i.e. in
|
If you have used [pass](https://www.passwordstore.org) before i.e. in
|
||||||
[krops](https://github.com/krebs/krops) than you can use the following one-liner
|
[krops](https://github.com/krebs/krops) than you can use the following one-liner
|
||||||
to convert all your secrets to a yaml structure.
|
to convert all your secrets to a YAML structure:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ for i in *.gpg; do echo "$(basename $i .gpg): |\n$(pass $(dirname $i)/$(basename $i .gpg)| sed 's/^/ /')"; done
|
$ for i in *.gpg; do echo "$(basename $i .gpg): |\n$(pass $(dirname $i)/$(basename $i .gpg)| sed 's/^/ /')"; done
|
||||||
|
@ -838,11 +843,10 @@ $ for i in *.gpg; do echo "$(basename $i .gpg): |\n$(pass $(dirname $i)/$(basena
|
||||||
|
|
||||||
Copy the output to the editor you have opened with sops.
|
Copy the output to the editor you have opened with sops.
|
||||||
|
|
||||||
## Realworld Examples
|
## Real-world examples
|
||||||
|
|
||||||
My [personal configuration](https://github.com/Mic92/dotfiles/tree/master/nixos) makes extensive usage of sops-nix.
|
My [personal configuration](https://github.com/Mic92/dotfiles/tree/master/nixos) makes extensive usage of sops-nix.
|
||||||
Each host has a [secrets](https://github.com/Mic92/dotfiles/tree/master/nixos/eve/secrets) directory containing secrets for the host.
|
Each host has a [secrets](https://github.com/Mic92/dotfiles/tree/master/nixos/eve/secrets) directory containing secrets for the host.
|
||||||
You can also check out [nix-community infrastructure repository](https://github.com/nix-community/infra).
|
|
||||||
|
|
||||||
## Known limitations
|
## Known limitations
|
||||||
|
|
||||||
|
@ -850,9 +854,9 @@ You can also check out [nix-community infrastructure repository](https://github.
|
||||||
|
|
||||||
sops-nix does not fully support initrd secrets.
|
sops-nix does not fully support initrd secrets.
|
||||||
This is because `nixos-rebuild switch` installs
|
This is because `nixos-rebuild switch` installs
|
||||||
the bootloader before running sops-nix activation hook.
|
the bootloader before running sops-nix's activation hook.
|
||||||
At the moment it is be possible to run `nixos-rebuild test`
|
As a workaround, it is possible to run `nixos-rebuild test`
|
||||||
before `nixos-rebuild switch` to provision initrd secrets key
|
before `nixos-rebuild switch` to provision initrd secrets
|
||||||
before the initrd secrets are built.
|
before actually using them in the initrd.
|
||||||
In future we hope to extend nixos to allow keys to be
|
In the future, we hope to extend NixOS to allow keys to be
|
||||||
provisioned in the bootloader install phase.
|
provisioned in the bootloader install phase.
|
||||||
|
|
Loading…
Add table
Reference in a new issue