Malachi.Auth.AclServer (malachi v0.22.7)

View Source

A thin named facade over Malachi.Cluster.RaCluster for the cluster's per-topic ACL store (Malachi.Auth.AclMachine): start the dedicated Raft cluster, submit ACL commands through the log, and read the replicated grants. Mirrors Malachi.Auth.UserServer; ra must already be running. This module owns only the ACL cluster, not ra's lifecycle.

Writes (grant/revoke/revoke_user) go through the log, replicated by consensus, so every node enforces the same ACLs. Reads (authorized?/list_grants/list_all) use :ra.local_query against the local replica: fast (no consensus round-trip) and adequate for the produce/consume hot path, which authorizes every request. They are eventually consistent: a just-granted ACL propagates within replication lag, acceptable for authorization.

Summary

Functions

Whether username has a grant for operation on topic, read from the local replica.

Stops and deletes the ACL store's Raft cluster (removing its on-disk state).

Grants username an operation on resource ({:literal, topic} / {:prefix, prefix}). Reply :ok.

Every grant across all users, from the local replica.

The grants for username as {operation, resource}, from the local replica.

Ensures this node participates in the ACL cluster (self-join), so a staggered boot converges to a fully-replicated ACL store. Idempotent and best-effort. Mirrors UserServer.reconcile/2.

Revokes a single grant (idempotent). Reply :ok.

Revokes every grant for username (e.g. when the user is deleted). Reply :ok.

Starts the ACL store's Raft cluster named cluster_name across nodes (default the local node) and returns a server_id addressing a real member (the local node when it is one, else the first).

Types

cluster_name()

@type cluster_name() :: atom()

server_id()

@type server_id() :: {cluster_name(), node()}

Functions

authorized?(server_id, username, operation, topic)

@spec authorized?(
  server_id(),
  String.t(),
  Malachi.Auth.AclRegistry.operation(),
  String.t()
) ::
  {:ok, boolean()} | {:error, term()}

Whether username has a grant for operation on topic, read from the local replica.

delete(cluster_name)

@spec delete(cluster_name()) :: :ok

Stops and deletes the ACL store's Raft cluster (removing its on-disk state).

grant(server_id, username, operation, resource)

@spec grant(
  server_id(),
  String.t(),
  Malachi.Auth.AclRegistry.operation(),
  Malachi.Auth.AclRegistry.resource()
) :: {:ok, :ok} | {:error, term()}

Grants username an operation on resource ({:literal, topic} / {:prefix, prefix}). Reply :ok.

list_all(server_id)

@spec list_all(server_id()) ::
  {:ok, [Malachi.Auth.AclRegistry.grant()]} | {:error, term()}

Every grant across all users, from the local replica.

list_grants(server_id, username)

@spec list_grants(server_id(), String.t()) ::
  {:ok,
   [{Malachi.Auth.AclRegistry.operation(), Malachi.Auth.AclRegistry.resource()}]}
  | {:error, term()}

The grants for username as {operation, resource}, from the local replica.

reconcile(cluster_name, nodes)

@spec reconcile(cluster_name(), [node()]) :: :ok

Ensures this node participates in the ACL cluster (self-join), so a staggered boot converges to a fully-replicated ACL store. Idempotent and best-effort. Mirrors UserServer.reconcile/2.

revoke(server_id, username, operation, resource)

@spec revoke(
  server_id(),
  String.t(),
  Malachi.Auth.AclRegistry.operation(),
  Malachi.Auth.AclRegistry.resource()
) :: {:ok, :ok} | {:error, term()}

Revokes a single grant (idempotent). Reply :ok.

revoke_user(server_id, username)

@spec revoke_user(server_id(), String.t()) :: {:ok, :ok} | {:error, term()}

Revokes every grant for username (e.g. when the user is deleted). Reply :ok.

start(cluster_name, nodes \\ [node()])

@spec start(cluster_name(), [node()]) :: {:ok, server_id()} | {:error, term()}

Starts the ACL store's Raft cluster named cluster_name across nodes (default the local node) and returns a server_id addressing a real member (the local node when it is one, else the first).