AWS SSO를 사용할 수 없다면 Jump 계정을 사용하여 다수의 AWS 계정을 관리해봅시다.

2023.06.09

들어가기 앞서

안녕하세요, 클래스메소드의 서은우 입니다.

좀 더 효율적으로 AWS 환경을 관리하기 위해 서비스나 기능을 기준으로 AWS 계정을 생성해 사용하는 것을 다중 계정 전략(Multi-Account Strategy) 라고 합니다.

하지만 계정이 늘어나면 늘어날 수록 오히려 각 계정을 관리는데에 어려움이 생기게 됩니다.

계정을 효율적으로 관리하기 위한 방법의 일환으로 AWS Single Sign-On(IAM Identity Center)를 사용할 수 있지만, AWS Organizations를 필수로 사용해야한다는 전제가 있습니다.

때문에 본 블로그에서는 AWS Single Sign-On의 대안이 될 수 있는 "점프 계정(Jump Account)"의 사용에 대해 설명하고자 합니다.

점프 계정이란

점프 계정은 Bation Host를 생각하시면 쉽게 이해하실 수 있습니다. Bastion Host는 주로 외부에서 내부 서버에 접근하기 위해 사용합니다.

점프 계정도 이와 비슷한 역할을 하며, 점프 계정을 통하여 다른 계정의 권한을 사용(Switch Role)할 수 있수 있습니다.

점프 계정에 필요한 IAM 유저/그룹을 모아두고, 이를 통해 다른 여러 개의 계정의 권한을 이용하는 방식이기 때문에, 하나의 점프 계정을 사용하는 것으로 다수의 계정을 더욱 효율적으로 관리할 수 있게 됩니다.

또한, 하나의 AWS 계정을 점프 계정으로 이용하기 때문에 AWS Organizations를 사용하지 않는 환경의 경우 AWS Single Sign-On의 좋은 대안이 될 수 있습니다.

직접 해봅시다

하고자 하는 것

본 블로그에서는 점프 계정을 운용을 위해 다음과 같은 리소스들을 생성합니다.

  • 점프 계정
    • IAM Group: 다른 계정으로의 전환을 위해 AssumeRole을 허용하는 권한, 자체적으로 MFA를 관리하고 비밀번호를 변경할 수 있는 권한, 소스 ip 액세스 제한
    • 담당자가 사용할 IAM User
  • 대상 계정
    • 스위치 롤 대상 IAM Role: AmazonEC2ReadOnlyAccess, 특정 유저만 역할을 사용가능하게 제한

점프 계정의 IAM Group 과 IAM User에는 특정 사용자에 대해서만 해당 IAM 리소스의 액세스를 허가하기 위해 소스 ip로 액세스를 제한하는 정책을 설정합니다.

또한 대상 계정의 스위치 롤의 대상이 되는 IAM Role 에 대해서는 필요 최소한의 권한만 부여(본 블로그의 경우 AmazonEC2ReadOnlyAccess), 특정 유저만 역할을 사용할 수 있게 하기 위한 신뢰 관계를 정의합니다. (소스 ip로 제한하는 것도 가능합니다.)

점프 계정 IAM 리소스 생성

그렇다면 점프 계정으로 들어가 사용할 IAM Group / User 를 생성하도록 하겠습니다.

  • Jump group

다른 계정에 스위치 롤을 할 수 있고 소스 IP로 액세스를 제한하는 정책을 추가합니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "JumpAccount",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "x.x.x.x/x"
                    ]
                }
            }
        }
    ]
}

그리고 해당 그룹에 속한 유저 자신이 MFA를 자체적으로 관리할 수 있는 정책을 추가합니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListActions",
            "Effect": "Allow",
            "Action": [
                "iam:ListUsers",
                "iam:ListVirtualMFADevices"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowIndividualUserToListOnlyTheirOwnMFA",
            "Effect": "Allow",
            "Action": [
                "iam:ListMFADevices"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/*",
                "arn:aws:iam::*:user/${aws:username}"
            ]
        },
        {
            "Sid": "AllowIndividualUserToManageTheirOwnMFA",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ]
        },
        {
            "Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ],
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        },
        {
            "Sid": "AllowGetAccountPasswordPolicy",
            "Effect": "Allow",
            "Action": "iam:GetAccountPasswordPolicy",
            "Resource": "*"
        },
        {
            "Sid": "AllowChangePassword",
            "Effect": "Allow",
            "Action": "iam:ChangePassword",
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        },
        {
            "Sid": "BlockMostAccessUnlessSignedInWithMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:ListMFADevices",
                "iam:ListUsers",
                "iam:ListVirtualMFADevices",
                "iam:ResyncMFADevice",
                "iam:GetAccountPasswordPolicy",
                "iam:ChangePassword"
            ],
            "Resource": [
                "arn:aws:iam::*:mfa/${aws:username}",
                "arn:aws:iam::*:user/${aws:username}"
            ],
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}

대상 계정 IAM 리소스 생성

스위치 롤 대상 역할로의 액세스를 제어하기 위해 대상 역할에 다음과 같은 신뢰 관계 정책을 정의할 수 있습니다.

  • 특정 IAM User를 보안 주체로 설정하여 엑세스를 제한
  • 특정 IP 주소를 기준으로 액세스를 제한

  • Target IAM Role

{
  "Version": "2012-10-17",
  "Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::AWS-account-ID:user/user-name"
        },
        "Action": "sts:AssumeRole",
        "Condition": {
            "Bool": {
                "aws:MultiFactorAuthPresent": "true" // MFA 사용을 확인
            },
            "IpAddress": {
                "aws:SourceIp": [
                    "x.x.x.x/x"
                ]
            }
        }
    }
  ]
}

확인

1. 점프 유저로 로그인 후 스위치 롤을 시도합니다

2. 대상 롤로 스위치 롤을 합니다

  • 만약 액세스 제어 정책에 의해 스위치 롤을 할 수 없는 경우에는 다음과 같이 됩니다.

신뢰 정책에 해당하는 유저의 경우, 성공적으로 액세스할 수 있습니다.

3. 위임 받은 역할을 사용합니다.

본 블로그의 대상 역할의 경우, AmazonEC2ReadOnlyAccess 정책이 할당되어 있기 때문에, 해당 정책의 권한 이외의 동작은 모두 거부되게 됩니다.

  • 현재 계정의 EC2 인스턴스 목록을 확인할 수 있습니다.

  • S3 콘솔에 액세스하면 권한 거부 오류가 발생합니다.

참조