複数AWSアカウントのユーザ管理を、ログイン用AWS環境に集約してみた

はじめに

AWSチームのすずきです。

IAM権限の分離や、請求情報の明確化を実現する手段として、AWSアカウントの分割を実施する事があります。

統合認証基盤と連携したSSOなどを利用しない場合、ユーザ管理の煩雑化が問題となる事がありましたが、 複数のAWSアカウントで構成された環境のIAMユーザ管理と、その権限管理を ログイン専用のAWS環境を用意し、効率化する機会がありました。

その内容について紹介させて頂きます。

概要図

iam-login-04

基本方針

当該環境のAWS、IAMの利用方針は以下としました。

  • 開発、本番環境では、IAMはRoleの利用を原則とします。
  • IAMユーザはログイン環境のみに設置します。
    • Roleに対応しないツールに限り、例外としてIAMユーザ(アクセスキー)の設置を認めます。
    • 全てのIAMユーザは定期的な棚卸し対象とし、放置を回避します。
  • 開発、本番環境のRole、2種類、参照専用(readonly)、変更可能(admin)を用意します。
    • 変更可能(admin)なRoleは、管理者グループに所属するユーザに限定して提供します。
  • Roleを利用(スイッチロール)する際、MFA必須、事前登録済みのIPアドレス以外での利用を禁止します。
    • ログイン環境のIAMユーザの不正利用に備えます。

参考

ログイン環境から、開発本番環境の操作にはスイッチロールを利用します。その概要、利用方法は以下をご覧ください。

実装詳細

ログイン環境

IAMグループ

  • IAMグループを利用し、ログイン環境のIAMユーザに付与する権限を管理します
  • インラインポリシーを作成し、付与するIAM権限を設定します。
IAM更新用ポリシー
  • 自身の認証情報(パスワード、MFA設定)に必要とするIAM権限を付与します。
  • 「000000000000」はログイン環境のAWSアカウントIDに置き換えます。
  • Policy-allow-iam-mfa-password
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "iam:ListUsers"
            ],
            "Resource": [
                "arn:aws:iam::000000000000:user/"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:ListVirtualMFADevices"
            ],
            "Resource": [
                "arn:aws:iam::000000000000:mfa/"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:EnableMFADevice",
                "iam:DeactivateMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListMFADevices",
                "iam:ChangePassword"
            ],
            "Resource": [
                "arn:aws:iam::000000000000:user/${aws:username}"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:DeleteVirtualMFADevice",
                "iam:CreateVirtualMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::000000000000:mfa/${aws:username}"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:GetAccountPasswordPolicy"
            ],
            "Resource": [
                "arn:aws:iam::000000000000:*"
            ],
            "Effect": "Allow"
        }
    ]
}
Role利用ポリシー
  • 203.0.113.0/24、192.0.2.0/24、198.51.100.0/24 は、作業拠点、VPN環境などのグローバルIPに置き換えます。
  • 開発環境(000000000001)、本番環境(000000000002)に設置したRoleの利用許可を、対象リソースを明示して与えます。
  • PolicyGroupAdmin(管理者用)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "203.0.113.0/24",
                        "192.0.2.0/24",
                        "198.51.100.0/24"
                    ]
                }
            },
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::000000000001:role/role-readonly*",
                "arn:aws:iam::000000000001:role/role-admin*",
                "arn:aws:iam::000000000002:role/role-readonly*",
                "arn:aws:iam::000000000002:role/role-admin*"
            ],
            "Effect": "Allow"
        }
    ]
}
  • PolicyGroupReadOnly(参照用)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "203.0.113.0/24",
                        "192.0.2.0/24",
                        "198.51.100.0/24"
                    ]
                }
            },
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::000000000001:role/role-readonly*",
                "arn:aws:iam::000000000002:role/role-readonly*",
            ],
            "Effect": "Allow"
        }
    ]
}

開発、本番環境

共通

  • 信頼関係「sts:AssumeRole」の許可先として、ログイン環境のAWSアカウントを指定します
    • ログイン環境のIAMユーザの「sts:AssumeRole」は、「Resource:」を明示して設定されているものとします。
  • AWS操作をMFA必須とするため、条件として「aws:MultiFactorAuthPresent」を「true」とします。

管理者用

  • 「Administrator」の管理ポリシーに相当する、IAMの全権限の許可を与えます
  • 実環境では、開発、運用のフェーズや担当者の役割に応じた、より適切な管理ポリシー、ロールの利用をお勧めします。

iam-login-01

参照専用

  • 平時の確認作業を想定し、「ReadOnlyAccess」の管理ポリシーを付与しています。
  • 管理ポリシー「ReadOnlyAccess」では不足するサービスの権限はインラインポリシーを追加します
  • 今回、DynamoDBの不正参照や、スロットル回避の為、DynamoDBのScanを禁止(Deny)としています。

iam-login-02

まとめ

AWSアカウントを複数用意した場合、アカウントの管理工数の増加が課題となる事がありましたが、 ログイン用のAWSアカウントを用意し、そのIAMを適切に設定する事で集約管理が実現できました。

Unixの「sudo」的にAWSアカウントをスイッチロールを実施する事で、 接続元IPの限定や、MFA利用の徹底、変更ログ(Cloudtrail)の作業者の明確化も可能になります。

ログイン環境で利用するIAMやSTSなどのAWSのサービスは課金対象外のサービスとなるため、 追加費用負担なく、多数のAWSアカウントを管理する環境として利用する事が可能です。

※CloudTrail、AWS Configなどを利用した場合、若干の費用は生じます。

複数のAWSアカウントの管理を効率化するサービスとしてAWS Organizationsが発表され、 2016年12月現在プレビュー募集が開始されていますが、 既存環境で、複数のAWSアカウントで構成されているIAM管理の見直しの機会がありましたら、 ログイン用のAWS環境を是非お試しください。

サンプル

  • 今回紹介したサンプル環境を再現可能なCloudFormationテンプレートです。

ログイン環境用

  • IAMグループ、IAMユーザを生成します
  • 接続元IP(203.0.113.0/24、192.0.2.0/24、198.51.100.0/24) は置き換えます
  • スイッチ先ロールのアカウント(000000000001、000000000002)も置き換えます
AWSTemplateFormatVersion: "2010-09-09"
Description: "login account (IAM user, group)"

Mappings: 
  #IP制限の許可対象
  IpAddress: 
    base01: 
      ip01: "203.0.113.0/24"
      ip02: "192.0.2.0/24"
      ip03: "198.51.100.0/24"

Resources:
  #IAMユーザ(ログイン用)
  #パスワードはAWSマネジメントコンソールを利用して発行
  IamUser01: 
    Type: "AWS::IAM::User"
    Properties: 
      UserName: "hogehoge"
      Groups: 
        - Ref: GroupAdmin
  IamUser02: 
    Type: "AWS::IAM::User"
    Properties: 
      UserName: "fugafuga"
      Groups: 
        - Ref: GroupReadonly

  #IAMグループ(Admin用)
  #000000000001、000000000002はスイッチ先のAWSアカウントに差替
  GroupAdmin: 
    Type: "AWS::IAM::Group"
    Properties: 
      GroupName: "group-admin"
      Policies: 
        - PolicyName: PolicyGroupAdmin
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: Allow
                Action: 
                  - "sts:AssumeRole"
                Resource: 
                  - "arn:aws:iam::000000000001:role/role-readonly*"
                  - "arn:aws:iam::000000000001:role/role-admin*"
                  - "arn:aws:iam::000000000002:role/role-readonly*"
                  - "arn:aws:iam::000000000002:role/role-admin*"
                Condition: 
                  IpAddress: 
                    "aws:SourceIp": 
                      - "Fn::FindInMap": 
                          - IpAddress
                          - base01
                          - ip01
                      - "Fn::FindInMap": 
                          - IpAddress
                          - base01
                          - ip02
                      - "Fn::FindInMap": 
                          - IpAddress
                          - base01
                          - ip03

  #IAMグループ(ReadOnly用)
  GroupReadonly: 
    Type: "AWS::IAM::Group"
    Properties: 
      GroupName: "group-readonly"
      Policies: 
        - PolicyName: PolicyGroupReadonly
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: Allow
                Action: 
                  - "sts:AssumeRole"
                Resource: 
                  - "arn:aws:iam::000000000001:role/role-readonly*"
                  - "arn:aws:iam::000000000002:role/role-readonly*"
                Condition: 
                  IpAddress: 
                    "aws:SourceIp": 
                      - "Fn::FindInMap": 
                          - IpAddress
                          - base01
                          - ip01
                      - "Fn::FindInMap": 
                          - IpAddress
                          - base01
                          - ip02
                      - "Fn::FindInMap": 
                          - IpAddress
                          - base01
                          - ip03

  #IAMポリシー(共通:自身のパスワードとMFA変更を許可) 
  PolicyAllowIamMfaPassword: 
    Type: "AWS::IAM::Policy"
    Properties: 
      PolicyName: "Policy-allow-iam-mfa-password"
      PolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Action: 
              - "iam:ListUsers"
            Resource: 
              - "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: "AWS::AccountId"
                    - ":user/"
          - Effect: Allow
            Action: 
              - "iam:ListVirtualMFADevices"
            Resource: 
              - "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: "AWS::AccountId"
                    - ":mfa/"
          - Effect: Allow
            Action: 
              - "iam:EnableMFADevice"
              - "iam:DeactivateMFADevice"
              - "iam:ResyncMFADevice"
              - "iam:ListMFADevices"
              - "iam:ChangePassword"
            Resource: 
              - "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: "AWS::AccountId"
                    - ":user/${aws:username}"
          - Effect: Allow
            Action: 
              - "iam:DeleteVirtualMFADevice"
              - "iam:CreateVirtualMFADevice"
            Resource: 
              - "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: "AWS::AccountId"
                    - ":mfa/${aws:username}"
          - Effect: Allow
            Action: 
              - "iam:GetAccountPasswordPolicy"
            Resource: 
              - "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: "AWS::AccountId"
                    - ":*"
      Groups: 
        - Ref: GroupAdmin
        - Ref: GroupReadonly

開発、本番環境用

  • 開発(000000000001)、本番(000000000002)のAWS環境に設置する、スイッチ先となるIAMロールを作成します。
  • スイッチ元、ログイン環境のAWSアカウント(000000000000)を差し替えて利用します。 - Roleの種類を増やさない場合、各アカウント共通で利用可能です。
AWSTemplateFormatVersion: "2010-09-09"
Description: "Create IAM Role (switch target) 201612"
Parameters: 
  OriginalAWSaccountID: 
    Description: "Switch original AWSaccount ID"
    Type: String
    Default: "000000000000"
Resources: 
  RoleAdmin: 
    Type: "AWS::IAM::Role"
    Properties: 
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Principal: 
              AWS: 
                "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: OriginalAWSaccountID
                    - ":root"
            Action: "sts:AssumeRole"
            Condition: 
              Bool: 
                "aws:MultiFactorAuthPresent": true
      Policies: 
        - PolicyName: RolepolicyAdmin
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: Allow
                Action: 
                  - "*"
                Resource: 
                  - "*"
      RoleName: "role-admin"
  RoleReadonly: 
    Type: "AWS::IAM::Role"
    Properties: 
      ManagedPolicyArns: 
        - "arn:aws:iam::aws:policy/ReadOnlyAccess"
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Principal: 
              AWS: 
                "Fn::Join": 
                  - ""
                  - - "arn:aws:iam::"
                    - Ref: OriginalAWSaccountID
                    - ":root"
            Action: "sts:AssumeRole"
            Condition: 
              Bool: 
                "aws:MultiFactorAuthPresent": true
      Policies: 
        - PolicyName: RolepolicyDeny
          PolicyDocument: 
            Version: "2012-10-17"
            Statement: 
              - Effect: Deny
                Action: 
                  - "dynamodb:Scan"
                Resource: 
                  - "*"
      RoleName: "role-readonly"