How does IAM evaluation logic work using an explicit Deny policy with multiple condition keys?

Last updated: 2019-12-19

I want to create an AWS Identity and Access Management (IAM) explicit Deny policy that restricts creating Amazon Elastic Compute Cloud (Amazon EC2) instances and Amazon Elastic Block Store (Amazon EBS) volumes. How do I do that?

Short Description

You can use IAM policy tags to restrict the launch of EC2 instances and EBS volumes by using Allow with StringLike or Deny with StringNotLike condition operators. For instructions about using Allow with StringLike condition operators, see How can I use IAM policy tags to restrict how an EC2 instance or EBS volume can be created?

Resolution

Use the following example IAM policy that uses Deny with StringNotLike to restrict creating EC2 instances and EBS volumes.

Note: Use of Deny with StringNotLike prevents accidental privileged access.

If your policy has multiple condition operators or multiple keys attached to a single condition operator, then the conditions are evaluated using AND logic. With Deny multiple tag values, each RequestTag key must be used in separate statements to get the same AND logic.

Note: Setting all RequestTag key values in one condition with a Deny policy might not work as expected. This is because the action is allowed until all conditions are met. When all conditions are met, the action is denied.

Take note of the following required tags:

  • The cost_center tag must have a non-null value.
  • The EC2 instance has a tag key named Production.
  • The identifier tag must be a combination of any five characters.
  • The env tag value must be sandbox, dev, or prod.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowToDescribeAll",
            "Effect": "Allow",
            "Action": [
                "ec2:Describe*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowRunInstances",
            "Effect": "Allow",
            "Action": "ec2:RunInstances",
            "Resource": [
                "arn:aws:ec2:*::image/*",
                "arn:aws:ec2:*::snapshot/*",
                "arn:aws:ec2:*:*:subnet/*",
                "arn:aws:ec2:*:*:network-interface/*",
                "arn:aws:ec2:*:*:security-group/*",
                "arn:aws:ec2:*:*:key-pair/*"
            ]
        },
        {
            "Sid": "AllowRunInstancesWithRestrictions1",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateVolume",
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*",
                "arn:aws:ec2:*:*:instance/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:RequestTag/cost_center": "?*"
                }
            }
        },
        {
            "Sid": "AllowRunInstancesWithRestrictions2",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateVolume",
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*",
                "arn:aws:ec2:*:*:instance/*"
            ],
            "Condition": {
                "ForAllValues:StringNotLike": {
                    "aws:TagKeys": "Production"
                }
            }
        },
        {
            "Sid": "AllowRunInstancesWithRestrictions3",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateVolume",
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*",
                "arn:aws:ec2:*:*:instance/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:RequestTag/identifier": "?????"
                }
            }
        },
        {
            "Sid": "AllowRunInstancesWithRestrictions4",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateVolume",
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*",
                "arn:aws:ec2:*:*:instance/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:RequestTag/env": [
                        "sandbox",
                        "dev",
                        "prod"
                    ]
                }
            }
        },
        {
            "Sid": "AllowRunInstances1",
            "Effect": "Allow",
            "Action": [
                "ec2:CreateVolume",
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*",
                "arn:aws:ec2:*:*:instance/*"
            ]
        },
        {
            "Sid": "AllowCreateTagsOnRunInstance",
            "Effect": "Allow",
            "Action": "ec2:CreateTags",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "ec2:CreateAction": "RunInstances"
                }
            }
        }
    ]
}

Take note of the following enforcement values:

  • The aws:TagKeys value enforces checks on case sensitivity of Production.
  • The ????? value enforces that the combination of any five characters can be used (leading or trailing spaces are ignored).
  • The ?* value enforces that at least one character is present in the value field so that EC2 instances can't launch with empty tag values.