IAM
AWS credentials a project has issued for object storage and container registries.
Some AWS-native tooling cannot use a Cosmoner API key — aws ecr get-login-password,
Kubernetes image pull secrets, S3 clients. These endpoints issue scoped AWS
credentials for those cases and list every credential a project has out there.
Cosmoner API keys are a different thing and are not listed here — see API Keys.
List Credentials
GET /v1/projects/:projectId/iamReturns every AWS credential the project has issued as one list. A credential
can cover both services at once, so it is listed once with a registry and a
storage half — either is null when the credential does not reach that
service. errors carries whatever could not be reached: a service that is
having a bad day reports itself instead of failing the request.
{
"success": true,
"data": {
"credentials": [
{
"iamUserName": "dbd-iam-<projectId>-ci-pipeline",
"label": "ci-pipeline",
"accessKeyId": "AKIA…",
"createdAt": "2026-08-04T12:00:00.000Z",
"origin": "project",
"registry": {
"access": "push",
"allRepositories": false,
"repositories": [
{
"repositoryId": "cmsh95uld0000ce9kkchanq4y",
"repositoryName": "frontend",
"registryId": "cmsh95uld0000ce9kkchanq4z"
}
]
},
"storage": {
"access": "write",
"allBuckets": false,
"buckets": [{ "bucketId": "…", "bucketName": "assets" }]
}
}
],
"errors": []
}
}origin says which shape a credential has. project credentials are the
current model, may span both services, and are the only ones that can be
re-scoped. registry and bucket are the two older single-service shapes —
still listed and still working, with the scope they were created with.
allRepositories and allBuckets mean the grant covers everything in the
project, including resources created later. The repositories and buckets
arrays alongside them then list what exists today, which is not the boundary —
do not read them as the grant.
Auth: Required (member, scope: iam:read)
Get Credentials
GET /v1/projects/:projectId/iam/:iamUserNameReturns one credential in the same shape the list uses. Returns 404 if the
project has no credential by that name.
Auth: Required (member, scope: iam:read)
Create Credentials
POST /v1/projects/:projectId/iam{
"label": "ci-pipeline",
"registry": { "access": "push", "repositoryIds": ["cmsh95uld0000ce9kkchanq4y"] },
"storage": { "access": "write", "bucketIds": [] }
}| Field | Default | Notes |
|---|---|---|
label | — | 1–20 characters. Must be unique within the project; it becomes part of the IAM user name. |
registry | null | Omit or set to null for a credential that reaches no registry. |
registry.access | pull | pull is read-only. push also allows uploading images. |
registry.repositoryIds | [] | Repositories the credential reaches. Empty means every repository in the project, including ones created later. |
storage | null | Omit or set to null for a credential that reaches no bucket. |
storage.access | write | read allows downloading and listing. write also allows uploading and deleting. |
storage.bucketIds | [] | Buckets the credential reaches. Empty means every bucket in the project, including ones created later. |
At least one of registry and storage is required — a credential that reaches
nothing is a key you have to rotate for no benefit.
The response includes secretAccessKey, which is returned once and never
stored. Lost secrets cannot be recovered — delete the credential and create a
new one.
Registry scoping stops at the repository: an ECR repository name carries the project and the repository but not the registry it was created under, so a credential can name individual repositories or cover the whole project, but not one registry within it. Pulls made with it go straight from AWS to the client and are not metered as egress; storage is billed as usual.
Returns 404 if registry is set and the project has no container registry, or
if any id in registry.repositoryIds or storage.bucketIds does not belong to
the project.
Auth: Required (member, write access, scope: iam:write)
Update Credentials
PATCH /v1/projects/:projectId/iam/:iamUserName{
"registry": { "access": "push", "repositoryIds": ["cmsh95uld0000ce9kkchanq4y"] },
"storage": { "access": "read", "bucketIds": [] }
}Rewrites what the credential reaches, keeping the same access key — nothing
using it has to be reissued. registry and storage take the same fields as on
create, and both halves are applied in full: a half sent as null or omitted is
dropped from the credential, so send the halves you want it to keep. At least
one of them is required.
The label cannot be changed. It is part of the credential's name in AWS, so a different label is a different credential: create a new one and delete this.
Returns the credential as it now reads, resolved the same way the list resolves
it. Returns 400 for a credential with origin of registry or bucket —
those are fixed at the scope they were created with — and 404 if the
credential no longer exists.
Auth: Required (member, write access, scope: iam:write)
Delete Credentials
DELETE /v1/projects/:projectId/iam/:iamUserNameDeletes the IAM user and its access keys, whichever origin it has. Anything
using the key stops working immediately. Returns 403 if the credential belongs
to another project.
Auth: Required (member, write access, scope: iam:write)
Create Registry Credentials (legacy)
POST /v1/projects/:projectId/iam/container-registry{
"label": "ci-pipeline",
"access": "push",
"repositoryId": "cmsh95uld0000ce9kkchanq4y"
}The registry-only shape, kept for callers written against it. It creates a
credential with origin: "registry", which cannot be widened to object storage
afterwards. Prefer POST /v1/projects/:projectId/iam.
Auth: Required (member, write access, scope: iam:write)
Delete Registry or Bucket Credentials (legacy)
DELETE /v1/projects/:projectId/iam/container-registry/:iamUserName
DELETE /v1/projects/:projectId/iam/object-storage/:bucketId/:iamUserNameBoth do what DELETE /v1/projects/:projectId/iam/:iamUserName does, for their
one shape. The bucket-only create endpoint they pair with is documented under
Object Storage and is likewise legacy — credentials made
there cannot be re-scoped afterwards.
Auth: Required (member, write access, scope: iam:write)