AWS Organizations の SCP を使って利用可能サービスを制限してみよう

こんにちは。
今回も[前回](https://qiita.com/hirosys-biz/items/ecc34f8574094dc6be15)と同様 AWS Organizations を使ってハンズオン、サンドボックス環境を作っていた際に出てきた要件の対応です。
高額なインスタンスタイプの指定やリザーブドインスタンスの購入、ハンズオンやサンドボックスには不要そうなサービスの使用を防ぐといったいった内容です。

ホワイトリスト、ブラックリストともにメリットデメリットがありますが、本稿ではブラックリストでの制限としています。

正直、どちらでもよかったのですが、ハンズオン、サンドボックス環境という性格上、できるかぎり新サービス・新機能リリース後、即時に学習や体験ができるようにしておきたかったので、追加サービスがでても自動的に制限がかからないブラックリストとしました。

## 今回使用に制限をかけたサービスや機能
一例として以下に列挙します。また、社内のハンズオンやサンドボックスという性格上、お楽しみ系サービス(DeepRacerやDeepComposer)についても制限をかける対象としました。
ほかにもこれを制限しているよ！とか、これをいれるといいよ！といったものがあったら、こっそりコメントで教えていただけると幸いですm(_ _)m

* Amazon EC2 の一部の高額なインスタンスタイプ
* Amazon EBS のプロビジョンド IOPS
* Amazon EBS の一定容量以上の割り当て
* Amazon EC2 のリザーブドインスタンス
* Amazon RDS のリザーブドインスタンス
* Amazon RDS のプロビジョンド IOPS
* Amazon Redshift のリザーブドインスタンス
* Amazon ElastiCacheのリザーブドノード
* Amazon DynamoDB のリザーブドキャパシティ
* Amazon Bracket
* AWS Outposts
* AWS DeepRacer
* AWS DeepComposer
* AWS DeepLens
* AWS Organizations
* AWS Snowball
* Amazon IVS
* Amazon SES
* Amazon Workspaces などの work シリーズ各種
* Amazon Route53 Domains
* AWS アカウント情報へのアクセス(請求情報や個人情報など)
など

## 制限をかけてみよう
前回の[記事](https://qiita.com/hirosys-biz/private/ecc34f8574094dc6be15)と同様の流れで設定します。
ポリシーは以下の通りです。

```json:denyServiceAndFunctions.json
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "notUseExpensiveService",
			"Effect": "Deny",
			"Action": [
				"ec2:PurchaseReservedInstancesOffering",
				"ec2:ModifyReservedInstances",
				"ec2:GetReservedInstancesExchangeQuote",
				"ec2:DescribeReservedInstancesOfferings",
				"ec2:DescribeReservedInstancesModifications",
				"ec2:DescribeReservedInstancesListings",
				"ec2:DescribeReservedInstances",
				"ec2:CreateReservedInstancesListing",
				"ec2:CancelReservedInstancesListing",
				"ec2:AcceptReservedInstancesExchangeQuote",
				"ec2:CancelCapacityReservation",
				"ec2:CreateCapacityReservation",
				"ec2:DescribeCapacityReservations",
				"ec2:DescribeHostReservationOfferings",
				"ec2:DescribeHostReservations",
				"ec2:ModifyCapacityReservation",
				"ec2:ModifyInstanceCapacityReservationAttributes",
				"ec2:PurchaseHostReservation",
				"outposts:*",
				"s3-outposts:*",
				"rds:DescribeReservedDBInstances",
				"rds:DescribeReservedDBInstancesOfferings",
				"rds:PurchaseReservedDBInstancesOffering",
				"redshift:PurchaseReservedNodeOffering",
				"redshift:GetReservedNodeExchangeOfferings",
				"redshift:DescribeReservedNodes",
				"redshift:DescribeReservedNodeOfferings",
				"redshift:AcceptReservedNodeExchange",
				"dynamodb:DescribeReservedCapacity",
				"dynamodb:DescribeReservedCapacityOfferings",
				"dynamodb:PurchaseReservedCapacityOfferings",
				"elasticache:DescribeReservedCacheNodes",
				"elasticache:DescribeReservedCacheNodesOfferings",
				"elasticache:PurchaseReservedCacheNodesOffering",
				"aws-portal:ModifyAccount",
				"aws-portal:ModifyBilling",
				"aws-portal:ModifyPaymentMethods",
				"aws-portal:ViewAccount",
				"aws-portal:ViewBilling",
				"aws-portal:ViewPaymentMethods",
				"aws-portal:ViewUsage",
				"deepracer:*",
				"braket:*",
				"deepcomposer:*",
				"deeplens:*",
				"organizations:*",
				"snowball:*",
				"ivs:*",
				"ses:*",
				"workmailmessageflow:*",
				"workmail:*",
				"worklink:*",
				"workdocs:*",
				"workspaces:*",
				"route53domains:*"
			],
			"Resource": [
				"*"
			]
		},
		{
			"Sid": "notUseExpensiveInstanceType",
			"Effect": "Deny",
			"Action": [
				"ec2:RunInstances",
				"ec2:RunScheduledInstances"
			],
			"Resource": [
				"*"
			],
			"Condition": {
				"StringLike": {
					"ec2:InstanceType": [
						"p*.*",
						"x*.*",
						"f*.*",
						"i*.*",
						"g*.*",
						"h*.*",
						"r*.*xlarge",
						"c*.*xlarge",
						"m*.*xlarge",
						"z*.*xlarge",
						"a*.*xlarge",
						"*.metal"
					]
				}
			}
		},
		{
			"Sid": "notUsePIOPSEBS",
			"Effect": "Deny",
			"Action": [
				"ec2:CreateVolume",
				"ec2:ModifyVolume"
			],
			"Resource": [
				"*"
			],
			"Condition": {
				"StringLike": {
					"ec2:VolumeType": [
						"io1",
						"io2",
						"gp3"
					]
				}
			}
		},
		{
			"Sid": "notUse1000overEBS",
			"Effect": "Deny",
			"Action": [
				"ec2:CreateVolume",
				"ec2:ModifyVolume"
			],
			"Resource": [
				"*"
			],
			"Condition": {
				"NumericGreaterThanEquals": {
					"ec2:VolumeSize": [
						"1000"
					]
				}
			}
		},
		{
			"Sid": "notUseRDSPIOPSVolume",
			"Effect": "Deny",
			"Action": [
				"rds:CreateDBInstance",
				"rds:CreateDBCluster",
				"rds:CreateDBInstanceReadReplica",
				"rds:ModifyDBInstance"
			],
			"Resource": [
				"*"
			],
			"Condition": {
				"NumericGreaterThan": {
					"rds:Piops": [
						"250"
					]
				}
			}
		},
		{
			"Sid": "notUseRDSOverStorage",
			"Effect": "Deny",
			"Action": [
				"rds:CreateDBCluster",
				"rds:CreateDBInstance",
				"rds:ModifyDBInstance",
				"rds:ModifyDBCluster"
			],
			"Resource": [
				"*"
			],
			"Condition": {
				"NumericGreaterThan": {
					"rds:StorageSize": [
						"500"
					]
				}
			}
		}
	]
}
```

### 動作確認
1. まずは、SCP を割り当てた AWS アカウントへスイッチするなりログインするなりします。
2. 制限をかけていないサービスにアクセスし、操作します(例：Amazon EC2の制限をかけていないインスタンスタイプの起動)
3. 制限をかけたサービスにアクセスする(例：Amazon EC2の制限をかけていないインスタンスタイプの起動、AWS DeepRacer)

#### 制限をかけていないサービス
Amazon EC2 で t2.micro のインスタンスを起動してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/56ddaa3b-c18d-a51e-ab42-2aa193afd8c9.png)

問題なく、起動できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/e8403ee3-1ca8-f447-251a-9b17eb25c064.png)


#### 制限をかけたサービス
Amazon EC2 で 制限をかけた、"r*.*large" に該当する r5.2xlarge を起動しようとしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/3ebabc33-555b-bf72-2e4f-f7e9a1ac6453.png)

期待した通り、起動できませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/dd9725dd-29df-739a-0059-a4222d4ca535.png)

伏字にしているところは、以下のコマンドでデコードできるので、サクッと、 AWS CloudShell を使って確認します。

```sh
aws sts decode-authorization-message --encoded-message <encoded-message>

```

こんな感じで出てきました。見やすくするために少し整形し、省略もしています。
まず、冒頭で **explicitDeny** (明示的な拒否)が **true** と出力されています。また、どのステートメント(この場合は SCP で定義したポリシー/条件)に合致したかも出力されています。
このことから、定義した通りに制限が正しく動作したことがわかります。

```json
{
	"allowed":false,
	"explicitDeny":true,
	"matchedStatements":{
		"items":[
			{
				"statementId":"notUseExpensiveInstanceType",
				"effect":"DENY",
				"principals":{
					"items":[
						{
							"value":"AROAS46SY7***********"
						}
					]
				},
				"principalGroups":{
					"items":[]
				},
				"actions":{
					"items":[
						{
							"value":"ec2:RunInstances"
						},{
							"value":"ec2:RunScheduledInstances"
						}
					]
				},
				"resources":{
					"items":[
						{
							"value":"*"
						}
					]
				},
				"conditions":{
					"items":[
						{
							"key":"ec2:InstanceType",
							"values":{
								"items":[
									{
										"value":"p*.*"
									},{
										"value":"x*.*"
									},{
										"value":"f*.*"
									},{
										"value":"i*.*"
									},{
										"value":"g*.*"
									},{
										"value":"h*.*"
									},{
										"value":"r*.*xlarge"
									},{
										"value":"c*.*xlarge"
									},{
										"value":"m*.*xlarge"
									},{
										"value":"z*.*xlarge"
									},{
										"value":"a*.*xlarge"
									},{
										"value":"*.metal"
									}
								]
							}
						}
					]
				}
			}
		]
	}

(後略)

```

## まとめ
2回続けて、SCP まわりのお話でした。前回と今回でお伝えした内容は、ほんの一部であり、奥が深い機能であります。
今回はハンズオンやサンドボックスといった環境向けに、使われたら困るような高額サービスや不要なサービスの停止をメインにしましたが、例えば、セキュリティ周りのサービスの設定変更(ex. AWS CloudTrail の設定変更など)を防いだりももちろんできます。

各環境の要件に応じたポリシーを作って、アカウントを適切に運用していきましょう！

記載されている会社名、製品名、サービス名、ロゴ等は各社の商標または登録商標です。