Writing an IAM policy to restrict AWS SSM connections to EC2 instances by EC2 tags
Asked Answered
C

1

5

I'd like to be able to all users to connect to EC2 instances using the AWS SSM (Systems Manager) 'startsession' command, but restrict which ones they can connect to through tags on the EC2 instances. IAM users belonging to a 'webserver-dev' group would have a policy allowing them to aws ssm start-session --target i-12341234 to any EC2 instance with a tag name of 'SSMTag' and a value of 'WebServer'. Any users in the devserver-dev group would be able to connect to instances with SSMTag = 'DevServer', etc.

I have a policy that allows access to connect to any EC2 instances, but as soon as I add in a 'condition' clause to the policy JSON, access is always denied (or always allowed).

I've tried adding conditions with various different syntaxes for the policy, aws:TagKeys, ssm:ResourceTag, ec2:ResourceTag, and a few others, but none seem to allow me to do what I want. The documentation seems to indicate that I can do exactly this, but either I don't understand how tagging works, or am misunderstanding the documents.

My current policy for development servers looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ssm:StartSession",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringEquals": {
                    "ssm:ResourceTag/SSMTag": "DevServer"
                }
            }
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ssm:TerminateSession",
            "Resource": "arn:aws:ssm:*:*:session/${aws:username}-*"
        }
    ]
}

I've also tried for the condition line variations on:

            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/SSMTag": "DevServer"
                }
            }

and

            "Condition": {
                "ForAllValues:StringEquals": {
                    "ec2:ResourceTag:SSMTag": "DevServer"
                }
            }

What I want is if the user is not part of the webserver-dev group they cannot run aws ssm start-session and connect to any ec2 instances unless they are tagged with a tag SSMTag with the value of WebServer.

The results are either the user that is part of the group that the policy is attached to either gets access denied, or is allowed to connect to any instance, regardless of the tags attached to it.

I've read a lot of solutions to similar issues are basically "some functions don't support resource level tagging, but the documentation seems to explicitly say that it does.

Ceil answered 3/4, 2019 at 23:39 Comment(2)
When you say "current policy for development servers looks like this", you mean "current policy for the devserver-dev group looks like this", yes?Indurate
Yes, my mistake. That is the policy attached to the group that the user is in.Ceil
C
7

I got an email from AWS support and it looks like it was an issue with the way with the "StringEquals" part of the condition. This policy works correctly:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ssm:StartSession",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "ForAnyValue:StringEqualsIfExists": {
                    "ssm:resourceTag/SSMTag": "DevServer"
                }
            }
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ssm:TerminateSession",
            "Resource": "arn:aws:ssm:*:*:session/${aws:username}-*"
        }
    ]
}

The syntax difference being "ForAnyValue:StringEqualsIfExists": {

Hope this helps someone in the future.

Ceil answered 4/4, 2019 at 16:54 Comment(1)
Won't that allow instances without the SSMTag tag too?Grof

© 2022 - 2024 — McMap. All rights reserved.