Skip to main content

Roles

A Role describes a job someone does, as a list of things they're allowed to do. "Staging operator" might mean reading the staging configs and running the monitoring playbooks on them. "Auditor" might mean reading Scopes, Roles, and RoleBindings.

Each item in that list is a rule. A rule pairs one action, such as read or playbook:run, with the Scope of resources it applies to.

A Role doesn't give anyone anything by itself. You write it once, then give it to people, teams or playbooks with a RoleBinding. The same Role can be bound as many times as you like.

A first Role​

This Role has a single rule: read every config in the john-catalog-read Scope.

john-catalog-read.yaml
apiVersion: mission-control.flanksource.com/v1
kind: Scope
metadata:
name: john-catalog-read
namespace: default
spec:
targets:
- config:
name: "*"
---
apiVersion: mission-control.flanksource.com/v1
kind: Role
metadata:
name: john-catalog-read
namespace: default
spec:
description: Grant John read permissions to catalogs
rules:
- name: read-configs
action: read
resource:
scopeRef: john-catalog-read
---
apiVersion: mission-control.flanksource.com/v1
kind: RoleBinding
metadata:
name: john-catalog-read
namespace: default
spec:
role: john-catalog-read
subjects:
people:
- john@doe.com

The manifest has three parts:

  1. A Scope that selects every config.
  2. A Role with one rule, read, on that Scope.
  3. A RoleBinding that gives the Role to john@doe.com.

The three objects share a name only so the example reads clearly. Names are independent.

A rule has these fields:

FieldMeaning
nameA name for the rule, unique within the Role. It appears in status messages
actionWhat the rule allows, such as read or playbook:run
resource.scopeRefThe Scope of resources the action acts on
target.scopeRefFor playbook actions, the Scope of configs, components or checks a playbook may run against

A Role works only while every one of its rules is valid. If one rule breaks, for example because its Scope was deleted, the whole Role stops granting and its status shows Ready=False with the reason.

Running playbooks: resource and target​

Some actions involve two resources. When you run a playbook on a config, the playbook is what you act on, and the config is what you act against. A rule names each of them:

  • resource is the Scope of playbooks that may be run.
  • target is the Scope of configs, components or checks they may run on.
john-retry-echo-run.yaml
apiVersion: mission-control.flanksource.com/v1
kind: Scope
metadata:
name: retry-echo-playbook
namespace: default
spec:
targets:
- playbook:
name: retry-echo
---
apiVersion: mission-control.flanksource.com/v1
kind: Scope
metadata:
name: all-configs
namespace: default
spec:
targets:
- config:
name: "*"
---
apiVersion: mission-control.flanksource.com/v1
kind: Role
metadata:
name: john-retry-echo-run
namespace: default
spec:
description: allow user john to run retry-echo playbook on any config
rules:
- name: run
action: playbook:run
resource:
scopeRef: retry-echo-playbook
target:
scopeRef: all-configs
- name: approve
action: playbook:approve
resource:
scopeRef: retry-echo-playbook
target:
scopeRef: all-configs
- name: cancel
action: playbook:cancel
resource:
scopeRef: retry-echo-playbook
target:
scopeRef: all-configs
---
apiVersion: mission-control.flanksource.com/v1
kind: RoleBinding
metadata:
name: john-retry-echo-run
namespace: default
spec:
role: john-retry-echo-run
subjects:
people:
- john@doe.com

This Role lets John run, approve and cancel the retry-echo playbook on any config. Each action needs its own rule, which is why there are three.

A few things to keep in mind when granting playbooks:

  • Running a playbook on a config also needs read on that config. A run works with the data of the config, so whoever starts it must be able to see the config. Give John a separate read rule, or bind a Role such as viewer.
  • A rule without a target only covers runs that don't start from a config, component or check, such as a playbook you run from the playbooks list. To let a playbook run on configs, the rule needs a target.
  • To find a playbook in the UI, John needs read on it. The shipped viewer Role reads every playbook.
  • Keep each pairing in its own rule. A rule pairs its playbooks only with its own targets. If echo may run on staging and restart-pod only on production, write two rules, so neither playbook can run on the other's configs.

Common actions​

ActionLets someone
readSee resources, in listings and when opening them
create, update, deleteCreate, change or delete resources of a type
playbook:run, playbook:approve, playbook:cancelRun playbooks, approve runs that need approval, and cancel runs
mcp:runRun playbooks from an AI agent through MCP
connection:useAct with a connection's credentials, for example to send a notification
mcp:useConnect to Mission Control's MCP server

The Actions reference lists every action, including the plugin actions and the few that act on Mission Control itself, such as person:manage for managing users.

Seeing a connection versus using it​

Being able to see a connection and being able to use its credentials are different permissions:

  • read lets someone see a connection's name, type and settings. Credentials are always hidden.
  • connection:use lets someone, or something, act with those credentials.

This matters most for playbooks and notifications. A notification that sends to Slack needs connection:use on the Slack connection. A person who only needs to choose a connection in the UI needs read. Reading connections is granted for every connection at once, while connection:use can be limited to some. See also Connection permissions.

Writing is granted for a whole type​

create, update and delete, and read on connections, are always granted for every resource of a type. Their Scope must select the whole type, such as mission-control-builtin/all-configs. You can let someone edit all playbooks, but not only some of them.

Combining Roles​

A person can be bound to several Roles, and they can do everything any of them allows. Order doesn't matter, and adding a Role never takes access away.

So you can build up access from small Roles. Instead of one large "platform engineer" Role, you might bind three: viewer, a Role to run the monitoring playbooks, and a Role to use the alerting connections.

To take access away from someone regardless of what else they hold, use a deny RoleBinding.

Tips​

  • Start from the shipped Roles. viewer already reads the catalog, topology, health checks, playbooks and views. Bind it first, then write Roles only for what people need beyond that. See Shipped Roles.
  • Name rules after what they allow, such as read-staging or run-monitoring. The names appear in status messages and on the Subjects page.
  • Keep Roles small. Since one broken rule stops the whole Role, small Roles limit the damage.
  • Reference Scopes in other namespaces with namespace/name, such as mission-control-builtin/all-configs. A bare name refers to a Scope in the Role's own namespace.

Next steps​

Give your Role to someone with a RoleBinding.