VNX-TF-004 – Terraform IAM Policy with Wildcard Action (*)
Overview
This rule flags Terraform .tf files where a policy statement allows "*" as its action: Action = "*" or a list containing "*" in a jsonencode() policy, "Action": "*" or ["*"] (also over several lines) in a heredoc JSON policy, actions = ["*"] in a data "aws_iam_policy_document" statement, or actions = ["*"] in the permissions of an azurerm_role_definition. The effect is read from the statement itself, so a Deny statement (for example a region or MFA guard) is not reported even when an Allow statement sits beside it. Service-scoped wildcards such as "s3:*" are not reported.
Least-privilege IAM policies are the foundational access control mechanism in AWS. When a policy grants Action = "*", the associated role, user, or group can perform any operation on any resource in the account that is not blocked by a Service Control Policy (SCP) — including creating new IAM users, modifying security group rules, exfiltrating data from S3, or deleting production resources.
This rule corresponds to CWE-269: Improper Privilege Management.
Severity: High | CWE: CWE-269 – Improper Privilege Management
Why This Matters
Overly permissive IAM policies are one of the most common misconfigurations in AWS environments and a primary vector for privilege escalation. An attacker who compromises a workload running with an overly permissive role — through application-level vulnerabilities, container escape, SSRF, or credential theft — inherits all the permissions of that role.
A wildcard Action = "*" policy effectively grants administrative access. Even if the resource scope is limited (e.g., Resource = "arn:aws:s3:::my-bucket/*"), combined with a broad resource or Resource = "*", it grants full administrative control over the account. This means a compromised Lambda function, EC2 instance, or ECS task can create new IAM users with console access, modify CloudTrail settings to disable audit logging, exfiltrate secrets from Secrets Manager, and pivot to any other AWS service.
The risk extends beyond direct exploitation: over-permissive roles make the blast radius of any compromise much larger and make incident response much harder, since you cannot determine what an attacker did or did not access.
What Gets Flagged
resource "aws_iam_policy" "admin" {
policy = jsonencode({
Statement = [{
Effect = "Allow"
Action = "*" # FLAGGED
Resource = "*"
}]
})
}
data "aws_iam_policy_document" "admin" {
statement {
actions = ["*"] # FLAGGED: effect defaults to Allow
resources = ["*"]
}
}
Not flagged: a statement with effect = "Deny" and actions = ["*"], or Action = ["logs:CreateLogStream", "logs:PutLogEvents"].
Remediation
- Enumerate only the specific actions required by the workload. Review what the application actually does and grant only those actions. Use AWS IAM Access Analyzer to identify the minimum permissions from CloudTrail logs:
# SAFE: minimal permissions for a specific task
resource "aws_iam_role_policy" "app_policy" {
role = aws_iam_role.app.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject"]
Resource = "arn:aws:s3:::${var.bucket_name}/*"
},
{
Effect = "Allow"
Action = ["sqs:ReceiveMessage", "sqs:DeleteMessage"]
Resource = aws_sqs_queue.work_queue.arn
}
]
})
}
Use AWS managed policies with defined scopes as a starting point, then restrict further. Prefer service-specific managed policies (e.g.,
AmazonS3ReadOnlyAccess) overAdministratorAccess.Use IAM Access Analyzer to generate least-privilege policies from actual usage. This automatically produces a policy containing only the actions that were observed in CloudTrail logs during a review period.