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…
Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.
$ npx -y skills add controlplane-com/ai-plugin --skill setup-secret --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/setup-secretContext preview
The summary Claude sees to decide when to auto-load this skill.
Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.
name: setup-secret description: Secret access wiring and manifest authoring. Use when a workload needs to read a secret, the user asks to create a secret or generate secret YAML, configure a pull secret, or fix a deployment paused on a secret reference.
> **Tool availability:** secrets are read-only through MCP on every profile — `list_resources` / `get_resource` (kind="secret") show existence and metadata, never values. No tool creates, edits, deletes, or reveals a secret: secret data and lifecycle are managed by the user (Console, CLI, Terraform, Pulumi, or the API); you draft manifests with placeholders, the user fills the values and applies. `grant_workload_secret_access` (every profile) grants a workload access — it never returns values.
Secret access is the #1 thing users get wrong: a workload reads a secret only when **three** things are all in place. Miss any one and the value is silently absent at runtime — or the deployment pauses on an unresolved reference.
| Step | What must be true | Without it | |---|---|---| | **1. Identity** | an identity exists and is linked to the workload (`spec.identityLink`) | workload has no API credential — reads nothing | | **2. Policy** | a policy grants that identity `reveal` on the secret | reference resolves to empty | | **3. Reference** | the secret is injected as `cpln://secret/NAME` (env or volume) | nothing to read |
`reveal`, **not** `view` — `view` exposes only metadata. This is the single most common mistake.
To pull images from a private registry, don't build the chain. Add the registry secret to the **GVC's** `pullSecretLinks` and every workload in that GVC can pull. Pull secrets are registry credentials — `docker`, `ecr`, or `gcp` types.
kind: gvc
spec:
pullSecretLinks:
- //secret/my-registryDrafting the manifest is an expected part of the job — users ask for a scaffold, fill in the real values themselves, and apply it. Generate the YAML with UPPERCASE placeholders, then always hand back the next steps:
1. **Fill in the placeholders locally** — the value never enters the chat. 2. **Apply it**: `cpln apply -f secret.yaml --org ORG`, the Console's **cpln apply** button (paste the YAML), or the per-type CLI command that reads the value from a file (`cpln secret create-docker --name NAME --file config.json`). 3. **Treat the filled file as a live credential** — keep it out of git and delete it after applying. 4. **Say when it's done** — verify with `get_resource` (kind="secret") and continue with the access chain below.
Never ask for the real value in chat, and never apply the manifest yourself.
`data` has a fixed shape per `type`, validated by the backend on create. The trap: **for `docker`, `gcp`, and `azure-sdk`, `data` is a single JSON string** (a `>-` block scalar in YAML), never a YAML mapping — an object is rejected.
kind: secret
name: my-registry
type: docker
data: >-
{"auths":{"REGISTRY_HOST":{"username":"USERNAME","password":"PASSWORD"}}}| `type` | `data` | Backend validation | |---|---|---| | `opaque` | object `{payload, encoding?}` | `payload` valid base64 when `encoding: base64` (default `plain`) | | `dictionary` | object of string values | keys match `[-._a-zA-Z0-9]+` | | `userpass` | object `{username, password, encoding?}` | — | | `tls` | object `{cert, key?, chain?}` | `cert` and `key` must be valid PEM | | `keypair` | object `{secretKey, publicKey?, passphrase?}` | `secretKey` a valid PEM private key | | `aws` | object `{accessKey, secretKey, roleArn?, externalId?}` | `accessKey` starts `AKIA`, `roleArn` starts `arn:` | | `ecr` | aws fields + `repos` (1–20) | each `ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com[/REPO]` | | `azure-connector` | object `{url, code}` | `url` must be https | | `nats-account` | object `{accountId, privateKey}` | `accountId` a public nkey (`A…`), `privateKey` a seed (`SA…`) | | `docker` | **JSON string** | must parse with an `auths` object keyed by registry host, at least one entry | | `gcp` | **JSON string** | full service-account key: `type`, `project_id`, `private_key_id`, `private_key`, `client_email`, `client_id`, `auth_uri`, `token_uri`, `auth_provider_x509_cert_url`, `client_x509_cert_url` | | `azure-sdk` | **JSON string** | `subscriptionId` / `tenantId` / `clientId` (UUIDs) plus `clientSecret` |
`mcp__cpln__get_resource_schema` (kind="secret") returns the apply schema and REST endpoints.
The secret must already exist — the user creates and rotates it through any Control Plane surface: Console, CLI (value-in-a-file, never an inline flag), Terraform, Pulumi, or the API. Confirm it exists with `list_resources` or `get_resource` (kind="secret") before wiring anything; never ask for the value in chat and never invent a placeholder. If it does not exist yet, author the manifest (section above) and wait until the user has applied it.
**Preferred — one call.** `grant_workload_secret_access` (`gvc`, `workloadName`, `secretName`) creates the identity if missing (default `{gvc}-{workloadName}`), links it to the workload, and creates/updates a `reveal` policy (default `{gvc}-{workloadName}-secrets-policy`). It never returns secret values, and it does **not** inject the reference — step 3 still applies.
**Manual alternative** (granular control): `create_identity` → `update_workload` to set `spec.identityLink` → `create_policy` (targetKind `secret`, a `reveal` binding naming the identity). Policy shape lives in **access-control**.
**Ordering matters.** The workload must already exist. For a new workload that references a secret: `create_workload` first (its deployment pauses on the unresolved reference), then grant — the deployment resumes.
Identities are **GVC-scoped**: one per workload, shareable across workloads in the
Run containerized workloads across AWS, GCP, Azure, OCI, and your own hardware under one API.
Repo: controlplane-com/ai-plugin
Primary skill for access control, policies, and RBAC on Control Plane. Use when the user asks about permissions, policies, service accounts, user access, group…
Audit trail and compliance on Control Plane. Use when the user asks about audit logs, who changed what, change tracking, audit contexts, writing custom audit…
Workload autoscaling and Capacity AI on Control Plane. Use when the user asks about scaling up/down, min/max replicas, scale-to-zero,…
CDN caching and request rate limiting for Control Plane workloads. Use when the user asks about CDN, Cloudflare, CloudFront, edge caching, rate limiting,…
Writes cpln CLI commands and workflows for Control Plane. Use when the user asks about cpln login, cpln apply, cpln workload, CLI or CI/CD deploys, container…
Custom domains for Control Plane workloads. Use when the user asks to put a domain or subdomain in front of a workload, pick cname vs ns, configure routing or…