Skip to content

Experimental Manual Rotation Of Vault Dynamic Secret Through VSO #1032

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

jaireddjawed
Copy link
Collaborator

@jaireddjawed jaireddjawed commented Mar 14, 2025

Description

This is my project for Hack Week. I found this issue opened a few weeks ago, where the person who opened it would have liked to see this feature added and I wanted to see if it was possible. I managed to do it by creating a new annotation vault-secrets-operator/force-sync; once it's added to a dynamic secret, a sync for the secret is executed, allowing someone to manually rotate a dynamic secret.

Local Testing

  1. Started Vault Server in Dev Mode in one terminal
vault server -dev -dev-root-token-id=root -log-level=debug
  1. Enable Kubernetes Authentication in Vault for VSO
export K8S_HOST=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')


# Get the token from a service account you'll use
kubectl create serviceaccount vault-auth
kubectl create clusterrolebinding vault-auth-binding --clusterrole=system:auth-delegator --serviceaccount=default:vault-auth

# Create a service account token
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: vault-auth-secret
  annotations:
    kubernetes.io/service-account.name: vault-auth
type: kubernetes.io/service-account-token
EOF

# Get the token
export SA_JWT_TOKEN=$(kubectl get secret vault-auth-secret -o jsonpath="{.data.token}" | base64 --decode)
export K8S_CACERT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 --decode)

vault write auth/kubernetes/config \
  kubernetes_host="$K8S_HOST" \
  token_reviewer_jwt="$SA_JWT_TOKEN" \
  kubernetes_ca_cert="$K8S_CACERT" \
  issuer="https://kubernetes.default.svc.cluster.local"

# Create policy
vault policy write db-creds-policy - <<EOF
path "database/creds/my-db-role" {
  capabilities = ["read"]
}

path "database/roles/my-db-role" {
  capabilities = ["read"]
}

path "sys/leases/revoke" {
  capabilities = ["update"]
}

path "database/creds/*" {
  capabilities = ["read"]
}
EOF

# Create role
vault write auth/kubernetes/role/kubernetes-role \
  bound_service_account_names=vault-auth \
  bound_service_account_namespaces=default \
  policies=db-creds-policy \
  ttl=1h
  
# Confirm that kubernetes authentication was set up correctly
vault write auth/kubernetes/login role=kubernetes-role jwt=$SA_JWT_TOKEN'
  1. Set up a dynamic secret in Vault by using the database secrets engine.
vault secrets enable database

vault write database/config/my_database \
    plugin_name=postgresql-database-plugin \
    allowed_roles="my-role" \
    connection_url="postgresql://{{username}}:{{password}}@127.0.0.1:5432/my_database" \
    username="admin" \
    password="admin-password"
   
vault write database/roles/my-role \
    db_name=my_database \
    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" \
    default_ttl="20m" \
    max_ttl="30m"
  1. Setup the VaultConnection, VaultAuth, and VaultDynamicSecret in Vault Secrets Operator
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
  name: vault-connection
  namespace: default
spec:
  address: http://VAULT_URL # Adjust this URL to your Vault server
  skipTLSVerify: true # For dev/test only - use proper TLS in production
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: vault-auth
  namespace: default
spec:
  method: kubernetes
  mount: kubernetes
  kubernetes:
    role: kubernetes-role # The Vault Kubernetes auth role you created
    serviceAccount: vault-auth # The service account to use
  vaultConnectionRef: vault-connection
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
  name: db-creds
  namespace: default
spec:
  mount: database
  path: creds/my-role
  destination:
    name: postgres-creds
    create: true
  rolloutRestartTargets: []
  vaultAuthRef: vault-auth
  renewalPercent: 50
  revoke: true
  1. View the initial base64-encoded password saved in VSO before the rotation
apiVersion: v1
data:
  _raw: eyJwYXNzd29yZCI6IkNEM2xFLTFJbjFucnN6cTdNNkdWIiwidXNlcm5hbWUiOiJ2LWt1YmVybmV0LW15LXJvbGUtMER1bWY2RXRKUEhkblk1UXd0TTItMTc0MTk0MDQ4NCJ9
  password: Q0QzbEUtMUluMW5yc3pxN002R1Y=
  username: di1rdWJlcm5ldC1teS1yb2xlLTBEdW1mNkV0SlBIZG5ZNVF3dE0yLTE3NDE5NDA0ODQ=
kind: Secret
metadata:
  creationTimestamp: "2025-03-14T08:21:24Z"
  labels:
    app.kubernetes.io/component: secret-sync
    app.kubernetes.io/managed-by: hashicorp-vso
    app.kubernetes.io/name: vault-secrets-operator
    secrets.hashicorp.com/vso-ownerRefUID: 5775f6fd-4cd0-4f77-b5e3-dba8befe1f88
  name: postgres-creds
  namespace: default
  ownerReferences:
  - apiVersion: secrets.hashicorp.com/v1beta1
    kind: VaultDynamicSecret
    name: db-creds
    uid: 5775f6fd-4cd0-4f77-b5e3-dba8befe1f88
  resourceVersion: "2297"
  uid: 0e99e731-8c08-412f-9305-e48d64ead271
type: Opaque
  1. Added the annotation to trigger a manual rotation
kubectl annotate vaultdynamicsecrets.secrets.hashicorp.com db-creds vault-secrets-operator/force-sync="true" --overwrite
  1. Confirm that the value for the password in db-creds changed
apiVersion: v1
data:
  _raw: eyJwYXNzd29yZCI6IlBmSGZGMnZsanNTUVQtN1JyUURoIiwidXNlcm5hbWUiOiJ2LWt1YmVybmV0LW15LXJvbGUtT1FRamNWYzVvVEpHcFZNcUkwRm4tMTc0MTk0MDcxMyJ9
  password: UGZIZkYydmxqc1NRVC03UnJRRGg=
  username: di1rdWJlcm5ldC1teS1yb2xlLU9RUWpjVmM1b1RKR3BWTXFJMEZuLTE3NDE5NDA3MTM=
kind: Secret
metadata:
  creationTimestamp: "2025-03-14T08:21:24Z"
  labels:
    app.kubernetes.io/component: secret-sync
    app.kubernetes.io/managed-by: hashicorp-vso
    app.kubernetes.io/name: vault-secrets-operator
    secrets.hashicorp.com/vso-ownerRefUID: 5775f6fd-4cd0-4f77-b5e3-dba8befe1f88
  name: postgres-creds
  namespace: default
  ownerReferences:
  - apiVersion: secrets.hashicorp.com/v1beta1
    kind: VaultDynamicSecret
    name: db-creds
    uid: 5775f6fd-4cd0-4f77-b5e3-dba8befe1f88
  resourceVersion: "2712"
  uid: 0e99e731-8c08-412f-9305-e48d64ead271
type: Opaque

@jaireddjawed jaireddjawed self-assigned this Mar 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant