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

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:

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.

  1. apiVersion: eventing.knative.dev/v1alpha1
  2. kind: EventPolicy
  3. metadata:
  4. name: my-event-policy
  5. namespace: default
  6. spec:
  7. to:
  8. - ref:
  9. apiVersion: eventing.knative.dev/v1
  10. kind: Broker
  11. name: my-broker
  12. - selector:
  13. apiVersion: eventing.knative.dev/v1
  14. kind: Broker
  15. matchLabels:
  16. app: special-app
  17. from:
  18. - ref:
  19. apiVersion: sources.knative.dev/v1
  20. kind: PingSource
  21. name: my-source
  22. namespace: another-namespace
  23. - sub: system:serviceaccount:default:trusted-app
  24. - sub: "system:serviceaccount:default:other-*"
  25. filters:
  26. - cesql: "type IN ('order.created', 'order.updated', 'order.canceled')"
  27. - exact:
  28. 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:

  1. to.ref:

    • Definition: Directly references a specific resource.
    • Example: In the EventPolicy above, the my-broker Broker is directly referenced. This means the EventPolicy applies to this specific Broker.
    • Use Case: Use to.ref when you want to protect a specific resource by name.

      1. to:
      2. - ref:
      3. apiVersion: eventing.knative.dev/v1
      4. kind: Broker
      5. name: my-broker
  2. to.selector:

    • Definition: Uses a label selector to match multiple resources of a specific type.
    • Example: The EventPolicy includes a Broker with labels matching app: special-app. This means the EventPolicy applies to all Brokers with these labels.
    • Use Case: Use to.selector when you want the EventPolicy to apply to a group of resources that share common labels.
    1. to:
    2. - selector:
    3. apiVersion: eventing.knative.dev/v1
    4. kind: Broker
    5. matchLabels:
    6. 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:

  1. from.ref:

    • Definition: Directly references a specific event source resource.
    • Example: The my-source PingSource in another-namespace is referenced, meaning this specific source is allowed to send events.
    • Use Case: Use from.ref when you want to authorize a specific event source.

      1. from:
      2. - ref:
      3. apiVersion: sources.knative.dev/v1
      4. kind: PingSource
      5. name: my-source
      6. namespace: another-namespace
  2. 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 EventPolicy allows events from the trusted-app service account in the default namespace and any service account in default namespace that starts with other-.
    • Use Case: Use from.sub to allow specific users or service accounts, or to apply wildcard patterns for more flexibility.

      1. from:
      2. - sub: system:serviceaccount:default:trusted-app
      3. - sub: "system:serviceaccount:default:other-*"

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 type equals to com.github.push and matching a certain CESQL expression are allowed.
  • Use Case: Use filters when you want to have more fine grained criterias on allowed CloudEvents.

    1. from:
    2. filters:
    3. - cesql: "type IN ('order.created', 'order.updated', 'order.canceled')"
    4. - exact:
    5. 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.ref targets a specific resource.
  • to.selector targets a set of resources based on labels.
  • from.ref authorizes a specific event source resource.
  • from.sub authorizes specific users, service accounts, or patterns of accounts.
  • .spec.filters allows to define advanced CloudEvent filtering criterias

EventPolicy status

The status of an EventPolicy provides information about resolved sources and readiness:

  1. status:
  2. from:
  3. - system:serviceaccount:default:my-source-oidc-sources.knative.dev-pingsource
  4. - system:serviceaccount:default:trusted-app
  5. - "system:serviceaccount:default:other-*"
  6. conditions:
  7. - type: Ready
  8. status: "True"
  9. - type: SubjectsResolved
  10. status: "True"

Applying EventPolicies to Resources

Event consumers, such as a Broker, will list the applying EventPolicies in their status:

  1. apiVersion: eventing.knative.dev/v1
  2. kind: Broker
  3. metadata:
  4. name: my-broker
  5. spec:
  6. ...
  7. status:
  8. ...
  9. policies:
  10. - name: my-event-policy
  11. apiVersion: v1alpha1
  12. conditions:
  13. - type: Ready
  14. status: "True"
  15. - type: EventPoliciesReady
  16. 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).

Example Overview

First we create the Namespaces, Broker and PingSources:

  1. apiVersion: v1
  2. kind: Namespace
  3. metadata:
  4. name: namespace-1
  5. ---
  6. apiVersion: v1
  7. kind: Namespace
  8. metadata:
  9. name: namespace-2
  10. ---
  11. apiVersion: eventing.knative.dev/v1
  12. kind: Broker
  13. metadata:
  14. name: broker
  15. namespace: namespace-1
  16. ---
  17. apiVersion: sources.knative.dev/v1
  18. kind: PingSource
  19. metadata:
  20. name: pingsource-1
  21. namespace: namespace-1
  22. spec:
  23. data: '{"message": "Hi from pingsource-1 from namespace-1"}'
  24. schedule: '*/1 * * * *'
  25. sink:
  26. ref:
  27. apiVersion: eventing.knative.dev/v1
  28. kind: Broker
  29. name: broker
  30. namespace: namespace-1
  31. ---
  32. apiVersion: sources.knative.dev/v1
  33. kind: PingSource
  34. metadata:
  35. name: pingsource-2
  36. namespace: namespace-2
  37. spec:
  38. data: '{"message": "Hi from pingsource-2 from namespace-2"}'
  39. schedule: '*/1 * * * *'
  40. sink:
  41. ref:
  42. apiVersion: eventing.knative.dev/v1
  43. kind: Broker
  44. name: broker
  45. namespace: namespace-1

For debugging we also create an event-display Kservice and Trigger:

  1. apiVersion: serving.knative.dev/v1
  2. kind: Service
  3. metadata:
  4. name: event-display
  5. namespace: namespace-1
  6. spec:
  7. template:
  8. metadata:
  9. annotations:
  10. autoscaling.knative.dev/min-scale: "1"
  11. spec:
  12. containers:
  13. - image: gcr.io/knative-releases/knative.dev/eventing/cmd/event_display
  14. ---
  15. apiVersion: eventing.knative.dev/v1
  16. kind: Trigger
  17. metadata:
  18. name: trigger
  19. namespace: namespace-1
  20. spec:
  21. broker: broker
  22. subscriber:
  23. ref:
  24. apiVersion: serving.knative.dev/v1
  25. kind: Service
  26. 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:

  1. $ kubectl -n namespace-1 logs event-display-00001-deployment-56cd8dd644-64xl2
  2. ☁️ cloudevents.Event
  3. Context Attributes,
  4. specversion: 1.0
  5. type: dev.knative.sources.ping
  6. source: /apis/v1/namespaces/namespace-1/pingsources/pingsource-1
  7. id: 79d7a363-798d-40e2-b95c-6e007c81b05b
  8. time: 2024-08-28T11:33:00.168602384Z
  9. Extensions,
  10. knativearrivaltime: 2024-08-28T11:33:00.194124454Z
  11. Data,
  12. {"message": "Hi from pingsource-1 from namespace-1"}
  13. ☁️ cloudevents.Event
  14. Context Attributes,
  15. specversion: 1.0
  16. type: dev.knative.sources.ping
  17. source: /apis/v1/namespaces/namespace-2/pingsources/pingsource-2
  18. id: 94cfefc6-57aa-471c-9ce5-1d8c61370c7e
  19. time: 2024-08-28T11:33:00.287533878Z
  20. Extensions,
  21. knativearrivaltime: 2024-08-28T11:33:00.296630315Z
  22. Data,
  23. {"message": "Hi from pingsource-2 from namespace-2"}

Now enable OIDC

  1. $ kubectl -n knative-eventing patch cm config-features --type merge --patch '{"data":{"authentication-oidc":"enabled"}}'

and create the following EventPolicy

  1. apiVersion: eventing.knative.dev/v1alpha1
  2. kind: EventPolicy
  3. metadata:
  4. name: event-policy
  5. namespace: namespace-1
  6. spec:
  7. to:
  8. - ref:
  9. apiVersion: eventing.knative.dev/v1
  10. kind: Broker
  11. name: broker
  12. from:
  13. - ref:
  14. apiVersion: sources.knative.dev/v1
  15. kind: PingSource
  16. name: pingsource-2
  17. namespace: namespace-2

Afterwards you can see in the Brokers status, that this EventPolicy got applied to it:

  1. $ kubectl -n namespace-1 get broker broker -o yaml
  2. apiVersion: eventing.knative.dev/v1
  3. kind: Broker
  4. metadata:
  5. name: broker
  6. namespace: namespace-1
  7. ...
  8. spec:
  9. ...
  10. status:
  11. ...
  12. conditions:
  13. ...
  14. - lastTransitionTime: "2024-08-28T11:53:48Z"
  15. status: "True"
  16. type: EventPoliciesReady
  17. - lastTransitionTime: "2024-08-28T11:26:16Z"
  18. status: "True"
  19. type: Ready
  20. policies:
  21. - apiVersion: eventing.knative.dev/v1alpha1
  22. 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:

  1. $ kubectl -n namespace-1 logs event-display-00001-deployment-56cd8dd644-64xl2
  2. ☁️ cloudevents.Event
  3. Context Attributes,
  4. specversion: 1.0
  5. type: dev.knative.sources.ping
  6. source: /apis/v1/namespaces/namespace-2/pingsources/pingsource-2
  7. id: c0b4f5f2-5f95-4c0b-a3c6-6f61b6581a4b
  8. time: 2024-08-28T11:56:00.200782358Z
  9. Extensions,
  10. knativearrivaltime: 2024-08-28T11:56:00.20834826Z
  11. Data,
  12. {"message": "Hi from pingsource-2 from namespace-2"}
  13. ☁️ cloudevents.Event
  14. Context Attributes,
  15. specversion: 1.0
  16. type: dev.knative.sources.ping
  17. source: /apis/v1/namespaces/namespace-2/pingsources/pingsource-2
  18. id: 6ab79fb0-2cf6-42a0-a43e-6bcd172558e5
  19. time: 2024-08-28T11:57:00.075390777Z
  20. Extensions,
  21. knativearrivaltime: 2024-08-28T11:57:00.096497595Z
  22. Data,
  23. {"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:

  1. $ kubectl -n namespace-1 delete eventpolicy event-policy

This should be reflected in the Brokers status too:

  1. $ kubectl -n namespace-1 get broker broker -o yaml
  2. apiVersion: eventing.knative.dev/v1
  3. kind: Broker
  4. metadata:
  5. name: broker
  6. namespace: namespace-1
  7. ...
  8. spec:
  9. ...
  10. status:
  11. ...
  12. conditions:
  13. ...
  14. - lastTransitionTime: "2024-08-28T12:00:00Z"
  15. message: Default authz mode is "Allow-Same-Namespace
  16. reason: DefaultAuthorizationMode
  17. status: "True"
  18. type: EventPoliciesReady
  19. - lastTransitionTime: "2024-08-28T11:26:16Z"
  20. status: "True"
  21. 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:

  1. $ kubectl -n namespace-1 logs event-display-00001-deployment-56cd8dd644-64xl2
  2. ☁️ cloudevents.Event
  3. Context Attributes,
  4. specversion: 1.0
  5. type: dev.knative.sources.ping
  6. source: /apis/v1/namespaces/namespace-1/pingsources/pingsource-1
  7. id: cd173aef-373a-4f2b-915e-43c138ac0602
  8. time: 2024-08-28T12:01:00.2504715Z
  9. Extensions,
  10. knativearrivaltime: 2024-08-28T12:01:00.276151088Z
  11. Data,
  12. {"message": "Hi from pingsource-1 from namespace-1"}
  13. ☁️ cloudevents.Event
  14. Context Attributes,
  15. specversion: 1.0
  16. type: dev.knative.sources.ping
  17. source: /apis/v1/namespaces/namespace-1/pingsources/pingsource-1
  18. id: 22665003-fe81-4203-8896-89594077ae6b
  19. time: 2024-08-28T12:02:00.121025501Z
  20. Extensions,
  21. knativearrivaltime: 2024-08-28T12:02:00.13378992Z
  22. Data,
  23. {"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.