From 0c188118a58ea47c38720f1a3da31f24fa764278 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Thu, 16 Jul 2026 22:54:27 +1000 Subject: [PATCH] Register and mount the GPG secrets engine at gpg/ Puppet installs the openbao-plugin-secrets-gpg RPM onto the OpenBao nodes; this registers that binary in the plugin catalog and enables the secrets engine so gpg/ is actually usable (encrypt/decrypt/sign/verify). - Add a gpg_secret_backend module using the standard vault provider: vault_plugin (catalog register with a pinned sha256) + vault_mount. - Wire it through vault_cluster (variable + module) and the config discovery (config.hcl + syd1 terragrunt input), mirroring litellm_secret_backend. - Add config/gpg_secret_backend/gpg.yaml pinning the released v0.1.0 binary sha256 (0e92d740...a7b20). Puppet installs the RPM floating, so this sha must be bumped in lockstep on any plugin upgrade. Granting non-root access to gpg/* (auth roles + policies) is a follow-up, scoped to whoever consumes the engine. --- config/config.hcl | 5 ++++ config/gpg_secret_backend/gpg.yaml | 9 +++++++ environments/au/syd1/terragrunt.hcl | 1 + modules/vault_cluster/main.tf | 12 +++++++++ .../modules/gpg_secret_backend/main.tf | 20 ++++++++++++++ .../modules/gpg_secret_backend/terraform.tf | 9 +++++++ .../modules/gpg_secret_backend/variables.tf | 27 +++++++++++++++++++ modules/vault_cluster/variables.tf | 11 ++++++++ 8 files changed, 94 insertions(+) create mode 100644 config/gpg_secret_backend/gpg.yaml create mode 100644 modules/vault_cluster/modules/gpg_secret_backend/main.tf create mode 100644 modules/vault_cluster/modules/gpg_secret_backend/terraform.tf create mode 100644 modules/vault_cluster/modules/gpg_secret_backend/variables.tf diff --git a/config/config.hcl b/config/config.hcl index 03b25d7..0ecef24 100644 --- a/config/config.hcl +++ b/config/config.hcl @@ -198,5 +198,10 @@ locals { }) if startswith(file_path, "litellm_secret_backend_role/") } + gpg_secret_backend = { + for file_path, content in local.all_configs : + trimsuffix(basename(file_path), ".yaml") => content + if startswith(file_path, "gpg_secret_backend/") + } } } diff --git a/config/gpg_secret_backend/gpg.yaml b/config/gpg_secret_backend/gpg.yaml new file mode 100644 index 0000000..4088b4b --- /dev/null +++ b/config/gpg_secret_backend/gpg.yaml @@ -0,0 +1,9 @@ +# config/gpg_secret_backend/gpg.yaml +# Registers the vault-plugin-secrets-gpg plugin and mounts it at "gpg". +# The binary is installed on the OpenBao nodes by Puppet +# (openbao-plugin-secrets-gpg RPM -> /opt/openbao-plugins/vault-plugin-secrets-gpg). +# +# sha256 pins the released v0.1.0 binary; bump it in lockstep with any RPM +# upgrade or OpenBao will refuse to launch the plugin. +description: "GPG/OpenPGP secrets engine (sign/verify/encrypt/decrypt)" +sha256: "0e92d7408795688badb55789bc1604e8f1dd4d71998656c7f831991fce9a7b20" diff --git a/environments/au/syd1/terragrunt.hcl b/environments/au/syd1/terragrunt.hcl index 7b59f0e..e0e7e7e 100644 --- a/environments/au/syd1/terragrunt.hcl +++ b/environments/au/syd1/terragrunt.hcl @@ -70,6 +70,7 @@ inputs = { pki_mount_only = local.config.pki_mount_only litellm_secret_backend = local.config.litellm_secret_backend litellm_secret_backend_role = local.config.litellm_secret_backend_role + gpg_secret_backend = local.config.gpg_secret_backend # Pass policy maps to vault_cluster module policy_auth_map = local.policies.policy_auth_map diff --git a/modules/vault_cluster/main.tf b/modules/vault_cluster/main.tf index 80c4023..5db7207 100644 --- a/modules/vault_cluster/main.tf +++ b/modules/vault_cluster/main.tf @@ -334,6 +334,18 @@ module "litellm_secret_backend_role" { depends_on = [module.litellm_secret_backend] } +module "gpg_secret_backend" { + source = "./modules/gpg_secret_backend" + + for_each = var.gpg_secret_backend + + path = each.key + plugin = each.value.plugin + command = each.value.command + sha256 = each.value.sha256 + description = each.value.description +} + module "vault_policy" { source = "./modules/vault_policy" diff --git a/modules/vault_cluster/modules/gpg_secret_backend/main.tf b/modules/vault_cluster/modules/gpg_secret_backend/main.tf new file mode 100644 index 0000000..5a5cff2 --- /dev/null +++ b/modules/vault_cluster/modules/gpg_secret_backend/main.tf @@ -0,0 +1,20 @@ +# Registers the GPG/OpenPGP secrets plugin in the catalog and mounts it. The +# plugin binary is installed on the OpenBao nodes by Puppet +# (openbao-plugin-secrets-gpg RPM -> /opt/openbao-plugins/vault-plugin-secrets-gpg); +# `command` is that filename, resolved relative to the server's plugin_directory. +# +# The sha256 is pinned here to the released binary. Puppet installs the RPM +# floating, so on a plugin upgrade this sha256 must be bumped in lockstep or +# OpenBao will refuse to launch the plugin. +resource "vault_plugin" "this" { + type = "secret" + name = var.plugin + command = var.command + sha256 = var.sha256 +} + +resource "vault_mount" "this" { + path = var.path + type = vault_plugin.this.name + description = var.description +} diff --git a/modules/vault_cluster/modules/gpg_secret_backend/terraform.tf b/modules/vault_cluster/modules/gpg_secret_backend/terraform.tf new file mode 100644 index 0000000..ce22437 --- /dev/null +++ b/modules/vault_cluster/modules/gpg_secret_backend/terraform.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.10" + required_providers { + vault = { + source = "hashicorp/vault" + version = "5.6.0" + } + } +} diff --git a/modules/vault_cluster/modules/gpg_secret_backend/variables.tf b/modules/vault_cluster/modules/gpg_secret_backend/variables.tf new file mode 100644 index 0000000..f3be158 --- /dev/null +++ b/modules/vault_cluster/modules/gpg_secret_backend/variables.tf @@ -0,0 +1,27 @@ +variable "path" { + description = "Mount path of the GPG secrets engine (e.g. \"gpg\")" + type = string +} + +variable "plugin" { + description = "Name to register the plugin under in the catalog (also the mount type)" + type = string + default = "vault-plugin-secrets-gpg" +} + +variable "command" { + description = "Plugin binary filename, relative to the server plugin_directory" + type = string + default = "vault-plugin-secrets-gpg" +} + +variable "sha256" { + description = "SHA-256 of the installed plugin binary; must match the on-disk binary or OpenBao rejects it" + type = string +} + +variable "description" { + description = "Human-friendly description of the mount" + type = string + default = null +} diff --git a/modules/vault_cluster/variables.tf b/modules/vault_cluster/variables.tf index 157bd99..026e419 100644 --- a/modules/vault_cluster/variables.tf +++ b/modules/vault_cluster/variables.tf @@ -315,6 +315,17 @@ variable "litellm_secret_backend_role" { default = {} } +variable "gpg_secret_backend" { + description = "Map of GPG/OpenPGP secret engines to register + mount (path => plugin sha256 + config)" + type = map(object({ + plugin = optional(string, "vault-plugin-secrets-gpg") + command = optional(string, "vault-plugin-secrets-gpg") + sha256 = string + description = optional(string) + })) + default = {} +} + variable "policy_auth_map" { description = "Map of auth mounts -> auth roles -> policy names" type = map(map(list(string)))