SWE-5002

Cloud IAM Permission Overreach

Cantorian Technical Debt Magnitude: ℵ₁ (Systemic)

Description

Cloud IAM roles and policies configured with excessive permissions, violating the principle of least privilege. This includes EC2 instances with broad S3 access, Lambda functions with administrative permissions, or service accounts with wildcard resource access. Often combined with other vulnerabilities (like SSRF) to create catastrophic breaches.

Illustrative Cantor Point

The Cantor Point occurs when defining IAM policies - choosing between restrictive policies that might break functionality versus permissive policies that "just work." The decision to grant broad permissions to avoid troubleshooting creates a divergent path where any application vulnerability becomes a cloud-wide security breach.

Categories: CP-Schema, CP-API, CP-Process

Real-World Examples / Observed In

  • Capital One (2019): EC2 instance with overly permissive S3 access allowed extraction of 100M+ customer records via SSRF [See: Cases-By-Year/2019 Data Integrity Failures.md#4]
  • Common Pattern: S3:* permissions on production buckets, EC2 instances with full AWS access
  • Typical Mistake: Using AWS managed policies instead of custom least-privilege policies

Common Consequences & Impacts

Technical Impacts

  • - Complete cloud account compromise
  • - Lateral movement across services
  • - Data exfiltration at scale
  • - Cryptocurrency mining abuse

Human/Ethical Impacts

  • - Personal data exposure
  • - Financial information theft
  • - Regulatory violations
  • - Loss of customer trust

Business Impacts

  • - Massive data breaches
  • - Cloud service suspension
  • - Unexpected cloud bills
  • - Complete infrastructure compromise

Recovery Difficulty & Escalation

5.5
8.5

ADI Principles & Axioms Violated

  • Principle of Trust Insufficiency: Over-trusting application security
  • Principle of Boundary Criticality: IAM is the critical security boundary

Detection / 60-Second Audit

```sql
-- Track cloud IAM permissions in database
CREATE TABLE IF NOT EXISTS cloud_iam_audit (
    id SERIAL PRIMARY KEY,
    service_name VARCHAR(255),
    role_arn VARCHAR(500),
    policy_document JSONB,
    risk_score INTEGER,
    last_reviewed DATE
);

-- High-risk permission patterns
SELECT 
    service_name,
    role_arn,
    CASE 
        WHEN policy_document::text LIKE '%"*"%' THEN 'Contains wildcard permissions'
        WHEN policy_document::text LIKE '%AdministratorAccess%' THEN 'Has admin access'
        WHEN policy_document::text LIKE '%s3:*%' THEN 'Unrestricted S3 access'
        ELSE 'Review needed'
    END as risk_reason,
    risk_score
FROM cloud_iam_audit
WHERE risk_score > 7
   OR policy_document::text LIKE '%"*"%'
   OR policy_document::text LIKE '%:*"%';

-- Check for service accounts with excessive permissions
SELECT 
    username,
    CASE 
        WHEN has_superuser THEN 'Database superuser - CRITICAL'
        WHEN can_create_db THEN 'Can create databases - HIGH'
        WHEN can_create_role THEN 'Can create roles - HIGH'
        ELSE 'Review permissions'
    END as risk_level
FROM (
    SELECT 
        usename as username,
        usesuper as has_superuser,
        usecreatedb as can_create_db,
        usecreaterole as can_create_role
    FROM pg_user
    WHERE usename LIKE 'svc_%' OR usename LIKE 'app_%'
) service_accounts;
```
```sql
-- Track cloud IAM permissions in database
CREATE TABLE IF NOT EXISTS cloud_iam_audit (
    id INT AUTO_INCREMENT PRIMARY KEY,
    service_name VARCHAR(255),
    role_arn VARCHAR(500),
    policy_document JSON,
    risk_score INT,
    last_reviewed DATE
);

-- High-risk permission patterns
SELECT 
    service_name,
    role_arn,
    CASE 
        WHEN JSON_CONTAINS(policy_document, '"*"') THEN 'Contains wildcard permissions'
        WHEN JSON_SEARCH(policy_document, 'all', 'AdministratorAccess') IS NOT NULL THEN 'Has admin access'
        WHEN JSON_SEARCH(policy_document, 'all', 's3:*') IS NOT NULL THEN 'Unrestricted S3 access'
        ELSE 'Review needed'
    END as risk_reason,
    risk_score
FROM cloud_iam_audit
WHERE risk_score > 7
   OR JSON_CONTAINS(policy_document, '"*"')
   OR JSON_SEARCH(policy_document, 'all', ':*') IS NOT NULL;

-- Check for service accounts with excessive permissions
SELECT 
    user,
    host,
    CASE 
        WHEN super_priv = 'Y' THEN 'Database superuser - CRITICAL'
        WHEN create_priv = 'Y' THEN 'Can create databases - HIGH'
        WHEN grant_priv = 'Y' THEN 'Can grant privileges - HIGH'
        ELSE 'Review permissions'
    END as risk_level
FROM mysql.user
WHERE user LIKE 'svc_%' OR user LIKE 'app_%';
```
```sql
-- Track cloud IAM permissions in database
CREATE TABLE cloud_iam_audit (
    id INT IDENTITY PRIMARY KEY,
    service_name NVARCHAR(255),
    role_arn NVARCHAR(500),
    policy_document NVARCHAR(MAX),
    risk_score INT,
    last_reviewed DATE
);

-- High-risk permission patterns
SELECT 
    service_name,
    role_arn,
    CASE 
        WHEN policy_document LIKE '%"*"%' THEN 'Contains wildcard permissions'
        WHEN policy_document LIKE '%AdministratorAccess%' THEN 'Has admin access'
        WHEN policy_document LIKE '%s3:*%' THEN 'Unrestricted S3 access'
        ELSE 'Review needed'
    END as risk_reason,
    risk_score
FROM cloud_iam_audit
WHERE risk_score > 7
   OR policy_document LIKE '%"*"%'
   OR policy_document LIKE '%:*%';

-- Check for service accounts with excessive permissions
SELECT 
    p.name as username,
    CASE 
        WHEN IS_SRVROLEMEMBER('sysadmin', p.name) = 1 THEN 'Database sysadmin - CRITICAL'
        WHEN IS_SRVROLEMEMBER('dbcreator', p.name) = 1 THEN 'Can create databases - HIGH'
        WHEN IS_SRVROLEMEMBER('securityadmin', p.name) = 1 THEN 'Security admin - HIGH'
        ELSE 'Review permissions'
    END as risk_level
FROM sys.server_principals p
WHERE p.type = 'S'
  AND (p.name LIKE 'svc_%' OR p.name LIKE 'app_%');

Prevention & Mitigation Best Practices

  1. Implement Least Privilege Policies:

    // Bad: Overly permissive S3 policy
    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Action": "s3:*",
        "Resource": "*"
      }]
    }
    
    // Good: Specific, limited permissions
    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Action": [
          "s3:GetObject",
          "s3:ListBucket"
        ],
        "Resource": [
          "arn:aws:s3:::my-app-data-bucket",
          "arn:aws:s3:::my-app-data-bucket/*"
        ],
        "Condition": {
          "StringEquals": {
            "s3:ExistingObjectTag/Environment": "production"
          }
        }
      }]
    }
    
  2. Database Schema for IAM Management:

    CREATE TABLE iam_role_definitions (
        id SERIAL PRIMARY KEY,
        role_name VARCHAR(255) UNIQUE NOT NULL,
        service_name VARCHAR(255) NOT NULL,
        environment VARCHAR(50) NOT NULL,
        created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
        created_by VARCHAR(255) NOT NULL,
        approved_by VARCHAR(255),
        approval_date DATE
    );
    
    CREATE TABLE iam_permission_requirements (
        id SERIAL PRIMARY KEY,
        role_id INTEGER REFERENCES iam_role_definitions(id),
        aws_service VARCHAR(100) NOT NULL,
        actions TEXT[] NOT NULL,
        resources TEXT[] NOT NULL,
        conditions JSONB,
        justification TEXT NOT NULL,
        risk_assessment TEXT
    );
    
    CREATE TABLE iam_permission_reviews (
        id SERIAL PRIMARY KEY,
        role_id INTEGER REFERENCES iam_role_definitions(id),
        review_date DATE NOT NULL,
        reviewer VARCHAR(255) NOT NULL,
        findings TEXT,
        actions_taken TEXT,
        next_review_date DATE NOT NULL
    );
    
  3. Automated Permission Monitoring:

    -- Track permission usage
    CREATE TABLE iam_permission_usage (
        id BIGSERIAL PRIMARY KEY,
        role_arn VARCHAR(500),
        action VARCHAR(255),
        resource VARCHAR(500),
        used_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
        source_ip INET,
        user_agent TEXT
    );
    
    -- Identify unused permissions
    CREATE VIEW unused_permissions AS
    SELECT 
        pr.role_id,
        pr.aws_service,
        pr.actions,
        rd.role_name
    FROM iam_permission_requirements pr
    JOIN iam_role_definitions rd ON pr.role_id = rd.id
    WHERE NOT EXISTS (
        SELECT 1 FROM iam_permission_usage pu
        WHERE pu.role_arn LIKE '%' || rd.role_name || '%'
        AND pu.action = ANY(pr.actions)
        AND pu.used_at > NOW() - INTERVAL '90 days'
    );
    
  4. Service-Specific Roles:

    -- Enforce service isolation
    ALTER TABLE iam_role_definitions 
    ADD CONSTRAINT one_role_per_service_env 
    UNIQUE (service_name, environment);
    
    -- Prevent role sharing
    CREATE OR REPLACE FUNCTION prevent_role_sharing()
    RETURNS TRIGGER AS $
    BEGIN
        IF EXISTS (
            SELECT 1 FROM iam_role_definitions
            WHERE role_name = NEW.role_name
            AND service_name != NEW.service_name
        ) THEN
            RAISE EXCEPTION 'Role % already assigned to different service', NEW.role_name;
        END IF;
        RETURN NEW;
    END;
    $ LANGUAGE plpgsql;
    
  5. Additional Best Practices:

    • Use AWS Organizations SCPs to prevent dangerous actions
    • Implement mandatory MFA for all IAM operations
    • Regular access reviews (quarterly minimum)
    • Use AWS Access Analyzer for continuous monitoring
    • Implement break-glass procedures for emergencies

Real World Examples

# The vulnerability chain:
1. Web Application Firewall (WAF) misconfiguration
2. Server-Side Request Forgery (SSRF) vulnerability
3. EC2 instance with excessive S3 permissions

# The IAM role attached to EC2:
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3:GetObject",
      "s3:ListBucket"
    ],
    "Resource": "arn:aws:s3:::capital-one-*"  // Wildcard!
  }]
}

# How it was exploited:
1. Attacker found SSRF: http://app.com/api?url=http://169.254.169.254/
2. Retrieved IAM credentials from metadata service
3. Used credentials to list ALL Capital One S3 buckets
4. Downloaded 106 million credit applications

# Impact:
- 100 million US customers affected
- 6 million Canadian customers affected  
- $80M fine from regulators
- $190M total in fines and customer settlements
# Vulnerable configuration:
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-service-account
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/eksServiceRole

# The attached IAM role (too permissive):
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3:*",
      "dynamodb:*",
      "secretsmanager:*"
    ],
    "Resource": "*"
  }]
}

# Result: Any pod compromise = full AWS access
// Before (vulnerable):
{
  "Statement": [{
    "Effect": "Allow",
    "Action": "s3:*",
    "Resource": "*"
  }]
}

// After (secure):
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListSpecificBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::myapp-data-prod",
      "Condition": {
        "StringLike": {
          "s3:prefix": ["user-data/${aws:userid}/*"]
        }
      }
    },
    {
      "Sid": "ReadWriteUserData",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::myapp-data-prod/user-data/${aws:userid}/*"
    },
    {
      "Sid": "DenyUnencryptedUploads",
      "Effect": "Deny",
      "Action": "s3:PutObject",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      }
    }
  ]
}

# Additional security layers:
- Enable S3 Block Public Access
- Use VPC endpoints for S3
- Enable CloudTrail logging
- Set up AWS Config rules for compliance
- Implement session-based temporary credentials

AI Coding Guidance/Prompt

Prompt: "When creating cloud IAM policies:"
Rules:
  - Never use wildcard (*) permissions
  - Always specify exact resource ARNs
  - Require business justification for each permission
  - Flag any policy without conditions
  - Suggest time-based or IP-based restrictions
  - Require separate roles for each service/function
  
Example:
  # Bad: Kitchen sink permissions
  resource "aws_iam_role_policy" "bad_policy" {
    role = aws_iam_role.app_role.id
    policy = jsonencode({
      Statement = [{
        Effect = "Allow"
        Action = ["s3:*", "dynamodb:*", "lambda:*"]
        Resource = "*"
      }]
    })
  }
  
  # Good: Least privilege with conditions
  resource "aws_iam_role_policy" "good_policy" {
    role = aws_iam_role.app_role.id
    policy = jsonencode({
      Statement = [
        {
          Sid = "ReadSpecificS3Bucket"
          Effect = "Allow"
          Action = [
            "s3:GetObject",
            "s3:ListBucket"
          ]
          Resource = [
            "arn:aws:s3:::my-app-data-prod",
            "arn:aws:s3:::my-app-data-prod/*"
          ]
          Condition = {
            IpAddress = {
              "aws:SourceIp": ["10.0.0.0/8"]
            }
            DateGreaterThan = {
              "aws:CurrentTime": "2024-01-01T00:00:00Z"
            }
          }
        },
        {
          Sid = "WriteToSpecificDynamoTable"
          Effect = "Allow"
          Action = [
            "dynamodb:PutItem",
            "dynamodb:UpdateItem"
          ]
          Resource = "arn:aws:dynamodb:us-east-1:123456789012:table/AppData"
          Condition = {
            StringEquals = {
              "dynamodb:LeadingKeys": ["${aws:userid}"]
            }
          }
        }
      ]
    })
  }

Relevant Keywords

cloud permission overreach Symptoms: slow queries, data inconsistency, constraint violations Preventive: schema validation, constraint enforcement, proper typing Tech stack: PostgreSQL, MySQL, SQL Server, Oracle Industry: all industries, enterprise, SaaS

Related Patterns

The Cantorian Technical Debt Magnitude scale gives developers an intuitive sense of magnitude beyond simple hour counts - some debts aren't just larger in scale, but qualitatively different in their complexity.

Cantor Points are critical decision junctures—or even moments of non-decision—where seemingly small choices can create drastically divergent futures for a system's integrity, security, and evolvability. These are the "forks in the road" where one path might lead to manageable complexity, while another veers towards systemic entanglement or even chaos. They often appear trivial at the time but can set in motion irreversible or costly-to-reverse consequences.

Applied Data Integrity (ADI) is a framework to understanding the far-reaching consequences of schema and data decisions that impact security and reliability, and accumulate into ethical debt that affects real human lives. Built on research from real-world incidents, ADI uncovered 7 Principles to identify when these decisions are being made, and how to make them better, to avoid future technical debt and potentially catastrophic "butterfly effects" of small decisions that ripple into chaotic technical and ethical debt.