[アクセスポリシー] AllowとDenyはいつもセットで考えよう




はじめに
--------

最近、セキュリティ要件が厳しい環境のS3バケットポリシーを書こうとして禿げそうになった話です。
あ、本当に禿げてませんよ？ 本当ですよ？

#### 前提

* アクセスポリシー、バケットポリシーの話
* 例をたくさん貼りたかったのですが、力尽きたのでありません！

#### すぐ内容を知りたい せっかちさん向け まとめ

* AllowとCoditionを合わせて設定しただけだと特定の人だけに許可したわけじゃない。
* Denyで許可したくない人のアクセスは必ず閉じる。  
※そうしないとIAMポリシー側でAllowつけられたらアクセス許可される。



#### アクセスポリシーの基本

* ユーザー、グループ、ロールを定義し、AWSサービスへのアクセスを認可するしくみ 
* デフォルトDeny（不許可）
* めんどくさい 


#### IAMポリシーのベストプラクティス

IAMアクセスポリシーについては、細かいことはこれ読んでください。

* [IAMのベストプラクティス](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html)
* [AWS Black Belt Online Seminar AWS Identity and Access Management (AWS IAM) ](https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-aws-identity-and-access-management-aws-iam)

#### でも、そんな簡単に管理なんてできない

ベストプラクティスを読んでいると*「ははぁ～、なるほどな～。言われてみればたしかにな～。」*と思える内容が書かれています。たしかにこれを常日頃から実施できていれば問題なさそうです。

<font color="Red">***できればね？***</font>

もちろん、ベストプラクティスの「[最小権限を付与する](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html#bp-use-aws-defined-policies#grant-least-privilege)」にもありますが、払い出したユーザー、ロールに対して、 厳密にアクセスコントロールすればセキュリティを担保しやすくなります。
また、バケットであれば、専用のバケットにしてしまう、”環境をAWSアカウントごとでわける”なんてことができるのであれば更にシンプルにできます。
言いたいことはわかる・・・。
でも、ちょっと細かい条件をいれると途端に膨れ上がるのがアクセスポリシーなんです。


#### Default Denyは、雑なポリシー管理の前には意味を成さない。

IAMロール、IAMユーザーに着けられたポリシーが雑だと簡単に穴が開いてしまう。  
ええ、もちろんベストプラクティスに書いてあるようなことを実施できていれば問題はないです。 

でもね、無理なんですよ。

だって、めんどくさいんですもん。 
きっと大体の人は、**「とりあえず生」**の感覚でReadOnlyAccessやFullAccessでつけちゃうと思います。きっと・・・。 

ユーザーの人数が3ケタになりそうだとか、グループごとにアクセスの制御をディレクトリで分ける必要があるとかそんな状況になってくると専用の作業者またはツールを作成などしないといけないレベル。

特にS3へのアクセス制御が大変です。 
~~あれ？こういう性格の人はそもそも管理しちゃいけない？~~ 

***で、今回は、そのS3のバケットポリシー設定が大変だった話です。（長い）***


## ポリシーを作成する際のポイント

最近、IAMポリシーやS3バケットポリシーを書く上で気にした方が良いかな？と思った点を挙げたいとおもいます。


#### 1. IAMユーザー、グループ、ロールなどのIDを利用して特定のアクセスを制御する

useridを利用しconditionで個別に制限ができます。 特定の人（グループ、インスタンス）のみしかアクセスできないようにするなど リソースごとに細かい制御がしたいときに利用します。
`aws:userid`を使用することでアクセス元を制限することができます。
~~すぐに便利な機能がでてきてこの知識もすぐいらないものになる可能性がありますが・・・~~

 バケットポリシーで、特定のPrivateサブネットのインスタンスからしかオブジェクトを
取得できないようにする例：

```json

        {
            "Sid": "GetObjectPolicy",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::<データ保管バケット>",
                "arn:aws:s3:::<データ保管バケット>/*"
            ],
            "Condition": {
                "StringLike": {
                    // バッチを実行するインスタンスのID
                    "aws:userid": "ARHOGEHOGEFUGA2I:*"
                },
                 // NAT GatewayのIP経由のみにする または、 VPCendpointなどを指定
                "IpAddress": {
                    "aws:SourceIp": "11.222.333.444/32"
                }
            }
        },
```

###### ※ useridの取得の仕方

awscliをつかうことでuseridを取得することができます。

`aws iam get-user --user-name okuda`

```json
{
    "User": {
        "Path": "/",
        "UserName": "okuda",
        "UserId": "AIHOGEHOGEFUGAFUGA", // これ
    }
}

```

`aws iam get-role --role-name lambda-role`

```json

{
    "Role": {
        "Path": "/",
        "RoleName": "lambda-role",
        "RoleId": "ARHOGEHOGEFUGAFUGA", // これ

```


##### 2. 同じ名前でつくり直した場合のIDは変わる

同じIDでユーザーを作成しなおしたりすると、useridがかわってしまうので注意
ユーザーをつくりかえた場合は、気を付けましょう。
ACLで利用されるCanonicalIDなども同様です。

```json
{
    "User": {
        "Path": "/",
        "UserName": "okuda",
        "UserId": "AIDAIAROAPMBLFWPJK5JM",
        "Arn": "arn:aws:iam::123456789:user/okuda",
        "CreateDate": "2018-12-14T02:47:56Z"
    }
}
```

削除後再作成

```json
{
    "User": {
        "Path": "/",
        "UserName": "okuda",
        "UserId": "AIDAIIAT7HZWXKUGVNBLI",
        "Arn": "arn:aws:iam::123456789:user/okuda",
        "CreateDate": "2018-12-14T02:51:19Z"
    }
}
```

##### 3. Allowを設定したらDenyを設定するのを忘れずに

セキュリティガチガチな要件のバケットポリシーで必要なのは、特定のユーザー、リソースから
しかアクセスできなくする必要があります。
始めにも書いていましたが、雑な設定をしたユーザー、インスタンスロールにはDefault Denyは無力です。

1. ポリシーを設定する際にリソースにアクセスするユーザー、ロール、エンドポイントなどを挙げる
2. １のリソース以外からのアクセスをすべてDenyに設定。
3. １のリソースのうち必要なAllowを設定
4. ３で設定したAllowの条件を反転させてDenyを設定

Denyはどんな設定よりも強力なのでAllowとセットで細かく指定していく。



##### 4. プリンシパルでのユーザー指定、 ConditionでのIPでの指定は極力しないほうがよい。

プリンシパルでの指定では、設定方法を勘違いしてしまうと二度とアクセスできないバケットポリシーが出来上がります。"NotPrincipal" なAWSアカウントユーザー（ROOT)にしちゃうと、それはもう悲しいことになります。個人のアカウントなら良いですが、企業アカウントでしかもよその企業のアカウントでやったらとても恥ずかしい申請をすることになりますよ。

 <font color="Red">~~え？私ですか？もちろん やりましたよ？~~

バケットポリシーを設定するときのみの話ですが、IPも同様です。 IP指定で且つアクセスDenyをそのIP以外からのあらゆるアクセスが不許可になってしまうことになることがあります。これがもし自動割り当てEIPのインスタンスからだと・・・。


## 理想はどうアクセス制御していくのが良い？



##### IAMアクセスポリシー

* ユーザー、ロール（インスタンス、サービス）からのアクセスは、すべてこちら側でアクセス制御を厳密に設定する。

##### S3バケットポリシー

* Allow：静的Webサイトホスティングや、AWSサービスとの連携の許可。　IP直たたきしたいなどの要件に対応する場合。
* Deny ：セキュリティ要件により、Conditionを利用しuseridなどによる特定の条件によってリソースへのアクセスを制御する。

※　S3バケットポリシーでIPアドレスによる制限をするまえにCloudfront経由の設定だけで要件が満たせるのかを確認するのが先ですが。CloudFrontのIPが固定IPにできない限りは、まだ出番があるように思えます・・。



## 再度まとめ

AWSのインフラで1，2を争うくらいめんどくさい管理項目な気がします。
ただこの仕組みを理解しているとAWSサービスの構築時に仕組みが理解しやすくなります。
AWSのスキルをレベルアップしたい人はぜひ調べてみてください！