Knative Eventing Authorization¶
Tracking issue: #7256
Overview¶
Securing event delivery in Knative Eventing is essential to prevent unauthorized access. To enforce fine-grained control over event delivery, Knative Eventing introduces the EventPolicy custom resource, which allows users to specify which entities are authorized to send events to specific consumers within a namespace.
Prerequisites¶
- Eventing installation
- authentication-oidcfeature to be enabled.
Note
As described on the authentication-oidc, transport-encryption should be enabled as well for a secure authentication. Take a look at Transport-Encryption, which explains how to enable the transport encryption feature flag.
Compatibility¶
Authorization is currently supported for the following components:
- Brokers:
- Channels:
- Flows:
- Others:
Default Authorization Mode¶
Administrators can set a default authorization mode using the defaultAuthorizationMode feature flag, which Knative Eventing will use whenever no EventPolicy applies to a resource. The available modes are:
- allow-all: All requests are allowed.
- deny-all: All requests are denied, enforcing the creation of EventPolicies.
- allow-same-namespace: Only requests from subjects within the same namespace are allowed. (Default)
Defining an EventPolicy¶
An EventPolicy defines rules for event delivery by specifying which subjects (service accounts or event sources) are allowed to send events to designated event consumers.
apiVersion: eventing.knative.dev/v1alpha1
kind: EventPolicy
metadata:
  name: my-event-policy
  namespace: default
spec:
  to:
    - ref:
        apiVersion: eventing.knative.dev/v1
        kind: Broker
        name: my-broker
    - selector:
        apiVersion: eventing.knative.dev/v1
        kind: Broker
        matchLabels:
          app: special-app
  from:
    - ref:
        apiVersion: sources.knative.dev/v1
        kind: PingSource
        name: my-source
        namespace: another-namespace
    - sub: system:serviceaccount:default:trusted-app
    - sub: "system:serviceaccount:default:other-*"
  filters:
    - cesql: "type IN ('order.created', 'order.updated', 'order.canceled')"
    - exact:
        type: com.github.push
Specify for who the EventPolicy applies¶
The .spec.to section specifies where the events are allowed to be sent. This field is optional; if left empty, the policy applies to all resources within the namespace. By specifying multiple targets in .spec.to, the EventPolicies scope gets widened by applying the same rules to multiple targets.
There are two ways to define these targets:
- to.ref:- Definition: Directly references a specific resource.
- Example: In the EventPolicyabove, themy-brokerBroker is directly referenced. This means theEventPolicyapplies to this specificBroker.
- Use Case: Use to.refwhen you want to protect a specific resource by name.to: - ref: apiVersion: eventing.knative.dev/v1 kind: Broker name: my-broker
 
- 
to.selector:- Definition: Uses a label selector to match multiple resources of a specific type.
- Example: The EventPolicyincludes aBrokerwith labels matchingapp: special-app. This means theEventPolicyapplies to allBrokerswith these labels.
- Use Case: Use to.selectorwhen you want theEventPolicyto apply to a group of resources that share common labels.
 to: - selector: apiVersion: eventing.knative.dev/v1 kind: Broker matchLabels: app: special-app
Specify who is allowed to send events¶
The .spec.from section specifies who is allowed to send events to the targets defined in .spec.to. There are two ways to define these sources:
- 
from.ref:- Definition: Directly references a specific event source resource.
- Example: The my-sourcePingSourceinanother-namespaceis referenced, meaning this specific source is allowed to send events.
- Use Case: Use from.refwhen you want to authorize a specific event source.from: - ref: apiVersion: sources.knative.dev/v1 kind: PingSource name: my-source namespace: another-namespace
 
- 
from.sub:- Definition: Specifies a subject (a service account name), that is allowed to send events. It can include wildcard patterns as a postfix (*) for broader matching.
- Example: The EventPolicyallows events from thetrusted-appservice account in the default namespace and any service account indefaultnamespace that starts withother-.
- Use Case: Use from.subto allow specific users or service accounts, or to apply wildcard patterns for more flexibility.from: - sub: system:serviceaccount:default:trusted-app - sub: "system:serviceaccount:default:other-*"
 
- Definition: Specifies a subject (a service account name), that is allowed to send events. It can include wildcard patterns as a postfix (
Advanced CloudEvent filtering criterias¶
The .spec.filters section is optional and specifies additional criteria that the event itself must meet to be allowed. 
- Example: Only CloudEvents with the typeequals tocom.github.pushand matching a certain CESQL expression are allowed.
- Use Case: Use filterswhen you want to have more fine grained criterias on allowed CloudEvents.from: filters: - cesql: "type IN ('order.created', 'order.updated', 'order.canceled')" - exact: type: com.github.push
If the filters are specified, an event must match all the specified filters of an EventPolicy (in addition to its .spec.from) to be accepted. .spec.filters accepts the same filter dialects as Triggers.
Note
Filters apply in addition to .spec.from. This means, soon as an EventPolicy specifies .spec.filters, they must match the request, as well as the .spec.from (AND operand). Only then the EventPolicy allows the request.
Summary of .spec fields:¶
- to.reftargets a specific resource.
- to.selectortargets a set of resources based on labels.
- from.refauthorizes a specific event source resource.
- from.subauthorizes specific users, service accounts, or patterns of accounts.
- .spec.filtersallows to define advanced CloudEvent filtering criterias
EventPolicy status¶
The status of an EventPolicy provides information about resolved sources and readiness:
status:
  from:
    - system:serviceaccount:default:my-source-oidc-sources.knative.dev-pingsource
    - system:serviceaccount:default:trusted-app
    - "system:serviceaccount:default:other-*"
  conditions:
    - type: Ready
      status: "True"
    - type: SubjectsResolved
      status: "True"
Applying EventPolicies to Resources¶
Event consumers, such as a Broker, will list the applying EventPolicies in their status:
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
  name: my-broker
spec:
  ...
status:
  ...
  policies:
    - name: my-event-policy
      apiVersion: v1alpha1
  conditions:
    - type: Ready
      status: "True"
    - type: EventPoliciesReady
      status: "True"
The EventPoliciesReady condition indicates whether all applicable EventPolicies for a resource are ready and have been successfully applied.
Rejection Behavior¶
If a request does not pass any applicable EventPolicy, it will be rejected with a 403 Forbidden HTTP status code, ensuring that unauthorized event deliveries are blocked. If multiple policies apply to the same resource, the event will be delivered as long as it matches at least one of the applicable EventPolicies. This ensures that even if strict policies are in place, valid events that meet the criteria of any policy can still be processed.
Example¶
In the following, we give a full example how to configure authorization for resources. In this example, we want to protect a Broker (broker) in namespace-1 by only allowing requests from a PingSource (pingsource-2) which is in a different namespace (namespace-2).

First we create the Namespaces, Broker and PingSources:
apiVersion: v1
kind: Namespace
metadata:
  name: namespace-1
---
apiVersion: v1
kind: Namespace
metadata:
  name: namespace-2
---
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
  name: broker
  namespace: namespace-1
---
apiVersion: sources.knative.dev/v1
kind: PingSource
metadata:
  name: pingsource-1
  namespace: namespace-1
spec:
  data: '{"message": "Hi from pingsource-1 from namespace-1"}'
  schedule: '*/1 * * * *'
  sink:
    ref:
      apiVersion: eventing.knative.dev/v1
      kind: Broker
      name: broker
      namespace: namespace-1
---
apiVersion: sources.knative.dev/v1
kind: PingSource
metadata:
  name: pingsource-2
  namespace: namespace-2
spec:
  data: '{"message": "Hi from pingsource-2 from namespace-2"}'
  schedule: '*/1 * * * *'
  sink:
    ref:
      apiVersion: eventing.knative.dev/v1
      kind: Broker
      name: broker
      namespace: namespace-1
For debugging we also create an event-display Kservice and Trigger:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: event-display
  namespace: namespace-1
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "1"
    spec:
      containers:
      - image: gcr.io/knative-releases/knative.dev/eventing/cmd/event_display
---
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
  name: trigger
  namespace: namespace-1
spec:
  broker: broker
  subscriber:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: event-display
As long as OIDC is disabled and no EventPolicy is in place, we should see the events from both PingSources in the event-display kservice:
$ kubectl -n namespace-1 logs event-display-00001-deployment-56cd8dd644-64xl2
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: dev.knative.sources.ping
  source: /apis/v1/namespaces/namespace-1/pingsources/pingsource-1
  id: 79d7a363-798d-40e2-b95c-6e007c81b05b
  time: 2024-08-28T11:33:00.168602384Z
Extensions,
  knativearrivaltime: 2024-08-28T11:33:00.194124454Z
Data,
  {"message": "Hi from pingsource-1 from namespace-1"}
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: dev.knative.sources.ping
  source: /apis/v1/namespaces/namespace-2/pingsources/pingsource-2
  id: 94cfefc6-57aa-471c-9ce5-1d8c61370c7e
  time: 2024-08-28T11:33:00.287533878Z
Extensions,
  knativearrivaltime: 2024-08-28T11:33:00.296630315Z
Data,
  {"message": "Hi from pingsource-2 from namespace-2"}
Now enable OIDC
$ kubectl -n knative-eventing patch cm config-features --type merge --patch '{"data":{"authentication-oidc":"enabled"}}'
and create the following EventPolicy
apiVersion: eventing.knative.dev/v1alpha1
kind: EventPolicy
metadata:
  name: event-policy
  namespace: namespace-1
spec:
  to:
    - ref:
        apiVersion: eventing.knative.dev/v1
        kind: Broker
        name: broker
  from:
    - ref:
        apiVersion: sources.knative.dev/v1
        kind: PingSource
        name: pingsource-2
        namespace: namespace-2
Afterwards you can see in the Brokers status, that this EventPolicy got applied to it:
$ kubectl -n namespace-1 get broker broker -o yaml                                                                      
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
  name: broker
  namespace: namespace-1
  ...
spec:
  ...
status:
  ...
  conditions:
  ...
  - lastTransitionTime: "2024-08-28T11:53:48Z"
    status: "True"
    type: EventPoliciesReady
  - lastTransitionTime: "2024-08-28T11:26:16Z"
    status: "True"
    type: Ready
  policies:
  - apiVersion: eventing.knative.dev/v1alpha1
    name: event-policy
And in the event-display, you should see only events from pingsource-2 anymore, as we referenced this in our EventPolicy event-policy to be allowed to send events to Broker broker:
$ kubectl -n namespace-1 logs event-display-00001-deployment-56cd8dd644-64xl2
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: dev.knative.sources.ping
  source: /apis/v1/namespaces/namespace-2/pingsources/pingsource-2
  id: c0b4f5f2-5f95-4c0b-a3c6-6f61b6581a4b
  time: 2024-08-28T11:56:00.200782358Z
Extensions,
  knativearrivaltime: 2024-08-28T11:56:00.20834826Z
Data,
  {"message": "Hi from pingsource-2 from namespace-2"}
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: dev.knative.sources.ping
  source: /apis/v1/namespaces/namespace-2/pingsources/pingsource-2
  id: 6ab79fb0-2cf6-42a0-a43e-6bcd172558e5
  time: 2024-08-28T11:57:00.075390777Z
Extensions,
  knativearrivaltime: 2024-08-28T11:57:00.096497595Z
Data,
  {"message": "Hi from pingsource-2 from namespace-2"}
When we remove now the EventPolicy again and keep OIDC disabled, the Broker will fall back to the default authorization mode, which is allow-same-namespace:
$ kubectl -n namespace-1 delete eventpolicy event-policy
This should be reflected in the Brokers status too:
$ kubectl -n namespace-1 get broker broker -o yaml           
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
  name: broker
  namespace: namespace-1
  ...
spec:
  ...
status:
  ...
  conditions:
  ...
  - lastTransitionTime: "2024-08-28T12:00:00Z"
    message: Default authz mode is "Allow-Same-Namespace
    reason: DefaultAuthorizationMode
    status: "True"
    type: EventPoliciesReady
  - lastTransitionTime: "2024-08-28T11:26:16Z"
    status: "True"
    type: Ready
And we should see only events from pingsource-1 in the event-display, as pingsource-1 is in the same namespace as broker:
$ kubectl -n namespace-1 logs event-display-00001-deployment-56cd8dd644-64xl2
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: dev.knative.sources.ping
  source: /apis/v1/namespaces/namespace-1/pingsources/pingsource-1
  id: cd173aef-373a-4f2b-915e-43c138ac0602
  time: 2024-08-28T12:01:00.2504715Z
Extensions,
  knativearrivaltime: 2024-08-28T12:01:00.276151088Z
Data,
  {"message": "Hi from pingsource-1 from namespace-1"}
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: dev.knative.sources.ping
  source: /apis/v1/namespaces/namespace-1/pingsources/pingsource-1
  id: 22665003-fe81-4203-8896-89594077ae6b
  time: 2024-08-28T12:02:00.121025501Z
Extensions,
  knativearrivaltime: 2024-08-28T12:02:00.13378992Z
Data,
  {"message": "Hi from pingsource-1 from namespace-1"}
Summary¶
The EventPolicy resource in Knative Eventing offers a powerful way to control event delivery securely. By defining which sources can send events to specific consumers, users can ensure that only authorized entities interact within their event-driven architecture.