[AWS-level200]Manage multi AWS accounts using switch role created by Cloudformation StackSet
Published: 2023-01-30 09:08:38

**_Level: 200._**


## Vì sao sử dụng Switch Role

Hiện tại có các phương thức quản lý nhiều tài khoản khác nhau, nhưng để sử dụng cho mục đích auto deploy với nhiều tài khoản thì theo mình Switch Role làm khá tốt việc này.

ref: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-console.html

Ngoài ra, sử dụng Switch Role trong kế hoạch quản lý nhiều tài khoản AWS có những lợi ích sau:

- Giảm số lượng IAM users và credentials phải quản lý: thay vì tạo riêng cho mỗi tài khoản, chỉ cần có IAM user chung và sử dụng switch role để truy cập các tài khoản khác.
- Tăng bảo mật: Giới hạn truy cập của một IAM user hoặc service đến resource trên nhiều tài khoản.
- Kiểm soát truy cập chi tiết hơn: Có thể xác định quyền truy cập riêng cho mỗi IAM user hoặc service mà không cần cấp quyền rộng rãi trên tất cả các tài khoản.
- Mặc dù nó có thể khó tạo và quản lý hơn so với sử dụng IAM users và credentials cấp riêng, nhưng sử dụng Switch Role có lợi ích về tính bảo mật và kiểm soát truy cập tốt hơn.

## Vì sao sử dụng Cloudformation StackSet
ref: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html

CloudFormation StackSet là một tính năng của AWS CloudFormation cho phép bạn quản lý các Stack trong nhiều account AWS và region cùng một lúc, thay vì phải vào từng AWS account hoặc region để tạo stack...rất mất công.

Khi sử dụng StackSet để tạo switch role, bạn có thể tạo và quản lý các IAM role trong các AWS account khác nhau mà không cần đăng nhập vào từng AWS account. Bạn có thể sử dụng một mẫu CloudFormation để tạo IAM role và thực hiện các thao tác quản lý (create, update, delete) trên nhiều account và region cùng một lúc.

Với CloudFormation StackSet, bạn có thể tạo các IAM role chung cho tất cả các tài khoản và sau đó sử dụng chúng để switch role giữa các tài khoản. Nó có thể giúp bạn giảm thiểu số lượng công việc quản lý và giảm thiểu rủi ro do việc quản lý từng tài khoản riêng lẻ.

## Cách sử dụng Cloudformation StackSet để tạo Switch Role.

### Diagram

![Switch-Role Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ndcsuhu5uzfdqxmveo8.png)

Như hình trên thì IAM user `terraform` ở tài khoản `common-dev` sẽ có khả năng switch role qua các tài khoản khác.

Các bước cần làm:

**1. Tạo IAM user trên `common` account để sử dụng Switch Role được tạo ở mục 2,3.**

**2. Tạo IAM role cho Cloudformation StackSet hoạt động.**

**3. Sử dụng Cloudformation StackSet để tạo các IAM Role cho mục đích switch role.**

### 1. Tạo IAM user trên `common` account để sử dụng Switch Role được tạo ở mục 2,3.

Sử dụng template sau trên tài khoản `common` account
```
Resources:
  SwitchRoleGroup:
    Type: 'AWS::IAM::Group'
    Properties:
      GroupName: switch-role-group # give a name to this group
      Path: '/'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
      Policies:
        - PolicyName: switchrole-policy
          PolicyDocument: 
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 'sts:AssumeRole'
                Resource:
                  - "arn:aws:iam::123456789101:role/dev-SwitchRoleFromCommonAccount"
                  - "arn:aws:iam::123456789102:role/dev-SwitchRoleFromCommonAccount"
                  - "arn:aws:iam::123456789103:role/dev-SwitchRoleFromCommonAccount"
                  - "arn:aws:iam::123456789104:role/dev-SwitchRoleFromCommonAccount"
                  - "arn:aws:iam::123456789105:role/dev-SwitchRoleFromCommonAccount"
                  - "arn:aws:iam::123456789106:role/dev-SwitchRoleFromCommonAccount"

  TerraformUser:
    Type: 'AWS::IAM::User'
    Properties:
      UserName: terraform
      Groups:
          - !Ref SwitchRoleGroup
```


### 2. Tạo IAM role cho Cloudformation StackSet hoạt động.
Để StackSet hoạt động có 2 cách, một cách gọi là `self-managed` và cách còn lại là `service-managed`...Nôm nà là cách tự quản lý và cách để dịch vụ nào đó quản lý, dịch vụ nào đó chính là AWS Organizations...tự mình quản lý cho khỏe nhé! 
ref: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html

Yêu cầu:
- Trên tài khoản `common` + acc1-5: tạo role `AWSCloudFormationStackSetExecutionRole`
- Trên tài khoản `common`: tạo role `AWSCloudFormationStackSetAdministrationRole` cho phép dịch vụ Cloudformation sử dụng role này để assume role trên.

**Tạo `AWSCloudFormationStackSetExecutionRole`:**
- Phải login vào từng tài khoản để tạo.
- Sử dụng CFN template để tạo stack sau: Nhớ nhập AdministratorAccountId là AWS account ID của `common` account

```
AWSTemplateFormatVersion: 2010-09-09
Description: Configure the AWSCloudFormationStackSetExecutionRole to enable use of your account as a target account in AWS CloudFormation StackSets.

Parameters:
  AdministratorAccountId:
    Type: String
    Description: AWS Account Id of the administrator account (the account in which StackSets will be created).
    MaxLength: 12
    MinLength: 12

Resources:
  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: AWSCloudFormationStackSetExecutionRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !Ref AdministratorAccountId
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess
```

**Tạo role `AWSCloudFormationStackSetAdministrationRole`:**
- Chỉ cần tạo trên tài khoản `common`.
- Tạo bằng CFN template sau:
```
AWSTemplateFormatVersion: 2010-09-09
Description: Configure the AWSCloudFormationStackSetAdministrationRole to enable use of AWS CloudFormation StackSets.

Resources:
  AdministrationRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: AWSCloudFormationStackSetAdministrationRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: AssumeRole-AWSCloudFormationStackSetExecutionRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - sts:AssumeRole
                Resource:
                  - "arn:*:iam::*:role/AWSCloudFormationStackSetExecutionRole"
```

### 3. Sử dụng Cloudformation StackSet để tạo các IAM Role cho mục đích switch role

### a. Tạo Stack Set với template
- Tạo trên `common` account.
- Chuẩn bị template, ví dụ tạo role cho phép user `terraform` trên `common` account switch role vào các accounts.

`cross-account-terraform-users.yaml`
```
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create a role that authorizes access to admin users in another account'
Metadata:
  Version: 0.7
Parameters:
  RoleName:
    Type: String
  SourceAccountId:
    Type: String
    MaxLength: 12
    MinLength: 12
    Description: 12 digit id of the account containing the users to which you're granting access
  MultiFactorAuthRequired:
    Default: "True"
    Type: String
    AllowedValues:
      - "True"
      - "False"
Resources:
  AssumeRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref RoleName
      Policies:
          -
            PolicyName: "AdminUser"
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                -
                  Effect: "Allow"
                  Action: "*"
                  Resource: "*"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: 
            "AWS": 
              - !Join [ "", [ "arn:aws:iam::", !Ref SourceAccountId, ":user/terraform" ] ]
          Action:
          - sts:AssumeRole
```

- Copy template trên qua một S3 bucket của account `common` (cần có user và policy cần thiết để put object):
```
aws s3 cp cross-account-terraform-users.yaml s3://cf-templates-abcd1234-ap-northeast-1 
```

- Chạy command sau để tạo Stack Set với template trên
```
aws cloudformation create-stack-set \
    --stack-set-name dev-SwitchRoleTerraform \
    --template-url https://cf-templates-abcd1234-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/cross-account-terraform-users.yaml --parameters file://cross-account-terraform-users-params.json --capabilities CAPABILITY_NAMED_IAM
```

### b. Tạo Stack Instances
- Tạo trên `common` account.
- Stack Instances sẽ bom gồm: Các tài khoản/regions, để khi apply 1 template nhất định thì Stack Instance sẽ apply toàn bộ cho các tài khoản/regions được xác định.

Ví dụ tạo một Stack Instances bao gồm 6 tài khoản (kể cả `common`)

```
aws cloudformation create-stack-instances \
        --stack-set-name dev-SwitchRoleTerraform \
        --accounts '["123456789101","123456789102","123456789103","123456789104","123456789105","123456789106"]' \
        --regions '["ap-northeast-1"]' \
        --operation-preferences FailureToleranceCount=0,RegionConcurrencyType="PARALLEL",MaxConcurrentPercentage=100
```
Với:
 --stack-set-name dev-SwitchRoleTerraform: Tên của StackSet, thường đặt tương ứng với tên template, hoặc mục đích của StackSet này.
 --accounts: khai báo toàn bộ accounts cần thiết.
 --regions: Khai báo regions cần thiết. Có thể 1 tài khoản sẽ nhiều region


Sau khi chạy lệnh trên thì template sẽ lần lượt được apply cho các tài khoản của Stack Instances. Mình đã thử cách để chạy 1 lượt luôn cho nhanh bằng MaxConcurrentCount này nọ mà chưa thành công...nếu ai thành công và biết vì sao ko chạy được thì comment cho mình biết nhé!

Xin cảm ơn!

Các lệnh liên quan cần thiết:

```
aws cloudformation update-stack-set (Để update template mới)
aws cloudformation update-stack-instances (Để thêm bớt các tài khoản/regions)
aws cloudformation describe-stack-set-operation (Để verify Stack Set mới tạo)
```