|
| 1 | +# Rule Details |
| 2 | + |
| 3 | +## aws_iam_role_policy_hardcoded_region |
| 4 | + |
| 5 | +This rule checks `aws_iam_role_policy` resources for hardcoded AWS regions in policy documents. It examines both JSON policy strings and structured policy documents to detect: |
| 6 | + |
| 7 | +- Hardcoded regions in ARNs within policy statements (e.g., `arn:aws:s3:::bucket/us-east-1/*`) |
| 8 | +- Direct region references in policy JSON |
| 9 | + |
| 10 | +**Example violations:** |
| 11 | +```hcl |
| 12 | +resource "aws_iam_role_policy" "bad" { |
| 13 | + policy = jsonencode({ |
| 14 | + Statement = [{ |
| 15 | + Effect = "Allow" |
| 16 | + Action = "s3:GetObject" |
| 17 | + Resource = "arn:aws:s3:::bucket/us-east-1/*" # ❌ Hardcoded region |
| 18 | + }] |
| 19 | + }) |
| 20 | +} |
| 21 | +``` |
| 22 | + |
| 23 | +**Recommended fix:** |
| 24 | +```hcl |
| 25 | +resource "aws_iam_role_policy" "good" { |
| 26 | + policy = jsonencode({ |
| 27 | + Statement = [{ |
| 28 | + Effect = "Allow" |
| 29 | + Action = "s3:GetObject" |
| 30 | + Resource = "arn:aws:s3:::bucket/${data.aws_region.current.name}/*" # ✅ Dynamic region |
| 31 | + }] |
| 32 | + }) |
| 33 | +} |
| 34 | +``` |
| 35 | + |
| 36 | +## aws_iam_role_policy_hardcoded_partition |
| 37 | + |
| 38 | +This rule checks `aws_iam_role_policy` resources for hardcoded AWS partitions in policy documents. It detects: |
| 39 | + |
| 40 | +- Hardcoded partitions in ARNs (e.g., `arn:aws:`, `arn:aws-cn:`, `arn:aws-us-gov:`) |
| 41 | + |
| 42 | +**Example violations:** |
| 43 | +```hcl |
| 44 | +resource "aws_iam_role_policy" "bad" { |
| 45 | + policy = jsonencode({ |
| 46 | + Statement = [{ |
| 47 | + Effect = "Allow" |
| 48 | + Action = "s3:*" |
| 49 | + Resource = "arn:aws:s3:::bucket/*" # ❌ Hardcoded partition |
| 50 | + }] |
| 51 | + }) |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +**Recommended fix:** |
| 56 | +```hcl |
| 57 | +resource "aws_iam_role_policy" "good" { |
| 58 | + policy = jsonencode({ |
| 59 | + Statement = [{ |
| 60 | + Effect = "Allow" |
| 61 | + Action = "s3:*" |
| 62 | + Resource = "arn:${data.aws_partition.current.partition}:s3:::bucket/*" # ✅ Dynamic partition |
| 63 | + }] |
| 64 | + }) |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +## aws_iam_policy_hardcoded_region |
| 69 | + |
| 70 | +This rule checks `aws_iam_policy` resources for hardcoded AWS regions in policy documents. Similar to the role policy rule, it examines: |
| 71 | + |
| 72 | +- Hardcoded regions in ARNs within policy statements |
| 73 | +- Direct region references in policy JSON |
| 74 | + |
| 75 | +**Example violations:** |
| 76 | +```hcl |
| 77 | +resource "aws_iam_policy" "bad" { |
| 78 | + policy = jsonencode({ |
| 79 | + Statement = [{ |
| 80 | + Effect = "Allow" |
| 81 | + Action = "lambda:InvokeFunction" |
| 82 | + Resource = "arn:aws:lambda:eu-west-1:123456789012:function:*" # ❌ Hardcoded region |
| 83 | + }] |
| 84 | + }) |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +**Recommended fix:** |
| 89 | +```hcl |
| 90 | +resource "aws_iam_policy" "good" { |
| 91 | + policy = jsonencode({ |
| 92 | + Statement = [{ |
| 93 | + Effect = "Allow" |
| 94 | + Action = "lambda:InvokeFunction" |
| 95 | + Resource = "arn:aws:lambda:${data.aws_region.current.name}:123456789012:function:*" # ✅ Dynamic region |
| 96 | + }] |
| 97 | + }) |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +## aws_iam_policy_hardcoded_partition |
| 102 | + |
| 103 | +This rule checks `aws_iam_policy` resources for hardcoded AWS partitions in policy documents. It detects: |
| 104 | + |
| 105 | +- Hardcoded partitions in ARNs within policy statements |
| 106 | + |
| 107 | +**Example violations:** |
| 108 | +```hcl |
| 109 | +resource "aws_iam_policy" "bad" { |
| 110 | + policy = jsonencode({ |
| 111 | + Statement = [{ |
| 112 | + Effect = "Allow" |
| 113 | + Action = "sqs:*" |
| 114 | + Resource = "arn:aws-us-gov:sqs:*:*:*" # ❌ Hardcoded partition |
| 115 | + }] |
| 116 | + }) |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +**Recommended fix:** |
| 121 | +```hcl |
| 122 | +resource "aws_iam_policy" "good" { |
| 123 | + policy = jsonencode({ |
| 124 | + Statement = [{ |
| 125 | + Effect = "Allow" |
| 126 | + Action = "sqs:*" |
| 127 | + Resource = "arn:${data.aws_partition.current.partition}:sqs:*:*:*" # ✅ Dynamic partition |
| 128 | + }] |
| 129 | + }) |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +## aws_provider_hardcoded_region |
| 134 | + |
| 135 | +This rule checks AWS provider configurations for hardcoded regions. It detects: |
| 136 | + |
| 137 | +- Hardcoded regions in provider `region` attribute |
| 138 | +- Hardcoded regions in `assume_role` ARNs |
| 139 | + |
| 140 | +**Example violations:** |
| 141 | +```hcl |
| 142 | +provider "aws" { |
| 143 | + region = "us-east-1" # ❌ Hardcoded region |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +**Recommended fix:** |
| 148 | +```hcl |
| 149 | +provider "aws" { |
| 150 | + region = var.aws_region # ✅ Use variables |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +## aws_arn_hardcoded |
| 155 | + |
| 156 | +This is a comprehensive rule that checks ALL AWS resources for hardcoded regions and partitions in ARN values. It works by walking through all expressions in your Terraform files and detecting any string that looks like an ARN with hardcoded values. |
| 157 | + |
| 158 | +This rule covers resource types including: |
| 159 | +- Lambda (permissions, event source mappings, functions) |
| 160 | +- SNS/SQS (subscriptions, queue policies) |
| 161 | +- CloudWatch (event targets, log subscriptions, alarms) |
| 162 | +- API Gateway (integrations, authorizers) |
| 163 | +- KMS (grants, aliases, keys) |
| 164 | +- Secrets Manager (rotations, policies) |
| 165 | +- ECS (services, task definitions) |
| 166 | +- RDS (instances, event subscriptions, clusters) |
| 167 | +- S3 (notifications, policies, access points) |
| 168 | +- And many more... |
| 169 | + |
| 170 | +**Example violations:** |
| 171 | +```hcl |
| 172 | +resource "aws_lambda_permission" "test" { |
| 173 | + source_arn = "arn:aws:s3:us-east-1:123456789012:bucket/my-bucket" # ❌ Hardcoded region and partition |
| 174 | +} |
| 175 | +
|
| 176 | +resource "aws_kms_grant" "test" { |
| 177 | + key_id = "arn:aws:kms:eu-west-1:123456789012:key/12345678-1234-1234-1234-123456789012" # ❌ Hardcoded region and partition |
| 178 | +} |
| 179 | +``` |
| 180 | + |
| 181 | +**Recommended fixes:** |
| 182 | +```hcl |
| 183 | +data "aws_region" "current" {} |
| 184 | +data "aws_partition" "current" {} |
| 185 | +
|
| 186 | +resource "aws_lambda_permission" "test" { |
| 187 | + source_arn = "arn:${data.aws_partition.current.partition}:s3:${data.aws_region.current.name}:123456789012:bucket/my-bucket" # ✅ Dynamic |
| 188 | +} |
| 189 | +
|
| 190 | +resource "aws_kms_grant" "test" { |
| 191 | + key_id = "arn:${data.aws_partition.current.partition}:kms:${data.aws_region.current.name}:123456789012:key/12345678-1234-1234-1234-123456789012" # ✅ Dynamic |
| 192 | +} |
| 193 | +``` |
0 commit comments