【AWS API入門】CurlコマンドでAWS APIを利用したS3バケットの操作の基礎を理解しよう


※ 当ページには【広告/PR】を含む場合があります。
2024/12/26
【AWS Lambda使い方ガイド】odemailerのAWS SESクライアントを使ってLambdaからEmailを送信してみる
蛸壺の技術ブログ|CurlコマンドでAWS APIを利用したS3バケットの操作の基礎を理解しよう

AWS APIを使えばAWSの各種サービスを多様なクライアントエージェント側から操作できるようになります。

ただし、AWSサーバー側へアクセスするためには、
『AWS Signature V4』(以降SigV4)で署名を作成する必要があります。

とりわけネットワーク技術者には馴染み深いであろう「Curl」コマンドでは、Ver.7.75以降に追加された
「--aws-sigv4」オプションを使うことで、独自のロジックを実装することなく、SigV4でAuthorizationヘッダーに署名を付与してAWS側にアクセスできるようになっています。

今回は、AWS S3を対象に、いくつかAWS APIを利用したスクリプト例を試して、実際どのように使うのかを検証してみます。


合同会社タコスキングダム|蛸壺の技術ブログ【AWS独習術】AWSをじっくり独学したい人のためのオススメ書籍&教材特集

図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書

ListBuckets相当のAPIコマンド

S3に限らず他のサービスのAPIにも共通しますが、適切な実行権限を与えられたIAMユーザーのアクセスキーID(AWS_ACCESS_KEY_ID)アクセス秘密鍵(AWS_SECRET_ACCESS_KEY)が必要になります。

参考|AWS アクセスキー

AWSクレデンシャルは既に発行されているものとして、以下話を進めていきます。

手始めに、特定のリージョン内に置かれた個人管理のS3バケットを一覧として表示させるやつです。

参考|ListBuckets

例として
ap-northeast-1のリージョンにあるバケットを表示させてみますが、他のリージョンで取得する場合にはURLをhttps://s3.<リージョン名>.amazonaws.com/としてください。

            
            $ curl -XGET "https://s3.ap-northeast-1.amazonaws.com/" \
    --aws-sigv4 "aws:amz:ap-northeast-1:s3" \
    --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
    -vs
#👇出力例
* Host s3.ap-northeast-1.amazonaws.com:443 was resolved.
* IPv6: (none)
* IPv4: xxx.xxx.xxx.xxx,...
*   Trying xxx.xxx.xxx.xxx:443...
* Connected to s3.ap-northeast-1.amazonaws.com (xxx.xxx.xxx.xxx) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / x25519 / RSASSA-PSS
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=*.s3-ap-northeast-1.amazonaws.com
*  start date: Oct 26 00:00:00 2024 GMT
*  expire date: Oct 25 23:59:59 2025 GMT
*  subjectAltName: host "s3.ap-northeast-1.amazonaws.com" matched cert's "s3.ap-northeast-1.amazonaws.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M01
*  SSL certificate verify ok.
*   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* using HTTP/1.x
* Server auth using AWS_SIGV4 with user 'XXXXXXXXXXXXXXXXXXXX'
> GET / HTTP/1.1
> Host: s3.ap-northeast-1.amazonaws.com
> Authorization: AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20241224/ap-northeast-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxf
> X-Amz-Date: 20241224T071811Z
> x-amz-content-sha256: exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5
> User-Agent: curl/8.9.0
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 200 OK
< x-amz-id-2: /+TxxxxxxxxF/Cxxxxxxxxxxxxxxxxxxxxxxxxxf/uxxxxxxxi
< x-amz-request-id: 4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4
< Date: Tue, 24 Dec 2024 07:21:52 GMT
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Server: AmazonS3
< 
<?xml version="1.0" encoding="UTF-8"?>
<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>9xxxxxxxxxf</ID><DisplayName>xxxxxxxxx</DisplayName></Owner><Buckets><Bucket><Name>xxxxxxxxxxxx</Name><CreationDate>2024-11-09T01:42:18.000Z</CreationDate></Bucket>...</Buckets></ListAllMyBucketsResult>* Connection #0 to host s3.ap-northeast-1.amazonaws.com left intact
        
というようにXML形式のレスポンスで、S3バケットの一覧結果が返ってくると成功です。

このときのCurlコマンドについて解説をしておくと、
--aws-sigv4 "aws:amz:ap-northeast-1:s3"のオプション部分でSigV4をリクエストに自動署名させている部分になります。"aws:amz:ap-northeast-1:s3"は順に、プロバイダー1(aws)、プロバイダー2(amz)、リージョン名、サービス名を指定します。

これだけでHTTPメソッド、クレデンシャル情報、ヘッダー、ペイロードから算出されたSigV4値を
Authorizationリクエストヘッダーに入れて送り出してくれるようになります。

クレデンシャル情報については、
--user "<アクセスキーID>:<アクセス秘密鍵>"のオプションで指定してください。

補遺〜RoleからAWSクレデンシャルを得る

上述したように、AWS APIでの特定の操作に適切な権限をもったIAMユーザーを事前に設計しておくことが前提としてあります。

個人アカウントで開発段階でサッと試したいだけなどであれば場合によっては、既存のIAMロールからSTSを使って一時的なクレデンシャルを取得することで、AWS APIを扱うことも可能です。

例えば、Lambdaへフルアクセスしたい場合、
LambdaFullAccessのIAMロールを通じてSTSのassume-roleから期限付きクレデンシャルを発行することも可能です。

            
            $ session=$(aws sts assume-role \
    --role-arn arn:aws:iam::<AWSのアカウントID>:role/LambdaFullAccess \
    --role-session-name "role_session"
)

#👇取得したクレデンシャルを変数にセット
$ AWS_ACCESS_KEY_ID=$(echo "${session}" | jq -r ".Credentials.AccessKeyId")
$ AWS_SECRET_ACCESS_KEY=$(echo "${session}" | jq -r ".Credentials.SecretAccessKey")
$ AWS_SESSION_TOKEN=$(echo "${session}" | jq -r ".Credentials.SessionToken")
        
IAMロールからクレデンシャルを得る方法はこの記事では使いませんが、MFAなどの多重認証の仕組みと組み合わせて、セッショントークンを生成するなど、よりセキュアなAPIでの運用が可能となります。

公式としても、セッショントークンを積極的に利用する方法を推奨しているようです。


合同会社タコスキングダム|蛸壺の技術ブログ【AWS独習術】AWSをじっくり独学したい人のためのオススメ書籍&教材特集

図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書

CreateBucket相当のAPIコマンド

次にap-northeast-1にバケットを新規作成するCurlコマンドの例も試してみましょう。

参考|CreateBucket

このコマンドは、"汎用バケット"を作成する場合の例です。

適当なところで新規作成するバケット名は
hoge-hoge-hogeとします。

            
            $ curl -XPUT "https://hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com/" \
    --header "x-amz-date: $(date -u +%Y%m%dT%H%M%SZ)" \
    --header "Content-Type: application/xml" --data "<CreateBucketConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><LocationConstraint>ap-northeast-1</LocationConstraint></CreateBucketConfiguration>" \
    --aws-sigv4 "aws:amz:ap-northeast-1:s3" \
    --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
    -vs
#👇結果
* Host hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com:443 was resolved.
* IPv6: (none)
* IPv4: xxx.xxx.xxx.xxx, ...
*   Trying xxx.xxx.xxx.xxx:443...
* Connected to hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com (xxx.xxx.xxx.xxx) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / x25519 / RSASSA-PSS
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=*.s3-ap-northeast-1.amazonaws.com
*  start date: Oct 26 00:00:00 2024 GMT
*  expire date: Oct 25 23:59:59 2025 GMT
*  subjectAltName: host "hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com" matched cert's "*.s3.ap-northeast-1.amazonaws.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M01
*  SSL certificate verify ok.
*   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* using HTTP/1.x
* Server auth using AWS_SIGV4 with user 'XXXXXXXXXXXXXXXXXXXX'
> PUT / HTTP/1.1
> Host: hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com
> Authorization: AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20241224/ap-northeast-1/s3/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7
> x-amz-content-sha256: 2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2
> User-Agent: curl/8.9.0
> Accept: */*
> x-amz-date: 20241224T124136Z
> Content-Type: application/xml
> Content-Length: 159
> 
* upload completely sent off: 159 bytes
< HTTP/1.1 200 OK
< x-amz-id-2: WxxxxxxxxxxxR/sxxxxxxxxxxY/lxxxxxxxxxxxJ/Vxxxxxxxxxxx3/Wxxxxxxxxxxxxxxxxx=
< x-amz-request-id: 2xxxxxxxxxxxxxxxxS
< Date: Tue, 24 Dec 2024 12:41:41 GMT
< Location: http://hoge-hoge-hoge.s3.amazonaws.com/
< Content-Length: 0
< Server: AmazonS3
< 
* Connection #0 to host hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com left intact
        
エラーも発生せず処理が完了し、ap-northeast-1hoge-hoge-hogeという空バケットが作成されたことが通知されます。

コマンドの方を少し解説すると、
https://<バケット名>.s3.ap-northeast-1.amazonaws.com/がCreateBucketのAPIエンドポイントURLです。<バケット名>の箇所に新規に作成するバケット名を指定します。

また、
--header "x-amz-date: <DATE>"のヘッダーはリクエスト時の日付を指定します。

この日付情報をリクエストヘッダーへ組み込むことはAWS APIを使うにあたっては重要なポイントとなり、
<DATE>には現在の日付をISO8601形式(の略記系 ... 20240101T000000Zなど)で置き換える必要があります。

この辺は後述する節で詳しく説明します。

なお、
ディレクトリバケット(S3 Express One Zone)を作成する場合は、エンドポイントURLやリクエストヘッダーが異なりますのでご注意ください。

補遺〜AWS APIのDateヘッダーとx-amz-dateヘッダーの区別

SigV4で署名の材料として重要かつ理解しづらいのが、
「Dateヘッダー」です。

単なる日付を記すだけのヘッダーではなく、利用にはいくつかの規約が存在します。

公式の
Common Request Headersにもあるように、

            
            Date:
    The date that can be used to create the signature contained in the Authorization header.
    If the Date header is to be used for signing it must be specified in the ISO 8601 basic format.
    In this case, the x-amz-date header is not needed.

    Note that when x-amz-date is present, it always overrides the value of the Date header.

    If the Date header is not used for signing, it can be one of the full date formats specified by RFC 2616, section 3.3.
    For example, the date/time Wed, 01 Mar 2006 12:00:00 GMT is a valid date/time header for use with Amazon S3.

    If you are using the Date header for signing, then it must be in the ISO 8601 basic YYYYMMDD'T'HHMMSS'Z' format.
    If Date is specified but is not in ISO 8601 basic format, then you must also include the x-amz-date header.
    If Date is specified in ISO 8601 basic format, then this is sufficient for signing requests and you do not need the x-amz-date header.
    For more information, see Handling Dates in Signature Version 4 in the Amazon Web Services Glossary.

x-amz-date:
    The date used to create the signature in the Authorization header.
    The format must be ISO 8601 basic in the YYYYMMDD'T'HHMMSS'Z' format.
    For example, the date/time 20170210T120000Z is a valid x-amz-date for use with Amazon S3.
    x-amz-date is optional for all requests; it can be used to override the date used for signing requests. If the Date header is specified in the ISO 8601 basic format, then x-amz-date is not needed. When x-amz-date is present, it always overrides the value of the Date header. For more information, see Handling Dates in Signature Version 4 in the Amazon Web Services Glossary.
        
ということで、要点だけ掻い摘むと、

            
            + SigV4の署名としてDateヘッダーを使うなら、「ISO8601」形式(YYYYMMDD'T'HHMMSS'Z')に従うこと
+ DateヘッダーをISO8601形式とした場合、x-amz-dateヘッダーは必要ない
+ x-amz-dateが存在する場合はこちらが優先され、Dateヘッダーの値は上書きされる
+ DateヘッダーをSigV4の署名情報として利用したくない場合、
    値をISO8601形式以外に設定し、x-amz-dateヘッダーにはISO8601形式の日付を与えること
        
というルールが存在しているようです。

つまり、Dateヘッダーは多目的な役割をもつことができる一方で、x-amz-dateヘッダーはSigV4署名専用で他には影響を与えません。

そもそもこの記事に辿り着かれた方にとっては、「DateをSigV4署名に正しく入力したい」を思われているわけですので、
「x-amz-dateにISO8601形式で書く」のがもっとも問題が起こりにくい使い方になると思います。

逆にDateヘッダーは別のAPIサービスでもその値を利用する場合も考えられるため、こちらを常にISO8601形式で使っていると、いざというときにバグに気づきにくい問題が起こる可能性も考えられます。

ShellコマンドでUTCかつISO8601の簡略形式に仕立てたい場合には、例えば以下のような感じにします。

            
            $ date -u +"%Y%m%dT%H%M%SZ"
20241224T075233Z
        
なお、DateコマンドはPCの内部時間を取得するため、実際のサーバー側の時間とのズレが大きい場合には問題が起こるかもしれませんので、APIを叩く前にちゃんと時計を合わせておきましょう。


合同会社タコスキングダム|蛸壺の技術ブログ【AWS独習術】AWSをじっくり独学したい人のためのオススメ書籍&教材特集

図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書

DeleteBucket相当のコマンド

もう一例、空のバケットの削除を行うAPIも試してみましょう。

参考|DeleteBucket

考え方としては先程のCreateBucketと同じですが、HTTPメソッドは
DELETEになることに注意しましょう。

先程作成した
hoge-hoge-hogeバケットを早速消してみます。

            
            $ curl -XDELETE "https://hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com/" \
    --header "x-amz-date: $(date -u +%Y%m%dT%H%M%SZ)" \
    --aws-sigv4 "aws:amz:ap-northeast-1:s3" \
    --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
    -vs
#👇結果
* Host hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com:443 was resolved.
* IPv6: (none)
* IPv4: xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx
*   Trying xxx.xxx.xxx.xxx:443...
* Connected to hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com (xxx.xxx.xxx.xxx) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / x25519 / RSASSA-PSS
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=*.s3-ap-northeast-1.amazonaws.com
*  start date: Oct 26 00:00:00 2024 GMT
*  expire date: Oct 25 23:59:59 2025 GMT
*  subjectAltName: host "hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com" matched cert's "*.s3.ap-northeast-1.amazonaws.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M01
*  SSL certificate verify ok.
*   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* using HTTP/1.x
* Server auth using AWS_SIGV4 with user 'XXXXXXXXXXXXXXXXXXXX'
> DELETE / HTTP/1.1
> Host: hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com
> Authorization: AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20241224/ap-northeast-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=3xxxxxxxxxxxxxxxxxxxxxxxx5
> x-amz-content-sha256: exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5
> User-Agent: curl/8.9.0
> Accept: */*
> x-amz-date: 20241224T161715Z
> 
* Request completely sent off
< HTTP/1.1 204 No Content
< x-amz-id-2: Qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
< x-amz-request-id: 7xxxxxxxxxxxxxxxxxxQ
< Date: Tue, 24 Dec 2024 16:17:20 GMT
< Server: AmazonS3
< 
* Connection #0 to host hoge-hoge-hoge.s3.ap-northeast-1.amazonaws.com left intact
        
バケットリストから削除対象のバケットが消えていたらAPIの動作確認OKです。


合同会社タコスキングダム|蛸壺の技術ブログ【AWS独習術】AWSをじっくり独学したい人のためのオススメ書籍&教材特集

図解即戦力 Amazon Web Servicesのしくみと技術がこれ1冊でしっかりわかる教科書

まとめ

以上、AWS APIからS3を対象にListbucketsCreateBucketDeleteBucket、の3つを例にCurlコマンドで操作する内容をお届けしました。

取り上げた3つに限らず、AWS APIにはまだまだ便利なアクションが数多く存在していますので、今回のやり方を参考に、各自Curlコマンドからローカルで事前の動作チェックを行うと良いでしょう。

何かしらのプロダクトで利用するFetch APIから、AWS APIを叩く前のリクエスト確認ツールとして、Curlコマンドはとても重宝すると思います。

参考サイト

curl で AWS API を叩いてみた

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。

合同会社タコスキングダム|蛸壺の技術ブログ【AWS独習術】AWSをじっくり独学したい人のためのオススメ書籍&教材特集