AWS IAM Policy for IRSA (S3 and SES)
When the Credo AI application runs on EKS you can avoid static IAM user credentials by using IAM roles for service accounts (IRSA). The application then obtains temporary credentials from AWS STS to reach its S3 object storage and, optionally, Amazon SES for outbound email.
This appendix documents a reference IAM policy that grants the permissions the application needs.
This policy covers both S3 object storage and SES email. If you are not using SES for email delivery, omit the SendRawEmail statement.
Prerequisites
- An IAM OIDC provider associated with your EKS cluster
- The S3 bucket(s) provisioned for the Credo AI application
- A verified SES sender identity, if using SES
Reference IAM Policy
Replace example-service and example-public with the names of the bucket(s) you entered on the Object Store configuration screen. If you configured a single bucket with path prefixes, list that bucket in place of both.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllBuckets",
"Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
"Effect": "Allow",
"Resource": "arn:aws:s3:::*"
},
{
"Sid": "ListBucket",
"Action": "s3:ListBucket",
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::example-service",
"arn:aws:s3:::example-public"
]
},
{
"Sid": "ReadOnlyBucketAccess",
"Action": "s3:GetObject",
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::example-service/*",
"arn:aws:s3:::example-public/*"
]
},
{
"Sid": "SendRawEmail",
"Action": "ses:SendRawEmail",
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "ServiceBucketAccess",
"Action": "s3:*",
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::example-service",
"arn:aws:s3:::example-service/*",
"arn:aws:s3:::example-public",
"arn:aws:s3:::example-public/*"
]
}
]
}
Statement Reference
| Sid | Purpose |
|---|---|
AllBuckets | Allows the application and the AWS SDK to enumerate buckets and resolve a bucket's region. s3:GetBucketLocation avoids region redirect errors when the client region does not match the bucket region. |
ListBucket | Allows listing the objects within the Credo AI buckets. Required for object existence checks and prefix listings. |
ReadOnlyBucketAccess | Allows reading objects, such as user document downloads and policy pack assets. |
SendRawEmail | Allows the server to send email through SES. ses:SendRawEmail is the only SES action required. Omit this statement if you are using an SMTP server instead of SES. |
ServiceBucketAccess | Grants full object and bucket-level access, which is required for user document uploads, multipart uploads, deletes, and presigned URL generation. |
ServiceBucketAccess is a superset of the ListBucket and ReadOnlyBucketAccess statements. The narrower statements are kept separate so you can drop the s3:* statement and grant only the specific write actions your security policy allows (for example s3:PutObject, s3:DeleteObject, s3:AbortMultipartUpload, and s3:ListMultipartUploadParts).
s3:ListAllMyBuckets is account-wide and cannot be scoped to specific buckets. If your organization prohibits account-wide bucket enumeration, remove the AllBuckets statement and verify object storage operations in a non-production environment first.
Scoping SES
The SendRawEmail statement above uses "Resource": "*". To restrict sending to a specific verified identity, scope the statement to the SES identity ARN and, optionally, the sender address configured in kots.
{
"Sid": "SendRawEmail",
"Action": "ses:SendRawEmail",
"Effect": "Allow",
"Resource": "arn:aws:ses:us-east-1:123456789012:identity/example.com",
"Condition": {
"StringEquals": {
"ses:FromAddress": "noreply@example.com"
}
}
}
The sender address must be a verified SES identity, and the SES account must be out of the sandbox to send to arbitrary recipients. Refer to the AWS SES documentation for more details.
Create the Role
Create an IAM role with a trust policy for the cluster's OIDC provider, scoped to the namespace and service account the Credo AI application runs under.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:aud": "sts.amazonaws.com",
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:sub": "system:serviceaccount:credoai:credoai-server"
}
}
}
]
}
Attach the reference policy above to the role.
Replace the account id, region, OIDC provider id, and namespace (credoai) with the values for your installation. The backend service account name is credoai-server and does not change. If you prefer, use StringLike with system:serviceaccount:credoai:* to cover all service accounts in the application namespace.
Configure kots
Enter the role ARN as the IRSA annotation value on the AWS Credentials configuration screen, and leave the access key id and secret access key fields empty.
arn:aws:iam::123456789012:role/credoai-server
If you are also using SES for email, set the SMTP Server field to USE_SES and leave the SMTP Username and SMTP Password fields empty. See Configure Email for the full email configuration.
Verify
After deploying, confirm the credentials are being sourced from the role rather than static keys.
# confirm the service account carries the role annotation (IRSA)
kubectl get serviceaccount -n credoai -o yaml | grep -A1 eks.amazonaws.com/role-arn
# confirm the pod received the projected token and role environment
kubectl exec -n credoai <server-pod-name> -- env | grep AWS_
# confirm the assumed identity from within the pod
kubectl exec -n credoai <server-pod-name> -- aws sts get-caller-identity
If object storage operations fail after switching to IRSA, see the FAQ for common S3 authentication and SSE header errors.