Infra secrets management review
Skill ivanshamaev/de-agent-skills/group_skills/infra_dataops_group_skills/infra_secrets_management_review
Профессиональные Data Engineering Agent Skills для разработки AI Agentic Data Platform
npx -y skills add ivanshamaev/de-agent-skills --skill infra_secrets_management_reviewAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Secrets management review — HashiCorp Vault (KV v2/dynamic credentials/lease renewal/audit log), External Secrets Operator (Vault/AWS SSM/GCP Secret Manager → K8s secrets), secret rotation strategies (database dynamic credentials/TLS cert-manager), detecting secrets in code (gitleaks/truffleHog/Semgrep), Airflow connections from Vault backend, dbt profiles without hardcoded credentials, CI/CD secrets (GitHub OIDC/GitLab CI variables), no plaintext secrets in logs/configs
SKILL.md
8.8 KB, as published. Nobody here has run it
Secrets Management Review
When to Use
- Auditing how secrets are stored and accessed in a data platform
- Migrating from hardcoded credentials to a secrets manager
- Setting up dynamic database credentials via Vault
- Detecting secret leaks in git history or application logs
- Implementing automatic secret rotation
Vault KV v2 — Static Secrets
# Enable KV v2 secrets engine
vault secrets enable -path=data-platform kv-v2
# Store secrets
vault kv put data-platform/production/trino \
host="trino.prod.internal" \
user="etl_user" \
password="$(openssl rand -base64 32)"
vault kv put data-platform/production/kafka \
bootstrap_servers="kafka-1:9092,kafka-2:9092,kafka-3:9092" \
sasl_username="pipeline_user" \
sasl_password="$(openssl rand -base64 32)"
# Retrieve
vault kv get -format=json data-platform/production/trino | jq '.data.data'
# Version history
vault kv metadata get data-platform/production/trino
# Vault policy for Airflow workers
resource "vault_policy" "airflow_worker" {
name = "airflow-worker"
policy = <<EOT
# Read-only access to data platform secrets
path "data-platform/data/production/*" {
capabilities = ["read"]
}
path "data-platform/metadata/production/*" {
capabilities = ["read", "list"]
}
# Dynamic database credentials
path "database/creds/airflow-trino" {
capabilities = ["read"]
}
EOT
}
Vault Dynamic Database Credentials
# Vault generates short-lived DB credentials — no static password to rotate
resource "vault_database_secrets_mount" "main" {
path = "database"
}
resource "vault_database_secret_backend_connection" "trino" {
backend = vault_database_secrets_mount.main.path
name = "trino"
allowed_roles = ["airflow-trino", "dbt-trino"]
# Trino via PostgreSQL protocol
postgresql {
connection_url = "postgresql://{{username}}:{{password}}@trino-coordinator:5432/default"
username = "vault_admin"
password = var.vault_db_admin_password
}
}
resource "vault_database_secret_backend_role" "airflow" {
backend = vault_database_secrets_mount.main.path
name = "airflow-trino"
db_name = vault_database_secret_backend_connection.trino.name
creation_statements = [
"CREATE USER \"{{name}}\" WITH PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
"GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA silver TO \"{{name}}\";",
]
revocation_statements = ["DROP USER IF EXISTS \"{{name}}\";"]
default_ttl = "1h"
max_ttl = "24h"
}
# Airflow: dynamic Trino credentials via Vault
import hvac
from airflow.hooks.base import BaseHook
def get_trino_connection():
vault = hvac.Client(url=os.environ["VAULT_ADDR"])
vault.auth.kubernetes.login(
role="airflow-worker",
jwt=open("/var/run/secrets/kubernetes.io/serviceaccount/token").read()
)
creds = vault.secrets.database.generate_credentials(name="airflow-trino")
return {
"host": "trino.prod.internal",
"username": creds["data"]["username"],
"password": creds["data"]["password"],
"lease_id": creds["lease_id"], # renew before expiry
}
External Secrets Operator
# ClusterSecretStore: connect ESO to Vault
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: http://vault.vault.svc.cluster.local:8200
path: data-platform
version: v2
auth:
kubernetes:
mountPath: kubernetes
role: external-secrets-operator
serviceAccountRef:
name: external-secrets
namespace: external-secrets
---
# ExternalSecret: pull from Vault → K8s Secret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: trino-credentials
namespace: airflow
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: trino-credentials # name of K8s Secret to create
creationPolicy: Owner
template:
type: Opaque
data:
- secretKey: password
remoteRef:
key: production/trino
property: password
- secretKey: username
remoteRef:
key: production/trino
property: user
Airflow Vault Secret Backend
# airflow.cfg
[secrets]
backend = airflow.providers.hashicorp.secrets.vault.VaultBackend
backend_kwargs = {
"connections_path": "data-platform/data/airflow/connections",
"variables_path": "data-platform/data/airflow/variables",
"url": "http://vault.vault.svc.cluster.local:8200",
"auth_type": "kubernetes",
"role_id": "airflow"
}
# Store Airflow connection in Vault (not Airflow DB)
vault kv put data-platform/airflow/connections/trino_production \
conn_type="trino" \
host="trino.prod.internal" \
port="443" \
schema="gold" \
login="airflow_user" \
password="..." \
extra='{"auth": "ldap", "http_scheme": "https"}'
Secret Scanning (Prevent Leaks)
# .pre-commit-config.yaml — detect secrets before commit
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.67.0
hooks:
- id: trufflehog
args: [--only-verified]
# Scan git history for leaked secrets
gitleaks detect --source . --report-format json --report-path leaks.json
# Scan with TruffleHog (detects verified credentials)
trufflehog git file://. --only-verified
# Semgrep: find hardcoded credentials patterns
semgrep --config "p/secrets" --output results.sarif .
# GitHub Actions secret scanner on every PR
jobs:
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # full history for scanning
- name: Gitleaks scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
dbt Profiles Without Hardcoded Credentials
# profiles.yml — use env_var() everywhere
production:
target: prod
outputs:
prod:
type: trino
host: "{{ env_var('DBT_TRINO_HOST') }}"
port: 443
user: "{{ env_var('DBT_TRINO_USER') }}"
password: "{{ env_var('DBT_TRINO_PASSWORD') }}"
database: production
schema: gold
http_scheme: https
# Inject from Vault at runtime
eval $(vault kv get -format=json data-platform/production/trino \
| jq -r '.data.data | to_entries[] | "export DBT_TRINO_\(.key | ascii_upcase)=\(.value)"')
dbt run --target prod
Secret Rotation Checklist
[ ] No secrets in code (git pre-commit gitleaks hook active)
[ ] No secrets in Airflow Variables or Connections (use Vault backend)
[ ] No secrets in Kubernetes Secrets directly (use External Secrets Operator)
[ ] No secrets in terraform.tfvars committed to git
[ ] Database credentials: dynamic via Vault (TTL 1h)
[ ] TLS certificates: auto-renewed via cert-manager
[ ] API keys: rotated quarterly, stored in Vault
[ ] CI/CD: OIDC instead of static cloud credentials
[ ] Vault audit log enabled and shipped to SIEM
[ ] All secrets have owner label (team/system using them)
Anti-Patterns
- Secrets in environment variables in Deployment YAML — visible to anyone with
kubectl describe pod; use ExternalSecrets or secretKeyRef. - Long-lived static DB passwords — a leaked password is valid indefinitely; use Vault dynamic credentials with 1h TTL.
- Secrets in Airflow Variables (metadata DB) — Variables are not encrypted at rest by default; use Vault Secret Backend for sensitive values.
- GitHub repository secrets with never-expiring API keys — use OIDC for AWS/GCP/Azure; for services that don't support OIDC, set expiry and rotate.
- No pre-commit secret scanning — developers accidentally commit API keys; gitleaks catches them before push.
- Vault without audit log — who accessed what secret is unauditable; always enable Vault audit log and ship to a SIEM.
References
- HashiCorp Vault:
vaultproject.io/docs - External Secrets Operator:
external-secrets.io/docs/ - Gitleaks:
github.com/gitleaks/gitleaks - cert-manager:
cert-manager.io/docs/ - Related skills:
[[infra-kubernetes-security-audit]],[[infra-rbac-audit]],[[dataops-airflow-production-readiness]]