4
votes

I have an IAM user that launches a CloudFormation stack containing an - EC2 Instance with an - IAM Instance Profile associated with an - IAM Role

in the AWS::CloudFormation::Init block, the EC2 instance performs some actions that require it to call some ec2:* API actions. However, this instance should ONLY be able to call these actions for that instance itself.

The user that launches the stack has the permission to attach only a set of predefined policies and to create roles. Something like this

"CloudFormationStackLauncher": {
  "Type": "AWS::IAM::ManagedPolicy",
  "Properties": {
    "Description": "Allows attached entity to attach and detach required policies from roles it creates.",
    "PolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "iam:AttachRolePolicy",
            "iam:DetachRolePolicy"
          ],
          "Resource": "*",
          "Condition": {
            "ArnEquals": {
              "iam:PolicyArn": [
                "arn:aws:iam:::policy/InstanceThatCanManageItself",                    
              ]
            }
          }
        },
        {
          "Effect": "Allow",
          "Action": [
            "iam:CreateRole"
          ],
          "Resource": "*"
        }
      ]
    }
  }
}

So I need a definition for the policy InstanceThatCanManageItself (which needs to be defined ahead of time by a user with full admin permissions). Ideally, it would look something like:

    {
        "Effect": "Allow",
        "Action": [
            "ec2:*"
        ],
        "Resource": [
            "${ec2:SourceInstanceARN}"
        ]
    }

But it says this policy isn't valid because the policy variable ec2:SourceInstanceARN isn't in the format of a valid ARN. I've tried using tags on the EC2 instance and adding Conditions to the policy, but it doesn't seem to work when the condition is dynamic, like this:

   {
        "Effect": "Allow",
        "Action": [
            "ec2:*"
        ],
        "Resource": [
            "*"
        ],
        "Condition": {
            "StringLike": {
                "ec2:ResourceTag/role" : "${aws:userid}"
            }
        }
    }

in the above, I'm dynamically adding a tag to the launched EC2 instance with the format "RoleId:InstanceId" as defined for the value specified for {aws:userid}, based on the description here: http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html. This approach validates, but doesn't work...either because it's dynamic...or because the action types aren't supports for the ResourceTag context key maybe...

Is there any way to accomplish this?

Thanks.

1
This should be you are missing "2" there { "Effect": "Allow", "Action": [ "ec2:*" ], "Resource": [ "${ec2:SourceInstanceARN}" ] }error2007s
Not relevant to the issue at hand...doesn't change the resultJeff

1 Answers

2
votes

Resource tag-based authorizations will work only for certain operations. See, for example: EC2 Supported IAM actions. For example, all Describe operations are not supported and would have to be permissioned via a separate policy statement.
As an example of operations that support resource tags, attaching/detaching volumes (see same link above for supported operations and their requirements), so the following policy would work:

{
"Version": "2012-10-17",
"Statement": [        
    {
        "Effect": "Allow",
        "Action": [
            "ec2:AttachVolume",
            "ec2:DetachVolume"
        ],
        "Resource": "*",
        "Condition": {
            "StringLike": {
                "ec2:ResourceTag/policyuser": "${aws:userid}"
            }
        }
    }
]
}

, provided both the volume and ec2 instance are tagged with tag 'policyuser' and value equal to role-id:ec2-instance-id (see IAM User Guide Reference Policy Variables), where role-id is the unique identifier of the role, obtained via e.g.

aws iam get-role --role-name rolename