AWS CloudFormation을 사용할 때 Amazon Redshift에서 “IAM 역할이 Amazon Redshift 계정에 대한 액세스 권한을 위임해야 합니다.” 오류를 해결하려면 어떻게 해야 하나요?

최종 업데이트 날짜: 2022년 5월 24일

AWS CloudFormation을 사용하여 Amazon Redshift 클러스터 또는 예약된 작업을 생성하려고 합니다. 하지만 AWS Identity and Access Management(IAM) 역할 오류가 발생합니다. 이 오류를 해결하려면 어떻게 해야 합니까?

간략한 설명

AWS CloudFormation을 사용하면 필요한 모든 AWS 리소스를 설명하는 템플릿을 JSON 또는 YAML 형식으로 생성할 수 있습니다. 그런 다음 AWS CloudFormation이 AWS 리소스를 프로비저닝하고 구성합니다. AWS CloudFormation 템플릿을 사용하여 Amazon Redshift 클러스터 또는 예약된 작업을 생성할 수도 있습니다.

그러나 Amazon Redshift 클러스터가 다른 AWS 서비스에 액세스할 수 있도록 권한을 부여하는 IAM 역할을 올바르게 참조해야 합니다. 그렇지 않으면 다음과 같은 오류가 발생합니다.

"The IAM role <role> is not valid. The IAM role must delegate access to an Amazon Redshift account."

이 문제를 해결하려면 CloudFormation을 사용하여 AWS IAM 역할을 올바르게 생성하고 연결해야 합니다. CloudFormation 템플릿 파일이 생성되면 Amazon Redshift 클러스터와 지정된 AWS 리소스(예: 스택)도 자동으로 생성됩니다. 스택에 대한 추가(수동) 업데이트가 필요하지 않습니다.

해결 방법

(YAML 형식으로) AWS CloudFormation 템플릿 파라미터 업데이트

YAML 형식으로 AWS CloudFormation 템플릿 파라미터를 업데이트하려면 다음 단계를 수행하세요.

1.    파라미터를 다음과 같이 정의합니다.

AWSTemplateFormatVersion: 2010-09-09
Description: Create Redshift Stack. 
Parameters:
  Environment:
    Description: Environment of the resources.
    Type: String
    Default: staging
    AllowedValues:
      - production
      - staging
      - testing
  Name:
    Description: Cluster name.
    Type: String
    Default: 'mycluster'
  Service:
    Description: Service name.
    Type: String
    Default: redshift
    AllowedValues:
      - redshift 
  DatabaseName:
    Description:  Database name.
    Type: String
    Default: dev
    AllowedPattern: "([a-z]|[0-9])+"
  ClusterType:
    Description: The type of cluster
    Type: String
    Default: multi-node
    AllowedValues:
    - single-node
    - multi-node
  NumberOfNodes:
    Description: Compute nodes count. For multi-node clusters,
      the NumberOfNodes parameter must be greater than 1
    Type: Number
    Default: '2'
  NodeType:
    Description: The type of node to be provisioned
    Type: String
    Default: dc2.large
    AllowedValues: 
    - dc2.large
    - dc2.8xlarge
    - ra3.4xlarge
    - ra3.16xlarge
  MasterUsername:
    Description: Master user name.
    Type: String
    Default: awsuser
    AllowedPattern: "([a-z])([a-z]|[0-9])*"
  MasterUserPassword:
    Description: Master user password. Must have a length of 8-64 characters, contain one uppercase letter, one lowercase letter, and one number. Also only contain printable ASCII characters except for '/', '@', '"', ' ', '\' and '\'.
    Type: String
    NoEcho: 'true'
  PortNumber:
    Description: The port number on which the cluster accepts incoming connections.
    Type: Number
    Default: '5439'
Conditions:
  IsMultiNodeCluster:
    Fn::Equals:
    - Ref: ClusterType
    - multi-node

참고: AWS CloudFormation 템플릿에 중요한 정보를 포함하기보다는 스택 템플릿에서 동적 참조를 사용하는 것이 좋습니다. 모범 사례에 대한 자세한 내용은 AWS CloudFormation의 보안 모범 사례를 참조하세요.

2.    리소스(Resources)아래에서 RedShift 서비스가 다른 AWS 서비스에 액세스하기 위해 맡을 IAM 역할을 생성합니다. Resources: RedshiftRole: Type: AWS::IAM::Role Properties:

Resources:
  RedshiftRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${Environment}-${Name}-${Service}
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - redshift.amazonaws.com
          Action:
            - sts:AssumeRole
          Condition:
            StringEquals:
              sts:ExternalId: !Sub 'arn:aws:redshift:${AWS::Region}:${AWS::AccountId}:dbuser:${Environment}-${Name}-${Service}/awsuser'
      Path: "/"

3.    정책 아래에서 IAM 역할에 연결할 IAM 정책을 지정합니다.

Policies:  
  - PolicyName: policy-s3
    PolicyDocument:
    Version: 2012-10-17
    Statement:
    - Effect: Allow
    Action:
      - 's3:AbortMultipartUpload'
      - 's3:GetBucketLocation'
      - 's3:ListBucket'
      - 's3:ListBucketMultipartUploads'
      - 's3:GetObject'
      - 's3:PutObject'
    Resource:
      - !Sub "arn:aws:s3:::${Environment}-${Name}-tier1"
      - !Sub "arn:aws:s3:::${Environment}-${Name}-tier1/log-internal-${Service}/*"
      - !Sub "arn:aws:s3:::${Environment}-${Name}-tier2"
      - !Sub "arn:aws:s3:::${Environment}-${Name}-tier2/*"
    - Effect: Allow 
    Action:
      - 's3:DeleteObject'
    Resource:
      - !Sub "arn:aws:s3:::${Environment}-${Name}-tier1/log-internal-${Service}/*"
      - !Sub "arn:aws:s3:::${Environment}-${Name}-tier2/*"
  - PolicyName: policy-cloudwatch
    PolicyDocument:
    Version: 2012-10-17
    Statement:
    - Effect: Allow
    Action:
      - 'logs:CreateLogGroup'
      - 'logs:CreateLogStream'
      - 'logs:PutLogEvents'
    Resource: "*"

4.    함수 Fn::GetAtt 함수를 사용하여 Amazon Redshift 클러스터를 생성한 다음 IAM 역할(RedshiftRole)을 연결합니다.

RedshiftCluster:
  Type: AWS::Redshift::Cluster
  Properties: 

    IamRoles:
    - Fn::GetAtt: [ RedshiftRole, Arn ]

    AllowVersionUpgrade: true
    AutomatedSnapshotRetentionPeriod: 7 
    ClusterIdentifier: !Sub ${Environment}-${Name}-${Service} 
    ClusterVersion: 1.0
    ClusterType:
    Ref: ClusterType
    NumberOfNodes:
    Fn::If:
    - IsMultiNodeCluster
    - Ref: NumberOfNodes
    - Ref: AWS::NoValue
    NodeType:
    Ref: NodeType
    DBName:
    Ref: DatabaseName
    MasterUsername:
    Ref: MasterUsername
    MasterUserPassword:
    Ref: MasterUserPassword
    Port:
    Ref: PortNumber
    PreferredMaintenanceWindow: Sun:18:30-Sun:19:30
    PubliclyAccessible: yes 
    AvailabilityZone: !Select [0, !GetAZs ""]

Fn::GetAtt 함수는 지정된 속성의 값을 반환합니다.

참고: 잘못된 형식의 참조를 사용하여 IAM 역할(예: 참조 함수)에 연결하는 경우 IAM 역할 오류가 발생합니다.

(JSON 형식으로) AWS CloudFormation 템플릿 파라미터 업데이트

JSON 형식으로 AWS CloudFormation 템플릿 파라미터를 업데이트하려면 다음 단계를 수행하세요.

1.    파라미터를 다음과 같이 정의합니다.

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Create Redshift Stack.",
  "Parameters": {
    "Environment": {
      "Description": "Environment of the resources.",
      "Type": "String",
      "Default": "staging",
      "AllowedValues": [
        "production",
        "staging",
        "testing"
      ]
    },
    "Name": {
      "Description": "Cluster name.",
      "Type": "String",
      "Default": "mycluster"
    },
    "Service": {
      "Description": "Service name.",
      "Type": "String",
      "Default": "redshift",
      "AllowedValues": [
        "redshift"
      ]
    },
    "DatabaseName": {
      "Description": "Database name.",
      "Type": "String",
      "Default": "dev",
      "AllowedPattern": "([a-z]|[0-9])+"
    },
    "ClusterType": {
      "Description": "The type of cluster",
      "Type": "String",
      "Default": "multi-node",
      "AllowedValues": [
        "single-node",
        "multi-node"
      ]
    },
    "NumberOfNodes": {
      "Description": "Compute nodes count. For multi-node clusters, the NumberOfNodes parameter must be greater than 1",
      "Type": "Number",
      "Default": "2"
    },
    "NodeType": {
      "Description": "The type of node to be provisioned",
      "Type": "String",
      "Default": "dc2.large",
      "AllowedValues": [ 
        "dc2.large",
        "dc2.8xlarge",
        "ra3.4xlarge",
        "ra3.16xlarge"
      ]
    },
    "MasterUsername": {
      "Description": "Master user name.",
      "Type": "String",
      "Default": "awsuser",
      "AllowedPattern": "([a-z])([a-z]|[0-9])*"
    },
    "MasterUserPassword": {
      "Description": "Master user password. Must have a length of 8-64 characters, contain one uppercase letter, one lowercase letter, and one number. Also only contain printable ASCII characters except for '/', '@', '\"', ' ', '\\' and '\\'.",
      "Type": "String",
      "NoEcho": "true"
    },
    "PortNumber": {
      "Description": "The port number on which the cluster accepts incoming connections.",
      "Type": "Number",
      "Default": "5439"
    }
  },
  "Conditions": {
    "IsMultiNodeCluster": {
      "Fn::Equals": [
        {
          "Ref": "ClusterType"
        },
        "multi-node"
      ]
    }
  },

참고: AWS CloudFormation 템플릿에 중요한 정보를 포함하기보다는 스택 템플릿에서 동적 참조를 사용하는 것이 좋습니다. 모범 사례에 대한 자세한 내용은 AWS CloudFormation의 보안 모범 사례를 참조하세요.

2.    리소스 아래에서 Amazon Redshift 클러스터에 액세스하는 데 사용할 IAM 역할을 생성합니다.

"Resources": {
    "RedshiftRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {
          "Fn::Sub": "${Environment}-${Name}-${Service}"
        },
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "redshift.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ],
              "Condition": {
                "StringEquals": {
                  "sts:ExternalId": {
                    "Fn::Sub": "arn:aws:redshift:${AWS::Region}:${AWS::AccountId}:dbuser:${Environment}-${Name}-${Service}/awsuser"
                  }
                }
              }
            }
          ]
        },
        "Path": "/",

3.    정책 아래에서 IAM 역할에 연결할 IAM 정책을 지정합니다.

"Policies": [
      {
      "PolicyName": "policy-s3",
      "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
        {
          "Effect": "Allow",
          "Action": [
          "s3:AbortMultipartUpload",
          "s3:GetBucketLocation",
          "s3:ListBucket",
          "s3:ListBucketMultipartUploads",
          "s3:GetObject",
          "s3:PutObject"
          ],
          "Resource": [
          {
            "Fn::Sub": "arn:aws:s3:::${Environment}-${Name}-tier1"
          },
          {
            "Fn::Sub": "arn:aws:s3:::${Environment}-${Name}-tier1/log-internal-${Service}/*"
          },
          {
            "Fn::Sub": "arn:aws:s3:::${Environment}-${Name}-tier2"
          },
          {
            "Fn::Sub": "arn:aws:s3:::${Environment}-${Name}-tier2/*"
          }
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
          "s3:DeleteObject"
          ],
          "Resource": [
          {
            "Fn::Sub": "arn:aws:s3:::${Environment}-${Name}-tier1/log-internal-${Service}/*"
          },
          {
            "Fn::Sub": "arn:aws:s3:::${Environment}-${Name}-tier2/*"
          }
          ]
        }
        ]
      }
      },
      {
      "PolicyName": "policy-cloudwatch",
      "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
        {
          "Effect": "Allow",
          "Action": [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
          ],
          "Resource": "*"
        }
        ]
      }
      }
    ]
    }
  },

4.    함수 Fn::GetAtt 함수를 사용하여 Amazon Redshift 클러스터를 생성한 다음 IAM 역할(RedshiftRole)을 연결합니다.

"RedshiftCluster": {
      "Type": "AWS::Redshift::Cluster",
      "Properties": {
        "IamRoles": [
          {
            "Fn::GetAtt": [
              "RedshiftRole",
              "Arn"
            ]
          }
        ],
        "AllowVersionUpgrade": true,
        "AutomatedSnapshotRetentionPeriod": 7,
        "ClusterIdentifier": {
          "Fn::Sub": "${Environment}-${Name}-${Service}"
        },
        "ClusterVersion": 1,
        "ClusterType": {
          "Ref": "ClusterType"
        },
        "NumberOfNodes": {
          "Fn::If": [
            "IsMultiNodeCluster",
            {
              "Ref": "NumberOfNodes"
            },
            {
              "Ref": "AWS::NoValue"
            }
          ]
        },
        "NodeType": {
          "Ref": "NodeType"
        },
        "DBName": {
          "Ref": "DatabaseName"
        },
        "MasterUsername": {
          "Ref": "MasterUsername"
        },
        "MasterUserPassword": {
          "Ref": "MasterUserPassword"
        },
        "Port": {
          "Ref": "PortNumber"
        },
        "PreferredMaintenanceWindow": "Sun:18:30-Sun:19:30",
        "PubliclyAccessible": "true",
        "AvailabilityZone": {
          "Fn::Select": [
            0,
            {
              "Fn::GetAZs": ""
            }
          ]
        }
      }
    }
  }
}

Fn::GetAtt 함수는 지정된 속성의 값을 반환합니다.

참고: 잘못된 형식의 참조를 사용하여 IAM 역할(예: 참조 함수)에 연결하는 경우 IAM 역할 오류가 발생합니다.

AWS CloudFormation에서 새 스택 생성

JSON 또는 YAML 템플릿을 사용하여 스택을 생성하려면 다음 단계를 수행하세요.

1.    AWS CloudFormation 콘솔을 엽니다.

2.    스택 생성을 선택하여 새 스택을 생성합니다.

3.    1단계의 선행 조건 - 템플릿 준비에서 템플릿 준비 완료를 선택합니다.

4.    1단계의 템플릿 지정에서 템플릿 소스를 선택합니다.

5.    (선택 사항) 템플릿 파일을 업로드해야 하는 경우 템플릿 파일을 업로드합니다.

6.    [다음]을 선택합니다.

7.    2단계의 스택 세부 정보 지정에서 스택 이름파라미터를 지정합니다.

8.    다음(Next)을 선택합니다.

9.    3단계의 스택 옵션 구성에서 모든 스택 세부 정보를 검토합니다.

10.    (선택 사항) 스택 옵션을 수정하려면 업데이트할 페이지에 도달할 때까지 이전을 선택합니다. 필요에 따라 스택 옵션을 업데이트한 후 스택 옵션 구성 페이지로 돌아갈 때까지 다음을 선택합니다.

11.    스택 생성을 선택합니다.