How-To: Reference secrets in Dapr components

Learn how to manage secrets in Dapr components

This guide will provide an overview of how to:

Prerequisites

Step 1: Create a container and a Dapr sidecar

Begin by creating a file named app.bicep, which defines a container with a Dapr state store. If you need a detailed explanation on how to do so, refer to the Add a Dapr building block tutorial.

In this guide, you manually provision both a Redis instance and a Dapr state store component. Specify the Redis username in the Dapr state store, which will later be secured using a Dapr Secret Store.

extension radius

@description('The ID of your Radius Application. Automatically injected by the rad CLI.')
param application string

@description('The ID of your Radius environment. Automatically injected by the rad CLI.')
param environment string

resource demo 'Applications.Core/containers@2023-10-01-preview' = {
  name: 'demo'
  properties: {
    application: application
    container: {
      image: 'ghcr.io/radius-project/samples/demo:latest'
      ports: {
        web: {
          containerPort: 3000
        }
      }
    }
    extensions: [
      {
        kind: 'daprSidecar'
        appId: 'demo'
        appPort: 3000
      }
    ]
    connections: {
      redis: {
        source: stateStore.id
      }
    }
  }
}

resource redis 'Applications.Datastores/redisCaches@2023-10-01-preview' = {
  name: 'demo-redis-manual'
  properties: {
    environment: environment
    application: application
  }
}

resource stateStore 'Applications.Dapr/stateStores@2023-10-01-preview' = {
  name: 'demo-statestore'
  properties: {
    application: application
    environment: environment
    resourceProvisioning: 'manual'
    type: 'state.redis'
    version: 'v1'
    metadata: {
      redisHost: {
        value: '${redis.properties.host}:${redis.properties.port}'
      }
      // This value will be considered a secret later on
      redisUsername: {
        value: 'default'
      }
    }
  }
}

Deploy the application with the rad CLI:

rad run ./app.bicep -a demo-secret

While the application is running, verify that the redisUsername is exposed in the Dapr state store component by running the following command in another terminal:

kubectl -n default-demo-secret get component demo-statestore -o yaml

The output should look similar to:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: demo-statestore
  namespace: default-demo-secret
spec:
  metadata:
  - name: redisHost
    value: <HOST>
  - name: redisUsername
    # The Redis username is stored in plain text
    value: default
  type: state.redis
  version: v1

Step 2: Add a Dapr secret store resource and create a secret

Secure the Redis username using a Dapr Secret Store. In your app.bicep file, add a Dapr secret store resource. Use the local-dev recipe to deploy the secret store, leveraging Kubernetes secrets

extension radius

@description('The ID of your Radius Application. Automatically injected by the rad CLI.')
param application string

@description('The ID of your Radius environment. Automatically injected by the rad CLI.')
param environment string

resource demo 'Applications.Core/containers@2023-10-01-preview' = {
  name: 'demo'
  properties: {
    application: application
    container: {
      image: 'ghcr.io/radius-project/samples/demo:latest'
      ports: {
        web: {
          containerPort: 3000
        }
      }
    }
    extensions: [
      {
        kind: 'daprSidecar'
        appId: 'demo'
        appPort: 3000
      }
    ]
    connections: {
      redis: {
        source: stateStore.id
      }
    }
  }
}

resource redis 'Applications.Datastores/redisCaches@2023-10-01-preview' = {
  name: 'demo-redis-manual'
  properties: {
    environment: environment
    application: application
  }
}

resource stateStore 'Applications.Dapr/stateStores@2023-10-01-preview' = {
  name: 'demo-statestore'
  properties: {
    // The secret store to pull secret store 
    auth: {
      secretStore: secretstore.name
    }
    application: application
    environment: environment
    resourceProvisioning: 'manual'
    type: 'state.redis'
    version: 'v1'
    metadata: {
      redisHost: {
        value: '${redis.properties.host}:${redis.properties.port}'
      }
      redisUsername: {
        secretKeyRef: {
          // Secret object name 
          name: 'redis-auth'
          // Secret key
          key: 'username'
        }
      }
    }
  }
}

resource secretstore 'Applications.Dapr/secretStores@2023-10-01-preview' = {
  name: 'secretstore'
  properties: {
    environment: environment
    application: application
  }
}

Visit the Radius Recipe repo to learn more about local-dev Recipes and view the Dapr Secret Store Recipe used in this guide.

Now, create a Kubernetes secret for the Redis username by creating a redis-auth.yaml file with the following content:

apiVersion: v1
kind: Secret
metadata:
  name: redis-auth
  namespace: default-demo-secret
type: opaque
data:
  # Result of "echo -n 'default' | base64"
  username: ZGVmYXVsdA==

Apply the secret to your Kubernetes cluster by running:

kubectl apply -f redis-auth.yaml

Step 3: Configure the Dapr state store to use the Dapr secret store

Finally, update your Dapr state store to reference the created secret.

extension radius

@description('The ID of your Radius Application. Automatically injected by the rad CLI.')
param application string

@description('The ID of your Radius environment. Automatically injected by the rad CLI.')
param environment string

resource demo 'Applications.Core/containers@2023-10-01-preview' = {
  name: 'demo'
  properties: {
    application: application
    container: {
      image: 'ghcr.io/radius-project/samples/demo:latest'
      ports: {
        web: {
          containerPort: 3000
        }
      }
    }
    extensions: [
      {
        kind: 'daprSidecar'
        appId: 'demo'
        appPort: 3000
      }
    ]
    connections: {
      redis: {
        source: stateStore.id
      }
    }
  }
}

resource redis 'Applications.Datastores/redisCaches@2023-10-01-preview' = {
  name: 'demo-redis-manual'
  properties: {
    environment: environment
    application: application
  }
}

resource stateStore 'Applications.Dapr/stateStores@2023-10-01-preview' = {
  name: 'demo-statestore'
  properties: {
    // The secret store to pull secret store 
    auth: {
      secretStore: secretstore.name
    }
    application: application
    environment: environment
    resourceProvisioning: 'manual'
    type: 'state.redis'
    version: 'v1'
    metadata: {
      redisHost: {
        value: '${redis.properties.host}:${redis.properties.port}'
      }
      redisUsername: {
        secretKeyRef: {
          // Secret object name 
          name: 'redis-auth'
          // Secret key
          key: 'username'
        }
      }
    }
  }
}

resource secretstore 'Applications.Dapr/secretStores@2023-10-01-preview' = {
  name: 'secretstore'
  properties: {
    environment: environment
    application: application
  }
}

Step 4: Deploy the updated application

Deploy the application with the updated configuration:

rad run ./app.bicep -a demo-secret

You can verify that the Redis username is no longer exposed by running the following command in another terminal:

kubectl -n default-demo-secret get component demo-statestore -o yaml

The output should show the Redis username stored in the secret store:

apiVersion: dapr.io/v1alpha1
auth:
  secretStore: secretstore
kind: Component
metadata:
  name: demo-statestore
  namespace: default-demo-secret
spec:
  metadata:
  - name: redisHost
    value: <HOST>
  - name: redisUsername
    secretKeyRef:
      key: username
      name: redis-auth
  type: state.redis
  version: v1

Open http://localhost:3000 to view the Radius demo container. The TODO application should work as intended.

In a production environment, it’s recommended to use a more secure secret store, such as Azure Key Vault or HashiCorp Vault, instead of relying on Kubernetes secrets. You can find the list of all Dapr secret store components here.

Cleanup

To delete your app, run the rad app delete command to cleanup the app and its resources, including the Recipe resources:

rad app delete -a demo-secret
kubectl delete secret redis-auth -n default-demo-secret

Further reading