copilot-cli icon indicating copy to clipboard operation
copilot-cli copied to clipboard

Support IAM roles with permission boundaries

Open Lou1415926 opened this issue 4 years ago • 8 comments

Permission boundaries is supported for IAM entities, so that only actions that are allowed by both the identity-based policies and the permissions boundaries can be performed.

Some organizations require IAM roles to be created with permission boundaries, for example, #2933 and #2969. Copilot should be able to support that.

Lou1415926 avatar Nov 03 '21 20:11 Lou1415926

I second this request. Permission boundaries are vital to a least-privilege system in enterprise situations, and it is the only thing preventing me from recommending Copilot wholeheartedly for a migration involving 500 developers.

The simplest implementation would probably be to add a boundary_permission key to the service manifests for the various architectures, overridable per environment. It is important that Roles are created with permission boundaries, as SCPs otherwise will prevent a Role from being created.

PeterBengtson avatar Jun 14 '22 23:06 PeterBengtson

Hello @PeterBengtson. Thank you very much for your input! I have a few follow-up questions to understand your use case better:

  1. Are the manifests editable by developers, or are they strictly edited by DevOps/Platform teams?
  2. If the manifests are editable by developers - what prevents a developer to change the permission boundary policy in the manifest and get a lot more access?
  3. Do you want all IAM roles (e.g. EnvManagerRole, AppDelegationRole, etc.) to be created with permission boundary, or just IAM roles created with addon?

Lou1415926 avatar Jun 15 '22 16:06 Lou1415926

@Lou1415926 :

  1. Yes, the manifests are of course editable by developers. The Boundary Permission policy will restrict what teams actually can do, no matter what the teams put in their own policies.
  2. The permission boundary policies are presupplied by the Foundation Team (or a Platform Team). They are protected from modification by developers by an SCP which also prohibits any role from being created unless it is with the presupplied policy/policies. It also blocks the removal of the policy. The SCP in question is a best practice one from AWS; you can find it here: https://getstarted.awsworkshop.io/03-dev/07-reference/02-controlling-builder-team-access.html.
  3. It would have to be all roles, as the SCP will block all new roles without the presupplied Boundary Permission policy from being created.

Here's the relevant section of the SCP:

       {
            "Sid": "AllowRoleWithPBs",
            "Effect": "Allow",
            "Action": [
                "iam:CreateRole",
                "iam:AttachRolePolicy",
                "iam:DetachRolePolicy",
                "iam:PutRolePolicy",
                "iam:DeleteRolePolicy"
            ],
            "NotResource": "arn:aws:iam::*:role/example-infra-*",
            "Condition": {
                "StringLike": {
                    "iam:PermissionsBoundary": "arn:aws:iam::*:policy/example-infra-team-dev-boundary"
                }
            }
        },

PeterBengtson avatar Jun 15 '22 19:06 PeterBengtson

Hi @PeterBengtson, @qtangs, @corey-cole ! I'm wondering if it makes sense to setup different levels of permission boundaries 💭

  1. For example, do you foresee a need for limiting roles created in the application account differently than roles created in environments? Imagine a workflow like this:

    $ copilot app init --permission-boundary AppPermissionBoundaryPolicy
    $ copilot env init --name stg --permission-boundary StagingEnvPermissionBoundaryPolicy
    $ copilot env init --name prod --permission-boundary ProdEnvPermissionBoundaryPolicy
    
  2. Alternatively, do you just have a single managed policy that should be applied to all roles regardless of the account?

    $ copilot app init --permission-boundary AppPermissionBoundaryPolicy
    

    Option 2 automatically assumes that there is AppPermissionBoundaryPolicy existing in all environment accounts and Copilot will just use the AppPermissionBoundaryPolicy for roles created in the environment.

Option 2 is less flexible than Option 1 if you have particular restrictions to follow per account, but it is simpler to execute for developers.

efekarakus avatar Jun 27 '22 23:06 efekarakus

Hi @efekarakus, @qtangs, @corey-cole!

I think it would make great sense having levels here. Alternative 2 will do, and is simpler for developers, but there might be situations where the permission boundaries have to be tighter in production, so alternative 1 makes the most sense and would give the greatest flexibility to support possible enterprise account structures out there.

However, if the bottleneck is the Copilot team's developers, we could always start with alternative 2 and add the extra env conf later.

PeterBengtson avatar Jun 28 '22 11:06 PeterBengtson

Hi folks! Below is our proposal for this feature, please leave us feedback ❤️


Overview of Copilot IAM roles

As of v1.19, Copilot creates the following IAM roles:

  • 3 Application roles: AdministrationRole , ExecutionRole, and DNSDelegationRole. The AdministrationRole grants permission for CloudFormation to assume the ExecutionRole that will create resources part of a stackset. Stacksets are used to create regional infrastructure that span all environments in a single AWS accounts. The resources created today are ECR repositories, S3 buckets used by pipelines, and KMS keys to encrypt the buckets.

    The ExecutionRole holds the actual permissions for resources that CloudFormation can create in a stackset instance. We should definitely allow applying a PermissionBoundary to this role as clients can limit regional resources such as how s3 buckets should be created.

    The DNSDelegationRole allow environment accounts to modify Route53 hosted zone records.

  • Environment roles: most notably the CFNExecutionRole and EnvManagerRole. The remaining roles are mostly custom resource roles assumed by AWS Lambda. Both the CFNExecutionRole and EnvManagerRole should be limited by a PermissionBoundary.

Recommendations

Boundaries for Application Roles

Our recommendation is to start off by allowing a single PermissionBoundary for all application roles:

$ copilot app init --permission-boundary devBoundaryPolicy

Clients can create an SCP requiring the permission boundary for the roles like this:

"Condition": {
   "StringLike": {
      "iam:PermissionsBoundary": "arn:aws:iam::*:policy/devBoundaryPolicy"
  }
}

Which will limit the regional resources created by stack set instances. Copilot can gradually overtime add more granular permission boundary options per role (see comment)

Boundaries for Environment Roles

Environments is where the resources for the application live. Developers can add IAM roles however they want in these accounts using addons/ and the permissions of CFNExecutionRole is extremely large in order to be able to create various architectures. Clients will want to limit all these roles with a PermissionBoundary.

Our recommendation is that a single permission boundary should be used on all the IAM roles created in environment accounts.

$ copilot env init --permission-boundary devBoundaryPolicy

Alternatively, if customers want to do it through infrastructure-as-code. They’ll be able to set the field in the environment manifest:

name: prod
type: 'Environment'
permission_boundary: devBoundaryPolicy

efekarakus avatar Jun 29 '22 23:06 efekarakus

Hi Efe! This design looks very flexible indeed and should really do the trick. :)

There's just one thing: there cannot be such a thing as assigning Boundary Permissions only to some roles. The whole point of the BP exercise is to make escalation of privileges impossible. This allows platform architects such as myself to delegate role creation to the developers and not to a centralised platform team with wider permissions.

This means that the SCP attached to builder accounts must require all new roles to be created with a specific Boundary Permission (existing roles are not affected). There can be no choice in the matter. All IAM Roles, regardless of who creates them, must, when the SCP is applied to that account or OU, be created with specific, pre-supplied Boundary Permission policies. If builders can create and attach just any old BP they create themselves, escalation of privileges cannot be prevented.

In all likelihood there will be just a single BP for builders to use, though - after all, the BP specifies the outer limits possible for Roles in general in an account, the protection perimeter so to speak, and the policy of the Role narrows that down to the specifics. BPs and SCPs are very much alike apart from their scope: SCPs are for accounts and OUS, and BPs are for IAM entities. Platform architects might want to create different BPs for different accounts, though: prod accounts come to mind. But I'd say that there probably would be little point in using more than one BP in one and the same account.

The BP, like the SCPs installed, would be supplied by the platform team and thus are centralised, protected resources that builder teams cannot modify. All builders can do is specify the BP when creating a role. If they don't, the creation of the role fails. I should also add that the SCP doesn't require BPs when a platform team admin creates a role, only when non-admins like builders do so.

Check out this best-practice AWS document: https://getstarted.awsworkshop.io/03-dev/07-reference/02-controlling-builder-team-access.html, specifically the section "Allow Creation of IAM Roles Only When Permissions Boundary is Attached" which describes the considerations involved. Just as the authors say, the SCP snippets given in this document need to be adapted slightly for any real-world installation. In our case we exclude SSO platform admins and certain internal AWS roles from being affected. We have a standard Condition we apply to all our SCPs for this.

PeterBengtson avatar Jun 30 '22 06:06 PeterBengtson

Thanks Peter for the detailed background!

This means that the SCP attached to builder accounts must require all new roles to be created with a specific Boundary Permission (existing roles are not affected). There can be no choice in the matter.

Makes sense, I'll update the recommendation above for applications to take a single input that'll be applied to all IAM roles in the application!

I also think this decision isn't a one-way door so we can start with your suggestion. In the future, if a client wants to specify different permission boundaries per role, we can augment the manifest like this :

permission_boundary: policyName # gets applied to all IAM roles.

# In the future if customers demand it:
permission_boundary:
  env_manager_role: readOnlyPolicy
  exec_role: devTeamPolicy

efekarakus avatar Jun 30 '22 20:06 efekarakus

This feature is now released in v1.22 🚀 !

For the blog post: https://aws.github.io/copilot-cli/blogs/release-v122/ Release notes: https://github.com/aws/copilot-cli/releases/tag/v1.22.0

efekarakus avatar Sep 27 '22 17:09 efekarakus

Potential future milestones:

  1. allow passing/changing boundary policy in env manifest
  2. add flag to task run to pass in boundary policy for default/other clusters (non-app)
  3. have a pattern for policies that copilot autodetects and adds, like copilot-[app]-policy

huanjani avatar Sep 27 '22 20:09 huanjani

Thanks a million for this feature!

Cheers, / Peter

On Tue, 27 Sept 2022 at 22:22, Janice Huang @.***> wrote:

Potential future milestones:

  1. allow passing/changing boundary policy in env manifest
  2. add flag to task run to pass in boundary policy for default/other clusters (non-app)
  3. have a pattern for policies that copilot autodetects and adds, like copilot-[app]-policy

— Reply to this email directly, view it on GitHub https://github.com/aws/copilot-cli/issues/2986#issuecomment-1260005322, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAA6OI456P6MGHOGYNOBRLWANJO7ANCNFSM5HJ4DBJA . You are receiving this because you were mentioned.Message ID: @.***>

PeterBengtson avatar Oct 11 '22 08:10 PeterBengtson