Skip to main content

Create a permission set

POST 

/permission-sets

Defines a new permission set for your tenant.

This call touches nothing in AWS. It writes a single row to Prism's database; no IAM role is created and no AWS API is called. A permission set stays inert until you assign it to a principal for an account, and it is that assignment which cuts the role.

Pick name carefully: it is folded into the IAM role name Prism creates in every account, AWS role names are immutable, and Prism therefore refuses to rename a permission set for the rest of its life. Names must be unique within your tenant, but that uniqueness is enforced by a database constraint rather than by a check in the handler, so a duplicate name comes back as a 500, not a 409.

An IAM role can hold at most 10 attached policies, and managed_policies, customer_managed_policy_ids and policy_reference_ids share that budget. This endpoint does not reliably enforce it, and going over is not reported to you here. The total is only counted on a request that also names at least one customer_managed_policy_ids or policy_reference_ids entry; a request that busts the budget using managed_policies alone is accepted without complaint: 11 or 15 ARNs are stored, echoed in the 200, and read back by a later GET exactly as sent.

Nothing is broken in AWS at that point, because a create touches no AWS at all. The ceiling is AWS's and it bites when the role is finally cut: the first assignment that provisions this permission set into an account is what fails, long after the create said 200.

Read that failure the way POST /permission-set-assignments describes every provisioning failure, because nothing about this one is special. The ordinary path deletes the assignment row, so the id that call handed you starts answering 404 from GET /permission-set-assignments/{id}; treat that 404 as "the role could not be cut", not as "this never existed". A row that survives with status: "FAILED" and a populated errorMessage is the rare case where Prism could not clean up after itself, worth reading if you get one, but not what to wait for. Which of the two an over-budget permission set produces has not been isolated against a live AWS account, so handle both.

There is no signal at create time either way, so count the three lists yourself before sending.

A failed create can still leave a permission set behind. The row is written before customer_managed_policy_ids and policy_reference_ids are checked, so an unknown id returns 500 with the permission set already created, possibly with the customer-managed policies already attached and only the references rejected. After a 500, list or fetch before retrying rather than assuming nothing happened.

Two shape notes. The response is 200, not 201, and carries no Location header. And its realm is always the empty string, because the create path builds the response without that field; re-fetch with GET /permission-sets/{id} if you need the real value.

Request​

Responses​

The permission set was created. The body carries the stored definition, with managed_policies, inline_policies and attributes normalised to [] or {} where you sent nothing; this operation never returns them as null.