Skip to content
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

New Dapr Components Metadata Format + Tutorial on Referencing Secrets in Dapr Components #1234

Merged
merged 8 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions docs/content/guides/author-apps/dapr/how-to-dapr-secrets/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
type: docs
title: "How-To: Reference secrets in Dapr components"
linkTitle: "Reference secrets in components"
description: "Learn how to manage secrets in Dapr components"
weight: 300
categories: "How-To"
tags: ["Dapr"]
---

This how-to guide will provide an overview of how to:
willtsai marked this conversation as resolved.
Show resolved Hide resolved

- Securely manage secrets in Dapr components using [Dapr secret stores](https://docs.dapr.io/operations/components/setup-secret-store/)

## Prerequisites

- [rad CLI]({{< ref "installation#step-1-install-the-rad-cli" >}})
- [Bicep VSCode extension]({{< ref "installation#step-2-install-the-vs-code-extension" >}})
- [Radius environment]({{< ref "installation#step-3-initialize-radius" >}})
- [Radius local-dev Recipes]({{< ref howto-dev-recipes >}})
- [Dapr installed on your Kubernetes cluster](https://docs.dapr.io/operations/hosting/kubernetes/kubernetes-deploy/)

## Step 1: Start with a container and a Dapr sidecar
willtsai marked this conversation as resolved.
Show resolved Hide resolved

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]({{< ref how-to-dapr-building-block >}}) tutorial.
willtsai marked this conversation as resolved.
Show resolved Hide resolved

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.

{{< rad file="./snippets/app-statestore.bicep" embed=true >}}

Deploy the application with the `rad` CLI:

```bash
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**:
```sh
kubectl -n default-demo-secret get component demo-statestore -o yaml
```

The output should look similar to:
```yaml
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]({{< ref "guides/recipes/overview##use-lightweight-local-dev-recipes" >}}) to deploy the secret store, leveraging Kubernetes secrets

{{< rad file="./snippets/app-statestore-secret.bicep" embed=true marker="//SECRETSTORE" >}}

> Visit the [Radius Recipe repo](https://github.com/radius-project/recipes/blob/main/local-dev/secretstores.bicep) 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:
```yaml
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:
```sh
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.

{{< rad file="./snippets/app-statestore-secret.bicep" embed=true marker="//STATESTORE" >}}


## Step 4: Deploy the updated application

Deploy the application with the updated configuration:
```bash
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**:
```sh
kubectl -n default-demo-secret get component demo-statestore -o yaml
```

The output should show the Redis username stored in the secret store:
```yaml
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](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](https://docs.dapr.io/reference/components-reference/supported-secret-stores/).

## Cleanup

To delete your app, run the [rad app delete]({{< ref rad_application_delete >}}) command to cleanup the app and its resources, including the Recipe resources:

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

## Further reading

- [Dapr building blocks](https://docs.dapr.io/concepts/building-blocks-concept/)
- [Dapr resource schemas]({{< ref dapr-schema >}})

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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'
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ resource statestore 'Applications.Dapr/stateStores@2023-10-01-preview' = {
{ id: account::tableServices::table.id }
]
metadata: {
accountName: account.name
accountKey: account.listKeys().keys[0].value
tableName: account::tableServices::table.name
accountName: {
value: account.name
}
accountKey: {
value: account.listKeys().keys[0].value
}
tableName: {
value: account::tableServices::table.name
}
}
type: 'state.azure.tablestorage'
version: 'v1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@ resource stateStore 'Applications.Dapr/stateStores@2023-10-01-preview' = {
{ id: account::tableServices::table.id }
]
metadata: {
accountName: account.name
accountKey: account.listKeys().keys[0].value
tableName: account::tableServices::table.name
accountName: {
value: account.name
}
accountKey: {
value: account.listKeys().keys[0].value
}
tableName: {
value: account::tableServices::table.name
}
}
type: 'state.azure.tablestorage'
version: 'v1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ An `Applications.Dapr/pubSubBrokers` resource represents a [Dapr pub/sub](https:
| [recipe](#recipe) | n | Configuration for the Recipe which will deploy the backing infrastructure. | [See below](#recipe)
| [resources](#resources) | n | An array of resources which underlay this resource. For example, an Azure Service Bus namespace ID if the Dapr Pub/Sub resource is leveraging Service Bus. | [See below](#resources)
| type | n | The Dapr component type. Set only when resourceProvisioning is 'manual'. | `pubsub.kafka` |
| metadata | n | Metadata object for the Dapr component. Schema must match [Dapr component](https://docs.dapr.io/reference/components-reference/supported-pubsub/). Set only when resourceProvisioning is 'manual'. | `{ brokers: kafkaRoute.properties.url }` |
| metadata | n | Metadata object for the Dapr component. Schema must match [Dapr component](https://docs.dapr.io/reference/components-reference/supported-pubsub/). Set only when resourceProvisioning is 'manual'. | `{ brokers: { value: kafkaRoute.properties.url } }` |
| version | n | The version of the Dapr component. See [Dapr components](https://docs.dapr.io/reference/components-reference/supported-pubsub/) for available versions. Set only when resourceProvisioning is 'manual'. | `v1` |
| componentName | n | _(read-only)_ The name of the Dapr component that is generated and applied to the underlying system. Used by the Dapr SDKs or APIs to access the Dapr component. | `mypubsub` |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,15 @@ resource pubsub 'Applications.Dapr/pubSubBrokers@2023-10-01-preview' = {
resourceProvisioning: 'manual'
type: 'pubsub.kafka'
metadata: {
brokers: '<KAFKA-URL>'
authRequired: false
consumeRetryInternal: 1024
brokers: {
value: '<KAFKA-URL>'
}
authRequired: {
value: false
}
consumeRetryInternal: {
value: 1024
}
}
version: 'v1'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ This resource will automatically create and deploy the Dapr component spec for t
| [recipe](#recipe) | n | Configuration for the Recipe which will deploy the backing infrastructure. | [See below](#recipe)
| [resources](#resources) | n | An array of IDs of the underlying resources. | [See below](#resources)
| type | n | The Dapr component type. Used when resourceProvisioning is `manual`. | `secretstores.azure.keyvault`
| metadata | n | Metadata for the Dapr component. Schema must match [Dapr component](https://docs.dapr.io/reference/components-reference/supported-secret-stores/) | `vaultName: 'test'` |
| metadata | n | Metadata for the Dapr component. Schema must match [Dapr component](https://docs.dapr.io/reference/components-reference/supported-secret-stores/) | `{ vaultName: {value: 'test'} }` |
| version | n | The version of the Dapr component. See [Dapr components](https://docs.dapr.io/reference/components-reference/supported-secret-stores/) for available versions. | `v1` |
| componentName | n | _(read-only)_ The name of the Dapr component that is generated and applied to the underlying system. Used by the Dapr SDKs or APIs to access the Dapr component. | `mysecretstore` |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,18 @@ resource secretstore 'Applications.Dapr/secretStores@2023-10-01-preview' = {
resourceProvisioning: 'manual'
type: 'secretstores.azure.keyvault'
metadata: {
vaultName: 'myvault'
azureTenantId: '<GUID>'
azureClientId: '<GUID>'
azureClientSecret: '*****'
vaultName: {
value: 'myvault'
}
azureTenantId: {
value: '<GUID>'
}
azureClientId: {
value: '<GUID>'
}
azureClientSecret: {
value: '*****'
}
}
version: 'v1'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ This resource will automatically create and deploy the Dapr component spec for t
| [recipe](#recipe) | n | Configuration for the Recipe which will deploy the backing infrastructure. | [See below](#recipe)
| [resources](#resources) | n | An array of IDs of the underlying resources. | [See below](#resources)
| type | n | The Dapr component type. Used when `resourceProvisioning` is set to `manual`. | `state.couchbase`
| metadata | n | Metadata for the Dapr component. Schema must match [Dapr component](https://docs.dapr.io/reference/components-reference/supported-state-stores/). Used when `resourceProvisioning` is set to `manual`. | `couchbaseURL: https://*****` |
| metadata | n | Metadata for the Dapr component. Schema must match [Dapr component](https://docs.dapr.io/reference/components-reference/supported-state-stores/). Used when `resourceProvisioning` is set to `manual`. | `{ couchbaseURL: {value: 'https://*****' }` |
| version | n | The version of the Dapr component. See [Dapr components](https://docs.dapr.io/reference/components-reference/supported-state-stores/) for available versions. Used when `resourceProvisioning` is set to `manual`. | `v1` |
| componentName | n | _(read-only)_ The name of the Dapr component that is generated and applied to the underlying system. Used by the Dapr SDKs or APIs to access the Dapr component. | `mystatestore` |

Expand Down
Loading
Loading