AWS Security Blog

Granting Users Permission to Work in the Amazon EC2 Console

by Mike Pope | on | in Best Practices, How-to guides | | Comments

This week, Kati Paizee, a technical writer on the Amazon EC2 team, takes an in-depth look at the permissions you need to give your users so that they can administer EC2 using the console.


The Amazon EC2 console provides an easy-to-use interface that allows your users to carry out compute-based tasks without asking them to run multiple commands or API actions. But writing IAM policies to grant your users access to parts of the EC2 console can be a challenge, and omitting a small but critical permission can result in authorization errors that slow both you and your users down.

The reason is simple: the EC2 console calls on a number of different API actions to present EC2 resources in a way that’s useful to users, and to provide them with dialog boxes to help them achieve various tasks. It’s not always immediately obvious which API actions are required to make those screens and dialog boxes work. In addition, resource-level permissions, which are a useful means of restricting which resources your users can work with, are not supported for all APIs in EC2, so part of the process of writing policies is understanding how you can leverage them to achieve the right level of control.

This post takes you step-by-step through some frequently used areas of the EC2 console—launching instances, working with volumes, and managing security groups—and shows you how to create policies to make them work for you. I’ll show you opportunities to grant permissions not only to work in the console, but to work with specific resources in the console. 

The EC2 launch wizard

Let’s start with the permissions your users must have in order to use the EC2 launch wizard. The EC2 launch wizard consists of a series of screens that help users configure and launch an instance. The action that ultimately launches the instance is ec2:RunInstances. In order to present the launch options, the wizard calls several other API actions. If a user doesn’t have permission for these related actions, the options in the wizard can’t load, and a user can’t launch an instance. Users need permissions for at least the following API actions:

  • ec2:DescribeImages. To load the first step of the wizard, which displays a list of AMIs from which users can launch an instance.
  • ec2:DescribeVPCs. To view the available network options, which are EC2-Classic (if your account supports this) and a list of VPCs. This is required even if users aren’t launching into a VPC.
  • ec2:DescribeSubnets. If launching into a VPC, to view all available subnets for the chosen VPC.
  • ec2:DescribeSecurityGroups. To load the security groups page in the wizard.
  • ec2:DescribeKeyPairs or ec2:CreateKeyPair. To select an existing key pair or to create a new one.

As a reminder, resource-level permissions are supported for only some APIs in EC2. For example, none of the ec2:Describe* API actions support resource-level permissions, so you can’t control which individual resources users can see in the console. I suggest you take a look at the recent blog post about EC2 resource-based permissions and at the EC2 documentation to get a good overview of which EC2 API actions support resource-level permissions.

Now that you know the basics, you can start putting together your policy. Not only that, you can also apply resource-level permissions to the ec2:RunInstances API action to control which resources users can work with.

Imagine that you want to define permissions for this scenario:

  • Users can launch instances only of a specific instance type (m1.small).
  • Users are required to launch instances into a specific subnet (subnet-1a2b3c4d), using a specific key pair (group1-keypair), and using a specific security group (sg-111aaa22).

The following policy establishes these permissions to allow users to complete those tasks in the console.

{
   "Version": "2012-10-17",
   "Statement": [{
      "Sid": "ThisBitAllowsYouToWorkWithTheWizard",
      "Effect": "Allow",
      "Action": [
         "ec2:DescribeInstances",
         "ec2:DescribeImages",
         "ec2:DescribeKeyPairs",
         "ec2:DescribeVpcs",
         "ec2:DescribeSubnets",
         "ec2:DescribeSecurityGroups"
       ],
       "Resource": "*"
   },
   {
      "Sid": "ThisBitEnablesResourcesForRunInstances",
      "Effect": "Allow",
      "Action":"ec2:RunInstances",
      "Resource": [
         "arn:aws:ec2:region:accountid:network-interface/*",
         "arn:aws:ec2:region:accountid:volume/*",
         "arn:aws:ec2:region:accountid:key-pair/group1-keypair",
         "arn:aws:ec2:region:accountid:security-group/sg-111aaa22",
         "arn:aws:ec2:region::image/*",
         "arn:aws:ec2:region:accountid:subnet/subnet-1a2b3c4d"
      ]
   },
   {
      "Sid": "ThisBitAppliesResourceLevelPermissionsOnInstanceTypes",
      "Effect": "Allow",
      "Action": "ec2:RunInstances",
      "Resource": [
         "arn:aws:ec2:region:accountid:instance/*"
      ],
      "Condition": {
         "StringEquals": {
            "ec2:InstanceType": "m1.small"
         }
      }
   }
   ]
}

Let’s break down this policy to understand what it does. The policy contains three statements, which I’m distinguishing by color.

The first statement ensures that users can step through the launch wizard and view instances in the console. Because users must launch their instances into a specific subnet, using a specific key pair and a specific security group, they need permission to describe these resources so that they can select them in the wizard. Because the ec2:Describe* actions don’t support resource-level permissions, the Resource element for this statement is just *. Users can’t use the wizard to create a new security group or key pair. If they try, the launch will fail.

The second statement grants users permission to use the ec2:RunInstances action, but with some resource-level permissions—as noted earlier, I want to restrict permissions so that users can only launch instances with subnet subnet -1a2b3c4d, key pair group1-keypair, and security group sg-111aaa22. Don’t forget that when you use the ec2:RunInstances action, users must have permission to work with all the resources that are required to launch an instance. For more information, have a look at these examples in the EC2 documentation.

The third statement applies a condition key to the instances resource for the ec2:RunInstances action—the launch will only succeed if users select the m1.small instance type in the wizard.

You can add more actions to your policy to give users more options in the wizard. For example, you can add ec2:DescribeNetworkInterfaces to allow users to select from a list of existing network interfaces in Step 2 of the wizard.

Volumes

Suppose your users also need to list and attach volumes to instances. You might be wondering why granting users permission to use the ec2:DescribeVolumes API action in your policy doesn’t seem to display any volumes in the console. It’s because the console also uses the ec2:DescribeAvailabilityZones and ec2:DescribeVolumeStatus actions to display additional information about the volumes. Without permissions for these actions, the console can’t display this information. To let users view volumes, add a statement like the following:

{
   "Version": "2012-10-17",
   "Statement": [{
      "Sid": "ThisBitShowsYouTheVolumes",
      "Effect": "Allow",
      "Action": [
         "ec2:DescribeVolumes",
         "ec2:DescribeVolumeStatus",
         "ec2:DescribeAvailabilityZones"
       ],
       "Resource": "*"
   }
  ]
}

Now you can put together a policy that allows users to work with volumes. In this next example, users can create volumes, and then attach them to instances that have been tagged unit=group1.

{
   "Version": "2012-10-17",
   "Statement": [{
      "Sid": "ThisBitShowsYouTheVolumes",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeVolumes", "ec2:DescribeVolumeStatus",
          "ec2:DescribeAvailabilityZones", "ec2:CreateVolume",
          "ec2:DescribeInstances"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ThisBitAppliesResourceLevelPermissions",
      "Effect": "Allow",
      "Action": [
        "ec2:AttachVolume",
        "ec2:DetachVolume"
      ],
      "Resource": "arn:aws:ec2:region:accountid:instance/*",
      "Condition": {
        "StringEquals": {
          "ec2:ResourceTag/unit": "group1"
        }
     }
   },
   {
      "Sid": "ThisBitAllowsYouToWorkWithVolumes",
      "Effect": "Allow",
      "Action": [
        "ec2:AttachVolume",
        "ec2:DetachVolume"
      ],
      "Resource": "arn:aws:ec2:region:accountid:volume/*"
      }   
   ]
}

You might notice that I’ve added the ec2:DescribeInstances action to the first part of the statement. This isn’t required, but it makes the Attach Volume dialog box in the console easier to use—it populates the Instance field with a list of instances so that users can select one. If this permissions isn’t granted, users have to type in the instance ID manually.

Security groups

Now let’s examine one more scenario: working with security groups. Allowing users to view security groups in the EC2 console is straightforward—you only need to grant users permission to use the ec2:DescribeSecurityGroups API action. Allowing users to add and remove rules on existing security groups is also straightforward; just add the ec2:Authorize* and ec2:Revoke* actions to your policy. Plus you can add resource-level permission to these actions, so you can control how rules are managed.

But let’s say that you also want to allow users to create security groups. Now comes the less intuitive part—allowing access to the Create Security Group dialog box. Users need more than just the ec2:CreateSecurityGroup API action in order to use it properly. They also need permission to use the following:

  • ec2:DescribeVpcs: To view a list of existing VPCs in the VPC list. This action is required even if users are not creating a security group for a VPC.
  • ec2:AuthorizeSecurityGroupIngress: To add inbound rules.
  • ec2:AuthorizeSecurityGroupEgress: To add outbound rules to VPC security groups.
  • ec2:RevokeSecurityGroupIngress: To modify or delete existing inbound rules.
  • ec2:RevokeSecurityGroupEgress: To modify or delete outbound rules for VPC security groups. This is useful if users need to be able to modify or delete the default outbound rule that allows all outbound traffic.
  • ec2:DeleteSecurityGroup: To help prevent users from creating empty security groups. When users click Create in the dialog box, the console first creates the security group, and then attempts to add the rules to it. If that action fails, the security group is deleted, but the user remains in the dialog box and the rules remain listed, so that the user can fix the error and try again. If users don’t have permission to delete a security group, it gets created without any rules, and users have to add the rules again afterwards.

Here’s an example of a policy that allows users to view all security groups in the EC2 console as well as work with the Create Security Group dialog box. I’ve also added a resource-level permission in the second part of the statement that restricts users to working only with security groups that are associated with VPC vpc-1a2b3c4d.

{
   "Version": "2012-10-17",
   "Statement": [{
      "Sid": "ThisBitMakesTheDialogWork",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeSecurityGroups",
        "ec2:CreateSecurityGroup",
        "ec2:DescribeVpcs"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ThisBitIsForWorkingWithRules",
      "Effect": "Allow",
      "Action": [
        "ec2:DeleteSecurityGroup",
        "ec2:AuthorizeSecurityGroupIngress", 
        "ec2:RevokeSecurityGroupIngress",
        "ec2:AuthorizeSecurityGroupEgress",
        "ec2:RevokeSecurityGroupEgress"
      ],
      "Resource": "arn:aws:ec2:region:accountid:security-group/*",
      "Condition":{
         "ArnEquals": {
            "ec2:Vpc": "arn:aws:ec2:region:accountid:vpc/vpc-1a2b3c4d"
         }
      }
}
  ]
}

What next?

You may be reading this and thinking, “Great, but you haven’t covered the area of the console that matters to me.” It might take some trial and error to work out which API actions are required to carry out your set of tasks. Try making use of services such as AWS CloudTrail, which record all the API calls from the AWS Management Console. For example, to determine what actions you need to grant permissions for, sign in as a user with full access to the EC2 console, carry out a task, and then consult the CloudTrail log files afterwards to see which API actions were used during the task.

To troubleshoot permissions, you can use the AWS Security Token Service (STS) DecodeAuthorizationMessage action to interpret the encoded message that’s returned when users are denied access to perform an action. To find out more, have a look at Jeff Wierer’s blog post about working with EC2 resource-level permissions: Demystifying EC2 Resource-Level Permissions.

Everything I’ve written about here is also covered in the EC2 documentation. We will add more examples about working with different areas of the console to the documentation over time.

If you have any suggestions or comments about the EC2 documentation, feel free to click the Tell us about it… link on the documentation pages and provide feedback. If you have questions, please post them to the AWS IAM Forum.

– Kati