# Setup for AWS Role Based Access ## Overview AWS role based access (role chaining) allows your embedded service to access AWS resources in customer accounts through a sequence of temporary credential assumptions: ``` Embedded Service → Assumer Role → Customer Role → AWS Resources (ROOT) (Your AWS) (Customer AWS) ``` Role chaining eliminates the need for customers to share long-lived access keys. Instead, each role in the chain uses temporary credentials with scoped permissions, following the principle of least privilege. All role assumptions are logged in CloudTrail for auditability, and customers retain full control; they can revoke access at any time by modifying their role's trust policy. ## Prerequisites Before configuring role chaining, you need an AWS account where you can host your Assumer Role, along with IAM permissions to create roles and policies. The embedded service should already be deployed and running, and you should have access to modify its feature flags and startup configuration. ## Part 1: Integrator Setup These steps are performed by the team deploying the embedded service. ### Step 1: Create ROOT Credentials The ROOT identity is what your embedded service uses to authenticate with AWS. For development and testing, an IAM User is sufficient. For production deployments, it is best practice to assume an IAM Role through workload identity. Some examples of workload identity authentication include EC2 instance roles, ECS task roles, EKS IRSA, and EKS Pod Identity. Create a policy that allows assuming your Assumer Role: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::YOUR_ACCOUNT_ID:role/YOUR_ASSUMER_ROLE_NAME" } ] } ``` Attach this policy to your ROOT user or role. ### Step 2: Create the Assumer Role The Assumer Role is a public-facing role that customers reference in their trust policies. Create this role in your AWS account. **Trust Policy** (allows ROOT to assume this role): If using an IAM Role as ROOT: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:role/YOUR_ROOT_ROLE" }, "Action": "sts:AssumeRole" } ] } ``` If using an IAM User as ROOT: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:user/YOUR_ROOT_USER" }, "Action": "sts:AssumeRole" } ] } ``` **Permissions Policy** (allows assuming customer roles): ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::*:role/*" } ] } ``` > You can restrict the `Resource` to a specific naming pattern (e.g., `arn:aws:iam::*:role/YourCompanyAccess*`) for additional security. Note the ARN of this role - you'll need it for service configuration and to provide to customers. ### Step 3: Configure the Embedded Service Start the embedded service with the Assumer Role ARN and enable the feature flag: ```bash ./embedded \ --aws-assumer-role arn:aws:iam::YOUR_ACCOUNT_ID:role/YOUR_ASSUMER_ROLE_NAME \ --features '{"aws_role_based_access_enabled": {"value": true}}' ``` Alternatively, use a features file: ```bash ./embedded \ --aws-assumer-role arn:aws:iam::YOUR_ACCOUNT_ID:role/YOUR_ASSUMER_ROLE_NAME \ --features-file /path/to/features.json ``` Where `features.json` contains: ```json { "aws_role_based_access_enabled": { "value": true } } ``` ## Part 2: Customer Setup Provide these instructions to customers who want to connect their AWS accounts. ### Step 1: Create an IAM Role Customers create a role in their AWS account with a trust policy that allows your Assumer Role to assume it. **Trust Policy**: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "ASSUMER_ROLE_ARN" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "CUSTOMER_EXTERNAL_ID" } } } ] } ``` In this policy, replace `ASSUMER_ROLE_ARN` with the Assumer Role ARN provided by your integrator, and `CUSTOMER_EXTERNAL_ID` with a unique identifier you generate (typically a UUID). You will provide both your role ARN and ExternalId to your integrator during onboarding or when completing the AWS provider configuration. The ExternalId is critical for security—see [Security Considerations](#security-the-externalid) below. ### Step 2: Configure Permissions Customers attach a permissions policy to their role granting access to the required AWS services. Example for S3 read access: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::their-bucket-name", "arn:aws:s3:::their-bucket-name/*"] } ] } ``` When advising customers on permissions, recommend they follow the principle of least privilege by granting only the permissions necessary for your integration. This limits the blast radius if credentials are ever compromised and makes security audits straightforward. ## Security: The ExternalId The ExternalId is a critical security mechanism that prevents the [confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html). Without it, a malicious actor could create a role in their own account that trusts your Assumer Role, then trick your service into accessing another customer's resources by providing the wrong role ARN. Your service would unknowingly act as a proxy for the attacker. The ExternalId solves this by requiring a unique secret that must match in both your `sts:AssumeRole` API call and the customer's trust policy condition. When customers onboard, they generate their own unique ExternalId (typically a UUID), embed it in their role's trust policy, and provide it to you along with their role ARN. Since only the legitimate customer knows their ExternalId, attackers cannot trick your service into assuming roles on their behalf. ## Testing the Configuration Use the AWS CLI to verify the role chain works end-to-end: ```bash # Step 1: Assume the Assumer Role ASSUMER_CREDS=$(aws sts assume-role \ --role-arn "arn:aws:iam::YOUR_ACCOUNT:role/ASSUMER_ROLE" \ --role-session-name "test-assumer" \ --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \ --output text) export AWS_ACCESS_KEY_ID=$(echo $ASSUMER_CREDS | awk '{print $1}') export AWS_SECRET_ACCESS_KEY=$(echo $ASSUMER_CREDS | awk '{print $2}') export AWS_SESSION_TOKEN=$(echo $ASSUMER_CREDS | awk '{print $3}') # Step 2: Assume the Customer Role aws sts assume-role \ --role-arn "arn:aws:iam::CUSTOMER_ACCOUNT:role/CUSTOMER_ROLE" \ --role-session-name "test-customer" \ --external-id "CUSTOMER_EXTERNAL_ID" ``` ## Troubleshooting ### "User is not authorized to perform: sts:AssumeRole" This error typically indicates a break in the trust chain. The ROOT identity may lack permission to assume the Assumer Role, the Assumer Role's trust policy may not allow ROOT, or the customer's role trust policy may not allow your Assumer Role. To resolve this, verify that Principal ARNs in all trust policies match exactly and that permission policies include `sts:AssumeRole` for the target role ARN. ### "Access denied" or "ExternalId mismatch" This error occurs when the ExternalId in your `sts:AssumeRole` API call doesn't match the value in the customer's trust policy, or when the ExternalId condition is missing from the trust policy entirely. Verify that the ExternalId matches exactly—it is case-sensitive—and ensure the customer's trust policy includes the `sts:ExternalId` condition. ### "The requested DurationSeconds exceeds the MaxSessionDuration" This error means the requested session duration exceeds the role's configured maximum. Either reduce the duration in your configuration, or have the customer increase their role's MaxSessionDuration setting (up to 12 hours). ### Feature flag errors If you see the message "AWS role-based access is disabled: configure feature flag 'aws_role_based_access_enabled' to enable", the embedded service was not started with role chaining enabled. Restart the service with the `--features` or `--features-file` flag to enable `aws_role_based_access_enabled`. ## Additional Resources - [AWS STS AssumeRole API Reference](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) - [How to Use External ID When Granting Access](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) - [IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) - [The Confused Deputy Problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)