--- name: hashicorp-vault description: Manage secrets and PKI with HashiCorp Vault. Configure secret engines, authentication methods, and policies. Use when implementing centralized secrets management, dynamic credentials, or certificate management. license: MIT metadata: author: devops-skills version: "1.0" --- # HashiCorp Vault Centrally manage secrets, encryption, and access with HashiCorp Vault. ## When to Use This Skill Use this skill when: - Centralizing secrets management - Implementing dynamic credentials - Managing PKI and certificates - Encrypting sensitive data - Meeting compliance requirements ## Prerequisites - Vault server (dev or production) - Vault CLI installed - Network access to Vault ## Quick Start ### Development Server ```bash # Start dev server vault server -dev # Set environment export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='root' # Verify connection vault status ``` ### Production Deployment ```hcl # config.hcl storage "raft" { path = "/opt/vault/data" node_id = "vault-1" } listener "tcp" { address = "0.0.0.0:8200" tls_cert_file = "/opt/vault/tls/vault.crt" tls_key_file = "/opt/vault/tls/vault.key" } api_addr = "https://vault.example.com:8200" cluster_addr = "https://vault.example.com:8201" ui = true ``` ```bash # Initialize Vault vault operator init -key-shares=5 -key-threshold=3 # Unseal (run 3 times with different keys) vault operator unseal vault operator unseal vault operator unseal # Login vault login ``` ## Secret Engines ### KV Secrets ```bash # Enable KV v2 vault secrets enable -path=secret kv-v2 # Write secret vault kv put secret/myapp/config \ username="admin" \ password="s3cr3t" # Read secret vault kv get secret/myapp/config vault kv get -field=password secret/myapp/config # Update secret vault kv put secret/myapp/config \ username="admin" \ password="new-password" # List secrets vault kv list secret/ # Delete secret vault kv delete secret/myapp/config # Version history vault kv metadata get secret/myapp/config ``` ### Database Secrets ```bash # Enable database engine vault secrets enable database # Configure PostgreSQL connection vault write database/config/postgresql \ plugin_name=postgresql-database-plugin \ connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb" \ allowed_roles="readonly,readwrite" \ username="vault" \ password="vault-password" # Create role vault write database/roles/readonly \ db_name=postgresql \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \ GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="1h" \ max_ttl="24h" # Get credentials vault read database/creds/readonly ``` ### AWS Secrets ```bash # Enable AWS engine vault secrets enable aws # Configure root credentials vault write aws/config/root \ access_key=AKIA... \ secret_key=secret... \ region=us-east-1 # Create role vault write aws/roles/deploy \ credential_type=iam_user \ policy_document=-< ca_cert.crt # Configure URLs vault write pki/config/urls \ issuing_certificates="https://vault.example.com:8200/v1/pki/ca" \ crl_distribution_points="https://vault.example.com:8200/v1/pki/crl" # Create role vault write pki/roles/web-server \ allowed_domains="example.com" \ allow_subdomains=true \ max_ttl="720h" # Issue certificate vault write pki/issue/web-server \ common_name="web.example.com" \ ttl="24h" ``` ## Authentication Methods ### AppRole ```bash # Enable AppRole vault auth enable approle # Create role vault write auth/approle/role/myapp \ token_policies="myapp-policy" \ token_ttl=1h \ token_max_ttl=4h \ secret_id_ttl=10m # Get role ID vault read auth/approle/role/myapp/role-id # Generate secret ID vault write -f auth/approle/role/myapp/secret-id # Login vault write auth/approle/login \ role_id= \ secret_id= ``` ### Kubernetes ```bash # Enable Kubernetes auth vault auth enable kubernetes # Configure vault write auth/kubernetes/config \ kubernetes_host="https://kubernetes.default.svc" \ kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt # Create role vault write auth/kubernetes/role/myapp \ bound_service_account_names=myapp \ bound_service_account_namespaces=default \ policies=myapp-policy \ ttl=1h ``` ### OIDC ```bash # Enable OIDC auth vault auth enable oidc # Configure vault write auth/oidc/config \ oidc_discovery_url="https://accounts.google.com" \ oidc_client_id="your-client-id" \ oidc_client_secret="your-client-secret" \ default_role="default" # Create role vault write auth/oidc/role/default \ bound_audiences="your-client-id" \ allowed_redirect_uris="http://localhost:8250/oidc/callback" \ user_claim="sub" \ policies="default" ``` ## Policies ### Policy Definition ```hcl # myapp-policy.hcl # Read secrets path "secret/data/myapp/*" { capabilities = ["read", "list"] } # Database credentials path "database/creds/myapp-db" { capabilities = ["read"] } # PKI certificates path "pki/issue/web-server" { capabilities = ["create", "update"] } # Deny access to other secrets path "secret/data/other/*" { capabilities = ["deny"] } ``` ```bash # Create policy vault policy write myapp myapp-policy.hcl # List policies vault policy list # Read policy vault policy read myapp ``` ## Application Integration ### Python ```python import hvac # Initialize client client = hvac.Client(url='http://localhost:8200') # AppRole authentication client.auth.approle.login( role_id='role-id', secret_id='secret-id' ) # Read secret secret = client.secrets.kv.v2.read_secret_version( path='myapp/config', mount_point='secret' ) password = secret['data']['data']['password'] # Get database credentials db_creds = client.secrets.database.generate_credentials( name='myapp-db' ) ``` ### Kubernetes Sidecar ```yaml apiVersion: v1 kind: Pod metadata: name: myapp annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "myapp" vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config" vault.hashicorp.com/agent-inject-template-config: | {{- with secret "secret/data/myapp/config" -}} export DB_PASSWORD="{{ .Data.data.password }}" {{- end }} spec: serviceAccountName: myapp containers: - name: myapp image: myapp:latest command: ["/bin/sh", "-c", "source /vault/secrets/config && ./start.sh"] ``` ## Common Issues ### Issue: Sealed Vault **Problem**: Vault is sealed after restart **Solution**: Implement auto-unseal with cloud KMS or HSM ### Issue: Token Expired **Problem**: Application token has expired **Solution**: Implement token renewal, use shorter-lived tokens ### Issue: Permission Denied **Problem**: Cannot access secrets **Solution**: Review policies, check token capabilities ## Best Practices - Use short-lived tokens - Implement auto-unseal - Enable audit logging - Use namespaces for isolation - Rotate root tokens regularly - Implement least-privilege policies - Use dynamic secrets where possible - Regular backup and DR testing ## Related Skills - [aws-secrets-manager](../aws-secrets-manager/) - AWS native secrets - [sops-encryption](../sops-encryption/) - File encryption - [kubernetes-hardening](../../hardening/kubernetes-hardening/) - K8s security