From 1a555b92aa951c673a22fac98335c59cef486c5d Mon Sep 17 00:00:00 2001 From: Joey Hafner Date: Tue, 27 Aug 2024 21:19:54 -0700 Subject: [PATCH] #3 Switch back from git-crypt to sops --- .gitattributes | 3 ++- .sops/README.md | 20 ++++++++++++++++++++ homelab/.gitattributes | 1 - 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .sops/README.md delete mode 100644 homelab/.gitattributes diff --git a/.gitattributes b/.gitattributes index 250b3dc3..cdca4acf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -secrets.env filter=sops diff=sops \ No newline at end of file +secrets.env filter=sops diff=sops +*.secrets filter=sops diff=sops \ No newline at end of file diff --git a/.sops/README.md b/.sops/README.md new file mode 100644 index 00000000..502cf90c --- /dev/null +++ b/.sops/README.md @@ -0,0 +1,20 @@ +# sops Encryption/Decryption Workflow in Git + +1. The user creates a file called `secrets.env` anywhere in the repository. This file is [dotenv-formatted](https://stackoverflow.com/questions/68267862/what-is-an-env-or-dotenv-file-exactly) as simple key-value pairs where the value is a secret to be passed into a Stack or container. We want to be able to read the "shape" of the file (the names of the keys), even when the file is encrypted. +2. The [`.gitattributes`](.gitattributes) file assignes the following properties to files called `secrets.env`: + 1. `filter=sops` which tells the local git instance to run the "sops" filter configured in [`.git/config`](/.git/config). + 2. `diff=sops` which tells the local git instance to run the "sops" diff command instead of the normal `git diff` when diffing `secrets.env` files. +3. The [`.git/config`](/.git/config) is configured with the "sops" filter and diff blocks referenced above. + 1. `filter.sops.smudge=` will run the thing after the `=` when checking out the repository. This should decrypt our secrets, making them "dirty" again. We call [`decrypt-filter.sh`](/.sops/decrypt-filter.sh) and pass `%f` as a positional argument, which renders to the path of the file being filtered, relative to the repo root (e.g. `homelab/stacks/books/secrets.env`). + 2. `filter.sops.clean=` will run the thing after the `=` when staging changes to commit. This should encrypt our secrets, making them "clean". We call [`encrypt-filter.sh`](/.sops/decrypt-filter.sh) and pass `%f` as a positional argument, which renders to the path of the file being filtered, relative to the repo root (e.g. `homelab/stacks/books/secrets.env`). + 3. `filter.sops.required=true` will ensure that if the scripts fail, the commit will error out. + 4. `diff.sops.textconv=` will use the command after the `=` instead of `git diff` when comparing files. This affects whether files are considered "modified". +4. When the user stages a new `secrets.env` file at `homelab/stacks/books/secrets.env`, we automatically run `encrypt.sh homelab/stacks/books/secrets.env`. This implictly passes the contents of `secrets.env` to the script at `/dev/stdin`. The script takes the following steps to generate the encrypted content of the file: + 1. Assert privatekey existence at `~/.age/key`. + 2. Determine file extension. For now, we're only working with dotenv-formatted files, but sometimes we also need to support binary files. We use this information to set the `--input-type` parameter. + 3. Encrypt the file contents. This command infers recipients from [`.sops.yaml`](/.sops.yaml). The command uses the privatekey (at `~/.age/key`) of the local user to encrypt the secret. We use [Shamir's secret sharing](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing) with [sops key groups](https://github.com/getsops/sops?tab=readme-ov-file#215key-groups) to require *at least two of*: author key, CI/CD key, and deploy key. Of course, the original privatekey can always decrypt the secret. +5. Our new `secrets.env` file is committed to the repository. Encrypted and json-formatted ([why not dotenv-formatted?](https://github.com/getsops/sops/issues/857#issuecomment-2307658865)). +6. Now we want to deploy our new `homelab/stacks/books` Stack. We'll focus on the sops-related aspects of this process. + 1. Our CI/CD environment is configured with an age keypair. Additional CI/CD environments will each be configured with their own keypairs. + 2. Our deploy environments (hosts) are each configured with an age keypair. + 3. Our [CI/CD script](/.gitea/workflows/homelab_deploy-compose-stack.yml) is configured to decrypt secrets and export the variables before bringing up the Stack. \ No newline at end of file diff --git a/homelab/.gitattributes b/homelab/.gitattributes deleted file mode 100644 index f6c39c75..00000000 --- a/homelab/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -secrets.env filter=git-crypt diff=git-crypt \ No newline at end of file