Cloud Security

AWS IAM Best Practices for Indian SaaS (2026)

Manish Garg
Manish Garg Associate CISSP Β· RingSafe
April 19, 2026
5 min read

AWS IAM is the single highest-leverage security control in any AWS environment. Compromise IAM and you own everything. Configure it well and most other findings become lower-severity β€” a public S3 bucket with no credentials worth stealing is inconvenient, not existential. This is the practitioner’s guide to AWS IAM for Indian SaaS companies in 2026: the architecture decisions that matter, the tactical hygiene that catches the common failures, and the frameworks for doing this at scale without drowning in policy sprawl.

The architecture principles

1. Federate humans; never create IAM users for people

In 2026, the default identity pattern is: AWS IAM Identity Center (formerly SSO) integrated with your corporate identity provider (Okta, Azure AD, Google Workspace, JumpCloud). Users authenticate to IdP, IdP asserts identity to IAM Identity Center, Identity Center issues temporary credentials for the target account and role. No long-lived access keys. Every human action is tied to an identity attributable in the IdP.

Consequences: instant offboarding (disable in IdP, access in all accounts dies), centralized MFA enforcement, simplified audit trail. The one-time setup cost is three days of work. Every organization with more than five engineers should have done this already.

2. Use workload identity for services, not access keys

For workloads running on AWS: EC2 instance profiles, ECS task roles, EKS IRSA (IAM Roles for Service Accounts), Lambda execution roles. For workloads running outside AWS: IAM Roles Anywhere (for infrastructure with mTLS-capable certificates), OIDC federation (for CI/CD runners β€” GitHub Actions, GitLab, Buildkite all support this). Access keys should exist only for legacy systems that cannot be refactored.

3. Multi-account organization structure

One account for every meaningful blast-radius boundary. Minimum: production, staging, dev, security-tooling, logging, shared-services. Many organizations have more: separate accounts per product line, per customer (for multi-tenant isolation), per region (for data-residency compliance).

Service Control Policies at the organizational level enforce account-agnostic guardrails: no one β€” not even root β€” can disable CloudTrail, cannot opt out of GuardDuty, cannot create IAM users (forcing federated access), cannot create resources outside permitted regions.

4. Least privilege, built incrementally

The naive interpretation of least privilege is “figure out exactly what permissions are needed upfront and grant only those.” In practice this is infeasible for complex applications. The iterative version works better: start with a reasonable estimate, run the workload with logging, identify actually-used permissions with IAM Access Analyzer (the policy-generation feature), replace the over-broad initial policy with the refined one, and repeat.

Tactical hygiene β€” the 15 checks

  1. Root user β€” MFA with hardware token, no access keys, no console logins except for specific account-level operations AWS requires root for
  2. IAM users with access keys β€” none for human users; for legacy services, keys rotated every 90 days maximum, with automated rotation where possible
  3. Unused credentials β€” Credentials Report flags access keys unused for 90+ days; these should be disabled
  4. Unused roles β€” IAM Access Analyzer flags roles with no recent activity; these should be removed
  5. Wildcard policies β€” no policies with "Action": "*" on "Resource": "*" except break-glass roles with strong access controls
  6. Administrative policies β€” AdministratorAccess attached only to break-glass roles, not to individuals or service roles
  7. Permissions boundaries β€” developer-created roles constrained by permissions boundary that prevents privilege escalation
  8. Cross-account trust β€” every trust relationship requires external-ID when assumable by a third-party; sts:ExternalId condition enforced
  9. Password policy β€” 14+ characters, no reuse of previous 24, max age 90 days (though SSO-federated is preferred)
  10. MFA enforcement β€” IAM policy denying most actions unless aws:MultiFactorAuthPresent is true
  11. Inline vs managed policies β€” prefer managed (customer or AWS-managed) over inline; easier to audit, reuse, and update
  12. Service-linked roles β€” used for AWS services that support them; custom roles only where service-linked unavailable
  13. Resource-based policies β€” bucket policies, KMS key policies, Lambda resource policies audited as carefully as IAM policies; they can grant access independently
  14. Session duration β€” cap at 1 hour for most roles, 12 hours only for specific interactive-user roles; longer sessions are an audit exposure
  15. Regular review β€” quarterly IAM review with automated report: users with old credentials, unused roles, over-permissive policies, recent changes

Common anti-patterns and their fixes

Anti-pattern: Service account with user credentials

A CI/CD pipeline authenticates to AWS using an IAM user’s long-lived access keys. The keys are in an environment variable in the pipeline config.

Fix: OIDC federation. GitHub Actions, GitLab CI, and most modern CI systems can federate to AWS without storing credentials. Configure an IAM role with a trust policy that accepts the CI system’s OIDC token, assume the role at build time, get short-lived credentials.

Anti-pattern: Catch-all admin role for engineers

Every engineer assumes AdministratorAccess in the production account because “we need to debug things.” Every audit shows this. Every breach involves this.

Fix: role-per-job-function with minimum necessary permissions. A production-debugging role with read-only access to logs and metrics, separate from production-write-access role with narrow permissions for specific administrative actions. Break-glass role for true emergencies with out-of-band approval and full audit trail.

Anti-pattern: Roles that can elevate themselves

A role with iam:CreatePolicy, iam:PutRolePolicy, or iam:AttachRolePolicy can grant itself additional permissions. This is often hidden inside broader policy grants.

Fix: permissions boundaries that prevent policy modifications to self or to roles with permissions boundary. Explicit denial of iam:* actions in any role that does not legitimately need to manage IAM.

Anti-pattern: Credentials in source code or container images

AWS access keys, third-party API keys, database passwords committed to repositories or baked into container images.

Fix: secret scanning on every commit (git-secrets, trufflehog, GitHub secret scanning); secrets management via AWS Secrets Manager or Parameter Store; container-image scanning that flags embedded secrets.

Detection signals for IAM compromise

  • CloudTrail events showing iam:CreateAccessKey, iam:CreateUser, iam:AttachRolePolicy, iam:PutUserPolicy outside of expected provisioning windows
  • API calls from unusual source IPs β€” geographic anomaly, Tor exits, known attacker ranges
  • GetAccountAuthorizationDetails called by a non-admin principal β€” this is reconnaissance
  • Repeated AccessDenied events from the same principal in a short window β€” enumeration pattern
  • STS AssumeRole from an unexpected source account or IAM user
  • CloudTrail disabled, GuardDuty suspended, Config stopped β€” active attacker removing visibility

Related reading

For an IAM-focused AWS security review, book a scoping call.