Search code examples
amazon-web-servicesamazon-ec2amazon-iamaws-ssm

Why does restricting `ssm:sendCommand` to a specific document via an IAM policy show access denied?


I'm trying to have an IAM user who can only use SSM Run Command with a specific Document.

If I have the following policy attached to the user, that user can indeed only successfully execute AWS-RunShellScript (which is an AWS managed) document on EC2 instances.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:DescribeDocument",
                "ssm:DescribeDocumentParameters",
                "ssm:DescribeDocumentPermission",
                "ssm:GetCommandInvocation",
                "ssm:GetDocument",
                "ssm:ListCommandInvocations",
                "ssm:ListCommands",
                "ssm:ListDocumentMetadataHistory",
                "ssm:ListDocuments",
                "ssm:ListDocumentVersions"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "ssm:SendCommand",
            "Resource": "arn:aws:ssm:us-west-2:999999999999:document/AWS-RunShellScript"
        }
    ]
}

However, if I replace the resource item in the policy with a custom document ARN that I created (e.g. arn:aws:ssm:us-west-2:999999999999:document/CustomDocument), I get "Access Denied"

enter image description here


Solution

  • It's not really clear in the documentation but to limit ssm:SendCommand, you must use the Resource field to specify both what document(s) the IAM user is allowed to run and what instance(s) you allow commands to be run on.

    The user would see all instances when trying to run a command but will only be able to execute commands for the EC2 instance IDs specified in the IAM policy.

    You can specify the policy to allow any instance like below if needs be or specify a limited list of instance IDs in line with the standard security advice of granting least privilege in IAM policies.

    As to why the AWS managed document works, it's probably some internal magic 🤷‍♂️

    This should work:

    {
       "Version":"2012-10-17",
       "Statement":[
          {
             "Effect":"Allow",
             "Action":"ssm:SendCommand",
             "Resource":[
                "arn:aws:ec2:us-west-2:999999999999:instance/*",
                "arn:aws:ssm:us-west-2:999999999999:document/AWS-RunShellScript"
             ]
          }
       ]
    }