{
  "schema": "https://ai-atoms.com/schemas/skill-v1.json",
  "type": "skill",
  "id": "skill/aws-iam-best-practices",
  "version": "1.0.0",
  "name": "Aws Iam Best Practices",
  "description": "IAM policy review, hardening, and least privilege implementation",
  "system_prompt_fragment": "# AWS IAM Best Practices\n\nReview and harden IAM policies following AWS security best practices and least privilege principles.\n\n## When to Use\n\nUse this skill when you need to review IAM policies, implement least privilege access, or harden IAM security.\n\n## Core Principles\n\n**Least Privilege**\n- Grant minimum permissions needed\n- Use managed policies when possible\n- Avoid wildcard (*) permissions\n- Regular access reviews\n\n**Defense in Depth**\n- Enable MFA for all users\n- Use IAM roles instead of access keys\n- Implement service control policies (SCPs)\n- Enable CloudTrail for audit\n\n**Separation of Duties**\n- Separate admin and user roles\n- Use different roles for different environments\n- Implement approval workflows\n- Regular permission audits\n\n## IAM Security Checks\n\n### Find Overly Permissive Policies\n\n```bash\n# List policies with full admin access\naws iam list-policies --scope Local \\\n  --query 'Policies[*].[PolicyName,Arn]' --output table | \\\n  grep -i admin\n\n# Find policies with wildcard actions\naws iam list-policies --scope Local --query 'Policies[*].Arn' --output text | \\\nwhile read arn; do\n  version=$(aws iam get-policy --policy-arn \"$arn\" \\\n    --query 'Policy.DefaultVersionId' --output text)\n  doc=$(aws iam get-policy-version --policy-arn \"$arn\" \\\n    --version-id \"$version\" --query 'PolicyVersion.Document')\n  if echo \"$doc\" | grep -q '\"Action\": \"\\*\"'; then\n    echo \"Wildcard action in: $arn\"\n  fi\ndone\n\n# Find inline policies (should use managed policies)\naws iam list-users --query 'Users[*].UserName' --output text | \\\nwhile read user; do\n  policies=$(aws iam list-user-policies --user-name \"$user\" \\\n    --query 'PolicyNames' --output text)\n  if [ -n \"$policies\" ]; then\n    echo \"Inline policies on user $user: $policies\"\n  fi\ndone\n```\n\n### MFA Enforcement\n\n```bash\n# List users without MFA\naws iam get-credential-report --output text | \\\n  awk -F, 'NR>1 && $4==\"false\" {print $1}'\n\n# Check if MFA is required in policies\naws iam list-policies --scope Local --query 'Policies[*].Arn' --output text | \\\nwhile read arn; do\n  version=$(aws iam get-policy --policy-arn \"$arn\" \\\n    --query 'Policy.DefaultVersionId' --output text)\n  doc=$(aws iam get-policy-version --policy-arn \"$arn\" \\\n    --version-id \"$version\" --query 'PolicyVersion.Document')\n  if echo \"$doc\" | grep -q \"aws:MultiFactorAuthPresent\"; then\n    echo \"MFA enforced in: $arn\"\n  fi\ndone\n\n# Enable MFA for a user (returns QR code)\naws iam create-virtual-mfa-device \\\n  --virtual-mfa-device-name user-mfa \\\n  --outfile /tmp/qr.png \\\n  --bootstrap-method QRCodePNG\n```\n\n### Access Key Management\n\n```bash\n# Find old access keys (>90 days)\naws iam list-users --query 'Users[*].UserName' --output text | \\\nwhile read user; do\n  aws iam list-access-keys --user-name \"$user\" \\\n    --query 'AccessKeyMetadata[*].[AccessKeyId,CreateDate,Status]' \\\n    --output text | \\\n  while read key_id create_date status; do\n    age_days=$(( ($(date +%s) - $(date -d \"$create_date\" +%s)) / 86400 ))\n    if [ $age_days -gt 90 ]; then\n      echo \"$user: Key $key_id is $age_days days old\"\n    fi\n  done\ndone\n\n# Rotate access key\nOLD_KEY=\"AKIAIOSFODNN7EXAMPLE\"\nUSER=\"myuser\"\n\n# Create new key\nNEW_KEY=$(aws iam create-access-key --user-name \"$USER\")\necho \"New key created. Update applications, then run:\"\necho \"aws iam delete-access-key --user-name $USER --access-key-id $OLD_KEY\"\n\n# Deactivate old key (test first)\naws iam update-access-key \\\n  --user-name \"$USER\" \\\n  --access-key-id \"$OLD_KEY\" \\\n  --status Inactive\n```\n\n### Role and Policy Analysis\n\n```bash\n# List unused roles (no activity in 90 days)\naws iam list-roles --query 'Roles[*].[RoleName,RoleLastUsed.LastUsedDate]' \\\n  --output text | \\\nwhile read role last_used; do\n  if [ \"$last_used\" = \"None\" ]; then\n    echo \"Never used: $role\"\n  fi\ndone\n\n# Find roles with trust relationships to external accounts\naws iam list-roles --query 'Roles[*].RoleName' --output text | \\\nwhile read role; do\n  trust=$(aws iam get-role --role-name \"$role\" \\\n    --query 'Role.AssumeRolePolicyDocument')\n  if echo \"$trust\" | grep -q '\"AWS\":'; then\n    echo \"External trust: $role\"\n  fi\ndone\n\n# Analyze policy permissions\naws iam simulate-principal-policy \\\n  --policy-source-arn arn:aws:iam::123456789012:user/myuser \\\n  --action-names s3:GetObject s3:PutObject \\\n  --resource-arns arn:aws:s3:::mybucket/*\n```\n\n## IAM Policy Templates\n\n### Least Privilege S3 Access\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:GetObject\",\n        \"s3:PutObject\"\n      ],\n      \"Resource\": \"arn:aws:s3:::my-bucket/user-data/${aws:username}/*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"s3:ListBucket\",\n      \"Resource\": \"arn:aws:s3:::my-bucket\",\n      \"Condition\": {\n        \"StringLike\": {\n          \"s3:prefix\": \"user-data/${aws:username}/*\"\n        }\n      }\n    }\n  ]\n}\n```\n\n### MFA-Required Policy\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Deny\",\n      \"Action\": \"*\",\n      \"Resource\": \"*\",\n      \"Condition\": {\n        \"BoolIfExists\": {\n          \"aws:MultiFactorAuthPresent\": \"false\"\n        }\n      }\n    }\n  ]\n}\n```\n\n### Time-Based Access\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"ec2:*\",\n      \"Resource\": \"*\",\n      \"Condition\": {\n        \"DateGreaterThan\": {\n          \"aws:CurrentTime\": \"2026-01-01T00:00:00Z\"\n        },\n        \"DateLessThan\": {\n          \"aws:CurrentTime\": \"2026-12-31T23:59:59Z\"\n        }\n      }\n    }\n  ]\n}\n```\n\n### IP-Restricted Access\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Deny\",\n      \"Action\": \"*\",\n      \"Resource\": \"*\",\n      \"Condition\": {\n        \"NotIpAddress\": {\n          \"aws:SourceIp\": [\n            \"203.0.113.0/24\",\n            \"198.51.100.0/24\"\n          ]\n        }\n      }\n    }\n  ]\n}\n```\n\n## IAM Hardening Checklist\n\n**User Management**\n- [ ] Enable MFA for all users\n- [ ] Remove unused IAM users\n- [ ] Rotate access keys every 90 days\n- [ ] Use IAM roles instead of long-term credentials\n- [ ] Implement password policy (length, complexity, rotation)\n\n**Policy Management**\n- [ ] Replace inline policies with managed policies\n- [ ] Remove wildcard (*) permissions\n- [ ] Implement least privilege\n- [ ] Use policy conditions (MFA, IP, time)\n- [ ] Regular policy reviews\n\n**Role Management**\n- [ ] Use roles for EC2 instances\n- [ ] Implement cross-account roles properly\n- [ ] Review trust relationships\n- [ ] Remove unused roles\n- [ ] Use session tags for fine-grained access\n\n**Monitoring**\n- [ ] Enable CloudTrail for IAM events\n- [ ] Set up CloudWatch alarms for IAM changes\n- [ ] Use AWS IAM Access Analyzer\n- [ ] Regular access reviews\n- [ ] Monitor for privilege escalation\n\n## Automated IAM Hardening\n\n```python\n#!/usr/bin/env python3\n# iam-hardening.py\n\nimport boto3\nfrom datetime import datetime, timedelta\n\niam = boto3.client('iam')\n\ndef enforce_mfa():\n    \"\"\"Identify users without MFA\"\"\"\n    users = iam.list_users()['Users']\n    no_mfa = []\n    \n    for user in users:\n        mfa_devices = iam.list_mfa_devices(\n            UserName=user['UserName']\n        )['MFADevices']\n        \n        if not mfa_devices:\n            no_mfa.append(user['UserName'])\n    \n    return no_mfa\n\ndef rotate_old_keys():\n    \"\"\"Find access keys older than 90 days\"\"\"\n    users = iam.list_users()['Users']\n    old_keys = []\n    \n    for user in users:\n        keys = iam.list_access_keys(\n            UserName=user['UserName']\n        )['AccessKeyMetadata']\n        \n        for key in keys:\n            age = datetime.now(key['CreateDate'].tzinfo) - key['CreateDate']\n            if age.days > 90:\n                old_keys.append({\n                    'user': user['UserName'],\n                    'key_id': key['AccessKeyId'],\n                    'age_days': age.days\n                })\n    \n    return old_keys\n\ndef find_overpermissive_policies():\n    \"\"\"Find policies with wildcard actions\"\"\"\n    policies = iam.list_policies(Scope='Local')['Policies']\n    overpermissive = []\n    \n    for policy in policies:\n        version = iam.get_policy_version(\n            PolicyArn=policy['Arn'],\n            VersionId=policy['DefaultVersionId']\n        )\n        \n        doc = version['PolicyVersion']['Document']\n        for statement in doc.get('Statement', []):\n            if statement.get('Action') == '*':\n                overpermissive.append(policy['PolicyName'])\n                break\n    \n    return overpermissive\n\nif __name__ == \"__main__\":\n    print(\"IAM Hardening Report\")\n    print(\"=\" * 50)\n    \n    print(\"\\nUsers without MFA:\")\n    for user in enforce_mfa():\n        print(f\"  - {user}\")\n    \n    print(\"\\nOld access keys (>90 days):\")\n    for key in rotate_old_keys():\n        print(f\"  - {key['user']}: {key['age_days']} days\")\n    \n    print(\"\\nOverpermissive policies:\")\n    for policy in find_overpermissive_policies():\n        print(f\"  - {policy}\")\n```\n\n## Example Prompts\n\n- \"Review my IAM policies for security issues\"\n- \"Find users without MFA enabled\"\n- \"Create a least privilege policy for S3 access\"\n- \"Identify overly permissive IAM roles\"\n- \"Generate an IAM hardening report\"\n\n## Best Practices\n\n- Use AWS managed policies when possible\n- Implement policy versioning\n- Test policies in non-production first\n- Document policy purposes\n- Regular access reviews (quarterly)\n- Use IAM Access Analyzer\n- Implement SCPs for organization-wide controls\n\n## Kiro CLI Integration\n\n```bash\nkiro-cli chat \"Use aws-iam-best-practices to review my IAM setup\"\nkiro-cli chat \"Create a least privilege policy with aws-iam-best-practices\"\n```\n\n## Additional Resources\n\n- [IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)\n- [IAM Policy Simulator](https://policysim.aws.amazon.com/)\n- [IAM Access Analyzer](https://aws.amazon.com/iam/features/analyze-access/)",
  "applicable_domains": [
    "security"
  ],
  "category": "security",
  "invocation": [
    "/aws-iam-best-practices"
  ],
  "authored_by": "claudeskills.in community",
  "source_url": "https://claudeskills.in/skill/aws-iam-best-practices",
  "provenance": {
    "source": "claudeskills.in",
    "source_url": "https://claudeskills.in/skill/aws-iam-best-practices",
    "license": "unknown",
    "imported_at": "2026-09-03",
    "notes": "Aggregated by claudeskills.in from community GitHub lists."
  },
  "tags": [
    "claudeskills",
    "security",
    "risk-reviewed"
  ],
  "lifecycle": "draft"
}