How to limit shared AWS EC2 accounts’ access to view and start all VMs yet stop only certain VMs

If a team with many accounts share and manages the virtual machines under that same AWS accounts, it is a common practice to limit AWS EC2 accounts’ access to view or start all VMs yet stop only certain VMs. For example, one account has 50 VMs tagged “prod” while 25 VMs tagged “dev”. The developers should be able to start all the “prod” and “dev” VMs while they only be able to stop the “dev” VMs unless they have accesses to the “prod” VMs. These limitations can avoid accidentally shutting down production virtual machines.

AWS gives the mechanism to achieve so in the IAM management. We show how to make use of the policies in AWS IAM management to achieve such goals.

In AWS, VMs can be tagged, and there are policies the can filter VMs by tags. There are user groups and users. User can be assgined to one or many user groups and the policies can be attached to the user groups to give access rights.

users---belong to---> user group <---attached to---policy

To limit certain users’ accesses, we can create user groups and policies attached to the user groups, and assign the users to these groups.

Create policies

AWS’ policy system is very flexible and at fine granularity. The policies can be implemented as a JSON file and uploaded to AWS management console to take effect. In this example, we will create 2 policies to

  • list all instances
  • start all instances
  • stop instances that have a tag “Prod/Dev” set to “dev”

We will implement the rules in 2 policies.

The policy control web page interface in the IAM management allows us to create new policies as follows.

We create two policies with JSON content as follows.

ListAndStartInstances

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:StartInstances",
                "ec2:GetConsoleScreenshot"
            ],
            "Resource": "arn:aws:ec2:*:*:instance/*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeAggregateIdFormat",
                "ec2:DescribeVolumesModifications",
                "ec2:GetHostReservationPurchasePreview",
                "ec2:DescribeSnapshots",
                "ec2:DescribePlacementGroups",
                "ec2:DescribeHostReservationOfferings",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeVolumeStatus",
                "ec2:GetLaunchTemplateData",
                "ec2:DescribeScheduledInstanceAvailability",
                "ec2:DescribeSpotDatafeedSubscription",
                "ec2:DescribeVolumes",
                "ec2:DescribeFpgaImageAttribute",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeExportTasks",
                "ec2:DescribeNetworkInterfacePermissions",
                "ec2:DescribeReservedInstances",
                "ec2:DescribeKeyPairs",
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeRouteTables",
                "ec2:DescribeEgressOnlyInternetGateways",
                "ec2:DescribeReservedInstancesListings",
                "ec2:DescribeSpotFleetRequestHistory",
                "ec2:DescribeLaunchTemplates",
                "ec2:DescribeSnapshotAttribute",
                "ec2:DescribeVpcClassicLinkDnsSupport",
                "ec2:DescribeVpcPeeringConnections",
                "ec2:DescribeVpnConnections",
                "ec2:DescribeIdFormat",
                "ec2:DescribeReservedInstancesOfferings",
                "ec2:DescribeFleetInstances",
                "ec2:DescribeVpcEndpointServiceConfigurations",
                "ec2:DescribePrefixLists",
                "ec2:GetReservedInstancesExchangeQuote",
                "ec2:DescribeInstanceCreditSpecifications",
                "ec2:DescribeVolumeAttribute",
                "ec2:DescribeVpcClassicLink",
                "ec2:DescribeImportSnapshotTasks",
                "ec2:DescribeVpcEndpointServicePermissions",
                "ec2:GetPasswordData",
                "ec2:DescribeScheduledInstances",
                "ec2:DescribeImageAttribute",
                "ec2:DescribeFleets",
                "ec2:DescribeElasticGpus",
                "ec2:DescribeReservedInstancesModifications",
                "ec2:DescribeVpcEndpoints",
                "ec2:DescribeSubnets",
                "ec2:DescribeVpnGateways",
                "ec2:DescribeMovingAddresses",
                "ec2:DescribeFleetHistory",
                "ec2:DescribeAddresses",
                "ec2:DescribePrincipalIdFormat",
                "ec2:DescribeInstanceAttribute",
                "ec2:DescribeFlowLogs",
                "ec2:DescribeRegions",
                "ec2:DescribeDhcpOptions",
                "ec2:DescribeVpcEndpointServices",
                "ec2:DescribeSpotInstanceRequests",
                "ec2:DescribeVpcAttribute",
                "ec2:GetConsoleOutput",
                "ec2:DescribeSpotPriceHistory",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeNetworkInterfaceAttribute",
                "ec2:DescribeVpcEndpointConnections",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeHostReservations",
                "ec2:DescribeIamInstanceProfileAssociations",
                "ec2:DescribeTags",
                "ec2:DescribeLaunchTemplateVersions",
                "ec2:DescribeBundleTasks",
                "ec2:DescribeClassicLinkInstances",
                "ec2:DescribeIdentityIdFormat",
                "ec2:DescribeImportImageTasks",
                "ec2:DescribeNatGateways",
                "ec2:DescribeCustomerGateways",
                "ec2:DescribeVpcEndpointConnectionNotifications",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSpotFleetRequests",
                "ec2:DescribeHosts",
                "ec2:DescribeImages",
                "ec2:DescribeFpgaImages",
                "ec2:DescribeSpotFleetInstances",
                "ec2:DescribeSecurityGroupReferences",
                "ec2:DescribeVpcs",
                "ec2:DescribeConversionTasks",
                "ec2:DescribeStaleSecurityGroups"
            ],
            "Resource": "*"
        }

StopDevInstances

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:StopInstances",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringEquals": {
                    "ec2:ResourceTag/Prod/Dev": "dev"
                }
            }
        }
    ]
}

ListAndStartInstances allows users to view and start EC2 VMs. StopDevInstances allows users to shutdown VMs whose tag “Prod/Dev” is “dev”.

Create group

In the next step, we create a “devs” user group so that the policies can be attached to.

This can be done in the “Group” page.

Attach policies to the group

We can then attache the 2 policies to the “devs” user group.

Add users

If the users are not yet created, we need to create the users.

Add users to the group

Then we add these users to the “devs” user group.

Now, we are done in setting the “devs” user group and the policies to limit its accesses to control the VMs in AWS EC2. You can use the technique shown here further to control and manage other resources in AWS or implement other management rules.

Eric Ma

Eric is a systems guy. Eric is interested in building high-performance and scalable distributed systems and related technologies. The views or opinions expressed here are solely Eric's own and do not necessarily represent those of any third parties.

Leave a Reply

Your email address will not be published. Required fields are marked *