こんにちは、櫻井です。
今回は、IAMの機能のひとつであるPermissions Boundaryについての説明と、Permissions BoundaryをデプロイするためのCloudFormationのテンプレートの作成、CloudFormationを利用した複数アカウントに対してのデプロイを行います。
CloudFormationを利用した複数アカウント・複数リージョンにデプロイする方法がわからない方、興味がある方は以前記事にしたので、下記のリンクを参照してください。
CloudFormationのStackSetsを使って複数アカウント・複数リージョンにデプロイする
目次
Permissions Boundaryとは
Permissions Boundaryとは、IAMの機能のひとつです。
Permissions Boundaryは、IAMユーザとIAMロールに対して付与することができます。IAMユーザ(またはロール)に付与されいているIAMポリシーとPermissions Boundaryの「両方」で許可されている場合は許可となり、「どちらか一方」で拒否されている場合は拒否となります。
したがって、IAMユーザ(ロール)に対して強い権限が与えられていたとしても、Permissions Boundaryで設定された制限の範囲を超えた権限を実行することができなくなります。
このサービスを適切に利用することで、社内AWS管理者は、AWSを利用する開発者全体に対して、AWSの利用をする際に最低限守ってほしい要件をガードレールとして設定することができます。
なぜ必要か
Permissions Boundaryが必要な理由として、「社内AWS管理者の運用負荷を軽減することができる」、「ガバナンスを強化することができる」、「開発速度の向上が見込める」などが挙げられます。
例えば、EC2を作成する権限は無いが、IAMロールを作成することはできる権限を持つIAMユーザがいるとします。その場合、このIAMユーザはEC2を作成する権限を付与したロールを作成し、そのロールに対してスイッチロールをすることで、EC2を作成することができてしまいます。
これは、あまりガバナンス的に良いとは考えにくいです。
では、上記のロールを作成する権限を持つIAMユーザからロールを作成する権限をデタッチした場合はどうなるでしょうか? 社内AWS管理者が、必要に応じ、その都度ロールを作成し、開発者に対してロールを払い出すことになるでしょう。
これでは、管理者の運用の負荷が高まってしまいます。また、ロール作成の都度、管理者と開発者間でやり取りを行う必要があるため、開発速度も低下してしまいます。
このような場合にPermissions Boundaryを使い、必要な権限を超えた権限を持たないようにするガードレールを設けることで、開発者は、管理者の想定範囲内で自由に開発を行うことができるようになります。
その結果、管理者と開発者間の必要なやり取りを減らすことができるがゆえに、管理者は運用負荷が軽減し、開発者はスピーディーな開発ができるようになり、ガバナンスの強化もすることができます。
CloudFormationテンプレートを作成する
先にテンプレートの全体像を見ていただき、その後、それぞれの制限についての説明を行います。
テンプレートの全体像
以下が今回作成したPermissions Boundaryのテンプレートの全体像です。
このあと、それぞれの制限についての説明をしていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
AWSTemplateFormatVersion: 2010-09-09 Parameters: BoundaryName: Type: String Default: GFPermissionsBoundary BoundaryArn: Type: String Default: arn:aws:iam::*:policy/GFPermissionsBoundary GFSSORoleArn: Type: String Default: arn:aws:iam::*:role/GFSSORole Conditions: IsEC2RestrictedAccount: !Or [ !Equals ["************", !Ref AWS::AccountId], !Equals ["************", !Ref AWS::AccountId], ] Resources: #-------------------------------------------------------------------------------------------------- # Boundary Policy #-------------------------------------------------------------------------------------------------- GFBoundaryPermissions: Type: AWS::IAM::ManagedPolicy Properties: Description: Policy for Permissions Boundary ManagedPolicyName: GFPermissionsBoundary Path: / PolicyDocument: Version: 2012-10-17 Statement: #-------------------------------------------------------------------------------------------------- # Allow All #-------------------------------------------------------------------------------------------------- - Effect: Allow Action: "*" Resource: "*" Sid: AllowAll #-------------------------------------------------------------------------------------------------- # Deny Create User #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:CreateUser - iam:UpdateUser Resource: "*" Sid: DenyCreateIAMUser #-------------------------------------------------------------------------------------------------- # Deny Modify Policy #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:DeletePolicy - iam:CreatePolicyVersion - iam:DeletePolicyVersion - iam:SetDefaultPolicyVersion Resource: - !Sub arn:aws:iam::${AWS::AccountId}:policy/GFPermissionsBoundary Sid: DenyModifyPolicy #-------------------------------------------------------------------------------------------------- # No Boundary Detach #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:DeleteRolePermissionsBoundary - iam:DeleteUserPermissionsBoundary Resource: "*" Condition: StringEquals: iam:PermissionsBoundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFPermissionsBoundary Sid: NOBoundaryDetach #-------------------------------------------------------------------------------------------------- # Only Create Role GF Boudary #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:CreateRole - iam:UpdateRole - iam:UpdateRoleDescription Resource: "*" Condition: StringNotEquals: iam:PermissionsBoundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFPermissionsBoundary Sid: OnlyCreateRoleAndGFBoundary #-------------------------------------------------------------------------------------------------- # Deny Accsess To Management Stack #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: "cloudformation:*" Resource: !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/StackSet-GFManagementStack*/* Sid: DenyAccessToManagementStack #-------------------------------------------------------------------------------------------------- # Control Instance #-------------------------------------------------------------------------------------------------- - Effect: !If [IsEC2RestrictedAccount, Allow, Deny] Action: ec2:RunInstances Resource: arn:aws:ec2:*:*:instance/* Condition: StringNotEquals: ec2:InstanceType: - t3a.nano - t3a.micro - t3a.small #-------------------------------------------------------------------------------------------------- # Control Region #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: "*" Resource: "*" Condition: StringNotEquals: aws:RequestedRegion: - ap-northeast-1 - us-east-1 #-------------------------------------------------------------------------------------------------- # geekfeed-AssumeRole #-------------------------------------------------------------------------------------------------- GFSSORole: Type: AWS::IAM::Role Properties: RoleName: GFSSORole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Federated: !Sub arn:aws:iam::${AWS::AccountId}:saml-provider/gf.awsapps Action: - sts:AssumeRoleWithSAML Condition: StringEquals: SAML:aud: "https://signin.aws.amazon.com/saml" Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess PermissionsBoundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFBoundaryPermissions DependsOn: GFBoundaryPermissions |
制限についての説明
今回作成したテンプレートのそれぞれの制限について個別に解説していきます。
まずは全て許可
暗黙的な拒否も含めてすべて許可し、その後、制限したい項目については明示的な拒否をしていきます。
1 2 3 4 5 6 7 |
#-------------------------------------------------------------------------------------------------- # Allow All #-------------------------------------------------------------------------------------------------- - Effect: Allow Action: "*" Resource: "*" Sid: AllowAll |
IAMユーザ作成を制限
ここでは、「IAMユーザの作成自体を制限する場合」と「IAMユーザの作成は制限せずに、IAMユーザの作成をPermissions Boundaryが付与されたIAMユーザに限定したい場合」について紹介します。こちらを参照し、テンプレートを作成しようと考えている方はどちらかひとつを選択し、テンプレートに書き込んでください。
- IAMユーザの作成自体を制限する場合
1 2 3 4 5 6 7 8 9 |
#-------------------------------------------------------------------------------------------------- # Deny Create User #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:CreateUser - iam:UpdateUser Resource: "*" Sid: DenyCreateIAMUser |
- Permissions Boundaryが付与されていないIAMユーザの作成を制限したい場合
Conditionというパラメータを利用して、Permissions Boundaryがアタッチされていない場合はIAMユーザの作成を拒否するというものです。
Conditionについて詳しく知りたい方は以下のリンクを参照してください
1 2 3 4 5 6 7 8 9 10 11 12 |
#-------------------------------------------------------------------------------------------------- # Deny Create User #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:CreateUser - iam:UpdateUser Resource: "*" Condition: StringNotEquals: iam:Permissions Boundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFPermissionsBoundary Sid: OnlyCreateUserWithGFBoudary |
Permissions Boundaryのデタッチを制限
IAMユーザ(またはロール)から、Permissions Boundaryをデタッチできないようにします。
1 2 3 4 5 6 7 8 9 10 11 12 |
#-------------------------------------------------------------------------------------------------- # No Boundary Detach #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:DeleteRolePermissionsBoundary - iam:DeleteUserPermissionsBoundary Resource: "*" Condition: StringEquals: iam:PermissionsBoundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFBoundaryPermissions Sid: NOBoundaryDetach |
Permissions Boundaryの変更・削除を制限
Permissions Boundaryのポリシーを変更・削除をできないようにします。
1 2 3 4 5 6 7 8 9 10 11 12 |
#-------------------------------------------------------------------------------------------------- # Deny Modify Policy #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:DeletePolicy - iam:CreatePolicyVersion - iam:DeletePolicyVersion - iam:SetDefaultPolicyVersion Resource: - !Sub arn:aws:iam::${AWS::AccountId}:policy/GFBoundaryPermissions Sid: DenyModifyPolicy |
Permissions Boundaryが付与されていないロールの作成を制限
Permissions Boundaryが付与されていないIAMロールの作成を制限します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#-------------------------------------------------------------------------------------------------- # Only Create Role GF Boudary #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: - iam:CreateRole - iam:UpdateRole - iam:UpdateRoleDescription Resource: "*" Condition: StringNotEquals: iam:PermissionsBoundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFPermissionsBoundary Sid: OnlyCreateRoleAndGFBoundary |
今回作成されるスタックへのアクセス制限
CloudFormationでデプロイする際に作成される、Stackというものを削除してしまった場合、デプロイしたリソースも削除されてしまいます。
Stackを消すことができてしまえば用意したガードレールの意味がなくなってしまうので、万が一に備えてテンプレートに加えておきます。
すべてのStackへのアクセスを制限しているわけではないので、CloudFormationの利用は通常通り行うことができます。
1 2 3 4 5 6 7 |
#-------------------------------------------------------------------------------------------------- # Deny Accsess To Management Stack #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: "cloudformation:*" Resource: !Sub arn:aws:cloudformation:*:${AWS::AccountId}:stack/StackSet-GFManagementStack*/* Sid: DenyAccessToManagementStack |
利用可能なインスタンスタイプ・インスタンスサイズの制限
普段利用しないインスタンスタイプやインスタンスサイズは利用できないようにしておきます。
また、複数アカウントにPermissions Boundaryデプロイする際、「インスタンスの制限をされては困る」というアカウントに関しては制限しない、といった設定を行います。
Conditionsというものを使い、利用の制限をしたくないアカウントのアカウントID(!Equalsのリストの左側)と、デプロイ先のアカウントID(!Equalsのリストの右側)が一致した場合はTrue、そうでない場合はFalseになるようにするIsEC2RestrictedAccountというものを作成しました。
1 2 3 4 5 6 |
Conditions: IsEC2RestrictedAccount: !Or [ !Equals ["************", !Ref AWS::AccountId], !Equals ["************", !Ref AWS::AccountId], ] |
Effectで条件分岐を行い、IsEC2RestrictedAccountがTrueだった場合はAllow、そうでない場合はDenyとなるように設定しています。
これで、「インスタンスの制限をされたら困る」アカウントに対して、別のテンプレートをわざわざ用意することなく対応することができます。
1 2 3 4 5 6 7 8 9 10 11 12 |
#-------------------------------------------------------------------------------------------------- # Control Instance #-------------------------------------------------------------------------------------------------- - Effect: !If [IsEC2RestrictedAccount, Allow, Deny] Action: ec2:RunInstances Resource: arn:aws:ec2:*:*:instance/* Condition: StringNotEquals: ec2:InstanceType: - t3a.nano - t3a.micro - t3a.small |
リージョンの制限
普段使わないリージョンでのリソース作成は、不要になった場合に放置されていても発見するまでに時間がかかってしまうので、東京リージョンとバージニアリージョン以外の利用を制限しました。
1 2 3 4 5 6 7 8 9 10 11 |
#-------------------------------------------------------------------------------------------------- # Control Region #-------------------------------------------------------------------------------------------------- - Effect: Deny Action: "*" Resource: "*" Condition: StringNotEquals: aws:RequestedRegion: - ap-northeast-1 - us-east-1 |
作成したポリシーをアタッチするロールを作成
GeekFeedでは、SAMLを利用したAssumeRoleでマネジメントコンソールにログインしています。そのため、AssumeRole用のロールGFSSORoleを作成し、このロールに上記で作成したPermissions Boundaryをアタッチする必要があります。
方式が異なる場合は別の方法でロールを作成してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#-------------------------------------------------------------------------------------------------- # geekfeed-AssumeRole #-------------------------------------------------------------------------------------------------- GFSSORole: Type: AWS::IAM::Role Properties: RoleName: GFSSORole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Federated: !Sub arn:aws:iam::${AWS::AccountId}:saml-provider/gf.awsapps Action: - sts:AssumeRoleWithSAML Condition: StringEquals: SAML:aud: "https://signin.aws.amazon.com/saml" Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess PermissionsBoundary: !Sub arn:aws:iam::${AWS::AccountId}:policy/GFPermissionsBoundary DependsOn: GFBoundaryPermissions |
以上でユーザに制限のガードレールを設けるためのテンプレートを作成することができました。
次は実際にテンプレートから複数のアカウントに対してデプロイをしていきます。
CloudFormationで複数アカウントにデプロイする
CloudFormationでの複数アカウントへのデプロイ方法については、以前に記事にしてますので、そちらを御覧ください。
CloudFormationのStackSetsを使って複数アカウント・複数リージョンにデプロイする
以前の記事では複数リージョンにもデプロイしていますが、今回デプロイするものはIAMなのでリソース自体がグローバルになっています。
複数リージョンを選択するとエラーになるので、リージョンはどこか一つを選ぶようにしてください。
まとめ
今回は、権限管理のガードレールを設けるためのPermissions Boundaryについて紹介しました。
少し手間がかかる作業ではありますが、得られるメリットは大きいと思います。
今回設けた制限については一例なので、各々アレンジして使用してください。
一緒に働く仲間を募集中!
ギークフィードではAWSエンジニアを募集しています。
興味がある方はこちらからエントリーをしてぜひ一緒に働きましょう!
- 特定の時間あたりのlambda実行数をSlackに通知する - 2023-12-23
- 公衆電話からでも使える電話帳サービスをLEX + AmazonConnectで作ってみた - 2023-12-19
- SQSを使ってlambdaを10秒ごとに定期実行する - 2023-12-14
- Slack と AWS の電話番号登録アプリ – Bolt + CDK ソースコード解説 - 2023-03-26
- SlackとAWSを組み合わせた電話番号登録アプリの開発 – Boltフレームワーク+CDKで作ってみた - 2023-03-26