Skip to content
Deployment
Skill

/access-control

Primary skill for access control, policies, and RBAC on Control Plane. Use when the user asks about permissions, policies, service accounts, user access, group membership, bindings, who can do what, least-privilege, or IAM.

From plugin
ai-plugin
1132 skills2 agents2 commands1 MCP

Claude Code

$ npx -y skills add controlplane-com/ai-plugin --skill access-control --agent claude-code

SKILL.md

access-control.SKILL.md
name: access-control
description: "Primary skill for access control, policies, and RBAC on Control Plane. Use when the user asks about permissions, policies, service accounts, user access, group membership, bindings, who can do what, least-privilege, or IAM."

Access Control & Policies — Primary Skill

> **Tool availability:** `get_permissions`, `create_group`, `edit_group`, `create_service_account`, `update_service_account`, `add_key_to_service_account`, and `invite_user_to_org` need `?toolsets=full`; reconnect with it or use the CLI. On core, `grant_workload_secret_access` (`remove: true` revokes) grants a workload secret access through its identity and a policy, creating either when missing; `grant_cloud_access` creates no policy: it makes sure the workload has an identity and sets that identity's cloud provider access.

A **policy** targets one resource kind and binds **permissions** to **principals** (users, groups, service accounts, workload identities). The common failure is a policy that **exists but grants nothing** — a wrong `targetKind`, permission name, or principal link fails with no error — so read the policy back after writing.

The model

| Layer | Scope | Controls | |---|---|---| | **Billing-account roles** | account-wide (set on the billing account, separate from org policies) | `billing_admin`, `billing_viewer`, `org_creator` — none grant org-resource access | | **Org policies** | per resource kind | all day-to-day access |

A caller is allowed an action when some policy on the resource's kind has a binding that lists that action (or a permission implying it) **and** names the caller — or a group the caller is in.

Policy anatomy

A policy = one **`targetKind`** + a **target scope** + **bindings**.

kind: policy
name: app-secret-access
targetKind: secret           # exactly one resource kind
targetLinks:                 # OR `target: all` OR `targetQuery:` (pick one)
  - //secret/database-url
bindings:                    # ≤ 50
  - permissions: [reveal, use]
    principalLinks:          # 1–200
      - //gvc/production/identity/app-identity

**Limits:** `bindings` ≤ 50; `principalLinks` 1–200 per binding; `targetLinks` ≤ 200. `origin` is read-only — `default` (yours) or `builtin` (locked; see Built-ins).

**Target scope (pick one):** `target: all` (org-wide roles) · `targetLinks` (specific resources) · `targetQuery` (tag query — see **query-spec**).

**Valid target kinds:** the `targetKind` enum accepts all **33** resource kinds, but only the **20 kinds with permission schemas** (the ones `get_permissions` accepts) are meaningful targets: `workload, secret, gvc, identity, image, org, policy, group, serviceaccount, user, volumeset, domain, location, ipset, mk8s, cloudaccount, agent, auditctx, quota, task`.

**Create vs update:**

  • `create_policy` builds **one** binding from `addPermissions` × (`addUsers`/`addGroups`/`addServiceAccounts`/`addIdentities`) — providing only one side is an **error** (a binding needs both). It takes the target scope as `targetAll`, `targetLinks`, or `targetQuery`; they may be combined, and `targetAll` wins. For several distinct bindings, use `update_policy` `addBindings`.
  • `update_policy` **merges** bindings (matched by exact permission set — you can't extend a set) but **replaces** targets (`targetLinks` wholesale, `removeTargetLinks` incremental, `targetAll` — mutually exclusive).

Permissions

**`get_permissions` (`kind`) is the source of truth** — it returns the kind's exact permission list and its implication map. Confirm names with it before writing a policy; never hand-write them, and don't assume a kind only has `create` / `delete` / `edit` / `view` / `manage`.

Two traps that don't need a lookup:

  • **`manage` implies every permission** for a kind — grant it only to true admins.
  • **Secret values need `reveal`, not `read`** — the most common mistake.

Many kinds add non-obvious permissions beyond CRUD — e.g. secret `reveal`/`use`, image `pull`, workload `connect`/`exec.*`, serviceaccount `addKey`, user `invite`/`impersonate`, mk8s `clusterAdmin` — so pull the real set with `get_permissions`.

Principals

| Type | Link | |---|---| | User | `//user/EMAIL` | | Group (preferred) | `//group/NAME` | | Service account | `//serviceaccount/NAME` | | Workload identity | `//gvc/GVC/identity/NAME` (**GVC-scoped** — never `//identity/NAME`) |

An **identity never belongs to a group**, so authorize it only with a binding that names its exact link. At runtime the attached identity is the workload's API credential: calls from inside the workload with the injected `CPLN_TOKEN` against `CPLN_ENDPOINT` carry exactly the permissions policies grant that identity — nothing more.

Groups

Members are **users and service accounts only** (≤ 200). Bind policies to groups, not individuals.

  • **Create / edit:** `create_group` (`name`, `memberLinks`, `memberQuery`, `identityMatcher`); `edit_group` (`addMemberLinks` / `removeMemberLinks` — read first with `get_resource` (kind="group")).
  • **Dynamic:** `memberQuery` matches users by tag query; `identityMatcher` matches identities by a `jmespath`/`javascript` expression.

Service accounts (non-human / CI/CD)

  • **Key:** `add_key_to_service_account` (`serviceAccountName`, optional `keyDescription` and `groupName`) creates the SA if missing and returns the Console keys page, where the user adds the key and sees it once; the key never passes through the chat (lost = revoke + remint). `create_service_account` makes one with no key.
  • **Revoke:** `update_service_account` `removeKeys: [NAME]` (immediate). `delete_resource` (kind="serviceaccount") revokes all keys.
  • **CI/CD auth:** store the key as the `CPLN_TOKEN` secret/env var — the CLI uses it ahead of any profile (and works without one); don't pass `--token` on the command line (it leaks into logs). Full setup: **gitops-cicd**.

Users (IDP-backed)

  • **Invite:** `invite_user_to_org` (`email`, optional `groupName`).
  • **Read
Read more
@controlplane-com
Ships withai-plugin

Run containerized workloads across AWS, GCP, Azure, OCI, and your own hardware under one API.

1132 skills2 agents1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
11
Star history of controlplane-com/ai-plugin on GitHub, a chart by star-history.com

Other skills on ai-plugin.

cpln

cpln

Writes cpln CLI commands and workflows for Control Plane. Use when the user asks about cpln login, cpln apply, cpln workload, CLI…

create-app

create-app

Writes, builds, and deploys an app the user asks for in the chat, with no repository and no image yet. Use when the user asks to…

domain

domain

Custom domains for Control Plane workloads. Use when the user asks to put a domain or subdomain in front of a workload, pick…

More skills from other plugins.

configuring-horizon

configuring-horizon

Use this skill whenever the user mentions Horizon by name in a Laravel context. Covers the full Horizon lifecycle: installing…

coolify11d66k
@coollabsio@coollabsioInstall Skill
vercel-cli

vercel-cli

Guides deployment, configuration, and troubleshooting with the Vercel CLI. Use when operating Vercel projects or resources…

vercel13d16k
@vercel@vercelInstall Skill
skypilot

skypilot

Use when launching cloud VMs, Kubernetes pods, or Slurm jobs for GPU/TPU/CPU workloads, training or fine-tuning models on cloud…

@skypilot-org@skypilot-orgInstall Skill
pinme

pinme

Use this skill when the user mentions "pinme", or needs to upload files, store to IPFS, create/publish/deploy websites or…

pinme2mo3.8k
@glitternetwork@glitternetworkInstall Skill

Questions about access-control.

Which coding agents can use access-control?
access-control installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.