AWS IAM Roles for Applications
Using IAM Roles with SDKs – No Access Keys Required
Table of Contents
Introduction
When building applications that need to interact with AWS services, you have two main options for authentication: Access Keys or IAM Roles. This tutorial focuses on using IAM roles, which is the recommended and more secure approach for applications running on AWS infrastructure.
IAM roles allow your applications to obtain temporary credentials automatically, eliminating the need to store long-lived access keys in your code, configuration files, or environment variables. This significantly reduces the security risk of credential exposure.
Why Use IAM Roles Instead of Keys?
🔐 Enhanced Security
Temporary credentials expire automatically, reducing the window of exposure if compromised.
🔄 Automatic Rotation
Credentials are automatically rotated by AWS, eliminating manual key rotation overhead.
🚫 No Key Storage
No need to store access keys in code, config files, or environment variables.
📊 Better Auditing
CloudTrail logs show which role was used, making it easier to track application actions.
🎯 Least Privilege
Roles can be scoped to specific services and resources, following the principle of least privilege.
⚡ Easy Scaling
Works seamlessly across multiple instances without managing keys per instance.
| Feature | IAM Roles | Access Keys |
|---|---|---|
| Credential Lifetime | Temporary (1-12 hours) | Permanent (until rotated) |
| Rotation | Automatic | Manual |
| Storage Risk | No keys to store | Keys must be stored securely |
| Use Case | Applications on AWS | Local development, CI/CD |
| Security | ✅ High | ⚠️ Medium (if managed well) |
How IAM Roles Work
When your application runs on AWS infrastructure (EC2, ECS, Lambda, EKS, etc.), it can assume an IAM role through the AWS metadata service. Here’s the flow:
- Role Assignment: An IAM role is attached to your AWS resource (EC2 instance, ECS task, Lambda function, etc.)
- Credential Request: Your application requests credentials from the AWS metadata service
- Automatic Provisioning: AWS automatically provides temporary credentials (access key, secret key, session token)
- SDK Usage: The AWS SDK automatically detects and uses these credentials
- Automatic Refresh: Credentials are automatically refreshed before expiration
Accessible AWS Services
IAM roles can access over 200+ AWS services depending on the permissions granted to the role. Your application can interact with virtually any AWS service using IAM role credentials through the AWS SDKs.
Popular Services by Category
💾 Storage Services
- Amazon S3 (Simple Storage Service)
- Amazon EBS (Elastic Block Store)
- Amazon EFS (Elastic File System)
- Amazon FSx
- AWS Storage Gateway
🗄️ Database Services
- Amazon RDS (Relational Database)
- Amazon DynamoDB
- Amazon ElastiCache
- Amazon Redshift
- Amazon DocumentDB
- Amazon Neptune
- Amazon Timestream
☁️ Compute Services
- Amazon EC2
- AWS Lambda
- Amazon ECS
- Amazon EKS
- AWS Fargate
- Amazon Lightsail
- AWS Batch
🌐 Networking & Content Delivery
- Amazon VPC
- Amazon CloudFront
- Amazon Route 53
- Amazon API Gateway
- AWS Direct Connect
- Elastic Load Balancing
📧 Messaging & Notifications
- Amazon SNS (Simple Notification Service)
- Amazon SQS (Simple Queue Service)
- Amazon SES (Simple Email Service)
- Amazon EventBridge
- AWS AppSync
🔍 Analytics & Big Data
- Amazon Athena
- Amazon EMR
- Amazon Kinesis
- Amazon QuickSight
- Amazon Glue
- AWS Data Pipeline
🤖 Machine Learning & AI
- Amazon SageMaker
- Amazon Comprehend
- Amazon Rekognition
- Amazon Translate
- Amazon Polly
- Amazon Textract
🔐 Security & Identity
- AWS IAM
- AWS Secrets Manager
- AWS KMS (Key Management)
- AWS Certificate Manager
- AWS WAF
- AWS Shield
📊 Monitoring & Logging
- Amazon CloudWatch
- AWS CloudTrail
- Amazon X-Ray
- AWS Config
- AWS Systems Manager
🔄 Integration & Workflow
- AWS Step Functions
- AWS AppSync
- Amazon MQ
- AWS Transfer Family
- AWS Service Catalog
🌍 Global Services
- AWS CloudFormation
- AWS Organizations
- AWS Resource Groups
- AWS Tag Editor
- AWS Cost Explorer
📱 Mobile & Application Services
- AWS Amplify
- Amazon Cognito
- AWS AppSync
- Amazon Pinpoint
- AWS Device Farm
Complete Service List
The following is a comprehensive list of major AWS services accessible via IAM roles. This list includes over 200+ services across all AWS categories:
View Complete Service List (200+ Services)
Compute
- Amazon EC2, AWS Lambda, Amazon ECS, Amazon EKS, AWS Fargate, Amazon Lightsail, AWS Batch, AWS Elastic Beanstalk, AWS App Runner, AWS Outposts, AWS Wavelength, AWS Local Zones
Storage
- Amazon S3, Amazon EBS, Amazon EFS, Amazon FSx, AWS Storage Gateway, AWS Backup, AWS DataSync, AWS Transfer Family, Amazon S3 Glacier
Databases
- Amazon RDS, Amazon DynamoDB, Amazon ElastiCache, Amazon Redshift, Amazon DocumentDB, Amazon Neptune, Amazon Timestream, Amazon QLDB, Amazon MemoryDB, Amazon Keyspaces
Networking & Content Delivery
- Amazon VPC, Amazon CloudFront, Amazon Route 53, Amazon API Gateway, AWS Direct Connect, Elastic Load Balancing, AWS PrivateLink, AWS Global Accelerator, AWS Transit Gateway, AWS VPN
Developer Tools
- AWS CodeCommit, AWS CodeBuild, AWS CodeDeploy, AWS CodePipeline, AWS CodeStar, AWS Cloud9, AWS X-Ray, AWS CloudShell
Management & Governance
- AWS CloudFormation, AWS CloudTrail, Amazon CloudWatch, AWS Config, AWS Systems Manager, AWS Service Catalog, AWS Control Tower, AWS Organizations, AWS Trusted Advisor, AWS Well-Architected Tool
Security, Identity & Compliance
- AWS IAM, AWS Secrets Manager, AWS KMS, AWS Certificate Manager, AWS WAF, AWS Shield, AWS GuardDuty, AWS Security Hub, Amazon Inspector, AWS Artifact, AWS Directory Service, Amazon Cognito
Analytics
- Amazon Athena, Amazon EMR, Amazon Kinesis, Amazon QuickSight, Amazon Glue, AWS Data Pipeline, Amazon OpenSearch Service, Amazon MSK, Amazon FinSpace, Amazon DataZone
Machine Learning
- Amazon SageMaker, Amazon Comprehend, Amazon Rekognition, Amazon Translate, Amazon Polly, Amazon Textract, Amazon Forecast, Amazon Personalize, Amazon Lex, Amazon Kendra, Amazon Bedrock, Amazon CodeGuru
Application Integration
- Amazon SNS, Amazon SQS, Amazon EventBridge, AWS Step Functions, Amazon MQ, Amazon AppFlow, AWS AppSync
Media Services
- Amazon Kinesis Video Streams, AWS Elemental MediaConvert, AWS Elemental MediaLive, AWS Elemental MediaPackage, AWS Elemental MediaStore, Amazon Interactive Video Service
Migration & Transfer
- AWS Migration Hub, AWS Application Migration Service, AWS Database Migration Service, AWS Server Migration Service, AWS Transfer Family, AWS DataSync, AWS Snow Family
Mobile
- AWS Amplify, Amazon Cognito, Amazon Pinpoint, AWS AppSync, AWS Device Farm, Amazon Location Service
AR & VR
- Amazon Sumerian
Game Development
- Amazon GameLift, Amazon Lumberyard
Internet of Things
- AWS IoT Core, AWS IoT Device Management, AWS IoT Analytics, AWS IoT Events, AWS IoT Greengrass, Amazon FreeRTOS, AWS IoT SiteWise, AWS IoT Things Graph
End User Computing
- Amazon WorkSpaces, Amazon AppStream 2.0, Amazon WorkDocs, Amazon WorkLink
Business Applications
- Amazon Connect, Amazon Chime, Amazon WorkMail, Amazon Honeycode
Customer Engagement
- Amazon Pinpoint, Amazon Simple Email Service (SES), Amazon Simple Notification Service (SNS)
Blockchain
- Amazon Managed Blockchain
Quantum Technologies
- Amazon Braket
Satellite
- AWS Ground Station
Setting Up IAM Roles
You can create IAM roles either through the AWS Management Console (manual) or using AWS CLI/API (programmatic). Choose the method that works best for you.
Method 1: Using AWS Management Console (Step-by-Step)
Step 1: Navigate to IAM Roles
- Sign in to the AWS Management Console
- Open the IAM service (search for “IAM” in the top search bar)
- In the left navigation pane, click on “Roles”
- Click the “Create role” button
Step 2: Select Trusted Entity Type
- Under “Select trusted entity”, choose the service that will use this role:
- For EC2 instances: Select “AWS service” → Choose “EC2”
- For Lambda functions: Select “AWS service” → Choose “Lambda”
- For ECS tasks: Select “AWS service” → Choose “Elastic Container Service”
- For EKS pods: Select “AWS service” → Choose “Elastic Kubernetes Service”
- Click “Next”
Step 3: Add Permissions
- In the “Add permissions” section, you can:
- Use AWS managed policies: Search for and select pre-built policies like:
AmazonS3ReadOnlyAccess– Read-only access to S3AmazonS3FullAccess– Full access to S3AmazonDynamoDBReadOnlyAccess– Read-only access to DynamoDBAmazonDynamoDBFullAccess– Full access to DynamoDB
- Create custom policy: Click “Create policy” to define specific permissions
- Use AWS managed policies: Search for and select pre-built policies like:
- For a custom S3 policy example:
- Click “Create policy”
- Choose “JSON” tab
- Paste the following policy (replace
my-app-bucketwith your bucket name):{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::my-app-bucket/*" }] } - Click “Next”, give it a name (e.g.,
MyAppS3Policy), and click “Create policy” - Go back to the role creation page and refresh, then select your new policy
- Click “Next” after selecting your permissions
Step 4: Name and Review
- Enter a Role name (e.g.,
MyAppRole) - Optionally add a Description (e.g., “IAM role for my application to access S3”)
- Review the role configuration
- Click “Create role”
Step 5: Attach Role to Your Resource
For EC2 Instances:
- Go to EC2 service → Instances
- Select your instance
- Click “Actions” → “Security” → “Modify IAM role”
- Select your role from the dropdown
- Click “Update IAM role”
For Lambda Functions:
- Go to Lambda service → Select your function
- Click on the “Configuration” tab
- Click “Permissions” in the left menu
- Under “Execution role”, click “Edit”
- Select your role and click “Save”
For ECS Tasks:
- Go to ECS service → Select your task definition
- Click “Create new revision”
- Under “Task role”, select your IAM role
- Click “Create”
Method 2: Using AWS CLI (Programmatic)
Step 1: Create an IAM Role
First, create an IAM role with the necessary permissions for your application:
# Using AWS CLI
aws iam create-role \
--role-name MyAppRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}'Step 2: Attach Permissions Policy
Attach a policy that grants the permissions your application needs:
# Example: Allow S3 read/write access
aws iam put-role-policy \
--role-name MyAppRole \
--policy-name S3AccessPolicy \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-app-bucket/*"
}]
}'Step 3: Create Instance Profile (for EC2)
For EC2 instances, create an instance profile and attach the role:
# Create instance profile
aws iam create-instance-profile --instance-profile-name MyAppInstanceProfile
# Add role to instance profile
aws iam add-role-to-instance-profile \
--instance-profile-name MyAppInstanceProfile \
--role-name MyAppRole
# Attach to EC2 instance
aws ec2 associate-iam-instance-profile \
--instance-id i-1234567890abcdef0 \
--iam-instance-profile Name=MyAppInstanceProfilePython Applications (boto3)
Python applications using boto3 automatically use IAM roles when running on AWS infrastructure.
No configuration is needed!
Basic Usage
Simply create your boto3 clients without specifying credentials:
import boto3
# boto3 automatically uses IAM role credentials when available
s3_client = boto3.client('s3')
dynamodb_client = boto3.client('dynamodb')
# Use the clients normally
response = s3_client.list_buckets()
print(response['Buckets'])Django/Flask Example
In a Django or Flask application, initialize AWS clients at startup:
# settings.py (Django) or app.py (Flask)
import boto3
# Initialize AWS clients - they'll use IAM role automatically
S3_CLIENT = boto3.client('s3')
DYNAMODB_CLIENT = boto3.client('dynamodb')
SES_CLIENT = boto3.client('ses')
# In your views/views.py
def upload_file(request):
file = request.FILES['file']
S3_CLIENT.upload_fileobj(
file,
'my-bucket',
f'uploads/{file.name}'
)
return JsonResponse({'status': 'success'})Explicit Region Configuration
You can specify the region while still using role credentials:
import boto3
# Specify region, credentials come from IAM role
s3_client = boto3.client(
's3',
region_name='us-east-1'
)Local Development
For local development, boto3 will look for credentials in this order:
- Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) - Shared credentials file (
~/.aws/credentials) - IAM role (if running on EC2/ECS/Lambda)
# For local development, use AWS CLI profiles
# ~/.aws/credentials
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
# Or set environment variables
export AWS_PROFILE=my-profileRuby on Rails Applications
Ruby applications using the aws-sdk gem automatically use IAM roles when running on AWS infrastructure.
Installation
# Gemfile
gem 'aws-sdk-s3'
gem 'aws-sdk-dynamodb'
gem 'aws-sdk-ses'
# Or install the full SDK
gem 'aws-sdk'Basic Usage
Create AWS clients without credentials – they’ll use the IAM role automatically:
# config/initializers/aws.rb
require 'aws-sdk-s3'
require 'aws-sdk-dynamodb'
# Clients automatically use IAM role credentials
Aws.config.update({
region: 'us-east-1'
})
S3_CLIENT = Aws::S3::Client.new
DYNAMODB_CLIENT = Aws::DynamoDB::Client.newRails Controller Example
# app/controllers/files_controller.rb
class FilesController < ApplicationController
def upload
file = params[:file]
S3_CLIENT.put_object(
bucket: 'my-app-bucket',
key: "uploads/#{file.original_filename}",
body: file.read
)
render json: { status: 'success' }
end
def list
response = S3_CLIENT.list_objects_v2(
bucket: 'my-app-bucket',
prefix: 'uploads/'
)
render json: { files: response.contents.map(&:key) }
end
endRails Model Example
# app/models/user.rb
class User < ApplicationRecord
def save_to_dynamodb
DYNAMODB_CLIENT.put_item(
table_name: 'users',
item: {
user_id: id,
email: email,
name: name,
created_at: created_at.iso8601
}
)
end
def self.find_in_dynamodb(user_id)
response = DYNAMODB_CLIENT.get_item(
table_name: 'users',
key: { user_id: user_id }
)
response.item
end
endLocal Development
# config/initializers/aws.rb
require 'aws-sdk-s3'
if Rails.env.development?
# Use credentials from ~/.aws/credentials or environment variables
Aws.config.update({
region: 'us-east-1',
credentials: Aws::SharedCredentials.new(profile_name: 'default')
})
else
# Production: Use IAM role (automatic)
Aws.config.update({
region: 'us-east-1'
})
end
S3_CLIENT = Aws::S3::Client.newNode.js / MERN Stack Applications
Node.js applications using the AWS SDK for JavaScript automatically use IAM roles when running on AWS infrastructure.
Installation
# Using npm
npm install @aws-sdk/client-s3 @aws-sdk/client-dynamodb
# Or install individual service clients as needed
npm install @aws-sdk/client-ses
npm install @aws-sdk/client-snsBasic Usage (AWS SDK v3)
The modern AWS SDK v3 automatically uses IAM role credentials:
// config/aws.js
import { S3Client } from '@aws-sdk/client-s3';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
// Clients automatically use IAM role credentials
export const s3Client = new S3Client({ region: 'us-east-1' });
export const dynamoDBClient = new DynamoDBClient({ region: 'us-east-1' });Express.js Example
// routes/files.js
import express from 'express';
import { PutObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';
import { s3Client } from '../config/aws.js';
const router = express.Router();
router.post('/upload', async (req, res) => {
try {
const file = req.files.file;
const command = new PutObjectCommand({
Bucket: 'my-app-bucket',
Key: `uploads/${file.name}`,
Body: file.data
});
await s3Client.send(command);
res.json({ status: 'success' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
router.get('/list', async (req, res) => {
try {
const command = new ListObjectsV2Command({
Bucket: 'my-app-bucket',
Prefix: 'uploads/'
});
const response = await s3Client.send(command);
res.json({ files: response.Contents.map(item => item.Key) });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
export default router;MongoDB + AWS Integration Example
// services/notification.js
import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';
import User from '../models/User.js';
const sesClient = new SESClient({ region: 'us-east-1' });
export async function sendWelcomeEmail(userId) {
const user = await User.findById(userId);
const command = new SendEmailCommand({
Source: '[email protected]',
Destination: {
ToAddresses: [user.email]
},
Message: {
Subject: { Data: 'Welcome!' },
Body: {
Text: { Data: `Welcome ${user.name}!` }
}
}
});
await sesClient.send(command);
}React Frontend (Using Backend API)
Important: Never use AWS credentials in frontend code. Always make API calls through your backend, which uses the IAM role.
// React component
import React, { useState } from 'react';
import axios from 'axios';
function FileUpload() {
const [file, setFile] = useState(null);
const handleUpload = async () => {
const formData = new FormData();
formData.append('file', file);
// Backend uses IAM role to upload to S3
await axios.post('/api/files/upload', formData);
};
return (
<div>
<input type="file" onChange={(e) => setFile(e.target.files[0])} />
<button onClick={handleUpload}>Upload</button>
</div>
);
}Local Development
// config/aws.js
import { S3Client } from '@aws-sdk/client-s3';
import { fromIni } from '@aws-sdk/credential-providers';
const isDevelopment = process.env.NODE_ENV === 'development';
export const s3Client = new S3Client({
region: 'us-east-1',
// In development, use AWS profile
// In production, automatically uses IAM role
...(isDevelopment && {
credentials: fromIni({ profile: 'default' })
})
});Java Applications
Java applications using the AWS SDK for Java automatically use IAM roles when running on AWS infrastructure.
Maven Dependency
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
<version>2.20.0</version>
</dependency>
</dependencies>Spring Boot Example
// Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// config/AwsConfig.java
@Configuration
public class AwsConfig {
@Bean
public S3Client s3Client() {
// Automatically uses IAM role when running on AWS
return S3Client.builder()
.region(Region.US_EAST_1)
.build();
}
@Bean
public DynamoDbClient dynamoDbClient() {
return DynamoDbClient.builder()
.region(Region.US_EAST_1)
.build();
}
}
// service/FileService.java
@Service
public class FileService {
@Autowired
private S3Client s3Client;
public void uploadFile(String bucket, String key, byte[] data) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucket)
.key(key)
.build();
s3Client.putObject(request, RequestBody.fromBytes(data));
}
}Go Applications
Go applications using the AWS SDK for Go automatically use IAM roles when running on AWS infrastructure.
Installation
go get github.com/aws/aws-sdk-go-v2/service/s3
go get github.com/aws/aws-sdk-go-v2/service/dynamodb
go get github.com/aws/aws-sdk-go-v2/configBasic Usage
package main
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func main() {
// Load default config - automatically uses IAM role on AWS
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithRegion("us-east-1"),
)
if err != nil {
panic(err)
}
// Create S3 client
client := s3.NewFromConfig(cfg)
// Use the client
result, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
if err != nil {
panic(err)
}
for _, bucket := range result.Buckets {
println(*bucket.Name)
}
}Best Practices
1. Principle of Least Privilege
Only grant the minimum permissions your application needs. Don't use "Action": "*" or "Resource": "*" unless absolutely necessary.
// ❌ Bad: Too permissive
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
// ✅ Good: Specific permissions
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-app-bucket/*"
}2. Use Resource-Based Policies When Possible
For services like S3, SNS, and SQS, you can use resource-based policies in addition to IAM role policies for defense in depth.
3. Separate Roles for Different Environments
Use different IAM roles for development, staging, and production environments. This limits the blast radius if a role is compromised.
# Development role
MyAppRole-Dev
# Staging role
MyAppRole-Staging
# Production role
MyAppRole-Prod4. Monitor Role Usage
Enable CloudTrail to monitor when roles are assumed and what actions are performed. Set up CloudWatch alarms for unusual activity.
5. Use Service-Specific Roles
For Lambda functions, ECS tasks, and other services, use service-specific roles rather than EC2 instance roles when possible.
6. Handle Credential Errors Gracefully
Your application should handle cases where credentials might not be available (e.g., during local development).
# Python example
import boto3
from botocore.exceptions import NoCredentialsError
try:
s3_client = boto3.client('s3')
response = s3_client.list_buckets()
except NoCredentialsError:
print("AWS credentials not found. Please configure credentials.")
# Fallback logic or exit gracefully
7. Use IAM Roles for Cross-Account Access
When your application needs to access resources in another AWS account, use cross-account IAM roles instead of sharing access keys.
Troubleshooting
Problem: "Unable to locate credentials"
Possible causes and solutions:
- Not running on AWS infrastructure: Use AWS CLI profiles or environment variables for local development
- Role not attached: Verify the IAM role is attached to your EC2 instance, ECS task, or Lambda function
- Instance profile missing: For EC2, ensure an instance profile is created and attached
Problem: "Access Denied" errors
Possible causes and solutions:
- Insufficient permissions: Check the IAM role's policy to ensure it has the required permissions
- Resource ARN mismatch: Verify the resource ARN in your policy matches the actual resource
- Condition restrictions: Check if there are IAM conditions (like IP restrictions) blocking access
Problem: Credentials expiring too quickly
IAM role credentials typically last 1 hour for EC2 and can be configured up to 12 hours for other services. The AWS SDK automatically refreshes credentials before expiration. If you're seeing expiration issues:
- Check that your SDK version is up to date (older versions may have refresh issues)
- Verify the metadata service is accessible from your application
- For Lambda, ensure the execution role has proper permissions
Debugging Tips
# Check if role is attached to EC2 instance
aws ec2 describe-instances --instance-ids i-1234567890abcdef0 \
--query 'Reservations[0].Instances[0].IamInstanceProfile'
# Test role permissions
aws sts get-caller-identity
# View current credentials (from EC2 instance)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Get temporary credentials
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/MyAppRoleQuestions & Answers
Common questions about using IAM roles in applications:
- Use AWS CLI profiles (
~/.aws/credentials) - Set environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) - Use AWS SSO or temporary credentials
- Assume a role programmatically using your local credentials
- EC2 instances: Credentials last 1 hour and are automatically refreshed
- Lambda functions: Credentials last for the duration of the execution context (up to 15 minutes)
- ECS tasks: Credentials last 1 hour and are refreshed automatically
- EKS pods: Credentials can be configured from 1-12 hours
- Human users accessing AWS console or CLI
- Applications running outside AWS
- CI/CD pipelines (though roles are preferred)
- Applications running on AWS infrastructure
- Cross-account access
- Federated access
- Attach multiple policies to a single role to grant access to different services
- Use role chaining to assume additional roles programmatically if needed
- Design your role with all necessary permissions for your application
- Start with AWS managed policies: Use policies like
AmazonS3ReadOnlyAccessorAmazonDynamoDBFullAccessas starting points - Use IAM Access Analyzer: Analyzes your code and suggests required permissions
- Monitor CloudTrail: Run your application and check CloudTrail logs to see what API calls are made
- Start restrictive and expand: Begin with minimal permissions and add more as needed based on error messages
- Review AWS documentation: Each service documents the required permissions for each action
- ECS: Assign a task role to your ECS task definition. The role credentials are available to all containers in the task.
- EKS: Use IAM Roles for Service Accounts (IRSA) to assign IAM roles to Kubernetes service accounts, which can then be used by pods.
AccessDenied error. Your application should:- Handle these errors gracefully
- Log the error for debugging
- Return appropriate error messages to users
- Creating IAM roles
- Using temporary credentials
- Credential rotation
- Role assumption
- Account A (your application) assumes a role in Account B (target account)
- The role in Account B has a trust policy allowing Account A to assume it
- Your application uses
sts:AssumeRoleto get temporary credentials for Account B - Use those credentials to access resources in Account B
- AWS IAM Policy Simulator: Test policies without making actual API calls
- Dry run mode: Some AWS services support dry-run mode to test permissions
- Test environment: Deploy to a test/staging environment with the same role
- AWS CLI: Use
aws sts get-caller-identityto verify role assumption - CloudTrail: Monitor API calls to see what permissions are actually used
- IP address: Use
aws:SourceIpcondition to restrict by IP - Time: Use
aws:CurrentTimeto restrict access to specific hours - VPC: Use
aws:SourceVpcoraws:SourceVpcefor VPC restrictions - MFA: Require multi-factor authentication
- Tags: Restrict based on resource tags
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}- API Gateway: Uses an execution role for invoking downstream services
- Lambda: Has its own execution role
- ECS tasks: Have task roles
- Create an IAM role with the same permissions your access keys had
- Attach the role to your AWS resource (EC2, Lambda, etc.)
- Remove access key references from your code (the SDK will automatically use the role)
- Test thoroughly in a staging environment
- Deploy to production and monitor for any issues
- Delete the old access keys once you've confirmed everything works
- Local development: Use a named AWS CLI profile (e.g.,
temp_profile) with access keys stored in~/.aws/credentials. Your app loads credentials viafromIni({ profile: 'temp_profile' }) - Production (EC2): Attach an IAM instance profile to your EC2 instance. Your app uses
fromNodeProviderChain()which automatically resolves credentials from the instance metadata service — no keys needed
NODE_ENV=production:const isProduction = process.env.NODE_ENV === 'production';
if (isProduction) {
// EC2: Uses IAM role automatically
config.credentials = fromNodeProviderChain();
} else {
// Local: Uses named profile with access keys
config.credentials = fromIni({ profile: 'temp_profile' });
}This way the same codebase works in both environments — only the .env file differs.- Local development: Use a standard database password stored in
.env(DB_PASSWORD=your-password). This is simpler for local dev. - Production (EC2): Use IAM Database Authentication — the EC2 instance's IAM role generates a temporary auth token instead of a password. No password is stored anywhere.
if (process.env.DB_PASSWORD) {
// Local: use password authentication
dbConfig.password = process.env.DB_PASSWORD;
} else {
// Production: use IAM auth token
const signer = new Signer({ hostname, port, username, credentials });
dbConfig.password = await signer.getAuthToken();
}Benefit: In production, no database password is stored on the EC2 instance. The IAM role generates short-lived tokens automatically.- IAM Role: Defines what permissions are granted (S3 access, SQS access, etc.)
- Instance Profile: Wraps the role so it can be attached to an EC2 instance
# Create instance profile
aws iam create-instance-profile --instance-profile-name MyAppProfile
# Add role to it
aws iam add-role-to-instance-profile \
--instance-profile-name MyAppProfile \
--role-name MyAppRole
# Attach to EC2 instance
aws ec2 associate-iam-instance-profile \
--instance-id i-0123456789 \
--iam-instance-profile Name=MyAppProfileOnce attached, any application running on that EC2 instance can use the role's credentials automatically via the instance metadata service at 169.254.169.254.- Environment variables:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY - Shared credentials file:
~/.aws/credentials(using the profile specified byAWS_PROFILE) - ECS container credentials: For tasks running on ECS/Fargate
- EC2 instance metadata: For applications running on EC2 (IAM role)
fromNodeProviderChain() implements this full chain. This is why the same SDK code works both locally (finds ~/.aws/credentials) and on EC2 (finds instance metadata). For explicit control, use fromIni() for profiles or let the chain resolve automatically.- SNS (publish messages): Add
sns:Publishto your role policy - SQS (send/receive messages): Add
sqs:SendMessage,sqs:ReceiveMessage,sqs:DeleteMessage - SES (send emails): Add
ses:SendEmail,ses:SendRawEmail - S3 (upload/download files): Add
s3:PutObject,s3:GetObject
const snsClient = new SNSClient({ region: 'us-east-1' });
const sqsClient = new SQSClient({ region: 'us-east-1' });
const sesClient = new SESClient({ region: 'us-east-1' });
// All automatically use IAM role on EC2The key is to ensure your IAM role policy grants the specific permissions needed for each service.- Temporary credentials: Role credentials expire (1-12 hours), limiting exposure if compromised
- Automatic rotation: Credentials are automatically rotated - no manual intervention needed
- No storage risk: No keys to store in code, config files, or environment variables
- Better auditing: CloudTrail logs show which role was used, making it easier to track actions
- Principle of least privilege: Easier to scope permissions to specific services and resources
- No key rotation overhead: Eliminates the need for manual key rotation processes
- Lambda: Every Lambda function has an execution role that defines its permissions
- API Gateway: Can use roles to invoke other AWS services
- Step Functions: Each state machine can have an execution role
- AppSync: Uses IAM roles for data source access
Complete Terraform Guide
Learn more about Rails
Learn more about Mern Stack
Learn more about DevOps
Learn more about AWS ECS Infrastructure guide


