AWS IAM Roles for Applications Without Access Keys Complete Guide

AWS IAM Roles for Applications – No Keys Required

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.

✅ Key Benefit With IAM roles, your application automatically receives temporary credentials that rotate regularly. No keys to manage, no keys to leak, no keys to rotate manually.

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.

FeatureIAM RolesAccess Keys
Credential LifetimeTemporary (1-12 hours)Permanent (until rotated)
RotationAutomaticManual
Storage RiskNo keys to storeKeys must be stored securely
Use CaseApplications on AWSLocal 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:

  1. Role Assignment: An IAM role is attached to your AWS resource (EC2 instance, ECS task, Lambda function, etc.)
  2. Credential Request: Your application requests credentials from the AWS metadata service
  3. Automatic Provisioning: AWS automatically provides temporary credentials (access key, secret key, session token)
  4. SDK Usage: The AWS SDK automatically detects and uses these credentials
  5. Automatic Refresh: Credentials are automatically refreshed before expiration
💡 Important IAM roles work automatically when your application runs on AWS infrastructure. For local development, you can use AWS CLI profiles, temporary credentials, or assume roles programmatically.

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
📋 Service Access Note The exact services your application can access depend on the IAM policies attached to your role. You can grant access to specific services, specific actions within services, and even specific resources. Always follow the principle of least privilege.

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

  1. Sign in to the AWS Management Console
  2. Open the IAM service (search for “IAM” in the top search bar)
  3. In the left navigation pane, click on “Roles”
  4. Click the “Create role” button

Step 2: Select Trusted Entity Type

  1. 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”
  2. Click “Next”

Step 3: Add Permissions

  1. In the “Add permissions” section, you can:
    • Use AWS managed policies: Search for and select pre-built policies like:
      • AmazonS3ReadOnlyAccess – Read-only access to S3
      • AmazonS3FullAccess – Full access to S3
      • AmazonDynamoDBReadOnlyAccess – Read-only access to DynamoDB
      • AmazonDynamoDBFullAccess – Full access to DynamoDB
    • Create custom policy: Click “Create policy” to define specific permissions
  2. For a custom S3 policy example:
    • Click “Create policy”
    • Choose “JSON” tab
    • Paste the following policy (replace my-app-bucket with 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
  3. Click “Next” after selecting your permissions

Step 4: Name and Review

  1. Enter a Role name (e.g., MyAppRole)
  2. Optionally add a Description (e.g., “IAM role for my application to access S3”)
  3. Review the role configuration
  4. Click “Create role”

Step 5: Attach Role to Your Resource

For EC2 Instances:

  1. Go to EC2 service → Instances
  2. Select your instance
  3. Click “Actions”“Security”“Modify IAM role”
  4. Select your role from the dropdown
  5. Click “Update IAM role”

For Lambda Functions:

  1. Go to Lambda service → Select your function
  2. Click on the “Configuration” tab
  3. Click “Permissions” in the left menu
  4. Under “Execution role”, click “Edit”
  5. Select your role and click “Save”

For ECS Tasks:

  1. Go to ECS service → Select your task definition
  2. Click “Create new revision”
  3. Under “Task role”, select your IAM role
  4. Click “Create”
✅ Console Setup Complete Your IAM role is now created and attached to your AWS resource. Your application can now use this role to access AWS services without access keys.

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=MyAppInstanceProfile
📝 Note For ECS tasks, Lambda functions, and EKS pods, you attach the role directly to the service configuration. No instance profile is needed.

Python 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:

  1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  2. Shared credentials file (~/.aws/credentials)
  3. 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-profile
✅ Best Practice Use the same code in development and production. boto3 automatically handles credential resolution, so your code works everywhere without changes.

Ruby 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.new

Rails 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
end

Rails 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
end

Local 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.new

Node.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-sns

Basic 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/config

Basic 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-Prod

4. 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.

⚠️ Security Reminder Never commit AWS credentials to version control. Even though IAM roles eliminate the need for keys in production, always use environment variables or secure credential stores for local development.

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/MyAppRole
💡 Pro Tip Use AWS CloudShell or Systems Manager Session Manager to SSH into your instances and test IAM role credentials directly. This helps verify that roles are configured correctly.

Questions & Answers

Common questions about using IAM roles in applications:

Do I need to store access keys when using IAM roles?
No. When your application runs on AWS infrastructure (EC2, Lambda, ECS, etc.), it automatically receives temporary credentials from the IAM role. You don't need to store, manage, or rotate access keys. The AWS SDK automatically handles credential retrieval and refresh.
Can I use IAM roles for local development?
IAM roles work automatically on AWS infrastructure. For local development, you have several options:
  • 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
The good news is your application code remains the same - the SDK automatically handles credential resolution.
How long do IAM role credentials last?
Temporary credentials from IAM roles have different lifetimes depending on the service:
  • 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
The AWS SDK automatically refreshes credentials before they expire, so you don't need to handle this manually.
What's the difference between an IAM role and an IAM user?
IAM Users are identities with long-lived credentials (access keys) that don't expire. They're typically used for:
  • Human users accessing AWS console or CLI
  • Applications running outside AWS
  • CI/CD pipelines (though roles are preferred)
IAM Roles provide temporary credentials and are preferred for:
  • Applications running on AWS infrastructure
  • Cross-account access
  • Federated access
Roles are more secure because credentials are temporary and automatically rotated.
Can one application use multiple IAM roles?
An application can only have one IAM role attached at a time to the resource it runs on (EC2 instance, Lambda function, etc.). However, you can:
  • 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
For most applications, a single well-designed role with appropriate policies is sufficient.
How do I know which permissions my application needs?
Here are several approaches:
  • Start with AWS managed policies: Use policies like AmazonS3ReadOnlyAccess or AmazonDynamoDBFullAccess as 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
Can I use IAM roles with containers running on ECS or EKS?
Yes! Both ECS and EKS support IAM roles:
  • 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.
Your application code remains the same - the SDK automatically detects and uses the role credentials.
What happens if my IAM role doesn't have the right permissions?
If your application tries to perform an action that the IAM role doesn't have permission for, AWS will return an AccessDenied error. Your application should:
  • Handle these errors gracefully
  • Log the error for debugging
  • Return appropriate error messages to users
To fix this, you need to update the IAM role's policy to include the missing permissions. You can do this without restarting your application - the new permissions take effect immediately.
Is there a cost for using IAM roles?
No. IAM roles and the temporary credentials they provide are completely free. There are no charges for:
  • Creating IAM roles
  • Using temporary credentials
  • Credential rotation
  • Role assumption
You only pay for the AWS services your application uses (S3 storage, DynamoDB requests, etc.), not for the authentication mechanism.
Can I use IAM roles for cross-account access?
Yes! IAM roles are the recommended way to access resources in another AWS account. Here's how:
  • 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:AssumeRole to get temporary credentials for Account B
  • Use those credentials to access resources in Account B
This is much more secure than sharing access keys between accounts.
How do I test IAM role permissions before deploying?
Several ways to test IAM role permissions:
  • 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-identity to verify role assumption
  • CloudTrail: Monitor API calls to see what permissions are actually used
Can I restrict IAM role access by IP address or time?
Yes! IAM policies support conditions that allow you to restrict access based on:
  • IP address: Use aws:SourceIp condition to restrict by IP
  • Time: Use aws:CurrentTime to restrict access to specific hours
  • VPC: Use aws:SourceVpc or aws:SourceVpce for VPC restrictions
  • MFA: Require multi-factor authentication
  • Tags: Restrict based on resource tags
Example policy with IP restriction:
{
    "Effect": "Allow",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my-bucket/*",
    "Condition": {
        "IpAddress": {
            "aws:SourceIp": "203.0.113.0/24"
        }
    }
}
What if my application runs on multiple AWS services?
If your application spans multiple AWS services (e.g., API Gateway → Lambda → ECS), each service can have its own IAM role:
  • API Gateway: Uses an execution role for invoking downstream services
  • Lambda: Has its own execution role
  • ECS tasks: Have task roles
Each role should have the minimum permissions needed for that component. This follows the principle of least privilege and makes it easier to audit and secure your application.
How do I migrate from access keys to IAM roles?
Migrating from access keys to IAM roles is straightforward:
  1. Create an IAM role with the same permissions your access keys had
  2. Attach the role to your AWS resource (EC2, Lambda, etc.)
  3. Remove access key references from your code (the SDK will automatically use the role)
  4. Test thoroughly in a staging environment
  5. Deploy to production and monitor for any issues
  6. Delete the old access keys once you've confirmed everything works
The best part: your application code doesn't need to change - just remove any hardcoded credentials and the SDK handles the rest.
How do I use access keys locally but IAM roles in production?
This is a common and recommended pattern. Use two separate configurations:
  • Local development: Use a named AWS CLI profile (e.g., temp_profile) with access keys stored in ~/.aws/credentials. Your app loads credentials via fromIni({ 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
Switch between modes using an environment variable like 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.
How do I handle database authentication differently for local vs production?
For services like Amazon RDS, you can use two authentication methods:
  • 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.
In your code, check if a password is provided:
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.
What is an EC2 instance profile and how does it relate to IAM roles?
An instance profile is a container for an IAM role that you attach to an EC2 instance. Think of it as the bridge between EC2 and IAM:
  • 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
When you create a role via the AWS Console for EC2, an instance profile is created automatically. When using the CLI, you must create it manually:
# 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=MyAppProfile
Once 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.
How does the AWS SDK credential provider chain work?
When you create an AWS SDK client without specifying credentials, the SDK searches for credentials in this order (called the credential provider chain):
  1. Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  2. Shared credentials file: ~/.aws/credentials (using the profile specified by AWS_PROFILE)
  3. ECS container credentials: For tasks running on ECS/Fargate
  4. EC2 instance metadata: For applications running on EC2 (IAM role)
In Node.js, 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.
Can I use IAM roles for SNS, SQS, and SES without access keys?
Yes! All AWS services work with IAM roles, including messaging and email services:
  • SNS (publish messages): Add sns:Publish to 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
Your code stays the same — just create the client with the region:
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 EC2
The key is to ensure your IAM role policy grants the specific permissions needed for each service.
Are IAM roles more secure than access keys?
Yes, significantly more secure. Here's why:
  • 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
Access keys are permanent until manually rotated, which means if they're compromised, they can be used indefinitely until discovered and rotated.
Can I use IAM roles with serverless applications?
Absolutely! IAM roles are the standard and recommended way to authenticate serverless applications:
  • 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
Serverless applications benefit greatly from IAM roles because they eliminate the need to manage credentials in a stateless environment.

Complete Terraform Guide
Learn more about Rails
Learn more about Mern Stack
Learn more about DevOps
Learn more about AWS ECS Infrastructure guide

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top