Skip to content

Instantly share code, notes, and snippets.

@magnetikonline
Last active June 7, 2023 20:57
Show Gist options
  • Star 65 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save magnetikonline/5034bdbb049181a96ac9 to your computer and use it in GitHub Desktop.
Save magnetikonline/5034bdbb049181a96ac9 to your computer and use it in GitHub Desktop.
AWS Elastic Beanstalk deploy user restricted IAM policy.

AWS Elastic Beanstalk deploy user restricted IAM policy

An IAM user policy document to give minimal rights for deploying an Elastic Beanstalk application.

Where:

  • REGION: AWS region.
  • ACCOUNT_ID: AWS account ID.
  • APPLICATION_NAME: Desired target Elastic Beanstalk application name(space).
  • IAM_INSTANCE_PROFILE_ROLE: The instance profile (IAM role) Elastic Beanstalk EC2 instaces will run under.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "autoscaling:*",
        "cloudformation:*",
        "ec2:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "*"
      ]
    },
    {
      "Action": [
        "elasticbeanstalk:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:elasticbeanstalk:*::solutionstack/*",
        "arn:aws:elasticbeanstalk:REGION:ACCOUNT_ID:application/APPLICATION_NAME",
        "arn:aws:elasticbeanstalk:REGION:ACCOUNT_ID:applicationversion/APPLICATION_NAME/*",
        "arn:aws:elasticbeanstalk:REGION:ACCOUNT_ID:environment/APPLICATION_NAME/*",
        "arn:aws:elasticbeanstalk:REGION:ACCOUNT_ID:template/APPLICATION_NAME/*"
      ]
    },
    {
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::elasticbeanstalk-*/*"
      ]
    },
    {
      "Action": [
        "s3:CreateBucket",
        "s3:DeleteObject",
        "s3:GetBucketPolicy",
        "s3:GetObjectAcl",
        "s3:ListBucket",
        "s3:PutBucketPolicy",
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::elasticbeanstalk-REGION-ACCOUNT_ID",
        "arn:aws:s3:::elasticbeanstalk-REGION-ACCOUNT_ID/*"
      ]
    },
    {
      "Action": [
        "iam:PassRole"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:iam::ACCOUNT_ID:role/IAM_INSTANCE_PROFILE_ROLE"
      ]
    }
  ]
}

Notes

  • The addition of the s3:CreateBucket action against the arn:aws:s3:::elasticbeanstalk-REGION-ACCOUNT_ID resource is critical for the creation of new Elastic Beanstalk application instances - even if the bucket itself already exists.
  • Policy has been designed to work with single container Docker environments - not multicontainer, which are ECS cluster environments under the hood and requires additional IAM action permissions.
@bakura10
Copy link

Hi,

Thank you for this!

For a reason I ignore, my worker environments required some related SNS permissions:

{
            "Sid": "CreateSnsTopic",
            "Effect": "Allow",
            "Action": [
                "sns:CreateTopic",
                "sns:GetTopicAttributes",
                "sns:ListSubscriptionsByTopic"
            ],
            "Resource": "arn:aws:sns:REGION:ACCOUNT_ID:ElasticBeanstalkNotifications-*"
        }

Not sure why though... Elastic Beanstalk IAM is black magic.

@richardsimko
Copy link

When using this I get the following error: Service:AmazonCloudFormation, Message:TemplateURL must reference a valid S3 object to which you have access.

Which I don't get with the ElasticBeanstalkFullAccess policy, so there is some obscure permission that's missing. Any idea what it might be? It started appearing after I added the .ebextensions folder.

EDIT: Solved it! The key part is that I had to add this:

{
    "Action": [
        "s3:Get*"
    ],
    "Effect": "Allow",
    "Resource": [
        "arn:aws:s3:::elasticbeanstalk-*/*"
    ]
},

It seems like some other Get permission is required and I can't be arsed to find out which one. I also had to add the following since from time to time it would complain about missing these permissions:

{
    "Action": [
        "elasticloadbalancing:DescribeLoadBalancers"
    ],
    "Effect": "Allow",
    "Resource": [
        "*"
    ]
},
{
    "Action": [
        "elasticloadbalancing:RegisterInstancesWithLoadBalancer"
    ],
    "Effect": "Allow",
    "Resource": [
        "arn:aws:elasticloadbalancing:REGION: ACCOUNT_ID:loadbalancer",
        "arn:aws:elasticloadbalancing:REGION: ACCOUNT_ID:loadbalancer/*"
}

@cnluzhang
Copy link

    {
        "Action": [
            "autoscaling:*",
            "cloudformation:*",
            "ec2:*"
        ],
        "Effect": "Allow",
        "Resource": [
            "*"
        ]
    }

Is this section too opened?
The User can remove ec2 not created by EB.

@magnetikonline
Copy link
Author

magnetikonline commented Apr 19, 2016

@cnluzhang that's correct - but sadly I have/had been unable to hone in the ARNs better for autoscaling:*, cloudformation:* and ec2:* since they don't really follow any naming scheme/pattern at runtime. If you can improve upon this - would be appreciated!

@Azrael808
Copy link

@magnetikonline @cnluzhang - I'm wondering if the autoscaling, cloudformation, and ec2 permissions could be restricted via the use of tags?

http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_examples.html#iam-policy-example-ec2-tag-permissions

As it stands, Elastic Beanstalk already tags resources created as part of an environment, so you could use those, or maybe even adding some custom tags yourself would make this easier.

http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.tagging.html

@Rob-B1
Copy link

Rob-B1 commented Jul 7, 2016

Yeah you can use tags. I am working on common tenancy with restrictions where they can be done for the ec2 resources.. However Autoscaling isn't as flexible. The EC2 access can be restricted and in anything but dedicated accounts should be.

@DeeElGee
Copy link

Did anyone manage to find a safe and consistently usable policy or approach? We're really struggling with this.

@seanlindo
Copy link

@drrhani I've got nothing for you so far. I've pretty much settled on using Jenkins to handle this, and attaching the ReadOnly policy to my developers along with some Github protected branch black magic.

@holyjak
Copy link

holyjak commented Apr 21, 2017

I have published a policy that works for me, IAM policy to allow Continuous Integration user to deploy to AWS Elastic Beanstalk. In some regards it is more restrictive (e.g. autoscaling), in some less (e.g. not only for a particular application) and it could certainly be tightened more (but life is too short for that :)).

I needed more of S3 permissions to make "Rolling with additional batch" updates working (contrary to "All at once that was already OK) so I added s3:Get*, s3:List*, though I guess that is too permissive.

@tsirolnik
Copy link

Here's the policy I've came up with after not being able to work with the posted policy. I'm sure that this could be tweaked more in order to make it more precise and etc.

The specific policy below will allow a user to interact with a single EB application. Do note that EB requires complete access for some AWS services like EC2, S3, Cloudformation and etc.

As said on Amazon's docs -

While you can restrict how a user interacts with Elastic Beanstalk APIs, there is not currently an effective way to prevent users who have permission to create the necessary underlying resources from creating other resources in Amazon EC2 and other services.

The Policy -

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CreateEnvironment",
      "Effect": "Allow",
      "Action": "elasticbeanstalk:CreateEnvironment",
      "Resource": [
        "arn:aws:elasticbeanstalk:[zone]:[user-id]:environment/[eb-app-name]/*",
        "arn:aws:elasticbeanstalk:[zone]:[user-id]:application/[eb-app-name]/*"
      ]
    },
    {
      "Sid": "GlobalUnspecificResources",
      "Effect": "Allow",
      "Action": [
        "sns:*",
        "iam:List*",
        "s3:*",
        "cloudwatch:*",
        "ecs:*",
        "ec2:*",
        "cloudformation:*",
        "sqs:*",
        "autoscaling:*",
        "elasticloadbalancing:*",
        "elasticbeanstalk:DescribePlatformVersion",
        "elasticbeanstalk:DescribeConfigurationSettings",
        "elasticbeanstalk:CheckDNSAvailability",
        "elasticbeanstalk:ListAvailableSolutionStacks",
        "elasticbeanstalk:ListPlatformVersions",
        "elasticbeanstalk:DescribeConfigurationOptions",
      ],
      "Resource": "*"
    },
    {
        "Sid": "IAMActions",
        "Effect": "Allow",
        "Action": [
            "iam:CreateInstanceProfile",
            "iam:Get*",
            "iam:PassRole",
            "iam:CreateRole",
            "iam:AddRoleToInstanceProfile"
        ],
        "Resource": [
          "*"
        ]
      },
    {
      "Sid": "VisualEditor2",
      "Effect": "Allow",
      "Action": [
        "elasticbeanstalk:ComposeEnvironments",
        "elasticbeanstalk:AbortEnvironmentUpdate",
        "elasticbeanstalk:TerminateEnvironment",
        "elasticbeanstalk:DescribeEnvironmentManagedActionHistory",
        "elasticbeanstalk:ValidateConfigurationSettings",
        "elasticbeanstalk:DescribeEnvironmentResources",
        "elasticbeanstalk:RequestEnvironmentInfo",
        "elasticbeanstalk:RebuildEnvironment",
        "elasticbeanstalk:UpdateApplicationVersion",
        "elasticbeanstalk:DescribeEnvironments",
        "elasticbeanstalk:DescribeInstancesHealth",
        "elasticbeanstalk:DescribeApplicationVersions",
        "elasticbeanstalk:DescribeEnvironmentHealth",
        "elasticbeanstalk:DescribeApplications",
        "elasticbeanstalk:DeleteConfigurationTemplate",
        "elasticbeanstalk:RestartAppServer",
        "elasticbeanstalk:CreateConfigurationTemplate",
        "elasticbeanstalk:UpdateConfigurationTemplate",
        "elasticbeanstalk:UpdateApplication",
        "elasticbeanstalk:DescribeEnvironmentManagedActions",
        "elasticbeanstalk:DescribeConfigurationOptions",
        "elasticbeanstalk:ApplyEnvironmentManagedAction",
        "elasticbeanstalk:DescribeEvents",
        "elasticbeanstalk:CreateEnvironment",
        "elasticbeanstalk:DeleteEnvironmentConfiguration",
        "elasticbeanstalk:UpdateEnvironment",
        "elasticbeanstalk:RetrieveEnvironmentInfo"
      ],
      "Resource": [
        "arn:aws:elasticbeanstalk:[zone]:[user-id]:application/[eb-app-name]",
        "arn:aws:elasticbeanstalk:[zone]:[user-id]:application/[eb-app-name]/*",
        "arn:aws:elasticbeanstalk:*:*:environment/*/*",
        "arn:aws:elasticbeanstalk:*:*:applicationversion/*/*",
        "arn:aws:elasticbeanstalk:*:*:configurationtemplate/*/*"
      ]
    }
  ]
}

Resources used:
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.iam.managed-policies.html
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.iam.policies.actions.html
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.iam.policies.arn.html
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts-roles-user.html

@magnetikonline
Copy link
Author

Thx for posting @tsirolnik!

@mrg2k8
Copy link

mrg2k8 commented Apr 4, 2019

Tighter permissions (just for uploading and deploying a new application version) can be found here: https://documentation.codeship.com/basic/continuous-deployment/deployment-to-elastic-beanstalk/

A good description of what's happening behind the scenes and how it can be scripted can be found here: http://www.deplication.net/2013/11/java-war-deployment-options-on-aws.html

In case they bring it down:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "elasticbeanstalk:CreateApplicationVersion",
        "elasticbeanstalk:DescribeEnvironments",
        "elasticbeanstalk:DeleteApplicationVersion",
        "elasticbeanstalk:UpdateEnvironment"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Action": [
        "sns:CreateTopic",
        "sns:GetTopicAttributes",
        "sns:ListSubscriptionsByTopic",
        "sns:Subscribe"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:sns:[region]:[accountid]:*"
    },
    {
      "Action": [
        "autoscaling:SuspendProcesses",
        "autoscaling:DescribeScalingActivities",
        "autoscaling:ResumeProcesses",
        "autoscaling:DescribeAutoScalingGroups"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Action": [
        "cloudformation:GetTemplate",
        "cloudformation:DescribeStackResource",
        "cloudformation:DescribeStackResources",
        "cloudformation:UpdateStack"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:cloudformation:[region]:[accountid]:*"
    },
    {
      "Action": [
        "ec2:DescribeImages",
        "ec2:DescribeKeyPairs"
      ],
      "Effect": "Allow",
      "Resource": "*"
   },
   {
    "Action": [
     "s3:PutObject",
     "s3:PutObjectAcl",
     "s3:GetObject",
     "s3:GetObjectAcl",
     "s3:ListBucket",
     "s3:DeleteObject",
     "s3:GetBucketPolicy",
     "s3:CreateBucket"
   ],
   "Effect": "Allow",
   "Resource": [
    "arn:aws:s3:::elasticbeanstalk-[region]-[accountid]",
    "arn:aws:s3:::elasticbeanstalk-[region]-[accountid]/*"
   ]
  }
 ]
}

With an LB:

{
  "Action": [
    "elasticloadbalancing:DescribeInstanceHealth",
    "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
    "elasticloadbalancing:RegisterInstancesWithLoadBalancer"
  ],
  "Effect": "Allow",
  "Resource": "*"
}

@owurman
Copy link

owurman commented Aug 16, 2019

@mrg2k8 I had to add elasticbeanstalk:CreateStorageLocation to the first statement, not sure why CreateApplicationVersion wasn't enough.

Even then, the app seemed like it was deploying (as verified in the web console) but the CLI wouldn't terminate. I ended up just giving it elasticbeanstalk:*.

@hanswesterbeek
Copy link

thnx for this!

@tommydongaws
Copy link

tommydongaws commented Jun 7, 2023

Had so many iam errors: had to add "elasticloadbalancing:ModifyListener", "elasticloadbalancing:describe*" as well. Replaced the multiple s3 actions with "s3:*"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment