Files
nixos-servers/terraform/vault/README.md
Torjus Håkestad 2b4dc424cc
All checks were successful
Run nix flake check / flake-check (push) Successful in 2m20s
Run nix flake check / flake-check (pull_request) Successful in 2m20s
vault: implement bootstrap integration
2026-02-03 00:54:31 +01:00

6.3 KiB

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

  1. Copy the example tfvars file:

    cp terraform.tfvars.example terraform.tfvars
    
  2. Edit terraform.tfvars with your OpenBao credentials:

    vault_address         = "https://vault01.home.2rjus.net:8200"
    vault_token           = "hvs.your-root-token-here"
    vault_skip_tls_verify = true
    
  3. Initialize Terraform:

    tofu init
    
  4. Review the plan:

    tofu plan
    
  5. Apply the configuration:

    tofu apply
    

Files

  • main.tf - Provider configuration
  • variables.tf - Variable definitions
  • approle.tf - AppRole authentication backend and roles
  • pki.tf - PKI engines (root CA and intermediate CA)
  • secrets.tf - KV secrets engine and test secrets
  • terraform.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 homelab for issuing certificates to *.home.2rjus.net
  • Certificate max TTL: 30 days

Secrets

  • KV v2 engine at secret/
  • Secrets and policies defined in locals.secrets and locals.host_policies

Usage Examples

Adding a New Host

  1. Define the host policy in approle.tf:
locals {
  host_policies = {
    "monitoring01" = {
      paths = [
        "secret/data/hosts/monitoring01/*",
        "secret/data/services/prometheus/*",
      ]
    }
  }
}
  1. Add secrets in secrets.tf:
locals {
  secrets = {
    "hosts/monitoring01/grafana-admin" = {
      auto_generate   = true
      password_length = 32
    }
  }
}
  1. Apply changes:
tofu apply
  1. 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:

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 secrets
  • services/{service}/* - Service-wide secrets (any host running the service)
  • shared/{category}/* - Shared secrets (SMTP, backup, etc.)

Security Notes

  • terraform.tfvars is gitignored to prevent credential leakage
  • Root token should be stored securely (consider using a limited admin token instead)
  • skip_tls_verify = true is 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

  1. Replace step-ca ACME endpoint with OpenBao in system/acme.nix
  2. Add more AppRoles for different host types
  3. Migrate existing sops-nix secrets to OpenBao KV
  4. Set up SSH CA for host and user certificates
  5. Configure auto-unseal for vault01