Tenancy and access¶
An ankka installation is divided into organizations, which contain projects, which contain services. People are members of organizations. Every call to the control plane carries a token from the installation's identity provider, and the control plane decides, from its own state, what that caller may do.
This page is about who may operate the platform. Who may call a deployed service's HTTP endpoints is a different question, answered by each endpoint's ACL; see HTTP endpoints.
Organizations, projects and services¶
An organization is the boundary of access. Membership is per organization, and a member can act on every project in it.
A project groups services and gives them a namespace. Each project gets its own Kubernetes namespace,
and a service is addressed within its project: two projects may each have a service called cart. A
project's services each get their own database, provisioned by the platform. A project is an identity
boundary rather than a network one: a service in one project can open a connection to a service in
another, and the callee's ACL decides from the caller's certificate whether to serve it — a certificate
names both the project and the service. A project's databases and its services' cluster ports are closed
to every other project. See Networking and TLS.
A service is a deployment target, described by its descriptor.
Deleted tenancy ids are not reused; service names are¶
Deleting an organization or a project leaves a tombstone. The id stays taken, and creating it again is refused with a conflict. A tenancy boundary that quietly came back carrying someone else's history would be worse than an error. An organization can be deleted only once it has no projects, and a project only once it has no services.
A service name is different. It is a deployment target, not a boundary, so applying a descriptor for a name you deleted creates the service again. Its generation keeps counting from where it was, so its history is still there, and its database, which deletion never removes, is recovered.
Authentication and authorization are separate¶
The identity provider authenticates. Every installation runs its own Keycloak, deployed with the rest of the platform. It decides who is a user of the installation, signs their tokens, and holds their passwords, sessions and second factors. Self-registration is off; an administrator adds people in its console. The control plane never sees a password.
The control plane authorizes. It verifies each token offline against the identity provider's published keys, takes the token's subject as the caller's identity, and answers every question about organizations and membership from its own entities. It holds no administrative credential for the identity provider and needs none. Only the token's subject is used as a key; a name or an email address is for display.
ankka login signs you in with the OAuth 2.0 device authorization grant: the CLI prints an address and a
code, and you sign in in any browser, on any device. The login is saved per control plane URL, readable
only by you, and renewed without a browser. A machine such as a CI job holds a deploy token
instead, which an owner creates; see Deploy from GitHub Actions.
Roles¶
Each member of an organization is an owner or a member.
| Action | Member | Owner |
|---|---|---|
| Read the organization, its projects and services | yes | yes |
| Create, rename and delete projects | yes | yes |
| Apply, pause, resume, restart, expose, unexpose and delete services; read their logs and history | yes | yes |
| Invite, remove and change the role of members | no | yes |
| Create, list and revoke deploy tokens | no | yes |
| Rename or delete the organization | no | yes |
Anyone signed in may create an organization and becomes its first owner. Owners invite people by email. An invitation becomes a membership the first time a token carrying that email address, verified by the identity provider, reaches the control plane. The last owner of an organization cannot be removed or demoted.
Membership is checked on every request against the organization's own entity, never against a listing, so removing someone takes effect on their very next request.
What you cannot see does not exist. For an organization, project or service you are not a member of,
the control plane answers exactly as it would for one that was never created: 404. An outsider learns
nothing about which ids are in use. A member who lacks the owner role for an action gets 403.
A deploy token is a member¶
A machine holds a deploy token, and a deploy token's subject is an ordinary member of the
organization it belongs to. Nothing above needs a second reading for machines: its role is member,
its membership is checked against the same entity on every request, it sees a 404 for an organization
it does not belong to, and every change it makes carries it as the actor.
That is a design decision rather than an implementation detail. A separate authorization path for
machines would be a second set of rules to keep in step with the first, and the place where the two
disagreed would be a way in. Instead there is one set, and a token is a subject like any other — one
that happens to be named token:<id> so a person reading a members list or an audit trail can tell.
Two consequences follow from the role being fixed at member. A token can never be the owner an
organization is required to retain, so a secret in a CI system can never become the only way to
administer it. And a token cannot manage deploy tokens, so a leaked credential cannot mint a
replacement for itself or revoke the one that would stop it.
A deploy token for one project¶
A deploy token can be created for one project of its organization rather than the whole of it. Such a token is a member of that project and of nothing else: in its project it does what any member does, and for every other project of the organization it is told there is no such project, exactly as an outsider is. It is refused everything above its project, the organization's own settings, its members and its tokens among them.
It can also do one thing an organization's token cannot: make and end its project's own grants. An agent that deploys into one project has to open to other projects what it deploys, and needing an owner for each grant would put a person in that loop. Answering a grant offered to the organization stays an owner's act. Every change it makes carries the token as the actor, as for any token, and once its project is deleted it can do nothing.
See Identity and machine accounts.
A client key belongs to a service¶
The credentials so far are the installation's: a person's token and a deploy token are issued for the control plane, and a registered machine's token by it. A client key is a service's own. A service with an MCP endpoint issues one, from its own code, to one customer's assistant; the key acts as the subject the service named, can call only that endpoint's tools, and is revoked by the service. The platform keeps the keys and checks them, holding only a digest of each, and the control plane never sees one. Who a key's subject is, and what that subject may do, is the service's decision, as it is for a token from an issuer the service lists.
Platform administrators¶
One role lives in the identity provider rather than the control plane: platform-admin, a realm role for
the people who run the installation. A platform administrator can see every organization, add an owner
to an organization whose owners have all left, and disable an organization. They can also act as an
owner in an organization they are not a member of: create a deploy token for it, organization-wide or
for one project, and accept a grant offered to it, which is how a product that provisions an
organization for a new customer deploys into it before any owner has signed in. Each such act is
recorded as administrative, in the token list and on the grant, so the organization's owners can see the
platform did it rather than one of them.
Disabling an organization suspends every service in its projects. Its members can still read everything,
but every change is refused with a conflict. Enabling it again brings back exactly what was running: a
service its members had paused stays paused. A suspended service reports Suspended rather than Paused,
so it is always clear who stopped it.
A platform administrator can also give an organization a quota: at most so many projects, services and instances. The organization keeps an exact record of what it holds, and the control plane refuses a project or a service that would exceed the quota at the moment it is asked for. Nothing that already runs is ever stopped by a quota, however it is lowered. See Quotas.
Access across projects and organizations¶
A project is a boundary: by default nothing outside it calls its routes or reads its topics. An owner opens one route, gRPC method or topic to a named service of another project, or to a registered machine outside the installation, with a grant. A grant within one organization takes effect when it is made. One whose grantee belongs to another organization is offered to that organization and opens nothing until an owner there accepts it, so no organization is recorded as holding access it never agreed to hold. Either side can end a grant on its own: the grantor withdraws or revokes it, the grantee's organization declines or relinquishes it, and deleting the grantee lapses it. Every change is recorded on both sides with the owner who made it. See Cross-project access.
Every change is attributed¶
Every command recorded by the control plane carries who asked for it, when, and whether it was the
platform-admin role rather than membership that allowed it. ankka services history reads that back for
a service, newest first. See Status and history.