AWS CLIでサービスの各種コマンドを動かしてみる(S3編1: バケットその1)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

S3編はバケットから攻めてみます。このバケット編然り、またその他の要素についても実行文的に分からない箇所もパラパラと増えて来たような気がします。その辺の詰まった点についても記録として残しておいたので、後日再チャレンジ&読者の方々のフィードバックを得たりしながら改善して行ければと思います。

バケット(bucket/buckets)に関する操作

バケット全般に関する操作は以下4つ。

list-buckets
create-bucket
delete-bucket
head-bucket	

list-buckets

ユーザーアカウントに紐付くS3バケットの一覧を表示します。

$ aws s3 list-buckets | jq '.Buckets[].Name'
"awscli-bucket-acltest"
"awscli-s3bucket"
"awscli-s3bucket-test"
"s3bucket-for-object-test"
"s3bucket-for-object-test-2nd"
"s3bucket-from-awssdk-groovy"
"s3bucket-from-awssdk-java"
"s3bucket-test"

create-bucket

S3バケットを作成します。

まずバケット名のみの指定で作成してみます。んがしかし!『指定された地域は互換性が無い』と言われてしまいました。

$ aws s3 create-bucket --bucket s3bucket-awscli-test
{
    "Errors": [
        {
            "HostId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 
            "Message": "The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.", 
            "Code": "IllegalLocationConstraintException", 
            "RequestId": "E95323BD96AAB311"
        }
    ], 
    "ResponseMetadata": {}
}A client error (IllegalLocationConstraintException) occurred: The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.

この時に設定しているリージョン情報は以下内容でした。

$ echo $AWS_DEFAULT_REGION
ap-northeast-1

調べてみると、以下の情報では、RubyのSDKでeu-west-1とする所を"EU"として実行しています。

試しに"AP"で実践してみましょう。環境変数に設定していた内容を書き換えて再度読み込みます。今度は実行出来ました。

$ echo $AWS_DEFAULT_REGION
AP
$ aws s3 create-bucket --bucket s3bucket-awscli-test
""

今度は環境変数自体を未設定にして試してみます。

$ unset $AWS_DEFAULT_REGION
$ echo $AWS_DEFAULT_REGION
(表示無し)
$

この場合でも問題無く作成出来ました。殊S3に関しては、通常設定しているregion内容が実行時に引っ掛かる事もあるようですね。何か上手い方法無いものかしら?都度環境変数切り替えるのもアレですしね…

$ aws s3 create-bucket --bucket s3bucket-awscli-test-v2
""

delete-bucket

任意のバケットを、バケット名を指定する事で削除します。

$ aws s3 create-bucket --bucket awscli-s3-new-bucket
""
$

head-bucket

バケットの存在及び利用可否を確認します。

指定のバケットが存在し、且つアクセス権限がある場合には空文字が、そうでない場合にはエラーメッセージが添えられて返って来るようです。以下は存在するケース。

$ aws s3 create-bucket --bucket awscli-s3bucket-test 
$ aws s3 head-bucket --bucket awscli-s3bucket-test
""

そしてこちらは存在しないケース。上記で作成したバケットを削除後再度確認しています。(同様に、試しにIAMユーザを作成し(EC2のフルアクセス権限を所有→S3に関する権限は持っていない)そのユーザで上記コマンドを確認してみましたが、同じ出力結果となりました)

$ aws s3 delete-bucket --bucket awscli-s3bucket-test
$ aws s3 head-bucket --bucket awscli-s3bucket-test | jq "."
A client error (Unknown) occurred: Unknown
""

バケットACL(bucket-acl)に関する操作

公式ドキュメント等からざっくり抜粋した要点は以下。

  • ACL(Access Control List)は、バケットやオブジェクトのサブリソースとして付属しており、アクセス許可に関する情報を定義しています。
  • 被付与者(Grantee)に対し、任意のアクセス許可情報を付与する事でアクセス管理を実現しています。
  • 被付与者情報として定義可能なものには、『AWSアカウント』『メールアドレス』『正規ユーザーID(Canonical User ID)』『予め定義されたS3グループ』等があり、また、付与出来るアクセス許可としては『READ』『WRITE』『READ_ACP』『WRITE_ACP』『FULL_CONTROL』があります。
  • ACLには『規定ACL(Canned ACL)』というものも用意されており、これらの定義をそのまま利用する事も可能です。

ACLに関する詳しい解説は以下公式ドキュメントをご参照ください。

そしてバケットACLに関するコマンドは以下の2つ。

get-bucket-acl
put-bucket-acl

get-bucket-acl

バケットに紐付くACL情報を取得します。特に指定せずにバケットを作成すると、バケット名所有者に対する『FULL_CONTROL』が許可されている状態となります。

$ aws s3 create-bucket --bucket awscli-bucket-acltest
""
$ aws s3 get-bucket-acl --bucket awscli-bucket-acltest
{
    "Owner": {
        "DisplayName": "(バケットのオーナー名)",
        "ID": "(オーナーの正規ユーザID文字列)"
    }, 
    "Grants": [
        {
            "Grantee": {
                "DisplayName": "(バケットのオーナー名)", 
                "ID": "(オーナーの正規ユーザID文字列)"
            }, 
            "Permission": "FULL_CONTROL"
        }
    ], 
    "ResponseMetadata": {}
}
$

put-bucket-acl

バケットに対してACL情報を設定します。

『--acl』オプションを指定する事で、規定ACL(Canned ACL)を以って設定する事が可能となります。指定可能な規定ACLの一覧は以下ドキュメントをご参照。

$ aws s3 put-bucket-acl --bucket awscli-bucket-acltest --acl log-delivery-write
""
$ aws s3 get-bucket-acl --bucket awscli-bucket-acltest
{
    "Owner": {
        "DisplayName": "(バケットのオーナー名)",
        "ID": "(オーナーの正規ユーザID文字列)"
    }, 
    "Grants": [
        {
            "Grantee": {
                "DisplayName": "(バケットのオーナー名)", 
                "ID": "(オーナーの正規ユーザID文字列)"
            }, 
            "Permission": "FULL_CONTROL"
        }, 
        {
            "Grantee": {
                "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery"
            }, 
            "Permission": "WRITE"
        }, 
        {
            "Grantee": {
                "URI": "http://acs.amazonaws.com/groups/s3/LogDelivery"
            }, 
            "Permission": "READ_ACP"
        }
    ], 
    "ResponseMetadata": {}
}
$

また、『--access-control-policy』オプションを用いACLの構造体を指定すると、より決め細やかなACLも可能となります。

バケットCORS(bucket-cors)に関する操作

バケットCORSに関するコマンドは以下。

put-bucket-cors
get-bucket-cors

put-bucket-cors

バケットに対し、CORS設定を行います。CORSについては以下のエントリが詳しいです。ざっくり言うと『クロスドメイン対応』、そのアプリケーションのドメイン以外のどのドメインのページならアプリケーションのリソースにアクセスしてもよいか、を指定する方法です。横田さんの以下エントリで詳しく解説されております。

以下公式ドキュメントに設定サンプルなどが載っていますので、参考にしてコマンドを実行してみます。

まずは設定サンプルのファイルを作成。

vi s3cors.json
-----------------
{
  "cors_rules":
  [
    {
      "expose_headers":["x-amz-server-side-encryption","x-amz-request-id","x-amz-id-2"],
      "allowed_methods":["PUT","POST","DELETE"],
      "max_age_seconds":3000,
      "allowed_origins":["http://www.example.com"]
    }
  ]
}

コマンド実行。しかし以下のようにエラーが出てしまいました。ヘルプでは『Content-MD5』は必須とはなっていなかったの(OPTIONAL PATEMETERS扱い)ですが...バケットに対するContent-MD5の設定をどのように行うべきなのか、ちょっと現時点では究明しかねてしまいましたのでここについてはまた後日。

$ aws s3 put-bucket-cors --bucket awscli-s3bucket-test --cors-configuration file://s3cors.json
{
    "Errors": [
        {
            "HostId": "5SE9Z1UVZl2aMplQleOnPtHlNn6xIr7jUc3D9ddme6bcBa8/sqqKl0HnI25v2W2D", 
            "Message": "Missing required header for this request: Content-MD5", 
            "Code": "InvalidRequest", 
            "RequestId": "9783469A64ADD28E"
        }
    ], 
    "ResponseMetadata": {}
}A client error (InvalidRequest) occurred: Missing required header for this request: Content-MD5

試しに、Groovy(経由でAWS SDK for Java)で同様の処理を書いてみます。こっちでは特にContent-MD5に関する設定は必要とされてないですね。う〜む。

AmazonS3Client s3 = new AmazonS3Client(getAwsCredentials());
CORSRule cors = new CORSRule()
    .withExposedHeaders([
        "x-amz-server-side-encryption",
        "x-amz-request-id",
        "x-amz-id-2"])
    .withAllowedMethods([
        CORSRule.AllowedMethods.GET,
        CORSRule.AllowedMethods.GET,
        CORSRule.AllowedMethods.DELETE])
    .withAllowedOrigins([
        "http://www.example1.com",
        "http://www.example2.com",
        "http://www.example3.com"])
    .withMaxAgeSeconds(86400)

List<CORSRule> corsRules = new ArrayList<CORSRule>();
corsRules.add(cors);
BucketCrossOriginConfiguration bucketCors = new BucketCrossOriginConfiguration(corsRules);
s3.setBucketCrossOriginConfiguration("awscli-s3bucket-test", bucketCors);

get-bucket-cors

バケットに関するCORS設定情報を取得します。上記Groovyで設定した内容を管理コンソールで見てみます。ちゃんと反映されていますね。

s3cors

awscliコマンドでは以下の形で取得出来ます。

$ aws s3 get-bucket-cors --bucket awscli-s3bucket-test
{
    "CORSRules": [
        {
            "AllowedOrigins": [
                "http://www.example1.com", 
                "http://www.example2.com", 
                "http://www.example3.com"
            ], 
            "MaxAgeSeconds": 86400, 
            "AllowedMethods": [
                "GET", 
                "GET", 
                "DELETE"
            ], 
            "ExposeHeaders": [
                "x-amz-server-side-encryption", 
                "x-amz-request-id", 
                "x-amz-id-2"
            ]
        }
    ], 
    "ResponseMetadata": {}
}

バケットのライフサイクル(bucket-lifecycle)に関する操作

関連するコマンドは以下。

get-bucket-lifecycle
put-bucket-lifecycle

get-bucket-lifecycle

バケットに設定されているライフサイクル設定を取得します。

まず素のバケットからgetしてみます。無いと言われました。

$ aws s3 get-bucket-lifecycle --bucket s3bucket-awscli-test
{
    "Rules": [], 
    "Errors": [
        {
            "HostId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 
            "Message": "The lifecycle configuration does not exist", 
            "Code": "NoSuchLifecycleConfiguration", 
            "BucketName": "s3bucket-awscli-test", 
            "RequestId": "1D04AB299DB020AD"
        }
    ], 
    "ResponseMetadata": {}
}A client error (NoSuchLifecycleConfiguration) occurred: The lifecycle configuration does not exist

管理コンソールで内容を見てみる。Glacierのアーカイブ及び削除に関する設定を行う箇所のようです。

  • ライフサイクルルールを用いて、オブジェクトのライフサイクルを管理する事が出来ます。
  • ルールを使うことで、あなたは自動的にAmazon Glacierへオブジェクトのアーカイブを行う事が出来ます。そして予め決めて置いた時間が来たら削除する事も出来ます。
  • 各ルールは、オブジェクトそれぞれ、または共通の接頭辞を共有するオブジェクトの集合に対してまとめて設定することができます。

s3-bucket-lifecycle_01

その他、ライフサイクルに関する情報は以下を参照。

ひとまず設定を追加してみましょう。

s3-bucket-lifecycle_02

s3-bucket-lifecycle_04

そして再度チャレンジ。今度は結果を取得出来ました。

$ aws s3 get-bucket-lifecycle --bucket s3bucket-awscli-test
{
    "Rules": [
        {
            "Status": "Enabled", 
            "Prefix": "s3test", 
            "Transition": {
                "Days": 28, 
                "StorageClass": "GLACIER"
            }, 
            "ID": "S3-archive-rule-for-awsclitest", 
            "Expiration": {
                "Days": 120
            }
        }
    ], 
    "ResponseMetadata": {}
}

put-bucket-lifecycle

バケットに対してライフサイクルの設定を更新します。既に情報が存在する場合、内容を上書き更新します。

ヘルプのJSONフォーマット、get--で得た情報を元にJSONファイルを作成してみます。

{
  "rules":[
    {
      "expiration": { "days": 180 },
      "id": "S3-archive-rule-for-awsclitest",
      "prefix": "s3test",
      "status": "Enalbed",
      "transition": {
        "days": 35,
        "storage_class": "REDUCED_REDUDANCY"
      }
    }
  ]
}

実行。content-md5に関する問題でコケますね…これはバケットに関するContent-MD5の値を設定する必要があるという事なのでしょうか?どこから取得・算出出来るのかな?幾つか調べてみましたがちょっと究明出来なかったです...。

$ aws s3 put-bucket-lifecycle --bucket s3bucket-awscli-test --lifecycle-configuration file://updateLifecycle.json
{
    "Errors": [
        {
            "HostId": "UeT4dzBM+aOk4t8niR/73X40+0BHoO/qh43k3Ysl35ZFUnsU/h1j1PbLx74hoqP7", 
            "Message": "Missing required header for this request: Content-MD5", 
            "Code": "InvalidRequest", 
            "RequestId": "B0A5772557DBDD01"
        }
    ], 
    "ResponseMetadata": {}
}A client error (InvalidRequest) occurred: Missing required header for this request: Content-MD5

バケットロギング(bucket-logging)に関する操作

対応するコマンドは以下2つ。

get-bucket-logging
put-bucket-logging

そして詳細については以下をご参照

get-bucket-logging

s3-bucket-logging_01

そしてコマンド実行。以下の内容で取得出来ました。

$ aws s3 get-bucket-logging --bucket s3bucket-awscli-test
{
    "LoggingEnabled": {
        "TargetPrefix": "logs/", 
        "TargetBucket": "s3bucket-awscli-test"
    }, 
    "ResponseMetadata": {}
}

put-bucket-logging

バケットのロギングパラメータを設定し、ロギングパラメータを表示・変更出来るユーザーの権限を指定します。バケットのロギングステータスを設定するには、バケットの所有者でなければなりません。

バケットのロケーション(bucket-location)に関する操作

get-bucket-location

get-bucket-location

バケットが属する地域を返します。…とありますが、実際実行してみると何も返って来ません。

s3に於いては地域が不要となっているところと何か関係があるのでしょうか。

$ aws s3 get-bucket-location --bucket s3bucket-awscli-test
{
    "ResponseMetadata": {}
}

バケット通知(bucket-notification)に関する操作

get-bucket-notification
put-bucket-notification

get-bucket-notification

バケット通知に関する情報を取得します。特に何もしてない状況で実行してみたところ、こんな感じでエラーが。

$ aws s3 get-bucket-notification --bucket s3bucket-awscli-test
{
    "Errors": [
        {
            "HostId": "K+y3G8qhMeLLLV540C8rHE5c5D8/SR9lWph67eR17koBZXnUd/FyBmDPIN62XIVX", 
            "AWSAccessKeyId": "XXXXXXXXXXXXXXXXXXXXXXXXX", 
            "StringToSign": "GET\n\n\nSat, 27 Jul 2013 17:29:49 GMT\n/s3bucket-awscli-test?notification", 
            "StringToSignBytes": "47 45 54 0a 0a 0a 53 (中略) 63 61 74 69 6f 6e", 
            "Code": "SignatureDoesNotMatch", 
            "RequestId": "68B3778194A1AC89", 
            "Message": "The request signature we calculated does not match the signature you provided. Check your key and signing method.", 
            "SignatureProvided": "UXh80Y2GSm5CcCnQSz67CKqXSi8="
        }
    ], 
    "ResponseMetadata": {}, 
    "TopicConfiguration": {}
}A client error (SignatureDoesNotMatch) occurred: The request signature we calculated does not match the signature you provided. Check your key and signing method.

管理コンソールを見ると、SNSのTopicを設定する欄があります。

s3-bucket-notification_01

まずは適当に通知用のTopicを作成。そしてNotificationに作成したTopicのARNを設定。…しかしエラーとなってしまいます。Regionに関する部分で指摘されているようです。

s3-bucket-notification_02.png

SNS利用時のリージョンはTokyoでした。S3でもてっきりTokyoで作成してたと思っていたのですが...管理コンソールを見てみると地域は"Global"となっており、『S3 does not require region selection.(S3は地域の選択を必要としません)』との文章が。

s3-bucket-notification_03v

上記メッセージで調べてみると、AWSのForumにもやり取りが挙がってました。

以下、やり取りをざっくり適当訳。

  • S3は地域選択を必要としてません。でも以前は地域を選べました。何で今出来ないようになってるの?
  • 管理インターフェース上ではグローバルですが、各バケットはあなたが作成時に選択していたregionに位置しています。
  • 全てのバケットは、地域に関係無く、一覧表示されます。
  • バケットを選択すると、右側の”プロパティ"領域内に地域を確認する事が出来ます。

とあります。見てみると確かにありました。あれ?US Standardになってる。普段通りアジアを選択していたつもりなのに…何も指定しないで作成するとUS Standardになってしまうのかな。

s3-bucket-notification_04

awscliでのcreate-bucketコマンドを改めて見てみます。オプションで、以下の様にリージョンを指定出来るようです。

JSON Parameter Syntax
{
  "location_constraint": "EU"|"eu-west-1"|"us-west-1"|"us-west-2"|"ap-southeast-1"|"ap-northeast-1"|"sa-east-1"|""
}

地域を指定しつつ、別途バケットを作成してみます。

$ aws s3 create-bucket --bucket s3bucket-awscli-test-asia --create-bucket-configuration '{ "location_constraint": "ap-northeast-1"}'
""

今度はちゃんと地域がTokyoになってますね。

s3-bucket-notification_05

新しく作ったバケットの方に先程作ったトピックを設定してみます。今度は保存出来ました。

s3-bucket-notification_06

地域を指定しつつ、get-bucket-notificationコマンドを実行。しかしまだエラーが...。この『SignatureDoesNotMatch』に関しては他の箇所でも幾つか出て来ていたので、別の機会に改めて解決を試みてみたいと思います。

$ aws s3 get-bucket-notification --bucket s3bucket-awscli-test-asia --region ap-northeast-1
{
    "Errors": [
        {
            "HostId": "tERclt+9OcPe0CJKybS+VJp6Ac7hZ8gkcbdyB5G8iu60Sf/lrB33lfcBIxyjIKlA", 
            "AWSAccessKeyId": "XXXXXXXXXXXXXXXXXXXX", 
            "StringToSign": "GET\n\n\nSat, 27 Jul 2013 18:55:55 GMT\n/s3bucket-awscli-test-asia?notification", 
            "StringToSignBytes": "47 45 54 0a 0a (中略) 69 63 61 74 69 6f 6e", 
            "Code": "SignatureDoesNotMatch", 
            "RequestId": "89C4FF6D9CCA6593", 
            "Message": "The request signature we calculated does not match the signature you provided. Check your key and signing method.", 
            "SignatureProvided": "LkgG7FO2i3A+zMTLzDeIWYytmUs="
        }
    ], 
    "ResponseMetadata": {}, 
    "TopicConfiguration": {}
}A client error (SignatureDoesNotMatch) occurred: The request signature we calculated does not match the signature you provided. Check your key and signing method.

put-bucket-notification

バケットの通知設定を更新します。ヘルプを参考に、以下のJSONファイルを作成して新規作成したバケットに適用させてみようと思います。

$ aws s3 create-bucket --bucket s3bucket-awscli-test-ntf --create-bucket-configuration '{ "location_constraint": "ap-northeast-1" }'
$ vi bucket-notification.json
----------
{
  "topic_configuration": {
    "event": "s3:ReducedRedundancyLostObject",
    "topic": "arn:aws:sns:ap-northeast-1:317282958305:s3-notification"
  }
}
----------
$ aws s3 put-bucket-notification --bucket s3bucket-awscli-test-ntf --region ap-northeast-1 --notification-configuration file://bucket-notification.json
{
    "Errors": [
        {
            "HostId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 
            "AWSAccessKeyId": "XXXXXXXXXXXXXXXXXXXX", 
            "StringToSign": "PUT\n\n\nSun, 28 Jul 2013 14:01:27 GMT\n/s3bucket-awscli-test-asia?notification", 
            "StringToSignBytes": "50 55 54 (中略) 61 74 69 6f 6e", 
            "Code": "SignatureDoesNotMatch", 
            "RequestId": "A8BEA81A8A0E774A", 
            "Message": "The request signature we calculated does not match the signature you provided. Check your key and signing method.", 
            "SignatureProvided": "GPqghHm6DNQj0gyMNdmCkx+erjo="
        }
    ], 
    "ResponseMetadata": {}
}A client error (SignatureDoesNotMatch) occurred: The request signature we calculated does not match the signature you provided. Check your key and signing method.

get-bucket-notificationと同じエラーが出てしまいました。バケットに関してはこの辺の問題は共通して立ちはだかっているようですね...