As I wrote in part 1, not only the license of Nomad was changed, but also the license of Vault. But more than this license change, I'd like to have a secrets solution that's not yet another deployment to manage. Here's the solution I'm currently using. Nothing is set in stone, but for now, it works great.

Introducing SOPS

From the README on the SOPS GitHub project:

SOPS is an editor of encrypted files that supports YAML, JSON, ENV, INI and BINARY formats and encrypts with AWS KMS, GCP KMS, Azure Key Vault, age, and PGP.

The TL;DR is that SOPS allows you to encrypt your files with an encryption key. You then store your encrypted files in your source control system. You decrypt them when they're needed.

I decided to use [AGE][3] as my way of encrypting my files. The first step is to create an encryption key:

age-keygen -o key.txt

This gives you a .txt file with both the public and private encryption key:

cat keys.txt
# public key: age1dsju67rlzu3law8gjpdfm3k00rwrwau8jmea4nutsje8kv0d2spq82js8e
AGE-SECRET-KEY-18VNTTPPXQW2FW9LCK5FWWGFJ75VCGTEG4NAPRMV95G4ZZCWU2E3SRWK8D8

The public key should be stored in a .sops.yaml file:

cat .sops.yaml
---
creation_rules:
  - age: "age1dsju67rlzu3law8gjpdfm3k00rwrwau8jmea4nutsje8kv0d2spq82js8e"

You can then encrypt a file with:

sops -e file.yaml > file.enc.yaml

Decrypt the file with:

SOPS_AGE_KEY=AGE-SECRET-KEY-18VNTTPPXQW2FW9LCK5FWWGFJ75VCGTEG4NAPRMV95G4ZZCWU2E3SRWK8D8 sops --decrypt file.enc.yaml > file.yaml

SOPS and OpenTofu

In my current homelab, I'm using Terraform and Vault. Both are perfectly integrated with one another. Now I need an integration for OpenTofu and SOPS. OpenTofu is a fork of Terraform as a reaction on the licensing change.

Luckily for me, there's a SOPS Terraform provider!

Let's see how it works.

I'm using a provider for MinIO to showcase my secrets solution, as I use OpenTofu to manage my S3 buckets.

provider "sops" {}

data "sops_file" "minio_credentials" {
  source_file = "minio_credentials.enc.yaml"
}

provider "minio" {
  minio_password = data.sops_file.minio_credentials.data["minio_password"]
  minio_region   = "us-east-1"
  minio_server   = "s3.service.tcassaert.com:443"
  minio_ssl      = true
  minio_user     = data.sops_file.minio_credentials.data["minio_user"]
}

So, what are we looking at? First we defined the SOPS provider. Second, we add a data_source, that references a file containing all of our MinIO secrets. Third, we define the configuration for the MinIO provider. Some values are provided by our encrypted minio_credentials.enc.yaml file.

The file is created just like I showed before:

sops -e minio_credentials.yaml > minio_credentials.enc.yaml

The non-encrypted file looked like:

---
minin_password: password
minio_user: username

Now we're ready to run tofu:

SOPS_AGE_KEY=AGE-SECRET-KEY-18VNTTPPXQW2FW9LCK5FWWGFJ75VCGTEG4NAPRMV95G4ZZCWU2E3SRWK8D8 tofu apply

Behind the scenes, the SOPS provider decrypts the minio_credentials.enc.yaml file and passes the values to the configuration of the MinIO provider.

This secrets solution allows me to not need a running service that holds all of my secrets. My secrets are stored in git with my source code, ready to be decrypted when requested.

To be continued when I explore more integrations throughout my homelab.