Per-resource authorization

Nakadi allows users to restrict access to resources they own - currently, event types are the only resources supported, but we plan to extend this feature to subscriptions in the near future.

The authorization model is simple: policies can be attached to resources. A policy P defines which subjects can perform which operations on a resource R. To do so, the policy contains, for each operation, a list of attributes that represent subjects who are authorized to perform the operation on the resource. For a subject to be authorized, it needs to match at least one of these attributes (not necessarily all of them).

There are three kinds of operation: admin, to update the resource and delete it; read, to read events from the resource; and write, to write events to the resource.

An authorization request is represented by the tuple

R(subject, operation, resource)

The request will be approved iff the resource policy has at least one attribute for operation that matches the subject.

Protecting an event type

Protecting an event type can be done either during the creation of the event type, or later, as an update to the event type. Users simply need to add an authorization section to their event type description, which looks like this:

  "authorization": {
    "admins": [{"data_type": "user", "value": "bfawlty"}],
    "readers": [{"data_type": "user", "value": "bfawlty"}],
    "writers": [{"data_type": "user", "value": "bfawlty"}]
  }

In this section, the admins list includes the attributes that authorize a subject to perform the admin operation; the readers list includes the attributes that authorize a subject to perform the read operation; and the writers list includes the attributes that authorize a subject to perform the write operation;

Whenever an event type is created, or its authorization section is updated, all attributes are validated. The exact nature of the validation depends on the plugin implementation.

Creating an event type

Here is a sample request with an authorization section. It gives read, write, and admin access to a single attribute, of type service:

curl -v -XPOST -H "Content-Type: application/json" http://localhost:8080/event-types -d '{
  "name": "order_received",
  "owning_application": "acme-order-service",
  "category": "business",
  "partition_strategy": "hash",
  "partition_key_fields": ["order_number"],
  "enrichment_strategies": ["metadata_enrichment"],
  "default_statistic": {
    "messages_per_minute": 1000,    
    "message_size":    5,
    "read_parallelism":    1,
    "write_parallelism": 1
  },
  "schema": {
    "type": "json_schema",
    "schema": "{ \"properties\": { \"order_number\": { \"type\": \"string\" } } }"
  },
  "authorization": {
    "admins": [{"data_type": "user", "value": "bfawlty"}],
    "readers": [{"data_type": "user", "value": "bfawlty"}],
    "writers": [{"data_type": "user", "value": "bfawlty"}]
  }
}'

Updating an event type

Updating an event type is similar to creating one. Here is a sample request, that gives read, write, and admin access to the same application:

curl -v -XPUT -H "Content-Type: application/json" http://localhost:8080/event-types/order_received -d '{
  "name": "order_received",
  "owning_application": "acme-order-service",
  "category": "business",
  "partition_strategy": "hash",
  "partition_key_fields": ["order_number"],
  "enrichment_strategies": ["metadata_enrichment"],
  "default_statistic": {
    "messages_per_minute": 1000,    
    "message_size":    5,
    "read_parallelism":    1,
    "write_parallelism": 1
  },
  "schema": {
    "type": "json_schema",
    "schema": "{ \"properties\": { \"order_number\": { \"type\": \"string\" } } }"
  },
  "authorization": {
    "admins": [{"data_type": "user", "value": "bfawlty"}],
    "readers": [{"data_type": "user", "value": "bfawlty"}],
    "writers": [{"data_type": "user", "value": "bfawlty"}]
  }
}'

When updating an event type, users should keep in mind the following caveats:

  • If the event type already has an authorization section, then it cannot be removed in an update;
  • If the update changes the list of readers, then all consumers will be disconnected. It is expected that they will try to reconnect, which will only work for those that are still authorized. WARNING: this also applies to consumers using subscriptions; if a subscription includes multiple event types, and as a result of the update, a consumer loses read access to one of them, then the consumer will not be able to consume from the subscription anymore.