Amazon S3 バケットポリシーで特定のIPアドレスのみS3へのファイルアップロードを許可する + cURLコマンドでjsonファイルをS3へアップロード(PUT)する

はじめに
===

本記事では、Amazon S3に関して、以下を実現する設定やコマンドについて記します。

　・Amazon S3のバケットポリシー設定により、AWS以外の指定したIPアドレスからS3バケットへのファイルアップロードを許可する設定。
　・cURLコマンドにより、S3バケットへファイルをアップロードするコマンド。
　・cURLコマンドにより、S3バケットに保存したファイル(オブジェクト)の内容を閲覧するコマンド。

概要
===

AWSの [Amazon S3](https://aws.amazon.com/jp/s3/?nc2=h_l3_sc "Amazon S3") はストレージとして様々な用途で利用されているかと思います。

中には、インターネット上に公開したいファイルの置き場所として、Amazon S3を利用されているケースもあるかと思います。

Amazon S3の利用要件によっては、以下のような事を実現したいケースがあるかもしれません。以下のようなケースを実現するのに、本記事が少しでも参考になりましたら幸いです。

| 要件の例   |
|-----------|
| S3バケットにアップロードしたファイルについては、閲覧制限をかけずに、どなたでも閲覧できるようにしたい。|
| S3バケットへのファイルアップロードについては、指定したマシンやIPアドレスだけに制限したい。|
| AWS以外のPCや指定したIPアドレスからS3バケットへのファイルアップロードを許可したい。|
| AWS以外のPCやIPアドレスからS3バケットへのファイルアップロードを許可するのに、むやみにIAMのアクセスキーを作成したくない。|
| S3バケットへファイルをアップロードするPCに対して、諸事情により [aws s3コマンド](http://docs.aws.amazon.com/cli/latest/reference/s3/index.html "aws s3コマンド") や [aws s3api](http://docs.aws.amazon.com/cli/latest/reference/s3api/ "aws s3api") をインストール出来ない。|



参考資料
===

本件につきましては、以下の資料を参考にさせて頂きました。

バケットポリシーの例
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies.html

アクセス管理の概要
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/access-control-overview.html

http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements.html

用語と表記について
===

S3に保存したファイルは、正確には [オブジェクト](http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UsingObjects.html "オブジェクト") になりますが、本記事では「ファイル」と表記させて頂きます。



cURLコマンドのバージョン
===

S3バケットへのファイルアップロードに使用するcURLコマンドのバージョンは 7.30.0 になります。

```
NotAllowAccessPC001:~ user1$ curl --version
curl 7.30.0 (x86_64-apple-darwin13.0) libcurl/7.30.0 SecureTransport zlib/1.2.5
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp 
Features: AsynchDNS GSS-Negotiate IPv6 Largefile NTLM NTLM_WB SSL libz 
NotAllowAccessPC001:~ user1$
```

Amazon S3バケットの作成
===

それでは、設定手順を以下に記載致します。

まずはテスト用に以下のS3バケットを作成します。

　s3://example-data-json/

AWSマネジメントコンソールへログインして「S3」をクリックします。

<img width="743" alt="スクリーンショット 2016-12-29 14.29.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/7f866ec3-180f-2a92-00be-b4089d7a9874.png">

「バケットを作成」をクリックします。

<img width="795" alt="スクリーンショット 2016-12-29 14.26.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/b8cb170f-f301-2e97-2e71-a43ce0aeeffa.png">

作成するバケット名を入力します。リージョンは「Tokyo」を選択して「作成」をクリックします。

<img width="730" alt="スクリーンショット 2016-12-29 14.27.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/b6897c10-17b5-41b3-000d-361dcd5995a4.png">

S3バケットが作成されます。

<img width="666" alt="スクリーンショット 2016-12-29 14.28.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/8aa07962-a286-0210-b109-1b5030d80759.png">

作成したS3バケットに以下のディレクトリを作成します。

　s3://example-data-json/test/

<img width="582" alt="スクリーンショット 2016-12-29 14.49.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/f3f727fb-10f3-6347-d105-895ace25df16.png">

作成したS3バケットにバケットポリシーを設定する
===

作成したテスト用S3バケットに以下のバケットポリシーを設定します。

　s3://example-data-json/

バケット名左側の虫眼鏡アイコンをクリックします。
バケットの画面右側に「アクセス許可」と表示されるのでクリックします。

<img width="1132" alt="f67be69e-e012-495c-5548-1c4503283e77.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/14340d98-29c1-9ff0-c253-6653289813ad.png">


「バケットポリシーの追加」をクリックします。

<img width="761" alt="スクリーンショット 2016-12-29 14.32.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/ead36753-01ad-ddb8-6927-142b8f52dd02.png">

「バケットポリシーエディター」が表示されます。

<img width="614" alt="スクリーンショット 2016-12-29 14.33.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/bfc45454-61e8-3d91-7b98-7bc16f696b88.png">

「バケットポリシーエディター」に以下のポリシーを記述します。

「aws:SourceIp」の部分にはS3バケットへのファイルアップロードを許可したいIPアドレスを記述します。

例えば、198.51.100.15/32, 192.0.2.0/24のIPアドレスやネットワークのPCからS3バケットに対するファイルアップロードを許可したい場合、以下のようなポリシーを記述します。

「111111111111」の部分はS3バケットを所有するAWSアカウントIDを記述します。
AWSマネジメントコンソールからはS3バケットに対する全操作を許可する為、以下のポリシー例では「111111111111」と記述しています。

```json:バケットポリシーに記述するポリシー例
{
	"Version": "2008-10-17",
	"Id": "ExampleBucketPolicy201612300001",
	"Statement": [
		{
			"Sid": "AccessControl-From-AWS-Account",
			"Effect": "Allow",
			"Principal": {
				"AWS": "111111111111"
			},
			"Action": [
				"s3:*"
			],
			"Resource": "arn:aws:s3:::example-data-json/*"
		},
		{
			"Sid": "AccessControl-From-IPaddress-001",
			"Effect": "Allow",
			"Principal": {
				"AWS": "*"
			},
			"Action": [
				"s3:GetObjectVersion",
				"s3:GetObject",
				"s3:PutObject",
				"s3:DeleteObject"
			],
			"Resource": "arn:aws:s3:::example-data-json/test/*",
			"Condition": {
				"IpAddress": {
					"aws:SourceIp": [
						"198.51.100.15/32",
						"198.51.100.16/32",
						"192.0.2.0/24"
					]
				}
			}
		},
		{
			"Sid": "AccessControl-From-IPaddress-002",
			"Effect": "Deny",
			"Principal": {
				"AWS": "*"
			},
			"Action": [
				"s3:PutObject",
				"s3:DeleteObject"
			],
			"Resource": "arn:aws:s3:::example-data-json/test/*",
			"Condition": {
				"NotIpAddress": {
					"aws:SourceIp": [
						"198.51.100.15/32",
						"198.51.100.16/32",
						"192.0.2.0/24"
					]
				}
			}
		}
	]
}
```


「バケットポリシーエディター」にポリシーを記述したら「保存」をクリックします。

<img width="609" alt="スクリーンショット 2016-12-30 2.24.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/4f49a4b7-0799-3f8d-052d-72cce024eb48.png">

S3バケットへのファイルアップロードテスト用jsonファイルを作成する
===

S3バケットへのファイルアップロードテストで使用するjsonファイルを作成します。

```
NotAllowAccessPC001:~ user1$ $ cat << EOS > example.json 
[
  {
    "Message":"Hello World"
  }
]
EOS
```



```
NotAllowAccessPC001:~ user1$ cat example.json 
[
  {
    "Message":"Hello World"
  }
]
NotAllowAccessPC001:~ user1$
```


cURLでS3バケットへjsonファイルをアップロードするコマンド (バケットポリシーでアクセス許可していないIPアドレスのPCで実行)
===

バケットポリシーでアクセスを許可していないIPアドレスからS3バケットへjsonファイルアップロードを試してみます。
以下のコマンドを実行します。PUTでS3へjsonファイルをアップロードします。

-Tでアップロード対象のjsonファイル名を指定します。

```
curl -X PUT https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json -T example.json
```

アクセス許可していないIPアドレスからのファイルアップロードなので、「AccessDenied」と表示されて、S3へのファイルアップロードに失敗する事を確認します。

```
NotAllowAccessPC001:~ user1$ curl -X PUT https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json -T example.json
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>****************</RequestId><HostId>**************************************************+**************/**********</HostId></Error>NotAllowAccessPC001:~ user1$
NotAllowAccessPC001:~ user1$
```



cURLでS3バケットへjsonファイルをアップロードするコマンド (バケットポリシーでアクセス許可したIPアドレスのPCで実行)
===

バケットポリシーでアクセスを許可したIPアドレス(198.51.100.15)からS3バケットへjsonファイルアップロードを試してみます。

アップロード対象のファイルは前述の手順で作成した example.json を使用します。

```
AllowAccessPC002-198.51.100.15:~ user2$ cat example.json 
[
  {
    "Message":"Hello World"
  }
]
AllowAccessPC002-198.51.100.15:~ user2$
```

以下のコマンドを実行します。

```
curl -X PUT https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json -T example.json
```

アクセス許可したIPアドレスからのファイルアップロードなので、アップロードが正常に終了する事を確認します。

```
AllowAccessPC002-198.51.100.15:~ user2$ curl -X PUT https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json -T example.json
AllowAccessPC002-198.51.100.15:~ user2$ 
```

AWSマネジメントコンソールから「S3」を見ても、アップロードしたファイルがS3バケットに保存されている事を確認出来ます。

<img width="1269" alt="スクリーンショット 2016-12-30 2.27.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/3323dc85-9efe-f22b-6a74-e25ded3c9637.png">



cURLでS3バケットにアップロードしたjsonファイルを閲覧するコマンド
===

S3バケットにアップロードして保存したファイルが閲覧出来るか試します。
以下のコマンドを実行します。

```
curl https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json
```

S3バケットへアップロードされたjsonファイルの内容を閲覧出来る事を確認します。

```
AllowAccessPC002-198.51.100.15:~ user2$ curl https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json
[
  {
    "Message":"Hello World"
  }
]
AllowAccessPC002-198.51.100.15:~ user2$
```


S3バケットへのファイルアップロード制限確認 (バケットポリシーでアクセス許可していないネットワークのマシンで実行)
===

念の為、ファイルアップロードを許可していないネットワークのマシンでは、S3バケットへのファイルアップロードが出来ない事を確認しておきます。

```
[ec2-user@example-ruby-sinatra-server ~]$ cat example.json 
[
  {
    "Message":"Hello World"
  }
]
[ec2-user@example-ruby-sinatra-server ~]$ 

[ec2-user@example-ruby-sinatra-server ~]$ curl httpbin.org/ip
{
  "origin": "203.0.113.11"
}
[ec2-user@example-ruby-sinatra-server ~]$ 

[ec2-user@example-ruby-sinatra-server ~]$ curl -X PUT https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json -T example.json
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>****************</Code><Message>Access Denied</Message><RequestId>F42C780B0C0C63A5</RequestId><HostId>**************************************************+**************/**********</HostId></Error>[ec2-user@example-ruby-sinatra-server ~]$ 
[ec2-user@example-ruby-sinatra-server ~]$ 
```

ファイルアップロードを許可していないネットワークのマシンでも、S3バケットに保存されているファイルは閲覧出来る事を確認しておきます。

```
[ec2-user@example-ruby-sinatra-server ~]$ curl httpbin.org/ip
{
  "origin": "203.0.113.11"
}
[ec2-user@example-ruby-sinatra-server ~]$ 

[ec2-user@example-ruby-sinatra-server ~]$ curl https://s3-ap-northeast-1.amazonaws.com/example-data-json/test/example.json
[
  {
    "Message":"Hello World"
  }
]
[ec2-user@example-ruby-sinatra-server ~]$ 
```

***

以上になります。