mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
385 lines
7.7 KiB
Markdown
385 lines
7.7 KiB
Markdown
---
|
|||
|
|
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 <key-1>
|
||
|
|
vault operator unseal <key-2>
|
||
|
|
vault operator unseal <key-3>
|
||
|
|
|
||
|
|
# Login
|
||
|
|
vault login <root-token>
|
||
|
|
```
|
||
|
|
|
||
|
|
## 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=-<<EOF
|
||
|
|
{
|
||
|
|
"Version": "2012-10-17",
|
||
|
|
"Statement": [
|
||
|
|
{
|
||
|
|
"Effect": "Allow",
|
||
|
|
"Action": ["s3:*"],
|
||
|
|
"Resource": ["arn:aws:s3:::my-bucket/*"]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Get credentials
|
||
|
|
vault read aws/creds/deploy
|
||
|
|
```
|
||
|
|
|
||
|
|
### PKI Secrets
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Enable PKI engine
|
||
|
|
vault secrets enable pki
|
||
|
|
vault secrets tune -max-lease-ttl=87600h pki
|
||
|
|
|
||
|
|
# Generate root CA
|
||
|
|
vault write -field=certificate pki/root/generate/internal \
|
||
|
|
common_name="example.com" \
|
||
|
|
ttl=87600h > 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=<role-id> \
|
||
|
|
secret_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
|