> For the complete documentation index, see [llms.txt](https://terraform201.devart.tv/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://terraform201.devart.tv/2.-aws-iam-role/1..md).

# 1. 로그인 계정 설정

### backend와 provider 설정

* `terraform/iam/art-id/backend.tf` 파일을 수정합니다.

{% code title="terraform/iam/art-id/backend.tf" %}

```hcl
terraform {
  required_version = ">= 1.0.0" # Terraform Version

  backend "s3" {
    bucket         = "art-id-apnortheast2-tfstate" # Set bucket name 
    key            = "art/terraform/iam/art-id/terraform.tfstate"
    region         = "ap-northeast-2"
    encrypt        = true
    dynamodb_table = "terraform-lock" # Set DynamoDB Table
  }
}
```

{% endcode %}

{% code title="vim provider.tf" %}

```hcl
provider "aws" {
  region = "us-east-1" # IAM is global
}
```

{% endcode %}

###

### 공통 권한 생성

* 모든 사용자가 공통으로 가져야 할 권한을 생성합니다.
* 이후 각 그룹마다 권한을 매핑할 예정입니다.

`terraform/iam/art-id/every_policy.tf` 를 확인합니다. 수정하실 필요는 없습니다.

{% code title="terraform/iam/art-id/every\_policy.tf" %}

```hcl
#### Permission to rotate key
resource "aws_iam_policy" "rotate_keys" {
  name        = "RotateKeys"
  description = "allow users to change their aws keys, and passwords."

  policy = data.aws_iam_policy_document.rotate_keys.json
}

data "aws_iam_policy_document" "rotate_keys" {
  statement {
    actions = [
      "iam:*LoginProfile",
      "iam:*AccessKey*",
      "iam:*SSHPublicKey*"
    ]
    resources = ["arn:aws:iam::${var.account_id}:user/$${aws:username}"]
  }

  statement {
    actions = [
      "iam:ListAccount*",
      "iam:GetAccountSummary",
      "iam:GetAccountPasswordPolicy",
      "iam:ListUsers"
    ]
    resources = ["*"]
  }
}

#### Permission to self managed MFA
resource "aws_iam_policy" "self_managed_mfa" {
  name        = "SelfManageMFA"
  description = "allow a user to manage their own MFA device."

  policy = data.aws_iam_policy_document.self_managed_mfa.json
}

data "aws_iam_policy_document" "self_managed_mfa" {
  statement {
    actions = [
      "iam:*VirtualMFADevice"
    ]
    resources = ["arn:aws:iam::${var.account_id}:mfa/$${aws:username}"]
  }

  statement {
    actions = [
      "iam:GetAccountPasswordPolicy"
    ]
    resources = ["*"]
  }

  statement {
    actions = [
      "iam:ChangePassword"
    ]
    resources = ["arn:aws:iam::${var.account_id}:user/$${aws:username}"]
  }

  statement {
    actions = [
      "iam:DeactivateMFADevice",
      "iam:EnableMFADevice",
      "iam:ListMFADevices",
      "iam:ResyncMFADevice"
    ]
    resources = ["arn:aws:iam::${var.account_id}:user/$${aws:username}"]
  }

  statement {
    actions = [
      "iam:ListVirtualMFADevices"
    ]
    resources = ["arn:aws:iam::${var.account_id}:mfa/*"]
  }

  statement {
    actions = [
      "iam:ListUsers"
    ]
    resources = ["arn:aws:iam::${var.account_id}:user/*"]
  }
}

#### Force user to use MFA for security issue
resource "aws_iam_policy" "force_mfa" {
  name        = "ForceMFA"
  description = "disallow a user anything unless MFA enabled"

  policy = data.aws_iam_policy_document.force_mfa.json
}


data "aws_iam_policy_document" "force_mfa" {
  statement {
    not_actions = [
      "iam:*",
      "sts:AssumeRole",
      "s3:*",
      "dynamodb:*",
    ]
    resources = ["*"]
    effect    = "Deny"

    condition {
      test     = "Null"
      variable = "aws:MultiFactorAuthAge"
      values   = ["true"]
    }
  }
}
```

{% endcode %}

###

### Module 세팅

* Multi-account 세팅을 위해서 각 account마다 필요한 정책을 생성해야 합니다.
* 공통 리소스는 module을 통해서 생성합니다.&#x20;
  * `terraform/iam/art-id/_module_assume_policy` 폴더를 생성하여 정의

`terraform/iam/art-id/_module_assume_policy/main.tf` 를 확인합니다. **따로 수정하실 필요는 없습니다.**

{% code title=" terraform/iam/art-id/\_module\_assume\_policy/main.tf" %}

```hcl
resource "aws_iam_policy" "policy" {
  name        = "assume-${var.aws_account}-${var.subject}-policy"
  path        = "/"
  description = "${var.aws_account}-${var.subject}-policy"
  policy      = data.aws_iam_policy_document.policy-document.json
}

data "aws_iam_policy_document" "policy-document" {
  statement {
    effect = "Allow"

    resources = var.resources

    actions = [
      "sts:AssumeRole",
    ]
  }
}
```

{% endcode %}

###

### Production 계정 접근을 위한 Policy 생성

* Production 계정에 **Assume하기 위해서는 권한이 필요합니다.**
* id 계정에서 production계정의 role을 사용하기 위한 권한 설정이므로, 추후에 **production 계정에 해당 Role을 생성해야 합니다.( 본 설정만으로는 assume할 수 없습니다.)**

`terraform/iam/art-id/assume_policy_prod.tf` 를 수정합니다.

{% code title="terraform/iam/art-id/assume\_policy\_prod.tf" %}

```hcl
### Create policies for allowing user to assume the role in the production account
### You can copy this file and change `prod` to other environment if you have any other account

# Admin Access policy 
# If this policy is applied, then you will be able to assume role in the production account with admin permission
module "art_prod_admin" {
  source      = "./_module_assume_policy/"
  aws_account = "art-prod"
  subject     = "admin"
  resources   = ["arn:aws:iam::${var.prod_account_id}:role/assume-art-prod-admin"]
}

output "assume_art_prod_admin_policy_arn" {
  value = module.art_prod_admin.assume_policy_arn
}

# Poweruser Access policy 
# If this policy is applied, then you will be able to assume role in the production account with poweruser permission
module "art_prod_poweruser" {
  source      = "./_module_assume_policy/"
  aws_account = "art-prod"
  subject     = "poweruser"
  resources   = ["arn:aws:iam::${var.prod_account_id}:role/assume-art-prod-poweruser"]
}

output "assume_art_prod_poweruser_policy_arn" {
  value = module.art_prod_poweruser.assume_policy_arn
}


# ReadOnly Access policy 
# If this policy is applied, then you will be able to assume role in the production account with readonly permission
module "art_prod_readonly" {
  source      = "./_module_assume_policy/"
  aws_account = "art-prod"
  subject     = "readonly"
  resources   = ["arn:aws:iam::${var.prod_account_id}:role/assume-art-prod-readonly"]
}

output "assume_art_prod_readonly_policy_arn" {
  value = module.art_prod_readonly.assume_policy_arn
}
```

{% endcode %}

### 팀별로 그룹과 사용자 생성

* 편의상 아래와 같이 세팅했습니다.
  * **group\_devops\_black**
    * 모든 계정에서 `admin 권한`을 사용할 수 있는 사용자의 그룹
    * 예제 사용자 : `jupiter@devart.com`
  * **group\_devops\_white**
    * 모든 계정에서 `readonly 권한`을 사용할 수 있는 사용자의 그룹
    * 예제 사용자 : `daniel@devart.com`

### 사용자 생성

로그인 계정에 실제 로그인을 할 사용자를 생성합니다.&#x20;

{% code title="terraform/iam/art-id/user\_samples.tf" %}

```hcl
resource "aws_iam_user" "jupiter_devart_com" {
  name = "jupiter@devart.com"
}

resource "aws_iam_user" "daniel_devart_com" {
  name = "daniel@devart.com"
}

```

{% endcode %}

### 그룹 생성

사용자를 할당할 그룹을 생성합니다.&#x20;

#### Black Group&#x20;

{% code title="terraform/iam/art-id/group\_devops\_black.tf" %}

```hcl
############## art DevOps Group ##################
resource "aws_iam_group" "art_devops_black" {
  name = "art_devops_black"
}

resource "aws_iam_group_membership" "art_devops_black" {
  name = aws_iam_group.art_devops_black.name

  users = [
    aws_iam_user.jupiter_devart_com.name,
  ]

  group = aws_iam_group.art_devops_black.name
}

############### DevOps Basic Policy ##################
resource "aws_iam_group_policy" "art_devops_black" {
  name  = "art_devops_black"
  group = aws_iam_group.art_devops_black.id

  policy = data.aws_iam_policy_document.art_devops_black.json
}

data "aws_iam_policy_document" "art_devops_black" {
  statement {
    actions = [
      "*"
    ]

    resources = [
      "*"
    ]
  }
}

######################################################

########### DevOps Assume Policies ####################
resource "aws_iam_group_policy_attachment" "art_devops_black" {
  count      = length(var.assume_policy_art_devops_black)
  group      = aws_iam_group.art_devops_black.name
  policy_arn = var.assume_policy_art_devops_black[count.index]
}

variable "assume_policy_art_devops_black" {
  description = "IAM Policy to be attached to user"
  type        = list(string)

  default = [
    # Please change <account_id> to the real account id number of id account 
    "arn:aws:iam::<account_id>:policy/assume-art-prod-admin-policy", # Add admin policy to black group user 
  ]
}

#######################################################


############### MFA Manager ###########################
resource "aws_iam_group_policy_attachment" "art_devops_black_rotatekeys" {
  group      = aws_iam_group.art_devops_black.name
  policy_arn = aws_iam_policy.rotate_keys.arn
}

resource "aws_iam_group_policy_attachment" "art_devops_black_selfmanagemfa" {
  group      = aws_iam_group.art_devops_black.name
  policy_arn = aws_iam_policy.self_managed_mfa.arn
}

resource "aws_iam_group_policy_attachment" "art_devops_black_forcemfa" {
  group      = aws_iam_group.art_devops_black.name
  policy_arn = aws_iam_policy.force_mfa.arn
}

#######################################################


```

{% endcode %}

#### **White Group**&#x20;

```hcl
############## art DevOps Group ##################
resource "aws_iam_group" "art_devops_white" {
  name = "art_devops_white"
}

resource "aws_iam_group_membership" "art_devops_white" {
  name = aws_iam_group.art_devops_white.name

  users = [
    aws_iam_user.daniel_devart_com.name,
  ]

  group = aws_iam_group.art_devops_white.name
}

#######################################################

########### DevOps Assume Policies ####################
resource "aws_iam_group_policy_attachment" "art_devops_white" {
  count      = length(var.assume_policy_art_devops_white)
  group      = aws_iam_group.art_devops_white.name
  policy_arn = var.assume_policy_art_devops_white[count.index]
}

variable "assume_policy_art_devops_white" {
  description = "IAM Policy to be attached to user"
  type        = list(string)

  default = [
    # Please change <account_id> to the real account id number of id account 
    "arn:aws:iam::<account_id>:policy/assume-art-prod-readonly-policy", # Add readonly policy to while group user
  ]
}

#######################################################


############### MFA Manager ###########################
resource "aws_iam_group_policy_attachment" "art_devops_white_rotatekeys" {
  group      = aws_iam_group.art_devops_white.name
  policy_arn = aws_iam_policy.rotate_keys.arn
}

resource "aws_iam_group_policy_attachment" "art_devops_white_selfmanagemfa" {
  group      = aws_iam_group.art_devops_white.name
  policy_arn = aws_iam_policy.self_managed_mfa.arn
}

resource "aws_iam_group_policy_attachment" "art_devops_white_forcemfa" {
  group      = aws_iam_group.art_devops_white.name
  policy_arn = aws_iam_policy.force_mfa.arn
}

#######################################################


```

### 사용자 비밀번호 초기화

* 테라폼으로 생성한 사용자에게 초기 비밀번호를 세팅해줍니다.
* 세팅한 후에 해당 사용자에게 id와 비밀번호를 알려주고 패스워드 변경과 MFA 설정을 요청하시면 됩니다.

IAM > Users > 사용자 선택 > Security credentials 로 이동합니다.

<figure><img src="/files/rSk1eEfCK6NwDQJhe6f4" alt=""><figcaption></figcaption></figure>

`Enable console access` 버튼을 클릭하여 아래와 같이 세팅합니다.

<figure><img src="/files/MptVq4rm2zYYf92yLwzW" alt=""><figcaption></figcaption></figure>

`Enable console access` 를 진행한 후에, 해당 정보를 사용자에게 전달합니다.

<figure><img src="/files/47CPOsRV5Ioo6mvocvg4" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://terraform201.devart.tv/2.-aws-iam-role/1..md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
