diff --git a/app/_data/kuma_to_mesh/config.yaml b/app/_data/kuma_to_mesh/config.yaml index a140e6a9f9..cc8489b20c 100644 --- a/app/_data/kuma_to_mesh/config.yaml +++ b/app/_data/kuma_to_mesh/config.yaml @@ -73,16 +73,6 @@ pages: url: /mesh/concepts/ - text: Service discovery url: /mesh/service-discovery/ - - - path: app/_src/policies/introduction.md - title: 'Policies' - description: 'Learn how policies in Kong Mesh configure Data Plane proxies by defining rules for traffic behavior, proxy targeting, and merging strategies. This reference covers `targetRef`, directional policies, producer/consumer scopes, and shadow mode simulation.' - url: '/mesh/policies-introduction/' - related_resources: - - text: Policy hub - url: '/mesh/policies/' - - text: Service meshes - url: /mesh/service-mesh/ - path: app/_src/production/deployment/multi-zone.md title: 'Multi-zone deployment' diff --git a/app/mesh/policies-introduction.md b/app/mesh/policies-introduction.md new file mode 100644 index 0000000000..5193b260eb --- /dev/null +++ b/app/mesh/policies-introduction.md @@ -0,0 +1,382 @@ +--- +title: "Policies" +description: 'Learn how to write and configure policies in {{ site.mesh_product_name }}, including policy roles, targetRef, and merging strategies.' +content_type: reference +layout: reference +products: + - mesh +breadcrumbs: + - /mesh/ + +tags: + - policy + - service-mesh + +related_resources: + - text: Policy hub + url: '/mesh/policies/' + - text: Service meshes + url: /mesh/service-mesh/ + +min_version: + mesh: '2.13' +--- + +Policies in {{ site.mesh_product_name }} let you **declare how traffic and workloads should behave**, +instead of configuring each [data plane proxy](/mesh/data-plane-proxy/) by hand. +They're the main way to enable features like mTLS, traffic permissions, retries, rate limits, access logging, and more. + +Every policy follows the same pattern: + +* **Target** – which workloads the policy applies to (`targetRef`) +* **Direction** – whether it controls outbounds (`to`) or inbounds (`rules`) +* **Behaviour** – the actual configuration (`default`) applied to the traffic + +For example, a policy that configures timeouts: + +```yaml +type: MeshTimeout +name: my-app-timeout +mesh: default +spec: + targetRef: # Target. Policy applies only to workloads with label `app: my-app` + kind: Dataplane + labels: + app: my-app + to: # Direction. Policy applies to outbound listener for `database` MeshService + - targetRef: + kind: MeshService + name: database + namespace: database-ns + sectionName: "443" + default: # Behaviour. Policy sets connection and idle timeouts + connectionTimeout: 10s + idleTimeout: 30m +``` + +## Policy roles + +Depending on where a policy is created (in an application namespace, the system namespace, or on the global control plane) +and how its schema is structured, {{ site.mesh_product_name }} assigns it a **policy role**. +A policy's role determines how it is synchronized in multi-zone deployments and how it is prioritized when multiple policies overlap. + +The table below introduces the policy roles and how to recognize them. + + +{% table %} +columns: + - title: "Policy Role" + key: role + - title: "Controls" + key: controls + - title: "Type by Schema" + key: schema + - title: "Multi-zone Sync" + key: sync +rows: + - role: "Producer" + controls: "Outbound behaviour of callers to my service (my clients' egress toward me)." + schema: "Has `spec.to`. Every `to[].targetRef.namespace`, if set, must equal `metadata.namespace`." + sync: "Defined in the app's namespace on a Zone CP. Synced to Global, then propagated to other zones." + - role: "Consumer" + controls: "Outbound behaviour of my service when calling others (my egress)." + schema: "Has `spec.to`. At least one `to[].targetRef.namespace` is different from `metadata.namespace`." + sync: "Defined in the app's namespace on a Zone CP. Synced to Global." + - role: "Workload Owner" + controls: "Configuration of my own proxy—inbound traffic handling and sidecar features (for example metrics, traces)." + schema: "Either has `spec.rules`, or has neither `spec.rules` nor `spec.to` (only `spec.targetRef` + proxy/sidecar settings)." + sync: "Defined in the app's namespace on a Zone CP. Synced to Global." + - role: "System" + controls: "Mesh-wide behaviour—can govern both inbound and outbound across services (operator-managed)." + schema: "Resource is created in the system namespace (for example `{{ site.mesh_namespace }}`)." + sync: "Created in the system namespace, either on a Zone CP or on the Global CP." +{% endtable %} + + +In summary: + +* **Producer** policies let you configure how clients call you +* **Consumer** policies let you configure how you call others +* **Workload-owner** policies let you configure your own proxy's inbound and sidecar features +* **System** policies let operators set mesh-wide defaults + +### Producer policies + +Producer policies **allow service owners to define recommended client-side behavior for calls to their service**, +by creating the policy in their service's own namespace. +{{ site.mesh_product_name }} then applies it automatically to the outbounds of client workloads. +This lets backend owners publish sensible defaults (timeouts, retries, limits) for consumers, +while individual clients can still refine those settings with their own [consumer](#consumer-policies) policies. + +The following policy tells {{ site.mesh_product_name }} to apply **3 retries** with a back off of `15s` to `1m` +on **5xx errors** to any client calling `backend`: + +```yaml +apiVersion: kuma.io/v1alpha1 +kind: MeshRetry +metadata: + namespace: backend-ns # created in the backend's namespace + name: backend-producer-timeouts +spec: + targetRef: + kind: Mesh # any caller + to: + - targetRef: + kind: MeshService + name: backend + namespace: backend-ns # same namespace as the policy (producer rule) + default: + numRetries: 3 + backOff: + baseInterval: 15s + maxInterval: 1m + retryOn: + - 5xx +``` + +### Consumer policies + +Consumer policies let **service owners adjust how their workloads call other services**. +They are created in the client's namespace and applied to that client's outbounds. +This way, the service owner can fine-tune retries, timeouts, or other settings for the calls their workloads make. + +```yaml +apiVersion: kuma.io/v1alpha1 +kind: MeshRetry +metadata: + namespace: frontend-ns # created in the namespace of a client + name: backend-consumer-timeouts +spec: + targetRef: + kind: Mesh # any caller, but only in 'frontend-ns' since consumer policies are always scoped to the namespace of origin + to: + - targetRef: + kind: MeshService + name: backend + namespace: backend-ns # different namespace from the policy (consumer rule) + default: + numRetries: 0 +``` + +### Workload-owner policies + +Workload-owner policies let **service owners configure their own workload's proxies**. +They are created in the workload's namespace and control how proxies handle inbound traffic, +while also enabling various proxy-level features such as `MeshMetric`, `MeshProxyPatch`, and others. + +Workload-owner policies either have `spec.rules` for inbound traffic configuration: + +```yaml +apiVersion: kuma.io/v1alpha1 +kind: MeshTrafficPermission +metadata: + namespace: backend-ns # created in the namespace of a server + name: backend-permissions +spec: + targetRef: + kind: Dataplane + labels: + app: backend + rules: + - default: + deny: + - spiffeID: + type: Exact + value: spiffe://trust-domain.mesh/ns/default/sa/legacy + allow: + - spiffeID: + type: Prefix + value: spiffe://trust-domain.mesh/ +``` + +Or only `spec.default` for proxy-level features like metrics and tracing: + +```yaml +apiVersion: kuma.io/v1alpha1 +kind: MeshMetric +metadata: + name: otel-metrics-delegated + namespace: backend-ns +spec: + default: + sidecar: + profiles: + appendProfiles: + - name: All + backends: + - type: OpenTelemetry + openTelemetry: + endpoint: opentelemetry-collector.mesh-observability.svc:4317 + refreshInterval: 30s +``` + +### System policies + +System policies provide **mesh-wide defaults managed by platform operators**. +Any policy can be a system policy as long as it's created in the system namespace (`{{ site.mesh_namespace }}` by default) on either a Zone Control Plane or the Global Control Plane. + +## Referencing Dataplanes, Services, and Routes inside policies + +{{ site.mesh_product_name }} provides an API for cross-referencing policies and other resources called `targetRef`: + +```yaml +targetRef: + kind: Dataplane + labels: + app: my-app +``` + +`targetRef` appears in all policy definitions wherever configuration needs to be associated with resources such as `MeshService`, `MeshExternalService`, `Dataplane`, and others. + +The `targetRef` API follows the same principles regardless of policy type: + +1. `targetRef.kind` must always refer to a resource that exists in the cluster. +2. A resource can be referenced either by `name` and `namespace` or by `labels`. +3. Using `name` and `namespace` creates an unambiguous reference to a single resource, while using `labels` can match multiple resources. +4. `targetRef.namespace` is optional and defaults to the namespace of the policy. +5. System policies must always use `targetRef.labels`. +6. When supported by the target resource, `sectionName` may reference a specific section rather than the entire resource (for example, `MeshService`, `MeshMultiZoneService`, `Dataplane`). +7. `sectionName` is resolved by first matching a section name, and if no match is found, by interpreting it as a numeric port value (provided the port name is unset). + +The set of valid `targetRef.kind` values is the same across all policies: + + +{% table %} +columns: + - title: "Field" + key: field + - title: "Available Kinds" + key: kinds +rows: + - field: "`spec.targetRef`" + kinds: "* `Mesh`
* `Dataplane`" + - field: "`spec.to[].targetRef`" + kinds: "* `MeshService`
* `MeshMultiZoneService`
* `MeshExternalService`
* `MeshHTTPRoute` (if the policy supports per-route configuration)" +{% endtable %} + + +## How policies are combined + +When multiple policies target the same proxy, {{ site.mesh_product_name }} merges them using a priority-based strategy. + +Policy priority is determined by a total ordering of attributes. The table below defines the sorting order, applied sequentially with ties broken by the next attribute in the list. + + +{% table %} +columns: + - title: "" + key: num + - title: "Attribute" + key: attribute + - title: "Order" + key: order +rows: + - num: "1" + attribute: "`spec.targetRef`" + order: "* `Mesh` (less priority)
* `MeshGateway`
* `Dataplane`
* `Dataplane` with `labels`
* `Dataplane` with `labels/sectionName`
* `Dataplane` with `name/namespace`
* `Dataplane` with `name/namespace/sectionName`" + - num: "2" + attribute: "Origin
Label `kuma.io/origin`" + order: "* `global` (less priority)
* `zone`" + - num: "3" + attribute: "Policy Role
Label `kuma.io/policy-role`" + order: "* `system` (less priority)
* `producer`
* `consumer`
* `workload-owner`" + - num: "4" + attribute: "Display Name
Label `kuma.io/display-name`" + order: "Inverted lexicographical order, that is:
* `zzzzz` (less priority)
* `aaaaa1`
* `aaaaa`
* `aaa`" +{% endtable %} + + +For policies with `to` or `rules`, matching policy arrays are concatenated. +For `to` policies, the concatenated arrays are sorted again based on the `spec.to[].targetRef` field: + + +{% table %} +columns: + - title: "" + key: num + - title: "Attribute" + key: attribute + - title: "Order" + key: order +rows: + - num: "1" + attribute: "`spec.to[].targetRef`" + order: "* `Mesh` (less priority)
* `MeshService`
* `MeshService` with `sectionName`
* `MeshExternalService`
* `MeshMultiZoneService`" +{% endtable %} + + +Configuration is then built by merging each level using [JSON patch merge](https://www.rfc-editor.org/rfc/rfc7386). + +For example, if you have two `default` configurations ordered this way: + +```yaml +default: + conf: 1 + sub: + array: [ 1, 2, 3 ] + other: 50 + other-array: [ 3, 4, 5 ] +--- +default: + sub: + array: [ ] + other-array: [ 5, 6 ] + extra: 2 +``` + +The merge result is: + +```yaml +default: + conf: 1 + sub: + array: [ ] + other: 50 + other-array: [ 5, 6 ] + extra: 2 +``` + +## Metadata + +Metadata identifies a policy by its `name`, `type`, and the `mesh` it belongs to: + +{% navtabs "environment" %} +{% navtab "Kubernetes" %} + +In Kubernetes, all {{ site.mesh_product_name }} policies are implemented as [custom resource definitions (CRD)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) in the group `kuma.io/v1alpha1`. + +```yaml +apiVersion: kuma.io/v1alpha1 +kind: ExamplePolicy +metadata: + name: my-policy-name + namespace: {{ site.mesh_namespace }} +spec: ... # spec data specific to the policy kind +``` + +By default, the policy is created in the `default` [mesh](/mesh/concepts#mesh). +You can specify the mesh by using the `kuma.io/mesh` label: + +```yaml +apiVersion: kuma.io/v1alpha1 +kind: ExamplePolicy +metadata: + name: my-policy-name + namespace: {{ site.mesh_namespace }} + labels: + kuma.io/mesh: "my-mesh" +spec: ... # spec data specific to the policy kind +``` + +{% endnavtab %} +{% navtab "Universal" %} + +```yaml +type: ExamplePolicy +name: my-policy-name +mesh: default +spec: ... # spec data specific to the policy kind +``` + +{% endnavtab %} +{% endnavtabs %}