Production engineering guide for cloud iam best practices covering patterns, implementation strategies, and operational best practices.
This reference documents practical approaches for managing identity and access in cloud environments, focusing on how to build and maintain secure, auditable, and maintainable access control systems. These practices apply when configuring authentication, authorization, and permission models across multiple cloud platforms, with attention to the common patterns that emerge regardless of vendor implementation.
When creating new identities for services or users, always start with minimal permissions and add access only as needed.
# Example: create a role with specific permissions
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role_name": "data-processor",
"permissions": [
"s3:GetObject",
"s3:PutObject",
"lambda:InvokeFunction"
]
}' \
https://iam.api.example.com/v1/roles
Avoid creating roles with broad permissions like AdministratorAccess or PowerUserAccess. These grant access to entire AWS managed policies that may include permissions not required for the specific function. The error message "Permission denied: cannot access resource" often indicates over-permissioned principals.
When configuring service accounts for applications, define explicit permission boundaries rather than relying on IAM policy inheritance.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/app-role"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringEquals": {
"s3:prefix": "data/"
}
}
}
]
}
This approach restricts access to specific resources and prefixes, preventing unintended access to other buckets or folders.
When one role assumes another role, explicitly define the trust relationship to prevent unauthorized access.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/lambda-execution-role"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "lambda-external-id"
}
}
}
]
}
The sts:ExternalId condition is critical for preventing cross-account role hijacking. Without it, any identity in the trusting account can assume the role.
Limit session durations to reduce the window of opportunity for credential compromise.
# Example IAM role configuration with session duration
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role_name": "ci-role",
"max_session_duration": 3600,
"trust_policy": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/cicd-role"
},
"Action": "sts:AssumeRole"
}
]
}
}' \
https://iam.api.example.com/v1/roles
Avoid setting session durations longer than 1 hour for production systems. Longer sessions increase risk from stolen credentials.
Applications should use temporary credentials instead of long-term access keys when possible.
# Using AWS CLI to assume a role with specific duration
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/application-role \
--role-session-name "app-session-12345" \
--duration-seconds 3600
Applications that generate temporary credentials must also handle credential rotation. If an application uses long-lived access keys, it cannot benefit from automatic credential rotation.
Require MFA for all administrative actions and high-privilege roles.
# Example: create policy requiring MFA for specific actions
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"policy_name": "require-mfa",
"statement": {
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:DeleteUser"
],
"Resource": "*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": false
}
}
}
}' \
https://iam.api.example.com/v1/policies
MFA enforcement requires that the authentication context includes MFA status. The error "Access denied due to missing MFA" indicates a misconfigured policy or missing MFA in the login flow.
When granting access between accounts, explicitly define which identities can assume roles.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::987654321098:role/monitoring-role",
"arn:aws:iam::987654321098:user/ops-user"
]
},
"Action": "sts:AssumeRole"
}
]
}
Never allow wildcard principal ("*") in cross-account trust policies. This can lead to unintended access from any account.
Set up monitoring for role usage and access events.
# Configure logging for role assumption events
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"log_name": "role-assumption-logs",
"filter_pattern": "AssumeRole",
"destination": "arn:aws:logs:us-east-1:123456789012:log-group:iam-audit-logs"
}' \
https://cloudwatch.api.example.com/v1/logs
Monitor for unusual role assumption patterns, such as unexpected regions, user agents, or IP addresses. Unexpected session durations also signal potential credential compromise.
Automate credential lifecycle management to reduce the risk of long-lived credentials.
#!/bin/bash
# Rotate access keys for a user
aws iam create-access-key --user-name "service-account"
aws iam delete-access-key --user-name "service-account" --access-key-id "$OLD_KEY_ID"
Rotating credentials requires updating all applications that use the old key. The failure mode is silent credential failure, where applications continue to run but cannot authenticate.
Prevent services from accessing resources they shouldn't need access to.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-bucket/data/*"
},
{
"Effect": "Deny",
"Action": [
"s3:DeleteBucket"
],
"Resource": "*"
}
]
}
The deny statement prevents access to bucket-level operations even when the principal has broader permissions. This pattern protects against accidental or malicious resource deletion.
Ensure all identity and access management actions are logged for compliance and troubleshooting.
# Enable IAM access logging for audit trail
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"log_destination": "arn:aws:s3:::audit-logs-bucket",
"log_format": "JSON",
"include_management_events": true
}' \
https://iam.api.example.com/v1/logging
IAM logs must include role assumption events, policy changes, and access key creation/deletion. Missing log entries create blind spots for security investigations.
Roles that assume other roles must properly handle the chain of trust.
# Verify role chain can be assumed
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/intermediate-role \
--role-session-name "test-chain" \
--duration-seconds 900 \
--external-id "test-external-id"
If the intermediate role has a trust policy that doesn't allow the assumed role, the operation fails with "Access denied" or "Invalid principal in policy". The --external-id parameter is often missing from role chains, causing silent failures.
Establish clear policies for access key creation, usage, and deletion.
# Create a policy that requires key rotation every 90 days
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"policy_name": "key-lifecycle-policy",
"statement": {
"Effect": "Deny",
"Action": [
"iam:CreateAccessKey"
],
"Resource": "*",
"Condition": {
"DateLessThan": {
"iam:AccessKeyLastUsed": "2023-01-01T00:00:00Z"
}
}
}
}' \
https://iam.api.example.com/v1/policies
Access keys that are not used for 90 days should be rotated or deleted. The policy enforcement must include checking when keys were last used.
Avoid allowing users to escalate privileges through role assumptions or access control bypasses.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"iam:AttachUserPolicy",
"iam:PutUserPolicy"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"iam:RequestedPolicyArn": "arn:aws:iam::123456789012:policy/FullAccess"
}
}
}
]
}
The policy prevents users from attaching full access policies to themselves, preventing privilege escalation. This is particularly important for roles that can assume other roles.
Set up alerts for unusual access patterns that might indicate compromised credentials.
# Create monitoring for unusual access patterns
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"alert_name": "unusual-access-pattern",
"metric": "role_assumption_count",
"threshold": 100,
"time_window": "1h",
"notification_channels": [
"arn:aws:sns:us-east-1:123456789012:security-alerts"
]
}' \
https://cloudwatch.api.example.com/v1/alarms
Unexpected access patterns include high-volume role assumption, access from unusual IP addresses, or access during off-hours. The system should alert on these anomalies to detect potential breaches.
Regularly validate that trust policies are correctly configured and not overly permissive.
# Check if a role's trust policy is properly configured
curl -X GET \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
https://iam.api.example.com/v1/roles/service-role/trust-policy
The validation should confirm that the trust policy doesn't allow arbitrary principals and includes appropriate conditions. The most common failure is missing sts:ExternalId or overly broad principal definitions.
Establish a regular process for reviewing active roles and permissions.
# List all roles with their attached policies
aws iam list-roles --query 'Roles[*].[RoleName,CreateDate]' --output table
Periodic reviews should include identifying unused roles, removing unnecessary permissions, and ensuring that role assumptions still align with operational needs. The review process should include checking for expired access keys and roles that have not been used in 90 days.
This page was rewritten on 16 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy