インフラエンジニアのみつの(@kotatsu360)です。
この記事はVASILY Advent Calendar 201710日目の記事です。
この記事では、AWSのIAMでAssumeRoleする権限周りを一撃でつくるCloudFormationテンプレートをまとめます。ご査収ください。
このドキュメントの目的
IAMは調べれば調べるほど情報が断片的になる。あとJSON書くの面倒(一一 )
CloudFormationならYAMLで書けるし再現性がある。テンプレートにまとめようヽ(゚∀゚)ノ パッ☆
AssumeRoleとは
- 役割ごとに必要な権限を持ったIAMロールを作っておく
- 開発
- 運用
- 請求
- 監査
- etc...
- IAMロールごとに「自分の権限を使うことを許可する」対象を設定しておく
- 開発用のロールはエンジニアAとBとCと...
- IAMロール「力がほしい時はいつでも我が名を呼ぶが良い」
- つかう
- 変身
- 普段はブラックRX。たまにはバイオライダー。
メリット
- 権限をロールという単位で整理できる
- 個人ごとに細かく設定するとスパゲッティになりがち
- 場面場面で必要な権限だけが使える
- 「開発時に誤って本番構成を変更してしまって泣く」ということが減る
- 権限の確認が楽
- 個人ごとに設定すると、権限付与者(おそらく強い権限持ち)と非付与者の差異が生まれる
- AssumeRoleであれば、そのロールにスイッチして自分で権限を確認できる
デメリット
- めんどう
- 「rootアカウントでいいじゃん」と言われたらそこまで・・・
- アカウント管理をやりたい時はとてもオススメ
なお、後から入れるのはカロリーを消費するので導入は早い方が良いと思います。
また、CloudFormationを使うとコード管理できるので、かなり楽になります。
CloudFormationテンプレートで実行されること
- IAMユーザの作成
- ユーザは4人
- 開発者
- 開発者&本番運用者
- 開発者&本番運用者
- 請求管理者
- 初ログイン時にパスワード変更画面を出す
- ユーザは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の具体的な使い方を紹介する記事がもっと増えますように)