Wire Forge-native release infrastructure
Some checks failed
Cache: Publish Nix / Publish Nix Cache (push) Waiting to run
Build Rust / Cargo Test (push) Successful in 4m14s
Build Site / Next.js Build (push) Failing after 6s
Infra: OpenTofu / OpenTofu (grafana) (push) Successful in 5s
Lint Governance / BEP Metadata (push) Successful in 0s
Build: Android / Android Rust Core Stub (push) Failing after 23s

This commit is contained in:
Conrad Kramer 2026-06-07 05:51:12 -07:00
parent 97c569fb35
commit 002bd382e9
199 changed files with 14268 additions and 185 deletions

5
infra/openbao/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
.terraform/
backend.hcl
terraform.tfstate
terraform.tfstate.backup
*.tfplan

43
infra/openbao/.terraform.lock.hcl generated Normal file
View file

@ -0,0 +1,43 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/hashicorp/google" {
version = "6.50.0"
constraints = ">= 5.40.0, < 7.0.0"
hashes = [
"h1:MAAe4zFFdqS9M5rpmJK/vKgdb6ZMD/s/0Xd97yTDipA=",
"zh:1d4695f807d998f11fcdcfa174766287b82a8093513af857bcdad2d81c642480",
"zh:3173ac5df0294624d113812e49e2a55714aff7db617488168cecdf4168df9e29",
"zh:34d2b3d44c23bd6354fc4ab5917b302872ea1ab8de107034567f955b1717fa5b",
"zh:3a77f3cc2f3664cd5aaeeef4d044e6ec1695a079588fffec3ca03953664e5f04",
"zh:6b444e4b629ea8dc8cb112a39dde098dc5584d26d6de4177558f556a9a226696",
"zh:96545c8cd4d3a57069c5d1799eab5aedd887e16d98b5559a195f6d2c2d9bc674",
"zh:ba464caafde95ee16671d6b5ec90f053ed77a9d06c567456db6efd9160fa3165",
"zh:d876938e5b0d3f57a984d9be72467995f87fef6569968623415dc51d9f54d30b",
"zh:dfd908d873e314ab807d0abc9cfd42d2611cd06dc1b9ec719ebdbb738e8e68d6",
"zh:f9f16819a7738d564afd45fd169ba61004ec4e4e7089d2a4950cb8895be1fe1f",
]
}
provider "registry.opentofu.org/hashicorp/vault" {
version = "5.9.0"
constraints = ">= 4.5.0, < 6.0.0"
hashes = [
"h1:9U4AT36IqNYXfQMR7nf+oywulVKYua473W4NmuwVb7M=",
"zh:03cb46fab606872e3fc06e27f8d14b911b7a9781d0f32af335c7287a9dbe4f4f",
"zh:1e69677b09329b009a8791f9cbb556790fb4dbddc1360f953345259892dc6c5b",
"zh:4e5a3dc82e70d88f5671968b7f2217163815be259d0b26dfcc9a897409c491fa",
"zh:51b82b358fe52099ef29cae62e2040ae0224ceea40a7dfdf0b69de90fb0233a8",
"zh:60ec3477fbe712b3269eec2e4d9d5921e2e68d0861d77e11e91bea088aab27bf",
"zh:64e58a3e3fd61005b54d71eee792b8576ab42ea4cd711515043a3ac0d8bc7919",
"zh:69142fb83aff31e27f5b3d9e7afb7594013b63e490cfcef8678fd0d724609359",
"zh:6f2e58ba6bd41c4d9e0e752e55eb7d86104f9d786cf57fa8dc960c61b574f9ce",
"zh:73390b7cb186310e5aaf4a1baaa639ab0302a8da4db130b4e28ebced3ba103fe",
"zh:a2214b3fda93cfed89ba1a7d714fe8b015176927605b215365978efdaae1c6db",
"zh:b275ee0f0a63765364d2e6979e3a11464d2c2ce6d3ce9bd15b3f503aea6f12b0",
"zh:bb2cd553b1c589a0f6f5b0575e1b176a9d91c1b20c6375d1afd63bb2a47fd014",
"zh:bc38e48ae5cdb8219fef326366f46e6a25e7f77f9bbcd9bdc80c7cb960de81ed",
"zh:e54af55cf667759a400af07b927b5034f1733e6527f9352b84001205561dcf9e",
"zh:f617688ef4568c0de8a28d5e1fa3714fb2eeab9f8cf7bcf20af42a1a511844be",
]
}

36
infra/openbao/README.md Normal file
View file

@ -0,0 +1,36 @@
# Burrow OpenBao Control Plane
This OpenTofu stack manages non-secret infrastructure around
`vault.burrow.net`.
It may manage:
- Google KMS seal-wrapping keys for OpenBao
- the OpenBao `age/` KV v2 mount used for migrated runtime secrets
- OpenBao policies and Authentik OIDC roles
- AppRole auth scaffolding for machine consumers
It must not manage:
- secret values
- root tokens
- AppRole SecretIDs
- release-signing key material
## Run
```sh
Scripts/openbao-tofu.sh init -backend-config=backend.hcl
Scripts/openbao-tofu.sh plan -var-file=terraform.tfvars
```
For local syntax work:
```sh
Scripts/openbao-tofu.sh init -backend=false
Scripts/openbao-tofu.sh validate
```
The Vault/OpenBao provider reads `VAULT_TOKEN` from the environment. Keep
`manage_openbao_config = false` until `vault.burrow.net` is initialized and an
operator token is available out of band.

View file

@ -0,0 +1,4 @@
bucket = "burrow-opentofu-state"
key = "openbao/openbao.tfstate"
region = "us-west-2"
encrypt = true

65
infra/openbao/google.tf Normal file
View file

@ -0,0 +1,65 @@
locals {
google_required_services = toset([
"cloudkms.googleapis.com",
"cloudresourcemanager.googleapis.com",
"iam.googleapis.com",
])
google_existing_kms_key_ring_id = var.google_kms_key_ring_id != "" ? var.google_kms_key_ring_id : "projects/${var.google_project_id}/locations/${var.google_kms_key_ring_location}/keyRings/${var.google_kms_key_ring_name}"
google_kms_key_ring_id = var.manage_google_kms_key_ring ? (
google_kms_key_ring.openbao[0].id
) : local.google_existing_kms_key_ring_id
}
resource "google_project_service" "openbao" {
for_each = var.manage_google ? local.google_required_services : toset([])
project = var.google_project_id
service = each.value
disable_on_destroy = false
}
resource "google_kms_key_ring" "openbao" {
count = var.manage_google && var.manage_google_kms_key_ring ? 1 : 0
project = var.google_project_id
location = var.google_kms_key_ring_location
name = var.google_kms_key_ring_name
depends_on = [google_project_service.openbao]
}
resource "google_kms_crypto_key" "openbao_seal" {
count = var.manage_google && local.google_kms_key_ring_id != "" ? 1 : 0
name = var.google_openbao_seal_key_name
key_ring = local.google_kms_key_ring_id
purpose = "ENCRYPT_DECRYPT"
labels = merge(
{
project = "burrow"
component = "openbao"
managed_by = "opentofu"
key_target = "seal"
},
var.tags,
)
version_template {
algorithm = "GOOGLE_SYMMETRIC_ENCRYPTION"
protection_level = "HSM"
}
lifecycle {
prevent_destroy = true
}
}
resource "google_kms_crypto_key_iam_member" "openbao_seal" {
for_each = var.manage_google && local.google_kms_key_ring_id != "" ? var.google_openbao_seal_members : toset([])
crypto_key_id = google_kms_crypto_key.openbao_seal[0].id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = each.value
}

125
infra/openbao/openbao.tf Normal file
View file

@ -0,0 +1,125 @@
resource "vault_mount" "age" {
count = var.manage_openbao_config ? 1 : 0
path = var.age_mount_path
type = "kv-v2"
description = "Migrated Burrow age-managed runtime secrets."
options = {
version = "2"
}
}
resource "vault_policy" "admin" {
count = var.manage_openbao_config ? 1 : 0
name = "burrow-openbao-admin"
policy = <<-EOT
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOT
}
resource "vault_policy" "runtime_read" {
count = var.manage_openbao_config ? 1 : 0
name = "burrow-runtime-read"
policy = <<-EOT
path "${var.age_mount_path}/data/*" {
capabilities = ["read"]
}
path "${var.age_mount_path}/metadata/*" {
capabilities = ["list", "read"]
}
EOT
}
resource "vault_auth_backend" "approle" {
count = var.manage_openbao_config ? 1 : 0
path = var.approle_auth_path
type = "approle"
description = "Machine auth for Burrow runtime secret consumers."
tune {
token_type = "default-service"
}
}
resource "vault_approle_auth_backend_role" "runtime" {
count = var.manage_openbao_config ? 1 : 0
backend = vault_auth_backend.approle[0].path
role_name = var.runtime_approle_role_name
bind_secret_id = true
token_policies = [vault_policy.runtime_read[0].name]
token_ttl = var.runtime_approle_token_ttl_seconds
token_max_ttl = var.runtime_approle_token_max_ttl_seconds
token_num_uses = 0
secret_id_ttl = var.runtime_approle_secret_id_ttl_seconds
secret_id_num_uses = var.runtime_approle_secret_id_num_uses
}
resource "vault_jwt_auth_backend" "authentik" {
count = var.manage_openbao_config ? 1 : 0
path = "oidc"
type = "oidc"
oidc_discovery_url = var.authentik_issuer
bound_issuer = var.authentik_issuer
oidc_client_id = var.authentik_client_id
default_role = "burrow-admin"
tune {
listing_visibility = "unauth"
token_type = "default-service"
}
}
resource "vault_jwt_auth_backend_role" "admin" {
count = var.manage_openbao_config ? 1 : 0
backend = vault_jwt_auth_backend.authentik[0].path
role_name = "burrow-admin"
role_type = "oidc"
user_claim = "email"
allowed_redirect_uris = [
"https://vault.burrow.net/ui/vault/auth/oidc/oidc/callback",
"http://localhost:8250/oidc/callback",
]
bound_audiences = [var.authentik_client_id]
bound_claims = {
groups = var.authentik_admin_group
}
oidc_scopes = ["openid", "profile", "email", "groups"]
token_policies = [vault_policy.admin[0].name]
}
resource "vault_jwt_auth_backend_role" "runtime" {
count = var.manage_openbao_config ? 1 : 0
backend = vault_jwt_auth_backend.authentik[0].path
role_name = "burrow-runtime-read"
role_type = "oidc"
user_claim = "email"
allowed_redirect_uris = [
"https://vault.burrow.net/ui/vault/auth/oidc/oidc/callback",
"http://localhost:8250/oidc/callback",
]
bound_audiences = [var.authentik_client_id]
bound_claims = {
groups = var.authentik_runtime_group
}
oidc_scopes = ["openid", "profile", "email", "groups"]
token_policies = [vault_policy.runtime_read[0].name]
}

14
infra/openbao/outputs.tf Normal file
View file

@ -0,0 +1,14 @@
output "google_kms_key_ring_id" {
description = "Google KMS key ring id used by the OpenBao stack."
value = local.google_kms_key_ring_id
}
output "google_openbao_seal_key_id" {
description = "Google KMS seal key id when managed."
value = try(google_kms_crypto_key.openbao_seal[0].id, null)
}
output "openbao_age_mount_path" {
description = "OpenBao KV v2 mount path for migrated age secrets."
value = var.age_mount_path
}

View file

@ -0,0 +1,8 @@
provider "google" {
project = var.google_project_id
}
provider "vault" {
address = var.openbao_address
skip_tls_verify = var.openbao_skip_tls_verify
}

View file

@ -0,0 +1,8 @@
manage_google = false
manage_openbao_config = false
google_project_id = "project-88c23ce9-918a-470a-b33"
openbao_address = "https://vault.burrow.net"
authentik_issuer = "https://auth.burrow.net/application/o/openbao/"
authentik_client_id = "vault.burrow.net"
authentik_admin_group = "burrow-admins"
authentik_runtime_group = "burrow-automation"

137
infra/openbao/variables.tf Normal file
View file

@ -0,0 +1,137 @@
variable "openbao_address" {
description = "OpenBao API address. The Vault provider reads the token from VAULT_TOKEN."
type = string
default = "https://vault.burrow.net"
}
variable "openbao_skip_tls_verify" {
description = "Skip TLS verification for local bootstrap only."
type = bool
default = false
}
variable "age_mount_path" {
description = "KV v2 mount path for migrated age-managed runtime secrets."
type = string
default = "age"
}
variable "manage_openbao_config" {
description = "Manage OpenBao mounts, policies, and Authentik OIDC auth. Requires VAULT_TOKEN."
type = bool
default = false
}
variable "authentik_issuer" {
description = "Authentik OpenBao OIDC issuer."
type = string
default = "https://auth.burrow.net/application/o/openbao/"
}
variable "authentik_client_id" {
description = "Public Authentik OpenBao OIDC client id."
type = string
default = "vault.burrow.net"
}
variable "authentik_admin_group" {
description = "Authentik group allowed to administer OpenBao."
type = string
default = "burrow-admins"
}
variable "authentik_runtime_group" {
description = "Authentik group allowed to read runtime secrets."
type = string
default = "burrow-automation"
}
variable "approle_auth_path" {
description = "OpenBao AppRole auth mount path for machine consumers."
type = string
default = "approle"
}
variable "runtime_approle_role_name" {
description = "AppRole role name used by Burrow runtime secret consumers."
type = string
default = "burrow-runtime"
}
variable "runtime_approle_token_ttl_seconds" {
description = "Token TTL for runtime AppRole login."
type = number
default = 3600
}
variable "runtime_approle_token_max_ttl_seconds" {
description = "Maximum token TTL for runtime AppRole login."
type = number
default = 7200
}
variable "runtime_approle_secret_id_ttl_seconds" {
description = "SecretID TTL for runtime AppRole. Zero means no expiry; rotate manually."
type = number
default = 0
}
variable "runtime_approle_secret_id_num_uses" {
description = "SecretID use limit for runtime AppRole. Zero means unlimited uses; rotate manually."
type = number
default = 0
}
variable "manage_google" {
description = "Manage Google Cloud KMS resources for OpenBao seal wrapping."
type = bool
default = false
}
variable "google_project_id" {
description = "Google Cloud project id for OpenBao seal wrapping."
type = string
default = "project-88c23ce9-918a-470a-b33"
}
variable "manage_google_kms_key_ring" {
description = "Create/manage the Google KMS key ring. Existing rings should be imported before enabling this."
type = bool
default = false
}
variable "google_kms_key_ring_name" {
description = "Google KMS key ring for OpenBao seal wrapping."
type = string
default = "burrow-identity"
}
variable "google_kms_key_ring_location" {
description = "Google KMS key ring location."
type = string
default = "global"
}
variable "google_kms_key_ring_id" {
description = "Existing Google KMS key ring id."
type = string
default = ""
}
variable "google_openbao_seal_key_name" {
description = "Google KMS symmetric key used for OpenBao seal wrapping."
type = string
default = "openbao-seal"
}
variable "google_openbao_seal_members" {
description = "IAM members allowed to encrypt/decrypt with the OpenBao seal key."
type = set(string)
default = []
}
variable "tags" {
description = "Additional labels applied to supported Google resources."
type = map(string)
default = {}
}

16
infra/openbao/versions.tf Normal file
View file

@ -0,0 +1,16 @@
terraform {
required_version = ">= 1.8.0"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 5.40.0, < 7.0"
}
vault = {
source = "hashicorp/vault"
version = ">= 4.5.0, < 6.0"
}
}
backend "s3" {}
}