diff --git a/README.md b/README.md index f179603..a9a354f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Git as Terraform backend? Seriously? I know, might sound like a stupid idea at f - [AWS KMS](#aws-kms) - [GCP KMS](#gcp-kms) - [Hashicorp Vault](#hashicorp-vault) + - [Age](#age) - [AES256](#aes256) - [Running backend remotely](#running-backend-remotely) - [TLS](#tls) @@ -248,6 +249,10 @@ Use `TF_BACKEND_HTTP_SOPS_GCP_KMS_KEYS` to provide a comma separated list of GCP Use `TF_BACKEND_HTTP_SOPS_HC_VAULT_URIS` to point it to the Vault Transit keys. It is a comma separated list of URLs in a form of `${VAULT_ADDR}/v1/transit/keys/key`, where `transit` is a name of Vault Transit mount and `key` is the name of the key in that mount. Under the hood Vault SDK is using standard credentials resolver to automatically discover Vault credentials in the environment, meaning you can either use `vault login` or set `VAULT_TOKEN` environment variable. +##### Age + +Use `TF_BACKEND_HTTP_SOPS_AGE_RECIPIENTS` to provide a comma separated list of age public keys. Ensure that corresponding private key is located in `keys.txt` in a `sops` subdirectory of your user configuration directory. Read [Encrypting using age](https://github.com/getsops/sops#encrypting-using-age) for further details. + #### AES256 To enable state encryption, you can use `TF_BACKEND_HTTP_ENCRYPTION_PASSPHRASE` environment variable to set a passphrase. Backend will encrypt and decrypt (using AES256, server-side) all state files transparently before storing them in Git. If it fails to decrypt the file obtained from Git, it will assume encryption was not previously enabled and return it as-is. Note this doesn't encrypt the traffic at REST, as Terraform doesn't support any sort of encryption for HTTP backend. Traffic between Terraform and this backend stays unencrypted at all times. diff --git a/crypt/sops/age.go b/crypt/sops/age.go new file mode 100644 index 0000000..9141840 --- /dev/null +++ b/crypt/sops/age.go @@ -0,0 +1,37 @@ +package sops + +import ( + "os" + + "go.mozilla.org/sops/v3" + "go.mozilla.org/sops/v3/age" +) + +func init() { + Configs["age"] = &AgeConfig{} +} + +type AgeConfig struct{} + +func (a *AgeConfig) IsActivated() bool { + _, ok := os.LookupEnv("TF_BACKEND_HTTP_SOPS_AGE_RECIPIENTS") + return ok +} + +func (a *AgeConfig) KeyGroup() (sops.KeyGroup, error) { + recepients := os.Getenv("TF_BACKEND_HTTP_SOPS_AGE_RECIPIENTS") + + var keyGroup sops.KeyGroup + + masterKeys, err := age.MasterKeysFromRecipients(recepients) + + if err != nil { + return nil, err + } + + for _, k := range masterKeys { + keyGroup = append(keyGroup, k) + } + + return keyGroup, nil +}