🏦 Vault Integration Recipes
HashiCorp Vault is the industry standard for secrets management. These recipes show practical ways to integrate Vault with shell scripts for secure automation.
🎯 Vault Setup and Authentication
Basic Vault Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | # Set Vault address
export VAULT_ADDR="https://vault.example.com:8200"
# Verify connectivity
vault status
# Authenticate (choose one method)
# Token auth
export VAULT_TOKEN="s.token_here"
# AppRole auth
vault write auth/approle/login \
role_id="$ROLE_ID" \
secret_id="$SECRET_ID"
# Kubernetes auth
vault write auth/kubernetes/login \
role="$VAULT_ROLE" \
jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
|
Vault Health Check Function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | # Vault health checking
check_vault_health() {
if ! command -v vault >/dev/null 2>&1; then
echo "Error: Vault CLI not found" >&2
return 1
fi
if [ -z "$VAULT_ADDR" ]; then
echo "Error: VAULT_ADDR not set" >&2
return 1
fi
local vault_status
vault_status=$(vault status -format=json 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Cannot connect to Vault at $VAULT_ADDR" >&2
return 1
fi
local initialized
initialized=$(echo "$vault_status" | jq -r '.initialized')
if [ "$initialized" != "true" ]; then
echo "Error: Vault is not initialized" >&2
return 1
fi
echo "Vault is healthy and initialized"
return 0
}
|
🔧 Secret Retrieval Patterns
Simple Secret Reading
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | # Get a single secret value
get_vault_secret() {
local secret_path="$1"
local field="${2:-value}"
if [ -z "$secret_path" ]; then
echo "Error: Secret path required" >&2
return 1
fi
local secret_value
secret_value=$(vault kv get -field="$field" "$secret_path" 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$secret_value" ]; then
echo "Error: Failed to retrieve secret from $secret_path" >&2
return 1
fi
echo "$secret_value"
return 0
}
# Usage
DATABASE_PASSWORD=$(get_vault_secret "database/prod" "password")
|
Multiple Secret Fields
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | # Get multiple fields from a secret
get_vault_secret_fields() {
local secret_path="$1"
shift
local fields=("$@")
local json_output
json_output=$(vault kv get -format=json "$secret_path" 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Failed to retrieve secret from $secret_path" >&2
return 1
fi
# Extract each field
for field in "${fields[@]}"; do
local value
value=$(echo "$json_output" | jq -r ".data.data.$field")
if [ "$value" != "null" ]; then
echo "$field=$value"
fi
done
}
# Usage
get_vault_secret_fields "database/prod" "username" "password" "host" "port"
|
Dynamic Secrets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | # Get dynamic database credentials
get_dynamic_database_creds() {
local role_name="$1"
local ttl="${2:-1h}"
local creds_json
creds_json=$(vault read -format=json "database/creds/$role_name" ttl="$ttl" 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Failed to generate dynamic credentials for role $role_name" >&2
return 1
fi
echo "$creds_json" | jq -r '.data | to_entries[] | "\(.key)=\(.value)"'
}
# Usage
eval "$(get_dynamic_database_creds "app-role" "2h")"
# Sets USERNAME and PASSWORD environment variables
|
🛡️ Secure Secret Injection
Temporary File Injection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 | # Inject secrets into temporary config file
inject_vault_secrets_to_file() {
local template_file="$1"
local output_file="$2"
# Create secure temporary file
local temp_file
temp_file=$(mktemp "${TMPDIR:-/tmp}/vault_config_XXXXXX") || {
echo "Error: Failed to create temporary file" >&2
return 1
}
chmod 600 "$temp_file"
# Get secrets
local db_password
db_password=$(get_vault_secret "database/prod" "password")
local api_key
api_key=$(get_vault_secret "api/prod" "key")
# Generate config from template
env DB_PASSWORD="$db_password" API_KEY="$api_key" \
envsubst < "$template_file" > "$temp_file"
# Move to final location
mv "$temp_file" "$output_file"
chmod 600 "$output_file"
echo "Secrets injected to $output_file"
}
# Template file example (config.template):
# database:
# password: ${DB_PASSWORD}
# host: prod-db.example.com
# api:
# key: ${API_KEY}
|
Process Substitution for Secrets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | # Secure secret injection via process substitution
run_with_vault_secrets() {
local cmd="$1"
shift
# Get secrets
local db_password
db_password=$(get_vault_secret "database/prod" "password")
# Inject via environment (but clear afterward)
DB_PASSWORD="$db_password" "$cmd" "$@"
}
# Usage
run_with_vault_secrets "myapp" "--config" "config.yaml"
|
🔄 Secret Rotation and Renewal
Lease Renewal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | # Renew Vault leases
renew_vault_lease() {
local lease_id="$1"
local increment="${2:-3600}" # 1 hour default
if [ -z "$lease_id" ]; then
echo "Error: Lease ID required" >&2
return 1
fi
vault lease renew -increment="$increment" "$lease_id"
return $?
}
# Auto-renewal background process
start_lease_renewal() {
local lease_id="$1"
local interval="${2:-1800}" # 30 minutes
(
while true; do
sleep "$interval"
if ! renew_vault_lease "$lease_id"; then
echo "Failed to renew lease $lease_id" >&2
break
fi
done
) &
echo "Lease renewal started for $lease_id"
}
|
Dynamic Secret Rotation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | # Rotate dynamic credentials
rotate_dynamic_credentials() {
local role_name="$1"
local current_lease_id="$2"
# Revoke old credentials if they exist
if [ -n "$current_lease_id" ]; then
vault lease revoke "$current_lease_id" 2>/dev/null
fi
# Generate new credentials
local new_creds
new_creds=$(vault read -format=json "database/creds/$role_name" 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Error: Failed to rotate credentials for role $role_name" >&2
return 1
fi
# Extract new lease ID
local new_lease_id
new_lease_id=$(echo "$new_creds" | jq -r '.lease_id')
# Export credentials
echo "$new_creds" | jq -r '.data | to_entries[] | "export \(.key)=\(.value)"' | while read -r line; do
eval "$line"
done
echo "Credentials rotated. New lease ID: $new_lease_id"
echo "$new_lease_id"
}
|
🧪 Vault Integration Testing
Mock Vault for Testing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 | # Mock Vault for local testing
mock_vault() {
local mock_dir="${1:-/tmp/mock_vault}"
mkdir -p "$mock_dir"
# Create mock secrets
cat > "$mock_dir/database_prod" << EOF
username: dbuser
password: dbpassword123
host: localhost
port: 5432
EOF
cat > "$mock_dir/api_prod" << EOF
key: apikey123
endpoint: https://api.example.com
EOF
# Mock vault command
cat > "$mock_dir/vault_mock" << 'EOF'
#!/bin/bash
if [[ "$1" == "kv" && "$2" == "get" ]]; then
local path="$4"
local field="${6:-value}"
# Map path to mock file
local mock_file="/tmp/mock_vault/$(echo "$path" | tr '/' '_')"
if [[ -f "$mock_file" ]]; then
grep "^$field:" "$mock_file" | cut -d' ' -f2-
else
echo "Error: Secret not found" >&2
exit 1
fi
else
echo "Mock Vault: $*" >&2
fi
EOF
chmod +x "$mock_dir/vault_mock"
echo "Mock Vault created in $mock_dir"
echo "Use: export PATH=\"$mock_dir:\$PATH\" for testing"
}
|
Integration Test Suite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | # Vault integration tests
test_vault_integration() {
echo "Testing Vault integration..."
# Test connectivity
if ! check_vault_health; then
echo "FAIL: Vault health check failed"
return 1
fi
# Test secret retrieval
local test_secret
test_secret=$(get_vault_secret "test/secret" 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$test_secret" ]; then
echo "PASS: Secret retrieval successful"
else
echo "WARN: Could not retrieve test secret (may be expected in CI)"
fi
# Test dynamic credentials
local dyn_creds
dyn_creds=$(get_dynamic_database_creds "test-role" "1m" 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$dyn_creds" ]; then
echo "PASS: Dynamic credential generation successful"
else
echo "WARN: Could not generate dynamic credentials (may be expected)"
fi
echo "Vault integration tests completed"
}
|
🧾 Summary
✅ Secure authentication using AppRole, Kubernetes, or token methods
✅ Robust secret retrieval with proper error handling
✅ Safe secret injection via temporary files and process substitution
✅ Dynamic credential management with lease renewal
✅ Comprehensive testing with mock Vault environments
🧾 See Also