Granting Read-Only AWS Console Access: The Right IAM Policy for Junior Developers

Onboarding a new junior developer to your AWS environment is a common scenario — but handing them full access is a security risk you cannot afford. The principle of least privilege demands you give them exactly what they need: the ability to see resources, never to change them.

TL;DR

GoalAWS Managed PolicyARN
Read-only access to ALL AWS servicesReadOnlyAccessarn:aws:iam::aws:policy/ReadOnlyAccess
View billing & cost data onlyAWSBillingReadOnlyAccessarn:aws:iam::aws:policy/AWSBillingReadOnlyAccess
View IAM resources onlyIAMReadOnlyAccessarn:aws:iam::aws:policy/IAMReadOnlyAccess

The primary policy you want is ReadOnlyAccess — an AWS managed policy that grants List*, Get*, Describe*, and View* actions across virtually all AWS services, with zero write permissions.


Architecture: What We're Building

The flow is straightforward: create a dedicated IAM user, attach the ReadOnlyAccess managed policy, enforce MFA, and provide console access credentials. Here's the full picture:

graph TD Admin["IAM Admin"] -->|1 Create User| User["IAM User: junior-dev-jane"] Admin -->|2 Create Group| Group["IAM Group: ReadOnlyDevelopers"] Admin -->|3 Attach Policy| Policy["AWS Managed Policy: ReadOnlyAccess"] Admin -->|4 Attach MFA Policy| MFAPolicy["Inline Policy: EnforceMFA"] Policy --> Group MFAPolicy --> Group User -->|5 Added to Group| Group Group -->|Effective Permissions| Perms["List / Get / Describe / View ONLY"] User -->|6 MFA Login| Console["AWS Console Read-Only View"] Perms --> Console
  1. IAM Admin creates a new IAM user with console access enabled.
  2. The ReadOnlyAccess AWS managed policy is attached directly to the user (or via a group — preferred).
  3. An MFA device is enforced via an IAM policy condition, preventing console use without MFA.
  4. The junior developer logs in via the AWS Console sign-in URL and can view — but never mutate — any resource.
Analogy: Think of ReadOnlyAccess like a museum visitor badge. You can walk through every gallery, read every exhibit label, and observe every artifact — but the velvet rope prevents you from touching anything.

Step-by-Step Implementation

Step 1 — Create an IAM Group (Best Practice)

Always attach policies to groups, not individual users. This makes future access management scalable — add or remove users from the group instead of managing per-user policies.

# Create the group
aws iam create-group --group-name ReadOnlyDevelopers

# Attach the AWS managed ReadOnlyAccess policy to the group
aws iam attach-group-policy \
  --group-name ReadOnlyDevelopers \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

Step 2 — Create the IAM User with Console Access

🔽 Click to expand: Full user creation CLI commands
# Create the IAM user
aws iam create-user --user-name junior-dev-jane

# Create a login profile (enables AWS Console access)
# Replace 'TempP@ssw0rd!' with a strong temporary password
aws iam create-login-profile \
  --user-name junior-dev-jane \
  --password 'TempP@ssw0rd!' \
  --password-reset-required

# Add the user to the ReadOnlyDevelopers group
aws iam add-user-to-group \
  --user-name junior-dev-jane \
  --group-name ReadOnlyDevelopers

Step 3 — Enforce MFA with an IAM Policy

Attaching ReadOnlyAccess alone is not enough. Without MFA enforcement, a leaked password exposes your entire AWS environment to a read-only attacker who can enumerate infrastructure, harvest ARNs, and plan further attacks. Attach the following inline policy to the group to deny all actions unless MFA is active.

🔽 Click to expand: MFA enforcement IAM policy (JSON)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyAllWithoutMFA",
      "Effect": "Deny",
      "NotAction": [
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:GetUser",
        "iam:ListMFADevices",
        "iam:ListVirtualMFADevices",
        "iam:ResyncMFADevice",
        "sts:GetSessionToken"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": {
          "aws:MultiFactorAuthPresent": "false"
        }
      }
    }
  ]
}
# Save the above JSON as enforce-mfa.json, then run:
aws iam put-group-policy \
  --group-name ReadOnlyDevelopers \
  --policy-name EnforceMFA \
  --policy-document file://enforce-mfa.json

Step 4 — Share the Console Sign-In URL

Your account-specific console URL follows this format:

https://<your-account-id>.signin.aws.amazon.com/console

Retrieve your Account ID with:

aws sts get-caller-identity --query Account --output text

Verification: Confirm the Policy is Attached

Always verify the effective permissions after setup. Never assume — confirm.

# List policies attached to the group
aws iam list-attached-group-policies --group-name ReadOnlyDevelopers

# Simulate what actions the user can perform (IAM Policy Simulator)
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:user/junior-dev-jane \
  --action-names "ec2:DescribeInstances" "ec2:TerminateInstances" "s3:GetObject" "s3:DeleteObject"

Expected result: ec2:DescribeInstances and s3:GetObjectallowed. ec2:TerminateInstances and s3:DeleteObjectdenied.


What ReadOnlyAccess Does NOT Cover

Be aware of these important boundaries before assuming full visibility:

ScopeIncluded in ReadOnlyAccess?Notes
AWS service resource metadata✅ YesEC2, S3, RDS, Lambda, etc.
AWS Billing & Cost data❌ NoRequires separate billing console activation + AWSBillingReadOnlyAccess
AWS Organizations data❌ NoRequires explicit Organizations read permissions
Secrets Manager secret values❌ NoGetSecretValue is a write-risk action; not included by design
S3 object contents⚠️ PartialBucket listing allowed; object-level access depends on bucket policy

IAM Best Practices Checklist

  • ✅ Use IAM Groups — never attach policies directly to individual users for team scenarios.
  • ✅ Use AWS Managed Policies (ReadOnlyAccess) — AWS maintains and updates them as new services launch.
  • ✅ Enforce MFA — mandatory for any human IAM user with console access.
  • ✅ Enable IAM Access Analyzer — continuously monitors for overly permissive access.
  • ✅ Set a password policy — enforce minimum length, complexity, and rotation via aws iam update-account-password-policy.
  • ✅ Consider AWS IAM Identity Center (SSO) for teams larger than 2-3 people — it's the modern, recommended approach over long-lived IAM users.

Modern Alternative: AWS IAM Identity Center

For teams, AWS recommends AWS IAM Identity Center (formerly AWS SSO) over creating individual IAM users. It provides centralized access management, supports external identity providers (Okta, Azure AD), and issues short-lived credentials — eliminating the risk of long-lived IAM user access keys entirely. Assign the ReadOnlyAccess permission set within IAM Identity Center for the same effect with far better security posture.


Glossary

TermDefinition
AWS Managed PolicyA standalone IAM policy created and maintained by AWS. Automatically updated when new services or actions are added.
Least PrivilegeThe security principle of granting only the minimum permissions required to perform a task — nothing more.
IAM GroupA collection of IAM users. Policies attached to a group apply to all users within it, simplifying access management.
MFA (Multi-Factor Authentication)A second layer of identity verification beyond a password, required before granting console or API access.
IAM Policy SimulatorAn AWS tool that evaluates IAM policies to determine what actions a principal is allowed or denied, without making real API calls.

Next Steps

Related Posts

Comments

Popular posts from this blog

EC2 No Internet Access in Custom VPC: Attaching an Internet Gateway and Fixing Route Tables

EC2 SSH Connection Timeout: The Exact Security Group Rules You Need to Fix It

IAM User vs. IAM Role: Why Your EC2 Instance Should Never Use a User