Configure Garage object storage on garage01 with S3 API, Vault secrets for RPC secret and admin token, and Caddy reverse proxy for HTTPS access at s3.home.2rjus.net via internal ACME CA. Includes flake entry, VM definition, and Vault policy for the host. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OpenBao Terraform Configuration
This directory contains Terraform/OpenTofu configuration for managing OpenBao (Vault) infrastructure as code.
Overview
Manages the following OpenBao resources:
- AppRole Authentication: For host-based authentication
- PKI Infrastructure: Root CA + Intermediate CA for TLS certificates
- KV Secrets Engine: Key-value secret storage (v2)
- Policies: Access control policies
Setup
-
Copy the example tfvars file:
cp terraform.tfvars.example terraform.tfvars -
Edit
terraform.tfvarswith your OpenBao credentials:vault_address = "https://vault01.home.2rjus.net:8200" vault_token = "hvs.your-root-token-here" vault_skip_tls_verify = true -
Initialize Terraform:
tofu init -
Review the plan:
tofu plan -
Apply the configuration:
tofu apply
Files
main.tf- Provider configurationvariables.tf- Variable definitionsapprole.tf- AppRole authentication backend and rolespki.tf- PKI engines (root CA and intermediate CA)secrets.tf- KV secrets engine and test secretsterraform.tfvars- Credentials (gitignored)terraform.tfvars.example- Example configuration
Resources Created
AppRole Authentication
- AppRole backend at
approle/ - Host-based roles and policies (defined in
locals.host_policies)
PKI Infrastructure
- Root CA at
pki/(10 year TTL) - Intermediate CA at
pki_int/(5 year TTL) - Role
homelabfor issuing certificates to*.home.2rjus.net - Certificate max TTL: 30 days
Secrets
- KV v2 engine at
secret/ - Secrets and policies defined in
locals.secretsandlocals.host_policies
Usage Examples
Adding a New Host
- Define the host policy in
approle.tf:
locals {
host_policies = {
"monitoring01" = {
paths = [
"secret/data/hosts/monitoring01/*",
"secret/data/services/prometheus/*",
]
}
}
}
- Add secrets in
secrets.tf:
locals {
secrets = {
"hosts/monitoring01/grafana-admin" = {
auto_generate = true
password_length = 32
}
}
}
- Apply changes:
tofu apply
- Get AppRole credentials:
# Get role_id
bao read auth/approle/role/monitoring01/role-id
# Generate secret_id
bao write -f auth/approle/role/monitoring01/secret-id
Issue Certificates from PKI
Method 1: ACME (Recommended for automated services)
First, enable ACME support:
bao write pki_int/config/acme enabled=true
ACME directory endpoint:
https://vault01.home.2rjus.net:8200/v1/pki_int/acme/directory
Use with ACME clients (lego, certbot, cert-manager, etc.):
# Example with lego
lego --email admin@home.2rjus.net \
--dns manual \
--server https://vault01.home.2rjus.net:8200/v1/pki_int/acme/directory \
--accept-tos \
run -d test.home.2rjus.net
Method 2: Static certificates via Terraform
Define in pki.tf:
locals {
static_certificates = {
"monitoring" = {
common_name = "monitoring.home.2rjus.net"
alt_names = ["grafana.home.2rjus.net", "prometheus.home.2rjus.net"]
ttl = "720h"
}
}
}
Terraform will auto-issue and auto-renew these certificates.
Method 3: Manual CLI issuance
# Issue certificate for a host
bao write pki_int/issue/homelab \
common_name="test.home.2rjus.net" \
ttl="720h"
Read a secret
# Authenticate with AppRole first
bao write auth/approle/login \
role_id="..." \
secret_id="..."
# Read the test secret
bao kv get secret/test/example
Managing Secrets
Secrets are defined in the locals.secrets block in secrets.tf using a declarative pattern:
Auto-Generated Secrets (Recommended)
Most secrets can be auto-generated using the random_password provider:
locals {
secrets = {
"hosts/monitoring01/grafana-admin" = {
auto_generate = true
password_length = 32
}
}
}
Manual Secrets
For secrets that must have specific values (external services, etc.):
# In variables.tf
variable "smtp_password" {
type = string
sensitive = true
}
# In secrets.tf locals block
locals {
secrets = {
"shared/smtp/credentials" = {
auto_generate = false
data = {
username = "notifications@2rjus.net"
password = var.smtp_password
server = "smtp.gmail.com"
}
}
}
}
# In terraform.tfvars
smtp_password = "super-secret-password"
Path Structure
Secrets follow a three-tier hierarchy:
hosts/{hostname}/*- Host-specific secretsservices/{service}/*- Service-wide secrets (any host running the service)shared/{category}/*- Shared secrets (SMTP, backup, etc.)
Security Notes
terraform.tfvarsis gitignored to prevent credential leakage- Root token should be stored securely (consider using a limited admin token instead)
skip_tls_verify = trueis acceptable for self-signed certs in homelab- AppRole secret_ids can be scoped to specific CIDR ranges for additional security
Initial Setup Steps
After deploying this configuration, perform these one-time setup tasks:
1. Enable ACME
export BAO_ADDR='https://vault01.home.2rjus.net:8200'
export BAO_TOKEN='your-root-token'
export BAO_SKIP_VERIFY=1
# Configure cluster path (required for ACME)
bao write pki_int/config/cluster path=https://vault01.home.2rjus.net:8200/v1/pki_int
# Enable ACME on intermediate CA
bao write pki_int/config/acme enabled=true
# Verify ACME is enabled
curl -k https://vault01.home.2rjus.net:8200/v1/pki_int/acme/directory
2. Download Root CA Certificate
For trusting the internal CA on clients:
# Download root CA certificate
bao read -field=certificate pki/cert/ca > homelab-root-ca.crt
# Install on NixOS hosts (add to system/default.nix or similar)
security.pki.certificateFiles = [ ./homelab-root-ca.crt ];
3. Test Certificate Issuance
# Manual test
bao write pki_int/issue/homelab common_name="test.home.2rjus.net" ttl="24h"
Next Steps
- Replace step-ca ACME endpoint with OpenBao in
system/acme.nix - Add more AppRoles for different host types
- Migrate existing sops-nix secrets to OpenBao KV
- Set up SSH CA for host and user certificates
- Configure auto-unseal for vault01