Policies
Reference for the declarative manifests that define Diagrid policies. For the conceptual story see Policies. For end-to-end usage see IDs.
Policies are applied with the diagrid CLI. The target project is provided by the --project flag, not by a field in the manifest:
diagrid configuration create -f configuration.yaml --project my-project
diagrid workflow access-policy create -f workflow-access-policy.yaml --project my-project
Manifest envelope
Every policy manifest shares the same top-level shape:
apiVersion: dapr.io/v1alpha1
kind: <Configuration | WorkflowAccessPolicy>
metadata:
name: <policy-name>
scopes:
- <app-id-1>
- <app-id-2>
spec:
# ...kind-specific spec below
| Field | Type | Required | Description |
|---|---|---|---|
apiVersion | string | yes | Must be dapr.io/v1alpha1. |
kind | string | yes | Configuration or WorkflowAccessPolicy. |
metadata.name | string | yes | Unique policy name within the project. |
scopes | string[] | no | Workloads the policy applies to. Top-level (sibling of spec). Omit to leave the policy unbound — except for WorkflowAccessPolicy, where omitting scopes applies the policy to every app in the project. |
Configuration
A configuration sets app-level runtime behaviour: access control lists, HTTP pipelines, distributed tracing (private regions only), and workflow runtime parameters. For the access-control rules model and the CLI commands to manage them, see Secure service invocation with access control.
Spec
spec:
accessControl:
defaultAction: allow | deny
trustDomain: <trust-domain> # ignored: set by the platform
policies:
- appId: <caller-app-id>
defaultAction: allow | deny
trustDomain: <trust-domain>
namespace: <namespace> # ignored: set by the platform
operations:
- name: <operation-name>
httpVerb: ["GET", "POST", ...]
action: allow | deny
appHttpPipeline:
handlers:
- name: <middleware-name>
type: <middleware-type>
httpPipeline:
handlers:
- name: <middleware-name>
type: <middleware-type>
tracing: # private regions only
samplingRate: "<float-as-string>"
otel:
endpointAddress: <url>
isSecure: <bool>
protocol: <http | grpc>
timeout: <duration>
headers:
- name: <header-name>
value: <header-value>
- name: <header-name>
secretKeyRef:
name: <secret-name>
key: <field-in-secret>
workflow:
maxConcurrentWorkflowInvocations: <int> # private regions only
maxConcurrentActivityInvocations: <int> # private regions only
globalMaxConcurrentWorkflowInvocations: <int> # accepted, not yet enforced
globalMaxConcurrentActivityInvocations: <int> # accepted, not yet enforced
workflowConcurrencyLimits:
- name: <workflow-name>
maxConcurrent: <int>
activityConcurrencyLimits:
- name: <activity-name>
maxConcurrent: <int>
stateRetentionPolicy:
completed: <duration>
failed: <duration>
terminated: <duration>
anyTerminal: <duration>
Field reference
| Field | Notes |
|---|---|
accessControl | Service-invocation ACLs. The top-level defaultAction applies when no per-caller policy matches. Per-caller policies[] can refine to specific operations and HTTP verbs. defaultAction and action accept only allow or deny; httpVerb accepts only the nine standard HTTP methods; a policies[] entry must set appId and every operations[] entry must set name. |
accessControl.trustDomain | Top-level only. Set by the platform: a value you supply is accepted and then discarded, on create and on update alike. |
accessControl.policies[].trustDomain | Yours to set, and kept. Leave it out and it defaults to your organization's trust domain, which is what you want unless you are naming a caller from somewhere else. |
accessControl.policies[].namespace | Set by the platform. Whatever you supply is replaced with your project's namespace, prj-<project-namespace>, because that is the namespace the access-control decision is actually made against. |
appHttpPipeline | Middleware applied to traffic from the data plane to your application (inbound to the app). |
httpPipeline | Middleware applied to traffic from your application out through the data plane (outbound). |
tracing | Distributed tracing config. Only honored on projects in private regions. samplingRate is a string between "0" and "1". |
tracing.otel.headers | Headers added to every OTLP exporter request. Give each entry a name and then one of value (plaintext), secretKeyRef (a name/key pair naming a secret and the field in it), or envRef (an environment variable to read the value from). |
tracing.otel.timeout | Duration string bounding each OTLP exporter request. |
workflow.maxConcurrentWorkflowInvocationsworkflow.maxConcurrentActivityInvocations | Per-sidecar ceilings: the most a single Dapr instance schedules at once. Invocations beyond the ceiling queue rather than fail. These are never unlimited — omit them and Diagrid applies its own ceilings of 5000 concurrent workflows and 10000 concurrent activities per sidecar. You can lower them but not raise them: a value above the ceiling is ignored and the ceiling stands, with no error. Honored in private regions only — see the note below. |
workflow.globalMaxConcurrentWorkflowInvocationsworkflow.globalMaxConcurrentActivityInvocations | The same ceilings across every replica rather than per sidecar. Not enforced yet: Diagrid accepts and stores both fields and does not pass them to the workflow engine, so setting one changes nothing today. Use the per-name limits below to bound concurrency across replicas. |
workflow.workflowConcurrencyLimitsworkflow.activityConcurrencyLimits | Per-name ceilings, enforced across every replica by the scheduler. Each entry takes a name (the workflow or activity name to limit) and a maxConcurrent. Names must be non-empty and unique within a list, and maxConcurrent must be non-negative. |
workflow.stateRetentionPolicy | How long a workflow instance's state is kept after it reaches a terminal state, after which it is purged automatically. Set completed, failed or terminated per state, or anyTerminal for all of them; a specific state wins over anyTerminal. Values are duration strings such as 72h or 30m, including 0s to purge immediately. Omit the whole block and instances are never purged automatically. |
Some of this spec is accepted and then overwritten, with no error to tell you so. accessControl.trustDomain is always cleared and accessControl.policies[].namespace is always replaced, because the platform owns both. On a project in a public region, workflow.maxConcurrentWorkflowInvocations and workflow.maxConcurrentActivityInvocations are cleared too — read them back with diagrid configuration get and they are gone, and Diagrid's own per-sidecar ceilings apply instead. The per-name limits and stateRetentionPolicy are kept and honored in every region. The global... ceilings are also kept, but nothing reads them yet. To bound concurrency in a public region, use the per-name limits.
Worked example
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: order-service-config
spec:
accessControl:
defaultAction: deny
policies:
- appId: api-gateway
defaultAction: deny
operations:
- name: /orders
httpVerb: ["POST"]
action: allow
workflow:
workflowConcurrencyLimits:
- name: OrderProcess
maxConcurrent: 20
activityConcurrencyLimits:
- name: ChargePayment
maxConcurrent: 5
stateRetentionPolicy:
completed: 24h
anyTerminal: 72h
The top-level accessControl.trustDomain and the per-caller namespace are left out because the platform sets both, and policies[].trustDomain is left out so it defaults to your organization's. The limits and the retention policy above are honored in every region. Add maxConcurrentWorkflowInvocations and maxConcurrentActivityInvocations only for a project in a private region, where they are not dropped, and only to lower Diagrid's per-sidecar ceilings.
Workflow access policy
A workflow access policy is an allow-list that controls which caller apps can schedule workflows and activities on the apps in scopes. Without a policy, all cross-app workflow calls are allowed; once a policy covers an app, every cross-app call must match a rule or it is denied. Self-calls are always allowed. For the conceptual story and CLI walkthrough see Secure workflows with access policies.
Spec
spec:
rules:
- callers:
- appID: <caller-app-id>
workflows:
- name: <workflow-name or glob>
operations: [schedule]
activities:
- name: <activity-name or glob>
Field reference
| Field | Type | Required | Description |
|---|---|---|---|
rules | list | no | Allow-list of rules; a call is permitted if any rule matches. An empty or omitted list denies every cross-app workflow call to the scoped apps. |
rules[].callers | list | yes | Caller apps this rule grants access to. At least one entry. |
rules[].callers[].appID | string | yes | The ID of the calling application. |
rules[].workflows | list | no* | Workflow rules granted to the matched callers. |
rules[].workflows[].name | string | yes | Exact workflow name or glob pattern (*, ?, [abc]). |
rules[].workflows[].operations | string[] | yes | Set to [schedule]. The API also accepts terminate, raise, pause, resume, purge, get, and rerun for forward compatibility, but these operations don't route cross-app yet, so policies have no effect on them. |
rules[].activities | list | no* | Activity rules granted to the matched callers. Activities only support scheduling, so there is no operations field. |
rules[].activities[].name | string | yes | Exact activity name or glob pattern. |
* At least one of workflows or activities must be present in each rule.
Worked example
apiVersion: dapr.io/v1alpha1
kind: WorkflowAccessPolicy
metadata:
name: order-app-policy
scopes:
- order-app
spec:
rules:
- callers:
- appID: orchestrator-app
workflows:
- name: order-processing
operations: [schedule]
- name: "report-*"
operations: [schedule]
activities:
- name: charge-payment
Applying and inspecting policies
# Apply or update
diagrid configuration create -f configuration.yaml --project <project>
diagrid configuration update <name> -f configuration.yaml --project <project>
diagrid apply -f configuration.yaml --project <project>
diagrid workflow access-policy create -f workflow-access-policy.yaml --project <project>
diagrid workflow access-policy update -f workflow-access-policy.yaml --project <project>
# Inspect
diagrid configuration list --project <project>
diagrid configuration get <name> --project <project>
diagrid workflow access-policy list --project <project>
diagrid workflow access-policy get <name> --project <project>
# Remove
diagrid configuration delete <name> --project <project>
diagrid workflow access-policy delete <name> --project <project>
A configuration can also be edited without a manifest. diagrid configuration create and diagrid configuration update take the same set of inline flags — --default-action, --policy, the --tracing-* flags, the --workflow-* and --activity-concurrency-limit flags, and the pipeline-handler flags — as an alternative to --file. On update, those flags merge section by section: a section is touched only when at least one of its flags is set, and fields you leave out keep their current value. To replace a configuration wholesale instead, pass --file or use diagrid apply -f.
See the diagrid configuration CLI reference for its full flag set.
See also
- Policies: conceptual overview.
- Secure workflows with access policies: workflow access policies end to end.
- Secure service invocation with access control: service-invocation ACLs end to end.
- IDs: how policies are bound and managed day-2.