クラウドインテグレーション部の渡邊です。
今回は、S3へのcurlリクエストについて考えます。
EC2からS3へリクエストをすることを想定すると、アクセス制限のまったくないS3バケットは外部からcurlなどを利用してオブジェクト情報を取得できます。
しかし、アクセス制限がある場合はIAMロールの認証情報などを含める必要があります。
curl
コマンドで--aws-sigv4
フラグを使えるようにするために、7.75以上のバージョンが必要です。アクセス先のS3へリクエストを送ると、オブジェクトの一覧を取得できます。
$ aws s3 ls watanabe-object-wp --recursive | grep -v '/$' | awk '{print $4}'
test.txt
中身を見るためにcurlによるオブジェクト情報の読み取りを試みます。
しかし、curlによるファイルの読み取りに失敗します。
$ curl -k -XGET "https://watanabe-object-wp.s3.amazonaws.com/test.txt"
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>SH31WFKGCWH91G00</RequestId><HostId>PeW/1mkgfDLHMFQo/7EAFRk5u7xN+R3AwKygfIDrZfwFOVRxm90VjwUTwP7TZoe8Uq/DgjCcB+Q=</HostId></Error>
なぜなら、リクエスト時にAWSの署名付与していないためです。
これでは、任意の外部のサーバからAWS S3にリクエストしているのと変わりません。
バケットポリシーやブロックパブリックアクセスの設定を変更して、外部からアクセスできるようにしない限り、リクエストは失敗します。
では次に署名情報を付与したリクエストをします。
まずは以下の環境情報を用意してください(リージョン情報などは適宜変更してください)
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
ROLE_NAME=`curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/iam/security-credentials/`
CRED=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/${ROLE_NAME}/`
AWS_ACCESS_KEY_ID=`echo $CRED | jq -r ".AccessKeyId"`
AWS_SECRET_ACCESS_KEY=`echo $CRED | jq -r ".SecretAccessKey"`
AWS_SESSION_TOKEN=`echo $CRED | jq -r ".Token"`
REGION="us-east-1"
SERVICE="s3"
では、リクエストを実行します。
リクエストに含むオブジェクトのURLはAWSのコンソール画面などから取得が可能です。
$ curl -k -XGET "https://watanabe-object-wp.s3.amazonaws.com/test.txt" -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" --aws-sigv4 "aws:amz:${REGION}:${SERVICE}" --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}"
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidRequest</Code><Message>Missing required header for this request: x-amz-content-sha256</Message><RequestId>RFK35PPH28X1NEVV</RequestId><HostId>Ni7j03DDfJVDhYZ8ctSedjs/YG205LucpRfNhMNm2YZJUMe+FQJRw1KRszaAOUka+Slut57e7sM=</HostId></Error>
必要なヘッダがないことが原因で、リクエストに失敗しています。
前項のリクエストにx-amz-content-sha256
ヘッダを含める必要があります。
値として、空文字のハッシュ値を表すe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
を指定すると、リクエストに成功しました。
$ curl -k -XGET "https://watanabe-object-wp.s3.amazonaws.com/test.txt" -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" -H "x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" --aws-sigv4 "aws:amz:${REGION}:${SERVICE}" --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}"
test
ブロックパブリックアクセスをオフにして、バケットポリシーを以下のようにすると外部からもアクセスできるようになり、署名情報や必要なヘッダが含まれていないcurlのリクエストに成功します。
バケットポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::watanabe-object-wp/*"
}
]
}
リクエスト
$ curl -k -XGET "https://watanabe-object-wp.s3.amazonaws.com/test.txt"
test