How-To: Reference secrets in components
Overview
Components can reference secrets for the spec.metadata section within the components definition.
In order to reference a secret, you need to set the auth.secretStore field to specify the name of the secret store that holds the secrets.
When running in Kubernetes, if the auth.secretStore is empty, the Kubernetes secret store is assumed.
Supported secret stores
Go to this link to see all the secret stores supported by Dapr, along with information on how to configure and use them.
Referencing secrets
While you have the option to use plain text secrets (like MyPassword), as shown in the yaml below for the value of redisPassword, this is not recommended for production:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: MyPassword
Instead create the secret in your secret store and reference it in the component definition. There are two cases for this shown below – the “Secret contains an embedded key” and the “Secret is a string”.
The “Secret contains an embedded key” case applies when there is a key embedded within the secret, i.e. the secret is not an entire connection string. This is shown in the following component definition yaml.
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
secretKeyRef:
name: redis-secret
key: redis-password
auth:
secretStore: <SECRET_STORE_NAME>
SECRET_STORE_NAME is the name of the configured secret store component. When running in Kubernetes and using a Kubernetes secret store, the field auth.SecretStore defaults to kubernetes and can be left empty.
The above component definition tells Dapr to extract a secret named redis-secret from the defined secretStore and assign the value associated with the redis-password key embedded in the secret to the redisPassword field in the component. One use of this case is when your code is constructing a connection string, for example putting together a URL, a secret, plus other information as necessary, into a string.
On the other hand, the below “Secret is a string” case applies when there is NOT a key embedded in the secret. Rather, the secret is just a string. Therefore, in the secretKeyRef section both the secret name and the secret key will be identical. This is the case when the secret itself is an entire connection string with no embedded key whose value needs to be extracted. Typically a connection string consists of connection information, some sort of secret to allow connection, plus perhaps other information and does not require a separate “secret”. This case is shown in the below component definition yaml.
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: servicec-inputq-azkvsecret-asbqueue
spec:
type: bindings.azure.servicebusqueues
version: v1
metadata:
- name: connectionString
secretKeyRef:
name: asbNsConnString
key: asbNsConnString
- name: queueName
value: servicec-inputq
auth:
secretStore: <SECRET_STORE_NAME>
The above “Secret is a string” case yaml tells Dapr to extract a connection string named asbNsConnstring from the defined secretStore and assign the value to the connectionString field in the component since there is no key embedded in the “secret” from the secretStore because it is a plain string. This requires the secret name and secret key to be identical.
Example
Referencing a Kubernetes secret
The following example shows you how to create a Kubernetes secret to hold the connection string for an Event Hubs binding.
First, create the Kubernetes secret:
kubectl create secret generic eventhubs-secret --from-literal=connectionString=*********Next, reference the secret in your binding:
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: eventhubs spec: type: bindings.azure.eventhubs version: v1 metadata: - name: connectionString secretKeyRef: name: eventhubs-secret key: connectionStringFinally, apply the component to the Kubernetes cluster:
kubectl apply -f ./eventhubs.yaml
Updating referenced secrets
Kubernetes secrets are hot reloaded
When running in Kubernetes and referencing secrets from the default kubernetes secret store (when auth.secretStore is set to kubernetes or left empty), Dapr automatically detects changes to the referenced Kubernetes secrets and reloads the affected components. No restart of the application pod or the Dapr sidecar is required.
Dapr reconciles components every 60 seconds. When the value of a referenced Kubernetes secret changes, hot reloading closes the component and re-initializes it using the new secret value.
For example, if the Redis state store from Referencing secrets was deployed to Kubernetes, then updating the referenced secret with the following command causes the state store component to be closed and re-initialized with the new password within 60 seconds. The same happens when the Kubernetes secret is updated by an external secret manager that keeps it in sync with an external source.
kubectl patch secret redis-secret --type merge -p '{"stringData":{"redis-password":"my-new-password"}}'
Note
Keep in mind the following when relying on this behavior:
- Changes to secret values are picked up by the periodic reconciler, so it can take up to 60 seconds for the new value to be applied.
- The component is unavailable for a short period of time while it is closed and re-initialized.
- This requires hot reloading to be enabled, which is the default. If the
HotReloadfeature is disabled, secret changes are only picked up when the Dapr sidecar is restarted. - Component types that are excluded from hot reloading include Actor state stores and Workflow backends, do not pick up secret changes and require a Dapr sidecar restart.
Other secret stores
Secrets referenced from any other secret store, for example HashiCorp Vault or Azure Key Vault configured through auth.secretStore, are resolved by the Dapr sidecar only once at start-up, when the component is initialized. Rotating a secret in these stores does not modify the Component definition, so the change is not detected by hot reloading and the component keeps using the value that was read at initialization time. To apply the new secret value, restart the Dapr sidecar, or trigger a hot reload by applying a change to the component manifest file.
To automatically pick up rotated secrets from an external secret manager when running in Kubernetes, sync the secrets into native Kubernetes secrets and reference them through the built-in kubernetes secret store as described above.
Scoping access to secrets
Dapr can restrict access to secrets in a secret store using its configuration. Read How To: Use secret scoping and How-To: Limit the secrets that can be read from secret stores for more information. This is the recommended way to limit access to secrets using Dapr.
Kubernetes permissions
Default namespace
When running in Kubernetes, Dapr, during installation, defines default Role and RoleBinding for secrets access from Kubernetes secret store in the default namespace. For Dapr enabled apps that fetch secrets from default namespace, a secret can be defined and referenced in components as shown in the example above.
Non-default namespaces
If your Dapr enabled apps are using components that fetch secrets from non-default namespaces, apply the following resources to that namespace:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: <NAMESPACE>
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dapr-secret-reader
namespace: <NAMESPACE>
subjects:
- kind: ServiceAccount
name: default
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
These resources grant Dapr permissions to get secrets from the Kubernetes secret store for the namespace defined in the Role and RoleBinding.
Note
In production scenario to limit Dapr’s access to certain secret resources alone, you can use theresourceNames field. See this link for further explanation.