Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RBAC support and authorization in all gRPC [WIP] #5533

Draft
wants to merge 6 commits into
base: license
Choose a base branch
from
Draft

Conversation

fulmicoton
Copy link
Contributor

@fulmicoton fulmicoton commented Nov 1, 2024

RBAC support

Authentication

Quickwit will maintain its own model of user, roles and permissions its the metastore.

For the first iteration, we will only allow LDAP authentication.
The user experience will be as follows.

When accessing the quickwit ui without being logged in, the user will
be redirected to a login form. After submitting their credential, the credential
will go through the front-end and be forwarded to a new
quickwit-auth service.

This service will in turn connect to LDAP to authenticate the user.
The username will be completed with a configured baseDN.
If successful, quickwit-auth will fetch the list of roles associated to the user in the
metastore.

If no user is found, a new user will be automatically created, with a default role,
and associated to the user DN.

Quickwit auth will then generate a biscuit token with at least the following information:

  • a TTL of a configurable amount of time
  • the user name
  • the list of roles

It may also include a partial list of permissions.
Some permissions are tied to a specific resource (e.g. role marketing is allowed to read
the index named access_log). The number of such index could be very large, so we limit the
number of resources that are included in this biscuit.

This biscuit token is then returned back to the front-end as a cookie.

quickwit-auth is in charge of authentication. It is the only service that has
the authority to create such a root token.

Token renewal

When the backend attempts to access a resource (e.g. read an index) that is not already listed in the biscuit,
a biscuit renewal request is sent to the quickwit-auth service. The quickwit-auth service will then
return a new biscuit with all of the permissions granted to the user for the specific resource.

Roles and permissions

Roles are simply strings identifying groups of users.
Each role is associated to a set of permissions.
The permissions of a user is the union of the permissions of all the roles they have.

A new user always receive the default role.
A request missing any authorization token will receive the anonymous role.

Permissions may be tied to a specific resource:

  • permission tied to a resource like an index. For instance:
    view:secret_app_log:read.
  • permission that are not tied to a resource, for instance:
    admin:create_index.

Unfortunately, the cardinality of resources (thousands) prevent us from adding all existing permissions
into the biscuit. We can however safely assume that the number of roles per user (dozens) is much smaller
and can fit in a biscuit.

Authorization

A biscuit token is added to all gRPC.
On the client side, the token is attenuated. We add a TTL of 1 minute, and its scope
is reduced to the need of the current request.

On the server side, we check that the token is sufficient to perform the request.

Datalog

Our biscuit token is a datalog program.

It starts with an authority block. This is the part that is emitted by the auth server.

// This is what comes from our biscuit stored as a cookie in the browser.
//
// It says what the user is and what role it is associated too.

user("fulmicoton");
member("developer");
member("admin");

// The TTL
check if time($time), $time <= 2024-12-02T08:00:00Z;

Before emitting a grpc, grpc clients attenuate this token and pass it with the request as
a bearer token, as a grpc metadata (in the "authority" header of the associated http/2 request).

The attenuation block includes a more aggressive TTL, and some restriction on the allowed operation.
In order to remove the burden of naming, we will name the operations after the grpc service methods.
It is important that this includes all of the suboperations induced by the grpc.

check all grpc($grpc), ["RootSearch", "FetchDocs"].contains($grpc);
check if time($time), $time <= 2024-12-02T07:01:00Z;

Finally an authorizer will be in

// We list resources here in order to generate facts for the root role.
resource("index1");
resource("index2");

// This is simply gRPC method.
grpc("SearchRequest");

// These relevant role rights are loaded from the database.
role_right("developer", "index1", "read");
role_right("developer", "index2", "read");
role_right("root", "index2", "read");

operation("read");

// We generate the actual user role, by generating facts using a rule.
right($operation) <- role($role), role_right($role, $operation);
right($operation, $resource) <- role($role), role_right($role, $resource, $operation);
right($operation, $resource) <- role("root"), operation($operation), resource($resource);

// Finally we check that we have access to index1 and index2.
check if right("read", "index1");
check if right("read", "index2");

allow if true;

Copy link

github-actions bot commented Nov 1, 2024

On SSD:

Average search latency is 1.01x that of the reference (lower is better).
Ref run id: 4045, ref commit: 105aa7d
Link

On GCS:

Average search latency is 0.932x that of the reference (lower is better).
Ref run id: 4046, ref commit: 105aa7d
Link

@fulmicoton fulmicoton changed the title Auth RBAC support and authorization in all gRPC Nov 1, 2024
@fulmicoton fulmicoton changed the title RBAC support and authorization in all gRPC RBAC support and authorization in all gRPC [WIP] Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant