pushsecret-datato.md 12 KB

PushSecret dataTo Examples

This page provides practical examples of using the dataTo field in PushSecret to bulk-push secrets to external providers.

Prerequisites

Before using these examples, ensure you have:

  • External Secrets Operator installed in your cluster
  • A configured SecretStore (or ClusterSecretStore)
  • A source Kubernetes Secret with the data you want to push

Example 1: Basic Database Credentials Push

Push all database-related secrets with organized naming.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: myapp
type: Opaque
stringData:
  db-host: "prod-db.example.com"
  db-port: "5432"
  db-username: "app_user"
  db-password: "super-secret-password"
  db-database: "myapp_db"
  db-ssl-mode: "require"

PushSecret with dataTo:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-db-credentials
  namespace: myapp
spec:
  refreshInterval: 1h
  secretStoreRefs:
    - name: aws-secrets-manager
      kind: SecretStore
  selector:
    secret:
      name: db-credentials
  dataTo:
    - storeRef:
        name: aws-secrets-manager
      match:
        regexp: "^db-.*"
      rewrite:
        - regexp:
            source: "^db-"
            target: "myapp/production/database/"

Result in AWS Secrets Manager:

  • myapp/production/database/host
  • myapp/production/database/port
  • myapp/production/database/username
  • myapp/production/database/password
  • myapp/production/database/database
  • myapp/production/database/ssl-mode

Example 2: Multi-Environment Configuration

Push the same secrets to different environments with different prefixes.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: app-config
  namespace: myapp
type: Opaque
stringData:
  api-key: "abc123xyz"
  api-secret: "secret456"
  redis-url: "redis://cache:6379"
  postgres-url: "postgres://db:5432/mydb"

Development Environment:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-dev-config
  namespace: myapp
spec:
  secretStoreRefs:
    - name: vault-dev
  selector:
    secret:
      name: app-config
  dataTo:
    - storeRef:
        name: vault-dev
      rewrite:
        - regexp:
            source: "^"
            target: "dev/myapp/"

Production Environment:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-prod-config
  namespace: myapp
spec:
  secretStoreRefs:
    - name: vault-prod
  selector:
    secret:
      name: app-config
  dataTo:
    - storeRef:
        name: vault-prod
      rewrite:
        - regexp:
            source: "^"
            target: "prod/myapp/"

Example 3: Organizing Secrets by Category

Push different types of secrets to organized paths.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: mixed-secrets
  namespace: myapp
type: Opaque
stringData:
  db-host: "database.local"
  db-password: "dbpass"
  api-github-token: "ghp_xxx"
  api-stripe-key: "sk_live_xxx"
  tls-cert: "-----BEGIN CERTIFICATE-----"
  tls-key: "-----BEGIN PRIVATE KEY-----"

PushSecret with Multiple Patterns:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: organize-secrets
  namespace: myapp
spec:
  secretStoreRefs:
    - name: vault-store
  selector:
    secret:
      name: mixed-secrets
  dataTo:
    # Database credentials -> config/database/*
    - storeRef:
        name: vault-store
      match:
        regexp: "^db-.*"
      rewrite:
        - regexp:
            source: "^db-"
            target: "config/database/"

    # API keys -> config/api/*
    - storeRef:
        name: vault-store
      match:
        regexp: "^api-.*"
      rewrite:
        - regexp:
            source: "^api-"
            target: "config/api/"

    # TLS certificates -> config/tls/*
    - storeRef:
        name: vault-store
      match:
        regexp: "^tls-.*"
      rewrite:
        - regexp:
            source: "^tls-"
            target: "config/tls/"

Result:

  • config/database/host
  • config/database/password
  • config/api/github-token
  • config/api/stripe-key
  • config/tls/cert
  • config/tls/key

Example 4: Template Transformation

Use Go templates to transform key names with advanced logic.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: service-keys
  namespace: myapp
type: Opaque
stringData:
  payment-gateway-key: "pk_xxx"
  email-service-key: "es_xxx"
  storage-service-key: "ss_xxx"

PushSecret with Template: {% raw %}

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-service-keys
  namespace: myapp
spec:
  secretStoreRefs:
    - name: gcp-secret-manager
  selector:
    secret:
      name: service-keys
  dataTo:
    - storeRef:
        name: gcp-secret-manager
      rewrite:
        - transform:
            template: "services/{{ .value | upper | replace \"-\" \"_\" }}"

{% endraw %}

Result:

  • services/PAYMENT_GATEWAY_KEY
  • services/EMAIL_SERVICE_KEY
  • services/STORAGE_SERVICE_KEY

Example 5: Chained Transformations

Apply multiple transformations sequentially for complex key restructuring.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: legacy-secrets
  namespace: myapp
type: Opaque
stringData:
  old-db-primary-host: "db1.old.local"
  old-db-replica-host: "db2.old.local"
  old-cache-redis-url: "redis://old-cache:6379"

PushSecret with Chained Rewrites:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: migrate-legacy-secrets
  namespace: myapp
spec:
  secretStoreRefs:
    - name: aws-secrets-manager
  selector:
    secret:
      name: legacy-secrets
  dataTo:
    - storeRef:
        name: aws-secrets-manager
      rewrite:
        # First: Remove "old-" prefix
        - regexp:
            source: "^old-"
            target: ""
        # Second: Add "migrated/" prefix
        - regexp:
            source: "^"
            target: "migrated/"
        # Third: Replace hyphens with slashes for hierarchy
        - regexp:
            source: "-"
            target: "/"

Result:

  • migrated/db/primary/host
  • migrated/db/replica/host
  • migrated/cache/redis/url

Example 6: Override Specific Keys

Use both dataTo and explicit data to handle exceptions.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
  namespace: myapp
type: Opaque
stringData:
  db-host: "database.local"
  db-port: "5432"
  db-user: "app"
  db-password: "secret123"
  db-admin-password: "admin-secret"  # Should go to different location

PushSecret with Override:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-with-override
  namespace: myapp
spec:
  secretStoreRefs:
    - name: vault-store
  selector:
    secret:
      name: app-secrets
  # Push all db-* keys to app/database/*
  dataTo:
    - storeRef:
        name: vault-store
      match:
        regexp: "^db-.*"
      rewrite:
        - regexp:
            source: "^db-"
            target: "app/database/"

  # Except db-admin-password which goes to admin/
  data:
    - match:
        secretKey: db-admin-password
        remoteRef:
          remoteKey: admin/database/password

Result:

  • app/database/host (from dataTo)
  • app/database/port (from dataTo)
  • app/database/user (from dataTo)
  • app/database/password (from dataTo)
  • admin/database/password (from explicit data override)

Example 7: AWS Secrets Manager with Metadata

Push secrets with AWS-specific metadata tags.

PushSecret with Metadata:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-with-aws-tags
  namespace: myapp
spec:
  secretStoreRefs:
    - name: aws-secrets-manager
  selector:
    secret:
      name: app-config
  dataTo:
    - storeRef:
        name: aws-secrets-manager
      match:
        regexp: "^prod-.*"
      rewrite:
        - regexp:
            source: "^prod-"
            target: "myapp/prod/"
      metadata:
        tags:
          - key: Environment
            value: production
          - key: Application
            value: myapp
          - key: ManagedBy
            value: external-secrets-operator

Example 8: Vault with KV Version 2

Push secrets to HashiCorp Vault KV v2 engine with proper paths.

Source Secret:

apiVersion: v1
kind: Secret
metadata:
  name: vault-secrets
  namespace: myapp
type: Opaque
stringData:
  service-a-key: "key-a"
  service-b-key: "key-b"
  shared-secret: "shared"

PushSecret for Vault:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-to-vault
  namespace: myapp
spec:
  secretStoreRefs:
    - name: vault-kv-v2
  selector:
    secret:
      name: vault-secrets
  dataTo:
    # Service-specific secrets
    - storeRef:
        name: vault-kv-v2
      match:
        regexp: "^service-.*-key$"
      rewrite:
        - regexp:
            source: "^service-(.*)-key$"
            target: "services/$1/api-key"  # Use capture group

    # Shared secrets
    - storeRef:
        name: vault-kv-v2
      match:
        regexp: "^shared-.*"
      rewrite:
        - regexp:
            source: "^shared-"
            target: "shared/"

Result:

  • services/a/api-key
  • services/b/api-key
  • shared/secret

Example 9: Azure Key Vault

Push secrets to Azure Key Vault with naming constraints (alphanumeric and hyphens only).

PushSecret for Azure:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: push-to-azure
  namespace: myapp
spec:
  secretStoreRefs:
    - name: azure-key-vault
  selector:
    secret:
      name: app-secrets
  dataTo:
    - storeRef:
        name: azure-key-vault
      rewrite:
        # Azure Key Vault only allows alphanumeric and hyphens
        # Convert underscores to hyphens
        - regexp:
            source: "_"
            target: "-"
        # Add prefix
        - regexp:
            source: "^"
            target: "myapp-"

Example 10: Migration from One Provider to Another

Backup secrets from AWS to GCP while maintaining structure.

Step 1: Pull from AWS using ExternalSecret:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: pull-from-aws
  namespace: backup
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
  target:
    name: aws-backup-secrets
  dataFrom:
    - find:
        name:
          regexp: "^myapp/.*"

Step 2: Push to GCP with dataTo:

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
  name: backup-to-gcp
  namespace: backup
spec:
  secretStoreRefs:
    - name: gcp-secret-manager
  selector:
    secret:
      name: aws-backup-secrets
  dataTo:
    - storeRef:
        name: gcp-secret-manager
      rewrite:
        # Maintain structure but add backup prefix
        - regexp:
            source: "^"
            target: "backup-from-aws/"

Troubleshooting

Check PushSecret Status

kubectl get pushsecret <name> -n <namespace> -o yaml

Look for the status.conditions field for error messages.

View Synced Secrets

kubectl get pushsecret <name> -n <namespace> -o jsonpath='{.status.syncedPushSecrets}' | jq

Common Issues

1. No keys matched:

  • Verify the source Secret has keys matching your pattern
  • Check regexp syntax: kubectl get secret <name> -o jsonpath='{.data}' | jq 'keys'

2. Invalid regexp error:

  • Validate your regexp using an online regexp tester
  • Ensure special characters are properly escaped

3. Duplicate remote keys:

  • Check if your rewrites produce unique keys
  • Adjust patterns or use explicit data overrides

Best Practices

  1. Start with match-all to verify: Test with dataTo: [{storeRef: {name: your-store}}] first
  2. Test regexp patterns: Use kubectl get secret -o jsonpath='{.data}' | jq 'keys'
  3. Use descriptive patterns: Make regexp patterns self-documenting
  4. Monitor status: Check PushSecret status after creation
  5. Version control: Keep PushSecret manifests in git
  6. Document transformations: Add comments explaining complex rewrites

See Also