Search code examples
amazon-ec2nullkeyamazon-iampolicy

Use of AWS null condition to prevent empty or missing tags?


The goal of my policy document:

  1. Prevent resource creation if it does not have proper tags
  2. Require that certain values be given to specific tags (e.g. env tag must either be dev OR stg OR prd, etc)

No. 2 works as expected; however, if the user creates an EC2 instance with the tag empty or simply forgets to add it, the policy still allows the user to create the instance.

I tried the null operator (referenced here), but it doesn't seem to work.

Another attempt was to use a condition matching aws:tag-keys values (referenced here), but it only appears to work when checking one single value with a StringLike comparison operator

This is prerequisite for a Lambda function to turn off dev instances.


 {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "RequireEnvTags",
            "Effect": "Deny",
            "Action": [
                "ec2:RunInstances"
            ],
            "Condition": {
                "ForAnyValue:StringNotEquals": {
                    "ec2:ResourceTag/env": [
                        "dev",
                        "stg",
                        "prd",
                        "dev-noshutdown"
                    ]
                }
            },
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "RequireDataSensitivity1",
            "Effect": "Deny",
            "Action": [
                "ec2:RunInstances"
            ],
            "Condition": {
                "ForAnyValue:StringNotEquals": {
                    "ec2:ResourceTag/data-sensitivity": [
                        "public",
                        "internal",
                        "confidential",
                        "highly confidential"
                    ]
                }
            },
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "NullChecksDontSeemToWork0",
            "Effect": "Deny",
            "Action": [
                "ec2:RunInstances"
            ],
            "Condition": {
                "Null": {
                    "ec2:ResourceTag/Name": "true"
                }
            },
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "NullChecksDontSeemToWork1",
            "Effect": "Deny",
            "Action": [
                "ec2:RunInstances"
            ],
            "Condition": {
                "Null": {
                    "ec2:ResourceTag/team": "true"
                }
            },
            "Resource": [
                "*"
            ]
        }
    ]
}

Solution

  • After working with this I found that it just needed to be tweaked a little. For some reason explicitly allowing the action in the same policy document (even though another policy document attached to the same user explicitly states an ALLOW) is required for AWS to implement the intended policy correctly:

    {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ec2:RunInstances",
            "Resource": [
                "arn:aws:ec2:*::image/ami-*",
                "arn:aws:ec2:*:ACCOUNT_ID:subnet/*",
                "arn:aws:ec2:*:ACCOUNT_ID:network-interface/*",
                "arn:aws:ec2:*:ACCOUNT_ID:volume/*",
                "arn:aws:ec2:*:ACCOUNT_ID:key-pair/*",
                "arn:aws:ec2:*:ACCOUNT_ID:security-group/*"
            ],
            "Sid": "AllowRunInstances"
        },
        {
            "Effect": "Deny",
            "Action": "ec2:RunInstances",
            "Resource": "arn:aws:ec2:*:ACCOUNT_ID:instance/*",
            "Condition": {
                "StringNotLike": {
                    "aws:RequestTag/env": [
                        "dev",
                        "stg",
                        "prd",
                        "dev-noshutdown",
                        "trn",
                        "tst"
                    ]
                }
            },
            "Sid": "RequireSpecificEnvTags"
        }
    ]
    }
    

    And it works!

    A quick note: currently this policy does not appear to allow Spot Instances to be created (Because of the differences in how spot requests handle tags). I filed a feature request with AWS.