悪意のある者にVPCエンドポイント経由でS3にデータを持ち出させないようにする

OpsJAWSということで、セキュリティ運用をテーマに、S3のVPCエンドポイントについて触れたいと思います。

# VPC エンドポイントとは
公式のドキュメントによれば、

**VPC エンドポイント**
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-endpoints.html
> VPC エンドポイント では、PrivateLink を使用する AWS サービスや VPC エンドポイントサービスに VPC をプライベートに接続できます。インターネットゲートウェイ、NAT デバイス、VPN 接続、または AWS Direct Connect 接続は必要ありません。VPC のインスタンスは、サービスのリソースと通信するためにパブリック IP アドレスを必要としません。VPC と他のサービス間のトラフィックは、Amazon ネットワークを離れません。

とあります。つまり、VPCのプライベートサブネットから直接AWSのサービスにアクセスできる有り難い機能です。

今回、次に示すVPCエンドポイントを利用したユースケースを考えてみます。

# インターネット接続のないVPCからS3にアクセスする
オンプレミスの企業ネットワークの延伸としてVPCを利用する環境を想定します。
VPCの要件は次の3つとします。

* VPCはインターネット接続しない
* VPCと企業ネットワークとは閉塞網など（DirectConnect）で接続
* VPC内のEC2からはS3（verysecure-bucket）を使いたい

VPCはインターネットゲートウェイをアタッチしないので、S3にアクセスするにはオンプレミスの企業ネットワーク経由でインターネットに抜けるか、VPCエンドポイントを利用するかの2択になります。

今回、前者は対象外とし、VPCエンドポイントを利用してS3にアクセスするケースを考えてみます。
この場合、下図のようにVPCエンドポイントを作成し、ルートテーブルにVPCエンドポイントへのルートを追加します。これでS3へのルートは確保されるため、EC2からS3へのアクセスが可能となります。

![vpc1.png](https://qiita-image-store.s3.amazonaws.com/0/104514/2455c2a4-1101-d800-265a-e27060290c15.png)

よりセキュアな構成にするためには、S3バケットには、このVPC以外からのアクセスを拒否するバケットポリシーを設定します。これにより、インターネットや他のVPCなどの別のネットワークからアクセスできなくなります。これでセキュリティも万全ですね :thumbsup: 

**特定の VPC へのアクセスの制限**
http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies-vpc-endpoint.html#example-bucket-policies-restrict-access-vpc

```json:S3バケットポリシー
{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Sid": "Access-to-specific-VPC-only",
       "Action": "s3:*",
       "Effect": "Deny",
       "Resource": ["arn:aws:s3:::verysecure-bucket",
                    "arn:aws:s3:::verysecure-bucket/*"],
       "Condition": {
         "StringNotEquals": {
           "aws:sourceVpc": "vpc-xxxxxxxx"
         }
       },
       "Principal": "*"
     }
   ]
}
```

# 悪意のある者が別のS3バケットにデータを持ち出す
では、タイトルに掲げた悪意のある者が、この環境から他のS3バケット（図のtakeout-bucket）にデータをアップロードできるのでしょうか？

![vpc2.png](https://qiita-image-store.s3.amazonaws.com/0/104514/063c98a5-307b-3986-85ed-5416b79fe153.png)

場合によっては、できてしまいます:weary:
ただしこれは、VPCエンドポイント作成時に、とりあえずフルアクセスにしていた場合など、エンドポイントに適切なアクセスコントロールを行っていない場合に限ります（ずるいですね、ここの説明を省いてました:sweat_drops:）。

![vpc3.png](https://qiita-image-store.s3.amazonaws.com/0/104514/f6e86623-dcbd-0392-96c4-95bac0ab0c56.png)


# 解決方法
解決方法は簡単で、VPCエンドポイントポリシーでアクセス可能な対象Resourceを絞るだけです。

![vpc4.png](https://qiita-image-store.s3.amazonaws.com/0/104514/81ad93d5-c1dd-4d6f-9930-6bd2e1153c1f.png)


なお、Actionの絞り込みについては別途検討が必要です。

```json:S3のエンドポイントポリシーの例
{
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::verysecure-bucket",
        "arn:aws:s3:::verysecure-bucket/*"
      ]
    }
  ]
}
```

# おわりに
これだけです…:cold_sweat: タイトルが大袈裟すぎてすみません:bow:
当然と言われれば当然なのですが、、ふと思い立って書いてみました。
VPCエンドポイントは大変便利な機能ですが、バックドアにならないよう適切にコントロールしましょう！

公式ドキュメントはここになります。
**Amazon S3 のエンドポイントポリシーの使用**
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/vpc-endpoints-s3.html#vpc-endpoints-policies-s3

Amazon Linux のYumリポジトリはS3であることは知られてますが、ここではリポジトリへのGET要求のみに限定するエンドポイントポリシーの書き方が記されてました。

```json:AmazonLinuxAMIリポジトリへのアクセスを有効化する例
{
  "Statement": [
    {
      "Sid": "AmazonLinuxAMIRepositoryAccess",
      "Principal": "*",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::packages.*.amazonaws.com/*",
        "arn:aws:s3:::repo.*.amazonaws.com/*"
      ]
    }
  ]
}
```

本記事は個人の見解であり、所属組織の立場、意見を代表するものではありません。
何かのお役に立てれば幸いです。