Access Control

Authentication, authorization, and infrastructure access controls.

The Sankofa Engine enforces access control at three layers: application authentication, policy-based authorization, and infrastructure-level isolation. This page documents each layer.

Authentication

API Key Provisioning

API keys are provisioned by Sankofa Labs during customer onboarding. Customers do not self-register or self-provision credentials.

StepDescription
1. Onboarding requestCustomer requests access through Sankofa Labs
2. Identity verificationSankofa Labs verifies the customer’s identity and authorization
3. Key generationA unique client_id and client_secret pair is generated
4. Secure deliveryCredentials are delivered through a secure channel
5. ActivationCredentials are activated in the target deployment

JWT Token Exchange

Clients authenticate by exchanging their API key credentials for a JWT bearer token:

Client                          API Gateway
  │                                  │
  │  POST /auth/token                │
  │  { client_id, client_secret }    │
  │ ────────────────────────────────▶│
  │                                  │  Validate credentials
  │                                  │  Generate JWT
  │  200 OK                          │
  │  { access_token, expires_in }    │
  │ ◀────────────────────────────────│
  │                                  │
  │  GET /api/v1/accounts            │
  │  Authorization: Bearer <JWT>     │
  │ ────────────────────────────────▶│
  │                                  │  Validate JWT signature
  │                                  │  Extract claims
  │                                  │  Enforce authorization
  │  200 OK                          │
  │ ◀────────────────────────────────│

Token Lifetime and Refresh

ParameterDescription
Token lifetimeConfigurable per deployment (e.g., 15 minutes, 1 hour)
Refresh modelClients request a new token using their client_id and client_secret when the current token expires
RevocationTokens can be revoked immediately by invalidating the signing key or adding the token to a deny list

Short-lived tokens limit the window of exposure if a token is compromised.

ECDSA P-256 Transaction Signing (Self-Custody)

For customers who require self-custody of transaction authorization, the Sankofa Engine supports ECDSA P-256 digital signatures:

AspectDetail
AlgorithmECDSA with P-256 curve (NIST)
Key ownershipCustomer generates and holds the private key
SigningCustomer signs transaction payloads before submission
VerificationThe engine verifies the signature against the customer’s registered public key
Non-repudiationSigned transactions provide cryptographic proof of authorization

This model gives customers full control over transaction authorization without sharing private keys with Sankofa Labs.

Authorization

Casbin v2 RBAC Model

The Sankofa Engine uses Casbin v2 for role-based access control. Casbin evaluates every API request against a policy file that defines who can do what on which resources.

Policy Structure

Casbin policies follow a subject, object, action model:

p, role:admin,    /api/v1/accounts/*,   *
p, role:operator, /api/v1/accounts/*,   GET
p, role:operator, /api/v1/transactions, POST
p, role:auditor,  /api/v1/accounts/*,   GET
p, role:auditor,  /api/v1/audit/*,      GET
ElementDescription
SubjectThe role or identity making the request (extracted from the JWT claims)
ObjectThe API resource being accessed (URL path)
ActionThe HTTP method (GET, POST, PUT, DELETE)

Built-in Roles and Permissions

RolePermissionsIntended Use
adminFull access to all API endpointsPlatform administrators at the customer organization
operatorRead access to accounts; create transactionsDay-to-day operational use
auditorRead-only access to accounts and audit endpointsCompliance and audit personnel

Custom roles can be defined in the Casbin policy file to match customer-specific requirements.

Permission Enforcement

Authorization is enforced at the API Gateway middleware layer:

Incoming Request
┌─────────────────┐
│ JWT Validation   │  Verify token signature and expiration
└───────┬─────────┘
┌─────────────────┐
│ Claims Extraction│  Extract role, subject, and tenant from JWT
└───────┬─────────┘
┌─────────────────┐
│ Casbin Enforcer  │  Evaluate (subject, object, action) against policy
└───────┬─────────┘
   ┌────┴────┐
   │         │
 Allow     Deny
   │         │
   ▼         ▼
 Route    403 Forbidden
 to        + audit log
 backend

Every authorization decision — both allow and deny — is logged for audit purposes.

Infrastructure Access Controls

Kubernetes Namespace Isolation

All Sankofa Engine components run in a dedicated sankofa-engine Kubernetes namespace:

ControlImplementation
Namespace boundaryAll pods, services, configmaps, and secrets are scoped to sankofa-engine
RBACKubernetes RBAC roles and role-bindings restrict who can access resources in the namespace
Resource quotasCPU and memory quotas prevent resource exhaustion
No cross-namespace accessServices in other namespaces cannot access Sankofa Engine resources

Network Policies

Kubernetes NetworkPolicies restrict pod-to-pod communication to only the paths required by the architecture:

SourceDestinationAllowed
API GatewayNATS JetStreamYes
Shard WorkersNATS JetStreamYes
Shard WorkersScyllaDBYes
API GatewayPostgreSQLYes
All servicesOpenBaoYes
Any other pathAnyDenied

Default-deny policies ensure that any new pod added to the namespace has no network access until an explicit policy is created.

Secret Scoping

Secrets are scoped to individual services following the principle of least privilege:

PrincipleImplementation
Per-service secretsEach service has its own set of secrets (database credentials, KMS tokens, TLS certificates)
No shared credentialsNo two services share the same secret
Runtime injectionSecrets are injected via OpenBao agent at pod startup, not stored in Kubernetes Secrets
No environment variablesSecrets are mounted as files, not exposed as environment variables (which can leak via process listings)

Principle of Least Privilege

Every component in the Sankofa Engine operates with the minimum permissions required:

  • Services authenticate to only the backends they need (e.g., shard workers access ScyllaDB but not PostgreSQL).
  • KMS access is scoped per service — each service can only access the key paths it requires.
  • Kubernetes RBAC grants only the verbs (get, list, watch) each service account needs.
  • Network policies allow only the specific ingress and egress paths required by the architecture.