Skip to main content

Overview

The Secrets Store CSI Driver mode provides secret management for clusters where External Secrets Operator cannot be installed due to organizational policies, cluster restrictions, or existing CSI driver deployments.
When to Use CSI Driver vs External Secrets Operator:Use CSI Secret Store when:
  • External Secrets Operator cannot be installed in your cluster
  • Secrets Store CSI Driver is already deployed
  • Cluster policies restrict which operators can run
Use External Secrets Operator when:
  • You have flexibility to install ESO
  • You need multi-backend support (Vault, GCP, etc.)
  • You prefer a more declarative secret management approach
See External Secrets Operator Guide for ESO setup.

How It Works

The CSI Secret Store integration uses three components:
  1. SecretProviderClass: Defines which AWS Secrets Manager secrets to fetch and how to map them to Kubernetes Secret keys
  2. CSI Syncer Deployment: A minimal pod that mounts the CSI volume to materialize the Kubernetes Secret (the CSI driver requires an active mount)
  3. Kubernetes Secrets: Standard crewai-platform-secrets consumed by workloads (identical to inline or ESO modes)
Key Differences from External Secrets Operator:
  • CSI driver materializes secrets via volume mounts instead of a controller reconciliation loop
  • Requires a pod to keep the volume mounted (handled automatically by the chart’s csi-syncer deployment)
  • Currently supports AWS Secrets Manager only (ESO supports multiple backends)

Prerequisites

Before enabling CSI Secret Store mode, ensure the following components are installed in your cluster:

1. Secrets Store CSI Driver

Install the core CSI driver with syncSecret.enabled=true:
Critical: You must set syncSecret.enabled=true during installation. This feature cannot be enabled after initial installation without re-creating the driver.

2. AWS Provider for Secrets Store CSI Driver

Install the AWS-specific provider, pinned to a release tag:
Do not install this from the main branch. The provider is a privileged, node-level component that reads every secret this chart mounts, so fetching it from a moving branch means applying whatever that branch holds at the moment you run the command. Pin a tag, record the checksum you applied, and review the release notes before moving to a newer version.

3. IAM Permissions

Configure IAM permissions for the pods to access AWS Secrets Manager. Choose one method:

Setup Instructions

1. Prepare Secrets in AWS Secrets Manager

Create secrets in AWS Secrets Manager with the required structure.

Platform Secrets

Create a secret containing all platform keys as a flat JSON object:
Property Names: The chart expects lowercase, underscore-separated property names by default. Use csiSecret.propertyMap to override if your secrets use different naming conventions.

Database Password Secret

Create a separate secret for the database password:
Why Separate? Separating the database password allows for independent rotation without touching platform secrets.

OAuth Secrets (Optional)

If using the OAuth service (oauth.enabled: true), create OAuth secrets:
Add OAuth properties to the main platform secret:
No additional Helm configuration needed — csiSecret.oauthSecretPath defaults to csiSecret.secretPath.

2. Configure Helm Values

Create a values.yaml file with CSI Secret Store configuration:

3. Deploy the Chart

Install or upgrade the chart with CSI Secret Store enabled:
What Happens During Installation:
  1. SecretProviderClass Created (hook weight -40): Defines which secrets to fetch
  2. CSI Syncer Deployed (hook weight -40): Pod mounts CSI volume, materializing the Secret
  3. Wait Job Runs (hook weight -20): Validates all required keys are present
  4. Migrations Run (hook weights -5, 0): Database schema updates
  5. Workloads Start: Web, worker, and other pods consume the synced secrets

4. Verify Secret Synchronization

Check that secrets were successfully materialized:
Expected Output:

Configuration Scenarios

GitHub App Integration

When using GitHub App authentication (envVars.GITHUB_APP_ID set), add these properties to your platform secret:
The chart automatically includes these secrets when envVars.GITHUB_APP_ID is configured.

Auth Provider Integration

When using external auth providers (envVars.AUTH_PROVIDER set), add the provider-specific secret:

OAuth Provider Credentials

When the OAuth service is enabled, the chart requests each configured provider’s credentials automatically. You do not list them in oauthPropertyMap.
Base credentials only. The chart expands each provider’s base client ID and secret across all of that provider’s product integrations, exactly as inline mode does. Configuring Google means storing two properties, not sixteen: google_client_id and google_client_secret become GOOGLE_CAL_*, GOOGLE_GMAIL_*, GOOGLE_DRIVE_*, GOOGLE_CONTACTS_*, GOOGLE_SHEETS_*, GOOGLE_SLIDES_* and GOOGLE_DOCS_*. Microsoft behaves the same way across Outlook, OneDrive, SharePoint, Teams, Word and Excel, including the tenant ID when you set one.
The properties the chart requests, per provider configured under oauth.secrets: Example (Google and Microsoft):
The oauth.secrets.* blocks declare which providers are in use, which is what tells the chart to request their properties. In CSI mode the values themselves come from the backend, so the secret fields do not need to hold the real value.
Every property the chart requests must exist in the backend. The AWS provider fails the entire mount when any single property is missing, not just the one key, so adding a provider to oauth.secrets without adding its properties to Secrets Manager stops all secrets from syncing.

When to use oauthPropertyMap

Only two cases need it:
  1. Renaming a backend property. If your secret stores the Google client secret as google_oauth_secret rather than google_client_secret:
  2. A product-specific credential that differs from the provider default. If Gmail uses a different client than the rest of your Google integration, list that key so it is sourced from its own property instead of inheriting the base one:
An entry in oauthPropertyMap always wins over the fan-out for that one key; every other key keeps inheriting the provider default. See the OAuth Provider Credentials table for the complete list of keys the OAuth Secret can carry.

Optional Services

Wharf Service (wharf.enabled: true):
Wharf Database URL: Unlike External Secrets Operator (which can compose the URL from individual parts), CSI mode requires the complete wharf_postgres_url stored in AWS Secrets Manager. The CSI driver has no templating engine.
Cube.js Service (cube.enabled: true):

Rotating Secrets

To rotate secrets in CSI Secret Store mode:

1. Update Secret in AWS Secrets Manager

2. Trigger Secret Re-sync

The CSI driver periodically polls for updates (default: 2 minutes). To force immediate update, restart the CSI syncer pod:

3. Restart Workloads

Pods do not automatically reload secrets from the Secret resource. Trigger a rolling restart:
Automatic Rotation: Unlike External Secrets Operator (which supports reloadOnChange annotations), CSI mode requires manual pod restarts after secret updates. Consider implementing an automated restart mechanism if frequent rotation is required.

Limitations and Considerations

Compared to External Secrets Operator

Unsupported Features

TLS Auto-Generation: The chart’s web.tls.autoGenerate feature is not compatible with CSI mode. Alternatives:
  1. Store certificates in AWS Secrets Manager (properties: platform_ssl_key, platform_ssl_cert, crew_ssl_cert, crew_ssl_key)
  2. Terminate TLS externally (load balancer or ingress controller)
ArgoCD Deployments: CSI mode works with ArgoCD, but you must manually create secrets in AWS Secrets Manager before deployment. The chart cannot auto-generate secrets via lookup + randAlphaNum in GitOps workflows.

Security Best Practices

  1. Least Privilege IAM: Grant only secretsmanager:GetSecretValue and secretsmanager:DescribeSecret for specific secret ARNs
  2. Separate Secrets: Use different secrets for database, OAuth, and platform secrets for rotation isolation
  3. Enable CloudTrail: Audit secret access via AWS CloudTrail logs
  4. Rotate Regularly: Implement a secret rotation schedule (database passwords, API keys, etc.)
  5. Use IRSA: Prefer IRSA over node IAM roles for fine-grained permissions

Troubleshooting

Pods in CrashLoopBackOff

Symptom: Workload pods crash with “missing environment variable” errors. Cause: Secret not synced or missing required keys. Solution:
  1. Check CSI syncer pod status:
  2. Verify SecretProviderClass configuration:
  3. Check IAM permissions (pod should have secretsmanager:GetSecretValue):
  4. Validate secret exists in AWS Secrets Manager:

Wait Job Timeout

Symptom: Pre-upgrade wait job times out before secrets sync. Cause: CSI driver not installed or misconfigured. Solution:
  1. Verify CSI driver is running:
  2. Check if syncSecret.enabled=true:
    Output should include --enable-secret-rotation=true.

IAM Permission Errors

Symptom: CSI driver logs show AccessDeniedException from AWS Secrets Manager. Solution:
  1. Verify IAM role permissions:
  2. Check IRSA trust policy (if using IRSA):
  3. Verify ServiceAccount annotation:
    Should contain eks.amazonaws.com/role-arn: arn:aws:iam::... annotation.

Secret Property Not Found

Symptom: CSI driver logs show Property not found: <property_name>. Cause: JSON property name mismatch between AWS secret and chart expectations. Solution: Use csiSecret.propertyMap to override property names: