This guide is for platform operators running Chainloop on-prem in AWS. If your users want to bring their own storage (OCI registry, their own S3 bucket, Azure Blob, etc.) instead, see the CAS backend concepts page.
How It Works
- Single shared bucket per Chainloop installation. There is no per-org bucket to provision or rotate.
- A periodic reconciler in the Chainloop backend creates one S3 Access Point per organization, named with a stable prefix (for example
chainloop-<org-uuid>). - The controlplane talks to the access point through ephemeral, per-request
sts:AssumeRolesessions. No long-lived credentials are ever stored in Chainloop’s secrets backend — only the tenant’s AP ARN and the base role ARN. - Org-level isolation is layered:
- The access point resource policy restricts who can address the AP, scoped via
aws:useridto the session minted for that org. - A per-tenant IAM managed session policy further narrows the assumed session to the org’s AP and its key prefix.
- The bucket policy rejects any request whose
s3:DataAccessPointArndoesn’t match your installation’s AP-name prefix, so a misconfigured role still cannot cross the boundary. - Every object is keyed under
<org-uuid>/sha256:<digest>inside the bucket.
- The access point resource policy restricts who can address the AP, scoped via
- Encryption at rest is delegated to a customer-managed KMS key on the bucket (
SSE-KMS).
Prerequisites
You will provision the following resources in your AWS account before enabling the feature in Chainloop. We recommend managing them with Terraform or OpenTofu.- A single S3 bucket for the installation
- A customer-managed KMS key for
SSE-KMSon the bucket - A tenant IAM role — the “base role” the Chainloop workloads assume per-request
- Workload identities (EKS Pod Identity or IRSA) attached to the Chainloop
backend,controlplane, andcaspods so they can call AWS APIs
chainloop- or chainloop-prod-. Every access point Chainloop creates will start with this prefix; the bucket policy and IAM permission policies below all reference it.
1. Create the S3 Bucket
Create one bucket in the region you want to operate from. Block all public access. Enable default encryption with the KMS key you create in the next step. Attach this bucket policy to constrain every request to go through an access point that matches your prefix:[bucketName], [region], [accountId], and [apPrefix] with your values.
2. Create the KMS Key
Create a customer-managed KMS key in the same region as the bucket and set it as the bucket’s default encryption key. Make sure the key policy allows both the tenant role (forEncrypt/Decrypt on the data path) and the backend workload identity (for AP lifecycle calls) to use it.
3. Create the Tenant IAM Role
This is the role the Chainloop workloads assume per-request via STS. Note its name — you will pass it to the chart asbaseRoleName.
Trust policy — allow the backend and controlplane workload identities to assume it, including sts:TagSession (the Chainloop backend tags every assume call with the tenant identifier):
4. Configure Workload Identities
The Chainloop pods need AWS credentials to call AWS APIs. We recommend EKS Pod Identity; IRSA works equivalently. You need two workload identity roles: Controlplane workload role — used by the controlplane and cas pods on the data path. Needs to callsts:AssumeRole against the tenant role:
[sessionPolicyPrefix] is the prefix Chainloop uses when naming the per-tenant managed policies it creates. Pick a short, installation-specific prefix such as cas-. The only requirement is that this IAM resource scope matches what the backend will actually create.
The IAM “1500 customer-managed policies per account” service quota applies because Chainloop creates one managed policy per organization. Request a quota increase if you expect to scale past it.
Enable in Chainloop EE
In yourchainloop-ee Helm chart values.yaml, configure backend.managedCas:
chainloop-ee values.yaml
chainloop-ee values.yaml
aws_eks_pod_identity_association per (namespace, service account) pair instead.
Apply the values and roll out the chart.
Verify
- Create a new organization in the Chainloop UI. Open Storage Backends for that org — you should see a default backend named
chainloop-cloud-storagelabelled “managed by Chainloop”.
- Watch the platform backend logs — within one reconciliation cycle you should see it create a new access point under your prefix, e.g.
chainloop-<org-uuid>. Verify in the AWS console under S3 → Access Points. - As a user of that org, run an attestation or upload an artifact:
- Inspect the bucket — the object should be under the org’s prefix, encrypted with your KMS key:
sts:TagSession action on the tenant role’s trust policy, or a bucket policy whose AP-prefix glob does not match the access point names Chainloop is creating.