Docs
Guidesince cloud@2026-09-10

An AWS workload

A server on AWS signs one harmless AWS call with the role it already runs as, and nothing secret leaves the machine.

Not verified yet

This page is an outline. Nothing here has been confirmed against source, so do not follow it as product behavior.

Your CI logs in like a person does, with no key to steal. A server on AWS does the same. It signs one harmless AWS call with the role it already runs as and sends the signed request to Penv Cloud. Penv Cloud replays that request to AWS to learn who signed it.

This page is incomplete on purpose. The penv binary signs content-type, host, x-amz-date and x-amz-security-token, and packages/store/src/aws-iam.ts refuses a request whose signed headers do not include x-penv-cloud-org carrying the workspace id. Until the binary signs that header there is no end-to-end command line path to document, so this page describes the mechanism and the console setup only. Issue a pck_ credential in the console and pass it in PENV_TOKEN meanwhile.

What the workload proves

The call is sts:GetCallerIdentity, signed with SigV4 using the role the workload already runs as. The body is byte for byte Action=GetCallerIdentity&Version=2011-06-15, because its hash is part of the signature. The server reads that body strictly and refuses a parameter it does not know, because ignoring an extra parameter is how CVE-2022-2385 worked against another AWS authenticator.

Nothing secret leaves the machine. The signature is useless for anything except that one call, against that one endpoint, for a couple of minutes. Penv Cloud never sees the secret access key.

These rules govern the exchange:

  • The workspace id travels inside the signature. x-penv-cloud-org has to appear in SignedHeaders, and a request where the header is merely present is refused. Presence alone can be fitted onto any captured signature, and nothing else in a GetCallerIdentity signature says who the request was meant for.
  • The matcher is the account plus the role's immutable id. A role name can be recreated and a session name is chosen by the caller, so neither is trusted.
  • The host is matched whole, against a pattern per partition. The global sts.amazonaws.com passes and so does a regional sts.<region>.amazonaws.com, with GovCloud and China on patterns of their own. Nothing here does a substring test, which would accept amazonaws.com.cn.evil.com. The binary signs a regional host, resolving the region from AWS_REGION, then AWS_DEFAULT_REGION, then us-east-1.

A captured signature cannot be replayed anywhere else, and it cannot be replayed here either: SigV4 carries no nonce, so single use is enforced on the Penv Cloud side by a distributed guard that records the request only once AWS has answered, which leaves a retry after an outage working.

Set up the trust

Open Machine Identities then All Identities, create an identity bound to the project and environment it should read, then add an AWS trust to it. Confirming it is you is required to create the identity.

FieldWhat it is
Partitionaws, or the partition your account lives in
Account IDThe twelve-digit account the role belongs to
Role unique IDThe role's immutable id, the AROA... string
ExpiryHow long the trust itself stays valid

Read the role's unique id with aws iam get-role --role-name YOUR_ROLE --query Role.RoleId. It is not the ARN, and it does not survive a delete and recreate, which is the point.

What the machine gets back

The exchange returns a pck_ credential that lasts fifteen minutes, capped by the trust's own expiry, bound to one project and one environment. A request naming any other environment is refused with 403 forbidden.

AnswerWhat it means
401 unauthorizedThe trust does not name this account and role id
401 expiredThe trust's own expiry has passed
503 unavailablePenv Cloud could not reach AWS STS. Retry once

Where the machine's credentials come from

The binary reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN from its own environment. Every AWS runtime that hands a role to a process sets all three. The session token is optional to the binary, and it is signed whenever it is there.

Do it in order

  1. Read the role's unique id: aws iam get-role --role-name YOUR_ROLE --query Role.RoleId.
  2. Open Machine Identities then All Identities and create an identity for that workload.
  3. Add an AWS trust to it with the partition, the account id and the role unique id.
  4. Until the binary signs the workspace header, issue a pck_ credential on the same identity.
  5. Put that credential in PENV_TOKEN on the host and run penv run -- <your command>.
  6. Open the audit log and confirm the read names the identity you just created.

A host that proves nothing