官术网_书友最值得收藏!

Understanding CloudFormation IAM permissions

We already know that CloudFormation performs API calls when we create or update the stack. Now the question is, does CloudFormation have the same powers as a root user?

When you work with production-grade AWS accounts, you need to control access to your environment for both humans (yourself and your coworkers) and machines (build systems, AWS resources, and so on). That is why controlling access for CloudFormation is important.

By default, when the user runs stack creation, they invoke the API method cloudformation:CreateStack. CloudFormation will use that user's access to invoke other API methods during the stack creation.

This means that if our user has an IAM policy with an allowed action ec2:*, but attempts to create an RDS instance with CloudFormation, the stack will fail to create with an error, User is unauthorized to perform this action.

Let's try this. We will create an IAM role with ec2:*, assume that role, and try to create the same bucket stack:

Important note

We already have an IAM user Admin in our AWS account and we will add that user as a principal.

MyIamRole.yaml

AWSTemplateFormatVersion: "2010-09-09"

Description: "This is a dummy role"

Resources:

  IamRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: 2012-10-17

        Statement:

          - Sid: AllowAssumeRole

            Effect: Allow

            Principal:

              AWS:

                - !Join

                  - ""

                  - - "arn:aws:iam::"

                    - !Ref "AWS::AccountId"

                    - ":user/Admin"

            Action: "sts:AssumeRole"

      ManagedPolicyArns:

        - "arn:aws:iam::aws:policy/AmazonEC2FullAccess"

        - "arn:aws:iam::aws:policy/AWSCloudformationFullAccess"

Outputs:

  IamRole:

    Value: !GetAtt IamRole.Arn

If we create this stack, assume that role, and try to create the previous mybucket stack, it will fail to create with an error. Let's take a look:

$ aws cloudformation create-stack \

                     --stack-name iamrole \

                     --capabilities CAPABILITY_IAM \

                     --template-body file://IamRole.yaml

$ IAM_ROLE_ARN=$(aws cloudformation describe-stacks \

                                    --stack-name iamrole \

--query "Stacks[0].Outputs[?OutputKey=='IamRole'].OutputValue" \

--output text)

$ aws sts assume-role --role-arn $IAM_ROLE_ARN \

                      --role-session-name tmp

# Here goes the output of the command. I will store the access credentials in the env vars

$ export AWS_ACCESS_KEY_ID=…

$ export AWS_SECRET_ACCESS_KEY=…

$ export AWS_SESSION_TOKEN=…

$ aws cloudformation create-stack \

                     --stack-name mybucket \

                     --template-body file://MyBucket.yaml

We will see the following error on the AWS console:

Figure 1.1 – CloudFormation console – stack events

Figure 1.1 – CloudFormation console – stack events

On the other hand, we cannot provide everyone with an AdminAccess policy, so we need to find a way to use CloudFormation with the necessary permissions while only letting CloudFormation use those permissions.

CloudFormation supports service roles. Service roles are the IAM roles that are used by different AWS services (such as EC2, ECS, Lambda, and so on). CloudFormation service roles are used by CloudFormation during stacks and StackSets operations—creation, update, and deletion:

  1. Let's create a specific role for CloudFormation:

    CfnIamRole.yaml

    AWSTemplateFormatVersion: "2010-09-09"

    Description: "This is a CFN role"

    Resources:

      IamRole:

        Type: AWS::IAM::Role

        Properties:

          AssumeRolePolicyDocument:

            Version: 2012-10-17

            Statement:

              - Sid: AllowAssumeRole

                Effect: Allow

                Principal:

                  Service: "cloudformation.amazonaws.com"

                Action: "sts:AssumeRole"

          ManagedPolicyArns:

            - "arn:aws:iam::aws:policy/AdministratorAccess"

    Outputs:

      IamRole:

        Value: !GetAtt IamRole.Arn

  2. We create this stack for the service role and obtain the CloudFormation role ARN:

    $ aws cloudformation create-stack \

                         --stack-name cfniamrole \

                         --capabilities CAPABILITY_IAM \

                         --template-body file://CfnIamRole.yaml

    $ IAM_ROLE_ARN=$(aws cloudformation describe-stacks \

                                        --stack-name cfniamrole \

    --query "Stacks[0].Outputs[?OutputKey=='IamRole'].OutputValue" \

    --output text)

  3. Now we run the creation of the stack, which will use our role, specifying the Role ARN:

    $ aws cloudformation create-stack \

                         --stack-name mybucket \

                         --template-body file://MyBucket.yaml \

                         --role-arn $IAM_ROLE_ARN

  4. After a while, we can verify that our stack has been created, and we see our bucket!

    $ aws s3 ls

    # Output

    2019-10-16 14:14:24 mybucket-mybucket-jqjpr6wmz19q

    Before we continue, don't forget to clean your account:

    $ for i in mybucket iamrole cfniamrole; do aws cloudformation delete-stack --stack-name $i ; done

    Important note

    Note that in the preceding example, we provide the CloudFormation role with an AdminPolicy (the one that is provided by AWS by default).

In production-grade systems, we want to allow CloudFormation only those privileges that are required for the stack.

There are two permission schemas that are being applied for CloudFormation roles:

  • We have a certain list of services that we can use (for example, EC2, RDS, VPC, DynamoDB, S3, and so on).
  • Each template/stack combination will use only those services it needs—for example, if we declare Lambda functions with Simple Notification Service (SNS), then we should create the role with policies only for Lambda and SNS.
主站蜘蛛池模板: 綦江县| 张掖市| 名山县| 深泽县| 南投县| 崇左市| 舒城县| 威宁| 九寨沟县| 夏津县| 临汾市| 武乡县| 梧州市| 蒙阴县| 沂源县| 酒泉市| 万载县| 门源| 宜阳县| 镇江市| 江川县| 武乡县| 龙海市| 鲁甸县| 宽城| 涟源市| 台东县| 秦皇岛市| 封丘县| 西吉县| 昌黎县| 苏尼特左旗| 合水县| 体育| 江源县| 鄂尔多斯市| 吴桥县| 鸡泽县| 颍上县| 余姚市| 白城市|