Replace a permission set
PUT/permission-sets/:id
Replaces a permission set's definition and re-synchronises the IAM roles already provisioned from it.
This is a full replacement, not a partial update, and any field you
omit is destroyed rather than preserved. managed_policies,
inline_policies and attributes are written from the request body
unconditionally, with no guard for a missing key, so leaving one out
stores a literal null in its place: the policies that were there are
detached, and this response and every later GET report that field as
null. Omitting description, session_duration or relay_state
clears them just as silently. Nothing about the response distinguishes
"you cleared this" from "this was already empty". Always read the
permission set with GET /permission-sets/{id} first and send every
field back, changing only what you mean to change.
The two attachment id lists are the sole exception. Both
customer_managed_policy_ids and policy_reference_ids are tri-state:
omit the key to leave the current attachments untouched, send [] to
detach all of them, or send a list to reconcile to exactly that list.
name must be present and must equal the stored name exactly. It is not
a no-op field: because AWS role names are immutable, any difference
(including omitting name, which sends an empty string) is refused with
400 and nothing is written. realm in the body is ignored, and realm
in the response is always the empty string.
This operation changes live AWS infrastructure, asynchronously. Once
the database write commits, Prism starts a background job that, for every
account where this permission set has a provisioned assignment, calls
UpdateRole with the new session duration, detaches the role's current
managed policies, deletes its existing inline policies, then attaches and
puts the new ones. Attaching or detaching customer-managed policies and
policy references is fanned out the same way. The 200 is returned
before any of that finishes and its outcome is never reported back.
The phrase "roles synchronized across all accounts" in the success
message describes the intent, not a completed fact. Check the roles in
AWS, or the assignment records, if you need confirmation.
Nothing is touched in AWS when there is nothing to do: if neither the policies nor the session duration changed, or if the permission set has no provisioned assignment yet, the update is a database write and nothing more.
The converse also holds: a non-2xx from this operation does not mean nothing changed. The database write commits before the assignments are listed for synchronisation, and a failure at that later step returns 500 with the new definition already stored. Re-fetch before retrying.
Request
Responses
- 200
- 400
- 401
- 403
- 404
- 500
The permission set was updated in Prism, and role synchronisation across the affected AWS accounts has been started if it was needed.
Most of the body echoes what you sent rather than re-reading the
stored row, which has two consequences: managed_policies,
inline_policies and attributes come back null if you omitted
them, and customer_managed_policies is absent when you did not
mention customer_managed_policy_ids, even though those policies are
still attached. Only policy_references is re-read after
reconciliation and so always reflects what is really attached. When
in doubt, GET /permission-sets/{id} gives the true state.
Nothing was written. Either the body was not valid JSON, or
session_duration, relay_state or an inline_policies key failed
validation, or, most commonly, name did not match the stored
name. A permission set cannot be renamed, so send its current name
back unchanged.
Authentication failed: the X-API-Token header was missing, malformed,
expired or not recognised.
This response is text/plain, not JSON. It is written by
http.Error in the authentication middleware, which runs before any
handler and therefore before anything that would build a JSON envelope.
A client that unconditionally JSON-parses response bodies will fail on
this one, so check the status code first.
The token is valid, but it is not allowed to act on this tenant.
An API token is minted inside one tenant and stays bound to it for life.
Sending it to a path whose tenant segment names a different tenant is
refused here, in middleware, before the operation runs, so this says
nothing about the resource you asked for, only about which tenant the
path named. Check the tenant server variable against the console the
token was created in.
A 404 here does not reliably mean the permission set is missing.
Two unrelated failures report through it, and only error tells them
apart.
The first is the one the status suggests, and means no permission set with this id exists in your tenant: either it never did, it belongs to another tenant, or it has been deleted. A tenant segment that names no tenant reports the same way.
The second is an unknown or out-of-tenant id in
customer_managed_policy_ids or policy_reference_ids. That is
mis-reported here, under the same misleading
"Permission set not found" message, even though the permission set
was found and still exists; a GET /permission-sets/{id} straight
afterwards returns it. error names the real cause, e.g. failed to update permission set in database: one or more customer-managed policies not found in realm "acme", and an unknown policy reference
reports the same way with one or more policy references not found.
Read error before concluding that anything is missing, and note
that POST /permission-sets answers the identical bad input with a
500 instead.
The update failed. Causes include a plain database failure, and more
than 10 policies across managed_policies,
customer_managed_policy_ids and policy_reference_ids on a request
that sends at least one of those two id lists. An over-budget
request that omits both lists is never counted and succeeds.
An unknown or out-of-tenant id in either list does not land here. It comes back as a 404 instead, misleadingly; see the 404 above for how to recognise it.
Do not read this as "nothing happened". The permission set row is saved before the provisioned assignments are gathered for synchronisation, so a failure at that stage returns 500 over an already-committed change. Re-fetch the permission set before retrying.