Edited at
VASILYDay 10

CloudFormationを使って一撃で作るAssumeRoleによる強い💪権限管理

More than 1 year has passed since last update.

インフラエンジニアのみつの(@kotatsu360)です。

この記事はVASILY Advent Calendar 201710日目の記事です。

この記事では、AWSのIAMでAssumeRoleする権限周りを一撃でつくるCloudFormationテンプレートをまとめます。ご査収ください。

CloudFormationが作る環境のイメージ

image.png


このドキュメントの目的

IAMは調べれば調べるほど情報が断片的になる。あとJSON書くの面倒(一一 )

CloudFormationならYAMLで書けるし再現性がある。テンプレートにまとめようヽ(゚∀゚)ノ パッ☆


AssumeRoleとは


  1. 役割ごとに必要な権限を持ったIAMロールを作っておく


    • 開発

    • 運用

    • 請求

    • 監査

    • etc...



  2. IAMロールごとに「自分の権限を使うことを許可する」対象を設定しておく


    • 開発用のロールはエンジニアAとBとCと...

    • IAMロール「力がほしい時はいつでも我が名を呼ぶが良い」



  3. つかう


    • 変身

    • 普段はブラックRX。たまにはバイオライダー。




メリット


  • 権限をロールという単位で整理できる


    • 個人ごとに細かく設定するとスパゲッティになりがち



  • 場面場面で必要な権限だけが使える


    • 「開発時に誤って本番構成を変更してしまって泣く」ということが減る



  • 権限の確認が楽


    • 個人ごとに設定すると、権限付与者(おそらく強い権限持ち)と非付与者の差異が生まれる

    • AssumeRoleであれば、そのロールにスイッチして自分で権限を確認できる




デメリット


  • めんどう


    • 「rootアカウントでいいじゃん」と言われたらそこまで・・・

    • アカウント管理をやりたい時はとてもオススメ



なお、後から入れるのはカロリーを消費するので導入は早い方が良いと思います。

また、CloudFormationを使うとコード管理できるので、かなり楽になります。


CloudFormationテンプレートで実行されること


  • IAMユーザの作成


    • ユーザは4人

    • 開発者

    • 開発者&本番運用者

    • 開発者&本番運用者

    • 請求管理者

    • 初ログイン時にパスワード変更画面を出す



  • IAMグループの作成


    • 全員用のグループ

    • 本番運用者用のグループ



  • IAMロールの作成


    • 開発者用の権限を管理するロール

    • 本番運用者用の権限を管理するロール

    • 請求管理者用の権限を管理するロール



  • ユーザをグループに追加

グループとロールの住み分けについては後で触れます。


CloudFormationテンプレート

初期パスワードが小文字と記号になっているので、アカウントのパスワードポリシーによっては作成に失敗します。

AWSTemplateFormatVersion: 2010-09-09

Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: 'IAM User Name'
Parameters:
- Dev1
- Prod1
- Prod2
- Billing1
Parameters:
Dev1:
Type: String
Default: 'kotatsu360a'
Prod1:
Type: String
Default: 'kotatsu360b'
Prod2:
Type: String
Default: 'kotatsu360c'
Billing1:
Type: String
Default: 'kotatsu360d'
Resources:
# ユーザ全員が所属するグループ
IAMGroupAllMember:
Type: 'AWS::IAM::Group'
Properties:
Policies:
- PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 'iam:List*'
Resource: '*'
- Effect: 'Allow'
Action:
- 'iam:GetLoginProfile'
- 'iam:ChangePassword'
- 'iam:CreateVirtualMFADevice'
- 'iam:DeleteVirtualMFADevice'
- 'iam:EnableMFADevice'
Resource:
- !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}'
- !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username}'
- Effect: 'Allow'
Action:
- 'am:DeactivateMFADevice'
Resource:
- !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}'
- !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username}'
Condition:
Bool:
aws:MultiFactorAuthPresent: true
PolicyName: 'mfa-attach'

# 本番運用者が所属するグループ
IAMGroupProductionOperator:
Type: 'AWS::IAM::Group'
Properties:
Policies:
- PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 'opsworks:UpdateMyUserProfile'
- 'opsworks:Describe*'
Resource: '*'
PolicyName: 'change-my-ssh-key'

# [NOTE] 開発者と請求管理者については個人宛のルールが必要ないのでグループを作らない

# 開発者の権限を管理するロール
IAMRoleDeveloper:
Type: 'AWS::IAM::Role'
Properties:
RoleName: 'developer'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS:
- !GetAtt IAMUserDev1.Arn
- !GetAtt IAMUserProd1.Arn
- !GetAtt IAMUserProd2.Arn
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/ReadOnlyAccess'

# 本番運用者の権限を管理するロール
IAMRoleProductionOperator:
Type: 'AWS::IAM::Role'
Properties:
RoleName: 'production-operator'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS:
- !GetAtt IAMUserProd1.Arn
- !GetAtt IAMUserProd2.Arn
Action: 'sts:AssumeRole'
Condition:
Bool:
aws:MultiFactorAuthPresent: true
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/ReadOnlyAccess'
- 'arn:aws:iam::aws:policy/AmazonS3FullAccess'

# 請求管理者の権限を管理するロール
IAMRoleBillingOwner:
Type: "AWS::IAM::Role"
Properties:
RoleName: 'billing-owner'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !GetAtt IAMUserBilling1.Arn
Action: 'sts:AssumeRole'
Condition:
Bool:
aws:MultiFactorAuthPresent: true
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/job-function/Billing'

IAMUserDev1:
Type: 'AWS::IAM::User'
Properties:
LoginProfile:
Password: 'i_love_whisky'
PasswordResetRequired: true
UserName: !Ref Dev1

IAMUserProd1:
Type: 'AWS::IAM::User'
Properties:
LoginProfile:
Password: 'i_love_cigar'
PasswordResetRequired: true
UserName: !Ref Prod1

IAMUserProd2:
Type: 'AWS::IAM::User'
Properties:
LoginProfile:
Password: 'i_love_sleeping'
PasswordResetRequired: true
UserName: !Ref Prod2

IAMUserBilling1:
Type: 'AWS::IAM::User'
Properties:
LoginProfile:
Password: 'i_love_money'
PasswordResetRequired: true
UserName: !Ref Billing1

IAMUserToGroupAdditionAllMember:
Type: 'AWS::IAM::UserToGroupAddition'
Properties:
GroupName: !Ref IAMGroupAllMember
Users:
- !Ref IAMUserDev1
- !Ref IAMUserProd1
- !Ref IAMUserProd2
- !Ref IAMUserBilling1

IAMUserToGroupAdditionProductionOperator:
Type: 'AWS::IAM::UserToGroupAddition'
Properties:
GroupName: !Ref IAMGroupAllMember
Users:
- !Ref IAMUserProd1
- !Ref IAMUserProd2


権限の補足


IAMグループの使いどころ

権限は次の方針で設定しています。


  • ユーザ自体には何の権限も与えない

  • IAMロールで権限管理

しかし、幾つかの権限はロール管理が難しいです。


  • 自分のパスワードの変更


    • 特に、初ログイン時のパスワード変更はユーザ権限での操作以外ムリ



  • 自分のMFA設定

  • 自分のSSH鍵管理


    • OpsWorksを使う場合



「自分の」という部分が曲者です。単に権限を与えるだけでなく、「自分だけできる」というのが重要です。

そのため、これら「自分の情報だけに対して更新権限を与えたい」という場合はIAMグループを使って権限付与しています。

              - Effect: 'Allow'

Action:
- 'iam:GetLoginProfile'
- 'iam:ChangePassword'
- 'iam:CreateVirtualMFADevice'
- 'iam:DeleteVirtualMFADevice'
- 'iam:EnableMFADevice'
Resource:
- !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}' # 自分のMFAだけを対象に
- !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username} # 自分のユーザ情報だけを対象に

OpsWorksはActionレベルで自分だけに対してのものを用意してくれているのでそれを使います。

              - Effect: 'Allow'

Action:
- 'opsworks:UpdateMyUserProfile' # 自分の情報だけの更新権限, 参照権限版もある(DescribeMyUserProfile)
- 'opsworks:Describe*'
Resource: '*'


AssumeRoleの条件

AssumeRoleは、ユーザの指定以外にも特定の条件を満たした場合のみ、という制約をつけることができます。

本番運用者と請求管理者にはユーザの指定以外にMFAでログインしている場合のみAssumeRoleを許可するという制約をつけました。

      AssumeRolePolicyDocument:

Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !GetAtt IAMUserBilling1.Arn
Action: 'sts:AssumeRole'
Condition:
Bool:
aws:MultiFactorAuthPresent: true # MFAログインでないとConditionが満たせずAssumeRoleできない


さいごに

AssumeRoleを理解してからは権限管理の世界が広がった感があります。

ぜひ権限を追加して、実態に即したロールに育ててください。


さいごのさいごに

(IAMの具体的な使い方を紹介する記事がもっと増えますように)