1. Tutorials
  2. Integrate Pulumi with Secret Store CSI Driver in Kubernetes

Integrate Pulumi with Secret Store CSI Driver in Kubernetes

Container Storage Interface (CSI)

The Container Storage Interface (CSI) is a standard to unify the interface between container orchestrators (like Kubernetes) and different storage vendors (like NetApp, Ceph, etc.). This helps to guarantee that implementing a CSI for a storage vendor is going to work with all orchestrators that support CSI.

Combining CSI, Kubernetes and Secrets = Secret Store CSI Driver

The Kubernetes Secret Store CSI Driver allows you to mount secrets, certificates, and keys from external secret stores into Kubernetes pods as volumes. After attaching the volume, the system mounts the secrets into the container file system.

The benefits of using the Secret Store CSI Driver are that you manage the lifecycle of the secrets outside of Kubernetes while still providing a Kubernetes-native experience of using the secrets in your pods.

In this tutorial, you'll learn:

  • How to deploy the Secret Store CSI Driver and Pulumi ESC Provider using Helm or Pulumi
  • How to mount secrets stored in Pulumi ESC as volumes in your Kubernetes pods

Prerequisites:

Deploy Secret Store CSI Driver

Deploy using Helm

First, you need to deploy the Secret Store CSI Driver before you can install the Pulumi ESC provider.

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm repo update
helm upgrade -i csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver --namespace kube-system

Running the above helm upgrade -i command will install the Secret Store CSI Driver on Linux nodes in the kube-system namespace.

To validate the installer is running as expected, run the following commands:

kubectl get pods -n kube-system

You should see the csi-secrets-store pod running.

NAME                                               READY   STATUS    RESTARTS   AGE
csi-secrets-store-secrets-store-csi-driver-drv44   3/3     Running   0          54s

Additionally, you should see the following CRDs installed:

kubectl get crds | grep secrets-store
secretproviderclasses.secrets-store.csi.x-k8s.io            2025-01-02T14:03:58Z
secretproviderclasspodstatuses.secrets-store.csi.x-k8s.io   2025-01-02T14:03:58Z

Now that the Secret Store CSI Driver is running, you can deploy the Pulumi ESC Provider.

helm upgrade -i pulumi-esc-csi-provider oci://ghcr.io/pulumi/helm-charts/pulumi-esc-csi-provider --namespace kube-system

After a few seconds, the pulumi-esc-csi-provider should be running.

kubectl get pods -n kube-system -l app=pulumi-esc-csi-provider
NAME                            READY   STATUS    RESTARTS   AGE
pulumi-esc-csi-provider-l8w5f   1/1     Running   0          76s

Now with everything running, we can start using the Pulumi ESC provider to retrieve our secrets from Pulumi ESC.

Create secret containing Pulumi access token

kubectl create secret generic pulumi-secret-provider-auth-credentials --from-literal=pulumi-access-token=${PULUMI_ACCESS_TOKEN}

Create your own SecretProviderClass object

To use the Pulumi ESC provider, you need to create a SecretProviderClass object. This object tells the Secret Store CSI Driver how to connect to the Pulumi ESC provider.

cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: example-provider-pulumi-esc
  namespace: default
spec:
  provider: pulumi
  parameters:
    apiUrl: https://api.pulumi.com/api/esc
    organization: ${PULUMI_ORG}
    project:  ${ESC_PROJECT}
    environment: ${ESC_ENV}
    authSecretName: pulumi-secret-provider-auth-credentials
    authSecretNamespace: default
    secrets: |
      - secretPath: "/"
        fileName: "hello"
        secretKey: "app.hello"      
EOF

Please replace ${PULUMI_ORG}, ${ESC_PROJECT}, ${ESC_ENV} with your Pulumi organization, project, and environment names.

In the secrets section, you can define the secrets you want to retrieve from Pulumi ESC. secretPath is the path in the Pulumi ESC project where the secret is stored, fileName is the name of the file that will be created.

Now, we will create a secret in the Pulumi ESC project and synchronize it into the Kubernetes cluster by creating an SecretProviderClass:

Create a new ESC environment called csi-secrets-store-app in the esc-secrets-store-csi-driver-demo project:

values:
  app:
    hello: world
    hello-secret:
      fn::secret: world

If you prefer to use the Pulumi CLI, you can create the environment by running:

pulumi env init <your-org>/esc-secrets-store-csi-driver-demo/csi-secrets-store-app

And set the configuration by running the env edit command and copy the above YAML into the editor:

pulumi env edit <your-org>/esc-secrets-store-csi-driver-demo/csi-secrets-store-app

Either way, you should see following environment configuration in the Pulumi Cloud Console:

img_5.png

Now we can update our deployment to use the example-provider-pulumi-esc provider.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-provider-pulumi-esc
  namespace: default
  labels:
    app: example-provider-pulumi-esc
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example-provider-pulumi-esc
  template:
    metadata:
      labels:
        app: example-provider-pulumi-esc
    spec:
      containers:
      - name: client
        image: busybox:latest
        command: ["sh", "-c"]
        args:
        - |
          set -eux
          ls /run/secrets
          find /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*' | xargs -t -I {} sh -c 'echo "$(cat "{}")"'
          tail -f /dev/null          
        volumeMounts:
        - name: data
          mountPath: /run/secrets
      volumes:
      - name: data
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: "example-provider-pulumi-esc"

An important part of the deployment is the secretProviderClass: "example-provider-pulumi-esc" attribute in the volumeAttributes section. This tells the Secret Store CSI Driver to use the example-provider-pulumi-esc provider to retrieve the secrets.

On pod start or restart, the Secret Store CSI Driver will communicate with the Pulumi ESC provider to retrieve the secrets content from Pulumi ESC as defined in the SecretProviderClass object.

Then the volume is mounted in the pod as tmpfs and the secret contents are written to the mounted volume.

Now you can deploy the deployment and validate that the secrets are mounted in the pod.

kubectl apply -f deployment.yaml

Verify the secret is mounted in the pod

NAME=$(kubectl get pods -o name | grep example-provider-pulumi-esc | cut -d'/' -f2)
kubectl logs $NAME

You should see the secret content world printed to the console.

+ ls /run/secrets
hello
+ find /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*'
+ xargs -t -I '{}' sh -c 'echo "$(cat "{}")"'
sh -c echo "$(cat "/run/secrets/hello")"
world
+ tail -f /dev/null

Or you can exec into the pod and check the content of the mounted secret:

kubectl exec -it $NAME -- cat /run/secrets/hello

You should see the following output:

world

Cleanup

To uninstall the pulumi-esc-csi-provider deployment:

kubectl delete secret pulumi-secret-provider-auth-credentials
kubectl delete -f deployment.yaml
helm uninstall pulumi-esc-csi-provider
helm uninstall csi-secrets-store

Deploy using Pulumi

Of course, you can also deploy the CSI driver and Pulumi ESC provider using Pulumi. To do so, you can use the following Pulumi program:

Select your Pulumi supported language

Create a new Pulumi program in your preferred language and add the following code to deploy the External Secrets Operator.

pulumi new <your-preferred-language> --name external-secrets-operator

Before we dig into the code, let’s head to the Pulumi Cloud Console and create a new Pulumi ESC project with the name esc-secrets-store-csi-driver-demo.

img_3.png

And create the environment dev:

img_4.png

In the editor add the following yaml into the Environment definition:

values:
  pulumiConfig:
    pulumi-pat:
      fn::secret: <your-pulumi-pat>
import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

const secretsStoreCSIDriver = new k8s.helm.v4.Chart("secrets-store-csi-driver", {
    chart: "secrets-store-csi-driver",
    namespace: "kube-system",
    repositoryOpts: {
        repo: "https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts",
    },
    values: {
        nodeSelector: {
            "kubernetes.io/os": "linux",
        },
    },
});

const secretsStoreCSIPulumiESCProvider = new k8s.helm.v4.Chart(
    "secrets-store-csi-pulumi-esc-provider",
    {
        chart: "oci://ghcr.io/pulumi/helm-charts/pulumi-esc-csi-provider",
        namespace: "kube-system",
        values: {
            nodeSelector: {
                "kubernetes.io/os": "linux",
            },
        },
    },
    { dependsOn: secretsStoreCSIDriver },
);

const config = new pulumi.Config();

const mySecret = new k8s.core.v1.Secret(
    "my-secret",
    {
        metadata: {
            namespace: "default",
            name: "pulumi-access-token",
        },
        stringData: {
            "pulumi-access-token": config.require("pulumi-pat"),
        },
        type: "Opaque",
    },
    { dependsOn: secretsStoreCSIPulumiESCProvider },
);
"use strict";
const pulumi = require("@pulumi/pulumi");
const k8s = require("@pulumi/kubernetes");

const secretsStoreCSIDriver = new k8s.helm.v4.Chart("secrets-store-csi-driver", {
    chart: "secrets-store-csi-driver",
    namespace: "kube-system",
    repositoryOpts: {
        repo: "https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts",
    },
    values: {
        nodeSelector: {
            "kubernetes.io/os": "linux",
        },
    },
});

const secretsStoreCSIPulumiESCProvider = new k8s.helm.v4.Chart(
    "secrets-store-csi-pulumi-esc-provider",
    {
        chart: "oci://ghcr.io/pulumi/helm-charts/pulumi-esc-csi-provider",
        namespace: "kube-system",
        values: {
            nodeSelector: {
                "kubernetes.io/os": "linux",
            },
        },
    },
    { dependsOn: secretsStoreCSIDriver },
);

const config = new pulumi.Config();

const mySecret = new k8s.core.v1.Secret(
    "my-secret",
    {
        metadata: {
            namespace: "default",
            name: "pulumi-access-token",
        },
        stringData: {
            "pulumi-access-token": config.require("pulumi-pat"),
        },
        type: "Opaque",
    },
    { dependsOn: secretsStoreCSIPulumiESCProvider },
);
import pulumi
import pulumi_kubernetes as k8s

secrets_store_csi_driver = k8s.helm.v4.Chart(
    "secrets-store-csi-driver",
    k8s.helm.v4.ChartArgs(
        chart="secrets-store-csi-driver",
        namespace="kube-system",
        repository_opts=k8s.helm.v4.RepositoryOptsArgs(
            repo="https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts",
        ),
        values={
            "nodeSelector": {
                "kubernetes.io/os": "linux",
            },
        },
    ),
)

secrets_store_csi_pulumi_esc_provider = k8s.helm.v4.Chart(
    "secrets-store-csi-pulumi-esc-provider",
    k8s.helm.v4.ChartArgs(
        chart="oci://ghcr.io/pulumi/helm-charts/pulumi-esc-csi-provider",
        namespace="kube-system",
        values={
            "nodeSelector": {
                "kubernetes.io/os": "linux",
            },
        },
    ),
    opts=pulumi.ResourceOptions(depends_on=[secrets_store_csi_driver]),
)

config = pulumi.Config()

my_secret = k8s.core.v1.Secret(
    "my-secret",
    metadata=k8s.meta.v1.ObjectMetaArgs(
        namespace="default", name="pulumi-access-token"
    ),
    string_data={
        "pulumi-access-token": config.require("pulumi-pat"),
    },
    type="Opaque",
    opts=pulumi.ResourceOptions(depends_on=[secrets_store_csi_pulumi_esc_provider]),
)
package main

import (
	k8s "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
	"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apiextensions"
	appv1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apps/v1"
	corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
	chartv4 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v4"
	metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		secretsStoreCsiDriver, err := chartv4.NewChart(ctx, "secrets-store-csi-driver", &chartv4.ChartArgs{
			Chart:     pulumi.String("secrets-store-csi-driver"),
			Namespace: pulumi.String("kube-system"),
			RepositoryOpts: chartv4.RepositoryOptsArgs{
				Repo: pulumi.String("https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts"),
			},
			Values: pulumi.Map{
				"nodeSelector": pulumi.Map{
					"kubernetes.io/os": pulumi.String("linux"),
				},
			},
		})
		if err != nil {
			return err
		}

		secretsStoreCsiPulumiEscProvider, err := chartv4.NewChart(ctx, "secrets-store-csi-pulumi-esc-provider", &chartv4.ChartArgs{
			Chart:     pulumi.String("oci://ghcr.io/pulumi/helm-charts/pulumi-esc-csi-provider"),
			Namespace: pulumi.String("kube-system"),
			Values: pulumi.Map{
				"nodeSelector": pulumi.Map{
					"kubernetes.io/os": pulumi.String("linux"),
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{secretsStoreCsiDriver}))
		if err != nil {
			return err
		}

		pulumiPAT := config.Get(ctx, "pulumi-pat")

		mySecret, err := corev1.NewSecret(ctx, "my-secret", &corev1.SecretArgs{
			Metadata: &metav1.ObjectMetaArgs{
				Namespace: pulumi.String("default"),
				Name:      pulumi.String("pulumi-access-token"),
			},
			StringData: pulumi.StringMap{
				"pulumi-access-token": pulumi.String(pulumiPAT),
			},
			Type: pulumi.String("Opaque"),
		}, pulumi.DependsOn([]pulumi.Resource{secretsStoreCsiPulumiEscProvider}))
		if err != nil {
			return err
		}


		return nil
	})
}
using Pulumi;
using Pulumi.Kubernetes.Core.V1;
using Pulumi.Kubernetes.Types.Inputs.Core.V1;
using Pulumi.Kubernetes.Helm.V3;
using Pulumi.Kubernetes.Helm;
using Pulumi.Kubernetes.Types.Inputs.Meta.V1;
using Pulumi.Kubernetes.ApiExtensions;
using System.Collections.Generic;



return await Deployment.RunAsync(() =>
{
    var secretsStoreCsiDriver = new Release("secrets-store-csi-driver", new()
    {
        Chart = "secrets-store-csi-driver",
        Namespace = "kube-system",
        RepositoryOpts = new Pulumi.Kubernetes.Types.Inputs.Helm.V3.RepositoryOptsArgs
        {
            Repo = "https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts",
        },
        Values = new Dictionary<string, object>
        {
            { "nodeSelector", new Dictionary<string, object>
            {
                { "kubernetes.io/os", "linux" },
            } },
        },
    });

    var secretsStoreCsiPulumiEscProvider = new Release("secrets-store-csi-pulumi-esc-provider", new()
    {
        Chart = "oci://ghcr.io/pulumi/helm-charts/pulumi-esc-csi-provider",
        Namespace = "kube-system",
        Values = new Dictionary<string, object>
        {
            { "nodeSelector",  new Dictionary<string, object>
            {
                { "kubernetes.io/os", "linux" },
            } },
        },
    }, new CustomResourceOptions { DependsOn = { secretsStoreCsiDriver } });

    var config = new Config();
    var pulumiPAT = config.Require("pulumi-pat");

    var mySecret = new Secret("my-secret", new SecretArgs
    {
        Metadata = new ObjectMetaArgs
        {
            Namespace = "default",
            Name = "pulumi-access-token",
        },
        StringData =
        {
            { "pulumi-access-token", pulumiPAT }
        },
        Type = "Opaque",
    }, new CustomResourceOptions { DependsOn = { secretsStoreCsiPulumiEscProvider } });

});


class SecretProviderClassArgs : CustomResourceArgs
{
    public SecretProviderClassArgs(): base("secrets-store.csi.x-k8s.io/v1", "SecretProviderClass")
    {
    }

    [Input("spec")]
    public Input<SecretProviderClassSpecArgs>? Spec { get; set; }
}


class SecretProviderClassSpecArgs : ResourceArgs
{
    [Input("provider")]
    public Input<string>? Provider { get; set; }

    [Input("parameters")]
    public Input<InputMap<object>>? Parameters { get; set; }
}

class SecretProviderParametersArgs : ResourceArgs
{
    [Input("apiUrl")]
    public Input<string>? ApiUrl { get; set; }

    [Input("organization")]
    public Input<string>? Organization { get; set; }

    [Input("project")]
    public Input<string>? Project { get; set; }

    [Input("environment")]
    public Input<string>? Environment { get; set; }

    [Input("authSecretName")]
    public Input<string>? AuthSecretName { get; set; }

    [Input("authSecretNamespace")]
    public Input<string>? AuthSecretNamespace { get; set; }

    [Input("secrets")]
    public Input<string>? Secrets { get; set; }
}

Deploy the stack by running:

pulumi up

You will see that the secret was created in the Kubernetes cluster and the ESO instance was deployed successfully.

kubectl get secret pulumi-access-token -o jsonpath='{.data.PULUMI_ACCESS_TOKEN}' | base64 -d

Create a SecretProviderClass

const secretProviderClass = new k8s.apiextensions.CustomResource(
    "example-provider-pulumi-esc",
    {
        apiVersion: "secrets-store.csi.x-k8s.io/v1",
        kind: "SecretProviderClass",
        metadata: {
            name: "example-provider-pulumi-esc",
            namespace: "default",
        },
        spec: {
            provider: "pulumi",
            parameters: {
                apiUrl: "https://api.pulumi.com/api/esc",
                organization: "dirien",
                project: "esc-secrets-store-csi-driver-demo",
                environment: "csi-secrets-store-app",
                authSecretName: mySecret.metadata.name,
                authSecretNamespace: mySecret.metadata.namespace,
                secrets: `- secretPath: "/"
  fileName: "hello"
  secretKey: "app.hello"
`,
            },
        },
    },
    { dependsOn: secretsStoreCSIPulumiESCProvider },
);
const secretProviderClass = new k8s.apiextensions.CustomResource(
    "example-provider-pulumi-esc",
    {
        apiVersion: "secrets-store.csi.x-k8s.io/v1",
        kind: "SecretProviderClass",
        metadata: {
            name: "example-provider-pulumi-esc",
            namespace: "default",
        },
        spec: {
            provider: "pulumi",
            parameters: {
                apiUrl: "https://api.pulumi.com/api/esc",
                organization: "dirien",
                project: "esc-secrets-store-csi-driver-demo",
                environment: "csi-secrets-store-app",
                authSecretName: mySecret.metadata.name,
                authSecretNamespace: mySecret.metadata.namespace,
                secrets: `- secretPath: "/"
  fileName: "hello"
  secretKey: "app.hello"
`,
            },
        },
    },
    { dependsOn: secretsStoreCSIPulumiESCProvider },
);
secret_provider_class = k8s.apiextensions.CustomResource(
    "example-provider-pulumi-esc",
    api_version="secrets-store.csi.x-k8s.io/v1",
    kind="SecretProviderClass",
    metadata=k8s.meta.v1.ObjectMetaArgs(
        name="example-provider-pulumi-esc", namespace="default"
    ),
    spec={
        "provider": "pulumi",
        "parameters": {
            "apiUrl": "https://api.pulumi.com/api/esc",
            "organization": "dirien",
            "project": "esc-secrets-store-csi-driver-demo",
            "environment": "csi-secrets-store-app",
            "authSecretName": my_secret.metadata["name"],
            "authSecretNamespace": my_secret.metadata["namespace"],
            "secrets": '- secretPath: "/"\n  fileName: "hello"\n  secretKey: "app.hello"\n',
        },
    },
    opts=pulumi.ResourceOptions(depends_on=[secrets_store_csi_pulumi_esc_provider]),
)
		secretProviderClass, err := apiextensions.NewCustomResource(ctx, "example-provider-pulumi-esc", &apiextensions.CustomResourceArgs{
			ApiVersion: pulumi.String("secrets-store.csi.x-k8s.io/v1"),
			Kind:       pulumi.String("SecretProviderClass"),
			Metadata: &metav1.ObjectMetaArgs{
				Name:      pulumi.String("example-provider-pulumi-esc"),
				Namespace: pulumi.String("default"),
			},
			OtherFields: k8s.UntypedArgs{
				"provider": pulumi.String("pulumi"),
				"parameters": pulumi.Map{
					"apiUrl":              pulumi.String("https://api.pulumi.com/api/esc"),
					"organization":        pulumi.String("dirien"),
					"project":             pulumi.String("esc-secrets-store-csi-driver-demo"),
					"environment":         pulumi.String("csi-secrets-store-app"),
					"authSecretName":      mySecret.Metadata.Name().Elem(),
					"authSecretNamespace": mySecret.Metadata.Namespace().Elem(),
					"secrets": pulumi.String(`- secretPath: "/"
  fileName: "hello"
  secretKey: "app.hello"
`),
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{secretsStoreCsiPulumiEscProvider}))
		if err != nil {
			return err
		}
    var secretProviderClass = new Pulumi.Kubernetes.ApiExtensions.CustomResource("example-provider-pulumi-esc", new SecretProviderClassArgs
    {
        Metadata = new ObjectMetaArgs
        {
            Name = "example-provider-pulumi-esc",
            Namespace = "default",
        },
        Spec = new SecretProviderClassSpecArgs
        {
            Provider = "pulumi",
            Parameters = new InputMap<object>
            {
                { "apiUrl", "https://api.pulumi.com/api/esc" },
                { "organization", "dirien" },
                { "project", "esc-secrets-store-csi-driver-demo" },
                { "environment", "csi-secrets-store-app" },
                { "authSecretName", mySecret.Metadata.Apply(metadata => metadata.Name) },
                { "authSecretNamespace", mySecret.Metadata.Apply(metadata => metadata.Namespace) },
                { "secrets", "- secretPath: \"/\"\n  fileName: \"hello\"\n  secretKey: \"app.hello\"\n" }
            },
        },
    }, new CustomResourceOptions { DependsOn = { secretsStoreCsiPulumiEscProvider } });

We can check that the secret was successfully synchronized by running:

kubectl get secretproviderclasses example-provider-pulumi-esc

Deploy an Application and Mount the Secret

Now, we can deploy an application that references the secret from the Kubernetes cluster. I am going to use busybox that reads mounted file in.

const deployment = new k8s.apps.v1.Deployment("example-provider-pulumi-esc", {
    metadata: {
        name: "example-provider-pulumi-esc",
        namespace: "default",
        labels: {
            app: "example-provider-pulumi-esc",
        },
    },
    spec: {
        replicas: 1,
        selector: {
            matchLabels: {
                app: "example-provider-pulumi-esc",
            },
        },
        template: {
            metadata: {
                labels: {
                    app: "example-provider-pulumi-esc",
                },
            },
            spec: {
                containers: [
                    {
                        name: "client",
                        image: "busybox:latest",
                        command: ["sh", "-c"],
                        args: [
                            `set -eux
                            ls /run/secrets
                            find /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*' | xargs -t -I {} sh -c 'echo "$(cat "{}")"'
                            tail -f /dev/null`,
                        ],
                        volumeMounts: [
                            {
                                name: "data",
                                mountPath: "/run/secrets",
                            },
                        ],
                    },
                ],
                volumes: [
                    {
                        name: "data",
                        csi: {
                            driver: "secrets-store.csi.k8s.io",
                            readOnly: true,
                            volumeAttributes: {
                                secretProviderClass: secretProviderClass.metadata.name,
                            },
                        },
                    },
                ],
            },
        },
    },
});

export const deploymentName = deployment.metadata.name;
const deployment = new k8s.apps.v1.Deployment("example-provider-pulumi-esc", {
    metadata: {
        name: "example-provider-pulumi-esc",
        namespace: "default",
        labels: {
            app: "example-provider-pulumi-esc",
        },
    },
    spec: {
        replicas: 1,
        selector: {
            matchLabels: {
                app: "example-provider-pulumi-esc",
            },
        },
        template: {
            metadata: {
                labels: {
                    app: "example-provider-pulumi-esc",
                },
            },
            spec: {
                containers: [
                    {
                        name: "client",
                        image: "busybox:latest",
                        command: ["sh", "-c"],
                        args: [
                            `set -eux
                            ls /run/secrets
                            find /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*' | xargs -t -I {} sh -c 'echo "$(cat "{}")"'
                            tail -f /dev/null`,
                        ],
                        volumeMounts: [
                            {
                                name: "data",
                                mountPath: "/run/secrets",
                            },
                        ],
                    },
                ],
                volumes: [
                    {
                        name: "data",
                        csi: {
                            driver: "secrets-store.csi.k8s.io",
                            readOnly: true,
                            volumeAttributes: {
                                secretProviderClass: secretProviderClass.metadata.name,
                            },
                        },
                    },
                ],
            },
        },
    },
});

exports.deploymentName = deployment.metadata.name;
deployment = k8s.apps.v1.Deployment(
    "example-provider-pulumi-esc",
    metadata=k8s.meta.v1.ObjectMetaArgs(
        namespace="default",
        name="example-provider-pulumi-esc",
        labels={
            "app": "example-provider-pulumi-esc",
        },
    ),
    spec=k8s.apps.v1.DeploymentSpecArgs(
        replicas=1,
        selector=k8s.meta.v1.LabelSelectorArgs(
            match_labels={
                "app": "example-provider-pulumi-esc",
            },
        ),
        template=k8s.core.v1.PodTemplateSpecArgs(
            metadata=k8s.meta.v1.ObjectMetaArgs(
                labels={
                    "app": "example-provider-pulumi-esc",
                },
            ),
            spec=k8s.core.v1.PodSpecArgs(
                containers=[
                    k8s.core.v1.ContainerArgs(
                        name="client",
                        image="busybox:latest",
                        command=["sh", "-c"],
                        args=[
                            "set -eux\nls /run/secrets\nfind /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*' | xargs -t -I {} sh -c 'echo \"$(cat \"{}\")\"'\ntail -f /dev/null",
                        ],
                        volume_mounts=[
                            k8s.core.v1.VolumeMountArgs(
                                name="data",
                                mount_path="/run/secrets",
                            ),
                        ],
                    ),
                ],
                volumes=[
                    k8s.core.v1.VolumeArgs(
                        name="data",
                        csi=k8s.core.v1.CSIVolumeSourceArgs(
                            driver="secrets-store.csi.k8s.io",
                            read_only=True,
                            volume_attributes={
                                "secretProviderClass": secret_provider_class.metadata[
                                    "name"
                                ],
                            },
                        ),
                    ),
                ],
            ),
        ),
    ),
)

pulumi.export("deploymentName", deployment.metadata["name"])
		deployment, err := appv1.NewDeployment(ctx, "example-provider-pulumi-esc", &appv1.DeploymentArgs{
			Metadata: &metav1.ObjectMetaArgs{
				Name:      pulumi.String("example-provider-pulumi-esc"),
				Namespace: pulumi.String("default"),
				Labels: pulumi.StringMap{
					"app": pulumi.String("example-provider-pulumi-esc"),
				},
			},
			Spec: &appv1.DeploymentSpecArgs{
				Replicas: pulumi.Int(1),
				Selector: &metav1.LabelSelectorArgs{
					MatchLabels: pulumi.StringMap{
						"app": pulumi.String("example-provider-pulumi-esc"),
					},
				},
				Template: &corev1.PodTemplateSpecArgs{
					Metadata: &metav1.ObjectMetaArgs{
						Labels: pulumi.StringMap{
							"app": pulumi.String("example-provider-pulumi-esc"),
						},
					},
					Spec: &corev1.PodSpecArgs{
						Containers: corev1.ContainerArray{
							&corev1.ContainerArgs{
								Name:  pulumi.String("client"),
								Image: pulumi.String("busybox:latest"),
								Command: pulumi.StringArray{
									pulumi.String("sh"),
									pulumi.String("-c"),
								},
								Args: pulumi.StringArray{
									pulumi.String(`set -eux
                            ls /run/secrets
                            find /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*' | xargs -t -I {} sh -c 'echo "$(cat "{}")"'
                            tail -f /dev/null`),
								},
								VolumeMounts: &corev1.VolumeMountArray{
									&corev1.VolumeMountArgs{
										Name:      pulumi.String("data"),
										MountPath: pulumi.String("/run/secrets"),
									},
								},
							},
						},
						Volumes: &corev1.VolumeArray{
							&corev1.VolumeArgs{
								Name: pulumi.String("data"),
								Csi: corev1.CSIVolumeSourceArgs{
									Driver:   pulumi.String("secrets-store.csi.k8s.io"),
									ReadOnly: pulumi.Bool(true),
									VolumeAttributes: pulumi.StringMap{
										"secretProviderClass": secretProviderClass.Metadata.Name().Elem(),
									},
								},
							},
						},
					},
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{secretProviderClass}))
		if err != nil {
			return err
		}
    var deployment = new Pulumi.Kubernetes.Apps.V1.Deployment("example-provider-pulumi-esc", new Pulumi.Kubernetes.Types.Inputs.Apps.V1.DeploymentArgs
    {
        Metadata = new ObjectMetaArgs
        {
            Name = "example-provider-pulumi-esc",
            Namespace = "default",
            Labels =
            {
                { "app", "example-provider-pulumi-esc" },
            },
        },
        Spec = new Pulumi.Kubernetes.Types.Inputs.Apps.V1.DeploymentSpecArgs
        {
            Replicas = 1,
            Selector = new Pulumi.Kubernetes.Types.Inputs.Meta.V1.LabelSelectorArgs
            {
                MatchLabels =
                {
                    { "app", "example-provider-pulumi-esc" },
                },
            },
            Template = new Pulumi.Kubernetes.Types.Inputs.Core.V1.PodTemplateSpecArgs
            {
                Metadata = new ObjectMetaArgs
                {
                    Labels =
                    {
                        { "app", "example-provider-pulumi-esc" },
                    },
                },
                Spec = new Pulumi.Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
                {
                    Containers =
                    {
                        new Pulumi.Kubernetes.Types.Inputs.Core.V1.ContainerArgs
                        {
                            Name = "client",
                            Image = "busybox:latest",
                            Command =
                            {
                                "sh",
                                "-c",
                            },
                            Args =
                            {
                                "set -eux\nls /run/secrets\nfind /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*' | xargs -t -I {} sh -c 'echo \"$(cat \"{}\")\"'\ntail -f /dev/null",
                            },
                            VolumeMounts =
                            {
                                new Pulumi.Kubernetes.Types.Inputs.Core.V1.VolumeMountArgs
                                {
                                    Name = "data",
                                    MountPath = "/run/secrets",
                                },
                            },
                        },
                    },
                    Volumes =
                    {
                        new Pulumi.Kubernetes.Types.Inputs.Core.V1.VolumeArgs
                        {
                            Name = "data",
                            Csi = new Pulumi.Kubernetes.Types.Inputs.Core.V1.CSIVolumeSourceArgs
                            {
                                Driver = "secrets-store.csi.k8s.io",
                                ReadOnly = true,
                                VolumeAttributes =
                                {
                                    { "secretProviderClass", secretProviderClass.Metadata.Apply(metadata => metadata.Name) },
                                },
                            },
                        },
                    },
                },
            },
        },
    }, new CustomResourceOptions { DependsOn = { secretProviderClass } });

After deploying the stack, you can get the logs of the busybox pod to see that the secret was successfully mounted:

NAME=$(kubectl get pods -o name | grep example-provider-pulumi-esc | cut -d'/' -f2)
kubectl logs $NAME

You should see the following output:

+ ls /run/secrets
hello
+ find /run/secrets/ -mindepth 1 -maxdepth 1 -not -name '.*'
+ xargs -t -I '{}' sh -c 'echo "$(cat "{}")"'
sh -c echo "$(cat "/run/secrets/hello")"
world
+ tail -f /dev/null

Or you can exec into the pod and check the content of the mounted secret:

kubectl exec -it $NAME -- cat /run/secrets/hello

You should see the following output:

world

Cleanup

To uninstall the pulumi-esc-csi-provider deployment:

pulumi destroy

Next Steps

In this tutorial, you learned how to integrate the Secret Store CSI Driver with Pulumi ESC to securely manage your secrets in Kubernetes. To learn more about Pulumi ESC, check out the Pulumi ESC documentation.

As we continue to improve the Pulumi ESC provider, we would love to hear your feedback. Please reach out to us on Slack or GitHub with any questions or suggestions.

To dive deeper into using Pulumi ESC for advanced scenarios, check out the following resources:

  • Pulumi ESC and External Secrets Operator: Learn how to use the External Secrets Operator to manage secrets in Pulumi ESC and synchronize them with your Kubernetes cluster. Check out the Pulumi ESC and External Secrets Operator tutorial.
  • Environment Composition: Learn more about how to effectively compose multiple environments to manage configurations across your infrastructure. Explore the Pulumi documentation on environment imports.
  • Managing Secrets: Learn how to securely manage and adopt dynamic, short-lived secrets on demand using Pulumi ESC, ensuring sensitive information is protected across different environments. Read more in the Pulumi ESC documentation.