Who can reach what
Identity answers who someone is. Once more than one person uses the installation, you also need to know what each of them may touch. This chapter covers that second question.
Nothing is implied
Access is deny by default. An account that signs in successfully but holds no grant reaches nothing. It can open the home screen and its own settings, but no applications, clusters or sections. Signing in establishes identity only.
The alternative, a baseline that every signed-in person gets for free, is convenient until someone asks what a new colleague can see and nobody can answer. With deny by default, the answer is always whatever someone granted them, and nothing else.
The one exception is the installation’s administrators, who
pass every check. The owner role below is the version of that
which can be written down, handed out and taken back.
The ladder: viewer, operator, maintainer, owner
There are four roles on a ladder, and one beside it. Each role carries everything the role below it carries, plus more.
Viewer. Reads the applications in scope, and can open the Clusters section so the machines those applications run on are visible.
Operator. The whole life of the applications in scope: create, deploy, operate, scale, migrate and remove them. No access management and no infrastructure.
Removal belongs to the operator role, not a higher one. What protects an application from a careless removal is the scope of the grant: you can only remove what your grant already reaches, and the removal tells you how much data goes with it before it asks you to confirm.
Maintainer. An operator, plus the installation itself: the clusters, who may reach what, the shared integrations, the showcase and the demonstration.
Owner. Everything, everywhere, including who else runs this installation.
Platform operator. Beside the ladder, not on it. It runs
clusters, nodes, updates and backups, and reads the applications
without reaching their data. Give it with --expires, so it
ends on its own.
flui iam roles prints the five roles and exactly what each one
carries. flui iam whoami prints what the identity you are
using holds right now, which is the quickest way to find out why
you cannot see something.
Who can make an owner
Giving someone the owner role, or removing it from someone
else, needs user-management authority over the whole
installation, not narrowed to one cluster or one set of
applications.
Without this rule there would be a gap. A maintainer can already hand out roles; that is most of the job. A maintainer could then give themselves the top role through the access screen, and the ladder would have no top. The same rule covers removal, because removing an installation’s owners one row at a time is the same climb in reverse.
A grant is a principal, a role, and a reach
Access is stored as grants, not on people. A grant says three things:
- who: a person, a group or a service account;
- which role: one of the five above;
- how far it reaches: the scope.
The scope can be:
- the whole installation: everything, everywhere;
- one cluster: everything that lives on it;
- one portal section: the Clusters section, the Mail section and so on;
- a selector: a standing description of applications.
A selector is a rule about applications rather than a list of them. It can constrain the application kind, the project, the provider, the cluster (by id or by name), whether the application is a platform one or a user one, a list of slugs, a set of tags, and the owner.
Every constraint you write must hold at once. Slugs are a membership test: the application must be one of them. Tags are an all-of test: the application must carry every tag you name, not just one. An attribute the application does not have never matches a selector that constrains it.
Because a selector is a rule, an application deployed tomorrow that matches it is covered tomorrow, with nothing to grant again and nothing to remember. It also means a selector is wider than it looks when you write it, so the sentence a person is asked to confirm states it explicitly: over every application a standing rule matches, including ones deployed later.
From the terminal:
flui iam grant add \ --principal alice@example.com \ --role operator \ --scope selector \ --project shop --tag production--dry-run shows what the grant would open and what the same
change closes, without creating anything.
Groups let you write a grant once instead of once per person:
flui iam group create, add-member, remove-member, list,
delete. Members are named by email address, and a grant
addressed to the group reaches all of them.
Taking a grant back says what it costs
flui iam grant remove <id> lists what the holder will no
longer be able to reach before it asks you to confirm.
--dry-run prints that and removes nothing.
Sections have three states
Holding the governing permission over the whole installation opens a portal section in full. Without it, by default, you do not see the section at all. That leaves no way to express what two kinds of reader need. A guest on a public demonstration should be able to look around the product without changing it. A read-only operator should be able to open the Backup section and read what is there without being able to start anything.
So there is a third state: read-only. The section is visible, its screens open, and its controls are shown disabled. Behind it, only safe reads get through and every write is refused, so the disabled buttons show the rule while the server enforces it.
There is one limitation. The only role that opens sections at this level is the one the platform writes for a guest of the public demonstration; none of the assignable roles carries it. The reason, as the product states it, is that two of these sections, Mail and Access, return other people’s personal data once the screen loads, and those screens do not filter per person. Opening them read-only to a colleague would expose more than it seems to.
A refusal that tells you nothing
There are two kinds of refusal, and confusing them leaks information about the installation.
“You may not do this” is useful: it tells a person what to ask for. But on some surfaces the existence of the thing is itself the secret, and a refusal that differs from “there is nothing here” gives a stranger a map: they can guess ids, read the wording and learn which ones run something worth reaching.
So on those surfaces (the data consoles, a shell on a machine, someone’s own model connection), every refusal other than “this belongs to someone else” reads as if nothing were there. It uses one wording and does not repeat the id back to you.
On the console the sentence is the same whether the application does not exist, exists but records no owner, belongs to the platform instead of a person, or is one of the two platform databases that no console may ever open. Four situations get one answer, so probing ids teaches you nothing.
“It belongs to someone else” stays a separate answer, because you can act on it: ask the owner.
Routes that take an id straight from the URL follow the same idea. A permission check made without a resource is satisfied by any grant that carries that permission, so a permission alone would let an operator scoped to their own applications reach someone else’s row by guessing a uuid. Those routes load the row and check that row: a row that records an owner cannot be reached by id by anyone else.
A key’s scopes are a ceiling
When a call arrives, two separate questions are asked:
- what may this person do: access control, the grants above;
- what may this key in their hand do: its scopes.
Scopes can only take away. A key issued to look at applications can do only that, even when the person who created it is an administrator. This holds everywhere, not only in the agent toolbox: plain HTTP calls and live-updates connections are held to the same scopes. A key is issued as its person, so without this rule a narrow key would quietly carry its owner’s full rights anywhere nothing checked.
A credential that declares no scopes at all (an interactive login, the CLI’s own key, the platform’s own service identities) has no ceiling and loses nothing. Scopes only narrow: no scope on any key lets anyone do something their grants do not already allow.
A key can also be limited to named applications, named projects, or both. The two lists are alternatives: an application is reachable as soon as either list covers it.
Why the two refusals are worded differently
A scope refusal says the credential’s scopes do not carry the permission this call needs. That is a grant problem, and you fix it by issuing the credential again with the right permission groups. No change to IAM will help.
An access-control refusal says the caller is not allowed on this resource. That is a permission problem, and you fix it with a grant.
Given the wrong one, a person goes to the wrong screen and an agent retries forever, so the two never share a wording.
The application-list refusal is a third case and says so: you fix it by widening the same key’s application list. Nothing needs to be issued again, and whatever holds the key keeps working with the new list.
The refusal also points out one trap. If agent scopes are attached to a person’s account in the identity provider instead of to a machine account, they also limit that person’s browser session, which is correct, because the key is that account. The refusal says where the scopes came from, so you can see the cause. Put agent scopes on a machine account, not on a person.
Access as a file
Grants can be read and written as a document:
flui iam export > access-policy.yamlflui iam apply -f access-policy.yamlexport writes a kind: AccessPolicy document with every grant
on the installation. apply reads one back and is idempotent:
it creates what is missing and leaves the rest alone. --prune
makes it a full sync that deletes grants the file does not
name.
A naming caution. The published @flui-cloud/spec package
types the roles as viewer, editor and manager, but the
product’s names are viewer, operator, maintainer and owner. Use
the product’s names. If a tool built on the spec package rejects
operator, the package is out of step with the product and your
file is correct.
Where this chapter goes from here
- Identity and OIDC: who somebody is, the question this chapter starts from.
- The database console: the most sensitive surface the rules above govern.