chitecture Decision:** Use IAM Roles for all EC2 instances, Lambda functions, and CI/CD pipelines. Reserve IAM Users for human operators and legacy systems that cannot support role assumption.
TypeScript Implementation: Role Assumption via AWS SDK v3
Instead of embedding credentials, applications should assume roles programmatically. This example demonstrates how to assume a role using the AWS SDK for JavaScript (v3), which is the modern standard for Node.js environments.
import { STSClient, AssumeRoleCommand } from "@aws-sdk/client-sts";
import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3";
interface RoleCredentials {
accessKeyId: string;
secretAccessKey: string;
sessionToken: string;
}
async function assumeTargetRole(roleArn: string, sessionName: string): Promise<RoleCredentials> {
const stsClient = new STSClient({ region: "us-east-1" });
const command = new AssumeRoleCommand({
RoleArn: roleArn,
RoleSessionName: sessionName,
DurationSeconds: 3600, // Max session duration
});
const response = await stsClient.send(command);
if (!response.Credentials) {
throw new Error("Failed to assume role: No credentials returned.");
}
return {
accessKeyId: response.Credentials.AccessKeyId!,
secretAccessKey: response.Credentials.SecretAccessKey!,
sessionToken: response.Credentials.SessionToken!,
};
}
// Usage Example
async function secureS3Operation() {
try {
const creds = await assumeTargetRole(
"arn:aws:iam::123456789012:role/S3ReadOnlyRole",
"secure-app-session"
);
// Use temporary credentials for S3 client
const s3Client = new S3Client({
region: "us-east-1",
credentials: creds,
});
const buckets = await s3Client.send(new ListBucketsCommand({}));
console.log("Accessible Buckets:", buckets.Buckets?.map(b => b.Name));
} catch (error) {
console.error("Identity operation failed:", error);
}
}
2. Granular Policy Design with Conditions
Policies must enforce the principle of least privilege by specifying exact actions and resources. Advanced policies should include conditions to restrict access based on context, such as source IP, MFA status, or time of day.
Policy Example: Conditional S3 Access
This policy allows GetObject only if the request originates from a specific CIDR block and MFA has been authenticated.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ConditionalS3ReadAccess",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::production-data-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
},
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
3. AWS CLI Automation and Querying
The AWS CLI enables infrastructure automation and rapid debugging. Advanced usage involves filtering outputs and formatting data for integration with other tools.
CLI Workflow: Filtering and Formatting
Instead of retrieving full JSON payloads, use JMESPath queries to extract specific data. This reduces bandwidth and simplifies scripting.
# List running EC2 instances with specific tags
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query "Reservations[].Instances[].{ID:InstanceId,Env:Tags[?Key=='Environment'].Value|[0],Type:InstanceType}" \
--output table
CLI Workflow: Identity Verification
Always verify the active identity before executing destructive commands. This prevents accidental operations in the wrong account.
# Retrieve current account and user/role ARN
aws sts get-caller-identity \
--query "Account" \
--output text
Pitfall Guide
1. The Root Account Shortcut
Explanation: Using the root account for daily tasks or creating root access keys.
Impact: Root has unlimited permissions. If compromised, the attacker can delete CloudTrail logs, disable MFA, and destroy all resources.
Fix: Delete root access keys immediately. Enable MFA on root. Create IAM users with administrative privileges for daily work.
2. Static Key Sprawl in Workloads
Explanation: Embedding AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in EC2 instance metadata, Docker images, or application config files.
Impact: Keys can be extracted via SSRF attacks or repository leaks. Rotation requires redeployment.
Fix: Attach IAM Roles to EC2 instances via Instance Profiles. Use IAM Roles for Service Accounts (IRSA) in EKS. Never store static keys in code.
3. Wildcard Policy Over-provisioning
Explanation: Using "Action": "*" and "Resource": "*" to resolve permission errors quickly.
Impact: Violates least privilege. Increases blast radius significantly. Fails security audits.
Fix: Use IAM Access Analyzer to generate policies based on actual usage. Scope actions to specific resources. Use Deny statements for sensitive operations.
4. MFA Bypass in CI/CD
Explanation: CI/CD pipelines running with IAM Users that have MFA requirements, causing authentication failures or leading to MFA being disabled for the pipeline user.
Impact: Security control is weakened. Pipeline credentials become high-value targets.
Fix: Use OIDC federation for GitHub Actions/GitLab CI to assume roles without long-lived keys. For other pipelines, use dedicated IAM Users without MFA but with strict IP conditions and short key rotation cycles.
5. CLI Profile Confusion
Explanation: Developers switching between accounts using environment variables (AWS_PROFILE) without clear visual indicators, leading to operations in production instead of dev.
Impact: Accidental data deletion or configuration changes in production.
Fix: Use distinct CLI profiles with clear naming. Implement shell prompts that display the active profile. Use aws configure sso for centralized identity management.
6. Role Trust Policy Misconfiguration
Explanation: Defining a role with a trust policy that allows Principal: "*" or overly broad service principals.
Impact: Any entity in AWS could potentially assume the role, leading to privilege escalation.
Fix: Restrict trust policies to specific AWS account IDs, service principals, or external identity providers. Regularly audit role trust relationships.
7. Ignoring Session Duration Limits
Explanation: Assuming roles with default or maximum session durations without considering the operational need.
Impact: Long-lived sessions increase the window of opportunity for token theft.
Fix: Set DurationSeconds to the minimum required for the task. For interactive CLI sessions, use shorter durations and rely on SSO token refresh.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Local Development | AWS SSO / CLI Profile | Centralized identity, no key management | Free |
| CI/CD Pipeline | OIDC Federation | No long-lived keys, secure token exchange | Free |
| Cross-Account Access | IAM Role Assumption | Isolation, auditability, temporary creds | Free |
| Legacy App Migration | IAM User + Key Rotation | Compatibility, controlled access | Free |
| High-Security Ops | IAM Roles + MFA + IP Conditions | Zero-trust, context-aware access | Free |
Configuration Template
AWS CLI Configuration (~/.aws/config)
This template demonstrates a secure setup with MFA enforcement and role assumption chaining.
[default]
region = us-east-1
output = json
[profile dev-admin]
region = us-west-2
mfa_serial = arn:aws:iam::111111111111:mfa/admin-user
source_profile = default
[profile prod-readonly]
region = us-east-1
role_arn = arn:aws:iam::222222222222:role/ReadOnlyRole
mfa_serial = arn:aws:iam::111111111111:mfa/admin-user
source_profile = dev-admin
[profile prod-admin]
region = us-east-1
role_arn = arn:aws:iam::222222222222:role/AdminRole
mfa_serial = arn:aws:iam::111111111111:mfa/admin-user
source_profile = dev-admin
Quick Start Guide
-
Install AWS CLI v2:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
-
Configure Initial Profile:
aws configure --profile dev-admin
# Enter Access Key, Secret Key, Region, and Output format
-
Verify Identity:
aws sts get-caller-identity --profile dev-admin
-
Test Role Assumption:
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/ReadOnlyRole \
--role-session-name "quickstart-test" \
--profile dev-admin
-
Execute Secure Command:
aws s3 ls --profile prod-readonly