Using AWS Permissions Boundaries to Scale Safely

As your organization grows and you look to move additional workloads to the cloud, you’ll probably need to empower more individuals to configure permissions without having to submit a ticket every time. The challenge is to do this properly to prevent those you delegate from misusing this powerful ability. This is where the AWS permissions boundary feature comes into play. AWS permissions boundaries help you set the maximum permissions an employee can grant to users and roles that they create and manage.

Permissions Boundaries Defined

Permissions boundaries allow admins to delegate permissions to users so they can create new AWS service roles (for use with services like EC2 and Lambda) without elevating their own permissions. This removes the need for admins to field requests for these role creations and promotes self-service for users. The ultimate goal is to remove blockers for enhanced productivity.

Remember: permissions boundaries set the maximum permissions an entity can have. For instance, if you have a permissions boundary IAM policy with ALLOW s3:* and a standard IAM policy with ALLOW * attached to an IAM role, the role will ONLY be able to interact with the S3 service while all other access is explicitly denied.

Automating via Cloud Rules

cloudtamer.io helps you automate much of this process through our Cloud Rule feature. You can create a Cloud Rule that contains both the necessary CloudFormation template and the IAM policy. (A sample CloudFormation template and IAM policy are included at the end of this article.) The Cloud Rule ensures the CloudFormation creates the IAM policy that will be used as the permissions boundary. It also ensures the IAM policy with the permissions boundary “Conditions” statement is applied to all the targeted Cloud Access Roles (roles used for AWS console access). In short, the Cloud Rule allows your users to create an IAM role, but only if they attach the limiting IAM policy as a permissions boundary during creation, allowing you to control what the IAM role can be used for.

Once you’ve created the Cloud Rule, the next step is to apply the Rule within the cloudtamer.io organizational hierarchy. cloudtamer.io helps you automate applying this Rule across your workloads. You can apply the Cloud Rule to an organization unit (OU) in your hierarchy and it’s then applied to all the Projects (AWS accounts) attached to the OU and below the OU.

There’s an important next step in this process: helping users you empower by giving them instructions on how to create roles. The AWS console is not the most intuitive when it comes to providing helpful error messages around why a user is denied a certain action. Help users reduce errors by providing them with documentation on the correct way to create roles. Here is a sample set of instructions you can provide to users.

Role Creation for Use with EC2 Instances

If you need an EC2 instance or Lambda function to access an approved AWS service, you must follow this process to create an IAM role:

    1. Once logged into the AWS console, navigate to the “IAM” service: https://console.aws.amazon.com/iam/home?region=us-east-1#/roles.
    2. Click “Create role”.
    3. Select either “EC2” or “Lambda” and click “Next: Permissions”.
    4. In the “Attach permissions policies” section, check the “AdministratorAccess” policy.
    5. In the “Set permissions boundary” section, check the “Use a permissions boundary to control the maximum role permissions” option.
    6. Check the “boundary-s3” policy and click “Next: Tags”.
    7. Click “Next: Review”.
    8. In the “Role name” field, you must prefix your name with: service-.
    9. Click “Create role”.

You can now assign the newly created IAM role/instance profile during or after the creation of an EC2 instance or a Lambda function. You can also delete your role when you are done. Once the “boundary-s3” policy is attached, you will only be able to perform the following operations using the role when it’s attached to an EC2 instance or a Lambda function: Read or write to S3.

For more about AWS Permissions Boundaries, refer to the AWS Identity and Access Management documentation.

Sample CloudFormation Template

This is a sample CloudFormation template that creates an IAM policy that can be attached as a permission boundary during the creation of an IAM role. A permission boundary acts as a whitelist: even if the “AdministratorAccess” IAM policy is attached as a policy, when you attach the “boundary-s3” IAM policy as a permissions boundary, the only permissions the user will have are: “s3:*” (the ability to read and write to S3).

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Creates an IAM policy that can be used as a permission boundary.",
    "Resources": {
        "PermissionBoundaryPolicy": {
            "Type": "AWS::IAM::ManagedPolicy",
            "Properties": {
                "ManagedPolicyName": "boundary-s3",
                "Description": "Policy only allows access to S3.",
                "Path": "/",
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": [
                                "s3:*"
                            ],
                            "Resource": "*"
                        }
                    ]
                }
            }
        }
    }
}

Sample IAM Policy

This is a sample IAM policy that allows a user to:

  • Read all information under the IAM service like roles, users, policies, etc.
  • Create an IAM role whose name must be prefixed with service- and must have the boundary-s3 IAM policy attached during creation.
  • Attach or detach an IAM policy to any role with a name that is prefixed with service- and that has the boundary-s3 IAM policy already applied.
  • Create or delete an instance profile (for use with EC2 instances) whose name must be prefixed with service-.
  • Add or remove a role to an instance profile where the instance profile’s name must be prefixed with service-.
  • Pass an IAM role whose name must be prefixed with service- to an EC2 instance or a Lambda function.
  • Delete an IAM role whose name must be prefixed with service-.

The service-* prefix is required to make it very easy to see which roles are user created as well give the users the ability to delete their roles when they are done. It’s currently not possible to only allow users to delete roles with a certain permission boundary so forcing users to use a prefix is a good method for controlling these roles.

Since IAM does not support a variable for the AWS account number, there is a built-in cloudtamer.io variable, {{CT::AWSAccountId}}, that will be replaced prior to cloudtamer.io creating the IAM policy in AWS.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BasicPermissions",
            "Effect": "Allow",
            "Action": [
                "iam:GenerateServiceLastAccessedDetails",
                "iam:Get*",
                "iam:List*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "PermissionsBoundary",
            "Effect": "Allow",
            "Action": [
                "iam:CreateRole",
                "iam:AttachRolePolicy",
                "iam:DetachRolePolicy"
            ],
            "Resource": "arn:aws:iam::{{CT::AWSAccountId}}:role/service-*",
            "Condition": {
                "StringEquals": {
                    "iam:PermissionsBoundary": "arn:aws:iam::{{CT::AWSAccountId}}:policy/boundary-s3"
                }
            }
        },
        {
            "Sid": "InstanceProfileCreation",
            "Effect": "Allow",
            "Action": [
                "iam:CreateInstanceProfile",
                "iam:AddRoleToInstanceProfile",
                "iam:RemoveRoleFromInstanceProfile",
                "iam:DeleteInstanceProfile"
            ],
            "Resource": "arn:aws:iam::{{CT::AWSAccountId}}:instance-profile/service-*"
        },
        {
            "Sid": "Cleanup",
            "Effect": "Allow",
            "Action": [
                "iam:PassRole",
                "iam:DeleteRole"
            ],
            "Resource": "arn:aws:iam::{{CT::AWSAccountId}}:role/service-*"
        }
    ]
}

Joe leads engineering at cloudtamer.io.