ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 테라폼으로 AWS IAM 관리하기 - 역할, 정책 (AWS 편)
    IaC/Terraform 2021. 3. 16. 23:02
    반응형

    AWS IAM이란 무엇인가?

    AWS IAM이란, AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스이다. IAM을 이용하여, 리소스를 사용하도록 인증 및 권한 부여된 대상을 제어한다.

     

    그냥 쉽게 AWS 리소스를 제어할 수 있는 유저, 그룹, 역할, 정책 등을 관리하는 것이라고 생각하면 된다. 이에 대한 자세한 내용은 다음을 참고하라.

    우리가 이번에 구성할 것은?

    우리가 이번에 구성할 인프라는 바로, IAM_ROLE, IAM_POLICY, IAM_INSTNCE_PROFILE이다. Cortex 클러스터를 AWS에서 동적으로 구성하기 위해서는, AWS AutoScaling 기능이 필요하다.

     

    이 때 IAM, S3, DynamoDB, AutoScaling 등의 리소스에 접근 권한을 가지는 정책(IAM_POLICY)가 필요하고, 이를 연결할 역할(IAM_ROLE)이 필요하다. 그리고 AWS AutoScaling 기능에서 이 역할을 참조할 수 있도록 인스턴스 프로파일(IAM_INSTANCE_PROFILE)을 만들어주어야 한다.

     

    이번 장에서 쓰일 코드는 다음 URL에서 얻을 수 있다.

    AWS Provider 구성

    먼저 프로바이더를 구성한다. provider.tf를 다음과 같이 생성한다.

     

    part3/ch12/provider.tf

    provider "aws" {
      region = "us-east-1"
    }

     

    끝이다. region의 경우는 적절하게 값을 주면 된다. 대한민국에서 코드를 작성하는 것이라면 ap-northeast-2를 추천한다.

    나는 이미 이 지역에 리소스가 있어서 us-east-1로 지정했다. 별 차이는 없다. 다만 다른 지역에 AWS 리소스가 생성되어 속도 차이가 조금 있을 뿐..?

     

    이제 이 provider.tf가 있는 위치에서 terraform init 명령어를 실행시킨다.

    $ terraform init

    정책 생성

    먼저 iam.tf를 생성한다. 그 후 다음을 복사한다.

     

    part3/ch12/iam.tf

    resource "aws_iam_policy" "cortex_auto_scale_policy" {
        name        = "cortex_auto_scale_policy"
        path        = "/"
        description = "auto scale policy for cortex cluster"
        policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
            {
                "Effect": "Allow",
                "Action": [
                    "iam:*",
                    "organizations:DescribeAccount",
                    "organizations:DescribeOrganization",
                    "organizations:DescribeOrganizationalUnit",
                    "organizations:DescribePolicy",
                    "organizations:ListChildren",
                    "organizations:ListParents",
                    "organizations:ListPoliciesForTarget",
                    "organizations:ListRoots",
                    "organizations:ListPolicies",
                    "organizations:ListTargetsForPolicy"
                ],
                "Resource": "*"
            },
            {
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": "*"
            },
            {
                "Action": [
                    "dynamodb:*",
                    "dax:*",
                    "application-autoscaling:DeleteScalingPolicy",
                    "application-autoscaling:DeregisterScalableTarget",
                    "application-autoscaling:DescribeScalableTargets",
                    "application-autoscaling:DescribeScalingActivities",
                    "application-autoscaling:DescribeScalingPolicies",
                    "application-autoscaling:PutScalingPolicy",
                    "application-autoscaling:RegisterScalableTarget",
                    "cloudwatch:DeleteAlarms",
                    "cloudwatch:DescribeAlarmHistory",
                    "cloudwatch:DescribeAlarms",
                    "cloudwatch:DescribeAlarmsForMetric",
                    "cloudwatch:GetMetricStatistics",
                    "cloudwatch:ListMetrics",
                    "cloudwatch:PutMetricAlarm",
                    "cloudwatch:GetMetricData",
                    "datapipeline:ActivatePipeline",
                    "datapipeline:CreatePipeline",
                    "datapipeline:DeletePipeline",
                    "datapipeline:DescribeObjects",
                    "datapipeline:DescribePipelines",
                    "datapipeline:GetPipelineDefinition",
                    "datapipeline:ListPipelines",
                    "datapipeline:PutPipelineDefinition",
                    "datapipeline:QueryObjects",
                    "ec2:DescribeVpcs",
                    "ec2:DescribeSubnets",
                    "ec2:DescribeSecurityGroups",
                    "iam:GetRole",
                    "iam:ListRoles",
                    "kms:DescribeKey",
                    "kms:ListAliases",
                    "sns:CreateTopic",
                    "sns:DeleteTopic",
                    "sns:ListSubscriptions",
                    "sns:ListSubscriptionsByTopic",
                    "sns:ListTopics",
                    "sns:Subscribe",
                    "sns:Unsubscribe",
                    "sns:SetTopicAttributes",
                    "lambda:CreateFunction",
                    "lambda:ListFunctions",
                    "lambda:ListEventSourceMappings",
                    "lambda:CreateEventSourceMapping",
                    "lambda:DeleteEventSourceMapping",
                    "lambda:GetFunctionConfiguration",
                    "lambda:DeleteFunction",
                    "resource-groups:ListGroups",
                    "resource-groups:ListGroupResources",
                    "resource-groups:GetGroup",
                    "resource-groups:GetGroupQuery",
                    "resource-groups:DeleteGroup",
                    "resource-groups:CreateGroup",
                    "tag:GetResources",
                    "kinesis:ListStreams",
                    "kinesis:DescribeStream",
                    "kinesis:DescribeStreamSummary"
                ],
                "Effect": "Allow",
                "Resource": "*"
            },
            {
                "Action": "cloudwatch:GetInsightRuleReport",
                "Effect": "Allow",
                "Resource": "arn:aws:cloudwatch:*:*:insight-rule/DynamoDBContributorInsights*"
            },
            {
                "Action": [
                    "iam:PassRole"
                ],
                "Effect": "Allow",
                "Resource": "*",
                "Condition": {
                    "StringLike": {
                        "iam:PassedToService": [
                            "application-autoscaling.amazonaws.com",
                            "application-autoscaling.amazonaws.com.cn",
                            "dax.amazonaws.com"
                        ]
                    }
                }
            },
            {
                "Effect": "Allow",
                "Action": [
                    "iam:CreateServiceLinkedRole"
                ],
                "Resource": "*",
                "Condition": {
                    "StringEquals": {
                        "iam:AWSServiceName": [
                            "replication.dynamodb.amazonaws.com",
                            "dax.amazonaws.com",
                            "dynamodb.application-autoscaling.amazonaws.com",
                            "contributorinsights.dynamodb.amazonaws.com",
                            "kinesisreplication.dynamodb.amazonaws.com"
                        ]
                    }
                }
            }
        ]
        })
    }

     

    위의 코드에서 policy에 값으로 설정된 jsonencode 함수의 파라미터로 전달된 JSON 값은 IAMFullAccess, S3FullAccess, DynamoDBFullAccess 정책이 모두 들어가 있다. 따라서 위 권한들을 모두 가진 정책이 생성된다.

     

    어떻게 이 정책들을 찾아서 한 것인지는 DynamoDBFullAccess를 예를 들어서 설명하겠다. 먼저 AWS 콘솔에 접속하여 IAM 서비스로 이동한다.

     

    그 후 왼쪽 탭의 "정책" 메뉴를 선택한다.

    그 후 검색창에 "DynamoDBFullAccess"를 입력한다.

    그럼 다 치기도 전에 관련 정책을 확인할 수 있다.

    이를 클릭하면 아래 화면처럼 JSON 형태의 값이 보인다. 이를 다 복사해서 resource의 policy = jsonencode() 함수 안에 넣어준다.

    그 후 다른 정책들에서 권한들을 빼올 때면 아래처럼 Statement 리스트 안에, { ... } 값들만 긁어서 iam.tf안에 Statement 리스트에 복사해두면 된다.

    이제 terraform plan를 입력한 후 실제 코드가 잘 반영되는지 테스트해보고 terraform apply 명령어를 입력해서 실제 리소스를 만든다.

    $ terraform apply
    ....
      Enter a value: yes
    
    aws_iam_policy.cortex_auto_scale_policy: Creating...
    aws_iam_policy.cortex_auto_scale_policy: Creation complete after 3s [id=arn:aws:iam::058242845874:policy/cortex_auto_scale_policy]
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

    그 후 다시 AWS 콘솔 정책 화면으로 돌아가자. 검색창 왼쪽에 "정책 필터"가 있는데 이를 클릭한다. 그럼 아래처럼 유형을 선택할 수 있다. "고객 관리형"을 클릭한다.

    그럼 아래처럼 "cortex_auto_scale_policy"가 만들어진 것을 확인할 수 있다.

    이를 클릭해보면 정책이 가진 권한들을 요약해서 확인할 수 있는데, DynamoDB, IAM, S3가 모든 리소스에 접근할 수 있으면 성공이다.

    역할 생성 및 정책 연결

    이제 위에서 만든 cortex_auto_scale_policy 정책을 가지는 역할을 만들어보자. 먼저 iam.tf에 다음을 추가한다.

     

    part3/ch12/iam.tf

    // ...
    resource "aws_iam_role" "cortex_auto_scale_role" {
        name = "cortex_auto_scale_role"
        path = "/"
        assume_role_policy = <<EOF
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "Service": "ec2.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }
    EOF
    }

     

    assume_role_policy는 필수 값인데, 보통 역할을 만들면 위와 같은 JSON 값으로 초기화된다. 역시 terraform plan, terraform apply 명령어를 쳐서 코드 반영 테스트와, 실제 리소스를 만든다.

     

    그럼 이제 다시 IAM 대시보드로 다시 접속한다. 그 후 왼쪽 탭의 "역할" 메뉴를 클릭한다.

    그럼 다음 검색창이 뜨는데 여기서, "cortex_auto_scale_role"를 입력한다.

    역시 채 다 치기도 전에 우리가 만든 역할이 만들어진 것을 확인할 수 있다.

    cortex_auto_scale_role을 들어가보면 아무 권한도 없는 것을 확인할 수 있다.

    정책이 연결되지 않아서 그렇다. 이제 우리가 만든 정책과 역할을 연결하자. iam.tf에 다음의 내용을 추가한다.

     

    part3/ch12/iam.tf

    // ...
    
    resource "aws_iam_role_policy_attachment" "cortex_auto_scale_role_attach" {
        role       = aws_iam_role.cortex_auto_scale_role.name
        policy_arn = aws_iam_policy.cortex_auto_scale_policy.arn
    }

     

    위의 코드에서 확인할 수 있듯이 우리가 만든 역할의 이름과 정책의 arn을 통해서, aws_iam_role_policy_attachment 리소스가 만들어진 것을 확인할 수 있다. 이렇게 하면 정책과 역할이 연결이 된다. terraform planterraform apply 명령어를 통해서 테스트와 리소스 생성을 해보자.

     

    그 후, 역할의 권한이 들어가나 확인해본다. 콘솔에서 새로고침을 하면 다음 화면처럼 우리가 생성한 정책이 잘 들어간 것을 확인할 수 있다.

    인스턴스 프로파일 생성

    앞서 언급했 듯이 AWS AutoScaling을 사용하기 위해서는 결국 위 역할의 "인스턴스 프로파일"이 필요하다. 이제 이를 만들어준다.

     

    part3/ch12/iam.tf

    // ...
    
    resource "aws_iam_instance_profile" "cortex_auto_scale_role_profile" {
        name = "cortex_auto_scale_role_profile"
        role = aws_iam_role.cortex_auto_scale_role.name
    }

     

    쉽다. namerole의 이름만 값으로 주면 된다. 이제 다시 terraform planterraform apply 명령어를 통해서 테스트와 리소스 생성을 해보자.

     

    그 후 역할에 인스턴스 프로파일이 생성되었는지 확인한다. 잘 생성이 되었다.

    이렇게 해서, AWS AutoScaling을 위한 IAM 리소스들을 모두 만들어두었다. 이 때 정책을 만들 때 혹은 역할을 만들 때 쓰인 JSON 들은 data로 빼서 테라폼 코드를 조금 더 깔끔하게 만들 수 있다. 이는 추후에 다시 알아보도록 하겠다.

Designed by Tistory.