APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【AWS】curlでAWS Signature Version 4 (AWS SigV4) を使用してみた

目次

はじめに

こんにちは、クラウド事業部の菅です。

前回の記事投稿後にcurlコマンドによるアクセス方法を調べていたところ、AWS Signature Version 4 (AWS SigV4)を使用したアクセス方法があることを知りました。
docs.aws.amazon.com

今回は、AWS SigV4をcurlで使用してAWSの操作を行ってみたいと思います。

※AWS SigV4について詳しく説明している記事が既にありますので、説明は省略します。

techblog.ap-com.co.jp

AWS SigV4を使用する

認証情報の取得

AWS SigV4を使用するためには、アクセスキーIDやシークレットアクセスキーなどの認証情報が必要です。
EC2インスタンスにアタッチされたIAMロールから認証情報を取得できるので、インスタンスメタデータ (IMDSv2) から認証情報を取得します。

sh-5.2$ TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 3600"`
sh-5.2$ PROFILE=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/`
sh-5.2$ CREDENTIALS=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$PROFILE`
sh-5.2$ echo $CREDENTIALS | jq 'keys'
[
  "AccessKeyId",
  "Code",
  "Expiration",
  "LastUpdated",
  "SecretAccessKey",
  "Token",
  "Type"
]

S3の操作

APIリファレンスを参考に、curlを使用してS3バケットの操作を行います。
docs.aws.amazon.com

ListObjectV2

S3バケット「apc-kan-s3-bucket」に格納されているファイルの一覧を取得します。

sh-5.2$ curl -s "https://apc-kan-s3-bucket.s3.ap-northeast-3.amazonaws.com/?list-type=2" --aws-sigv4 "aws:amz:ap-northeast-3:s3" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`" | xmllint --format -
<?xml version="1.0" encoding="UTF-8"?><ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Name>apc-kan-s3-bucket</Name>
  <Prefix/>
  <KeyCount>1</KeyCount>
  <MaxKeys>1000</MaxKeys>
  <IsTruncated>false</IsTruncated>
  <Contents>
    <Key>test.txt</Key>
    <LastModified>2025-04-17T01:08:51.000Z</LastModified>
    <ETag>"fe8e2156220b7550626693c26baeb2fe"</ETag>
    <ChecksumAlgorithm>CRC64NVME</ChecksumAlgorithm>
    <ChecksumType>FULL_OBJECT</ChecksumType>
    <Size>35</Size>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
</ListBucketResult>

S3オブジェクト内に「test.txt」というファイルが格納されていることを確認できました。

GetObject

S3バケット内のファイルにアクセスします。

sh-5.2$ curl -s https://apc-kan-s3-bucket.s3.ap-northeast-3.amazonaws.com/test.txt
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>XAMES1H8P7JTW27T</RequestId><HostId>(省略)</HostId></Error>sh-5.2$
sh-5.2$ curl -s "https://apc-kan-s3-bucket.s3.ap-northeast-3.amazonaws.com/test.txt" --aws-sigv4 "aws:amz:ap-northeast-3:s3" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`"
This is the contents of test.txt!

AWS SigV4無しではアクセスが拒否されましたが、AWS SigV4有りでは許可されました。

PutObject

S3バケットへファイルをアップロードします。

sh-5.2$ cat << EOS > test2.txt
> ----- test2 text -----
> EOS
sh-5.2$ aws s3 ls s3://apc-kan-s3-bucket
2025-04-17 01:08:51         35 test.txt
sh-5.2$ curl -T test2.txt "https://apc-kan-s3-bucket.s3.ap-northeast-3.amazonaws.com" --aws-sigv4 "aws:amz:ap-northeast-3:s3" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`"
sh-5.2$ aws s3 ls s3://apc-kan-s3-bucket
2025-04-17 01:08:51         35 test.txt
2025-04-17 01:27:34         23 test2.txt
sh-5.2$ curl -s "https://apc-kan-s3-bucket.s3.ap-northeast-3.amazonaws.com/test2.txt" --aws-sigv4 "aws:amz:ap-northeast-3:s3" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`"
----- test2 text -----

S3バケットへファイルをアップロードすることができました。
また、ファイルアップロード後にGetObjectアクションを使用してテキストデータが正常にアップロードされていることも確認できました。

DeleteObject

S3バケットに格納されているファイルを削除します。
今回は、S3バケットに格納されているファイル「test.txt」「test2.txt」のうち、「test.txt」のみ削除します。

sh-5.2$ aws s3 ls s3://apc-kan-s3-bucket
2025-04-17 01:08:51         35 test.txt
2025-04-17 01:27:34         23 test2.txt
sh-5.2$ curl -X DELETE https://apc-kan-s3-bucket.s3.ap-northeast-3.amazonaws.com/test.txt --aws-sigv4 "aws:amz:ap-northeast-3:s3" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`"
sh-5.2$ aws s3 ls s3://apc-kan-s3-bucket
2025-04-17 01:27:34         23 test2.txt

S3バケットからファイルを削除することができました。

EC2の操作

S3の操作ができましたので、EC2の操作も行ってみます。

docs.aws.amazon.com

DescribeRouteTables

VPCルートテーブルの一覧を取得します。
※VPCルートテーブルの数が多いので、ルートテーブルIDでフィルタしています。

sh-5.2$ curl "https://ec2.ap-northeast-3.amazonaws.com/?Action=DescribeRouteTables&Version=2016-11-15&RouteTableId.1=rtb-02cf6277a355f6a69" --aws-sigv4 "aws:amz:ap-northeast-3:ec2" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Tok
en'`"
<?xml version="1.0" encoding="UTF-8"?>
<DescribeRouteTablesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
    <requestId>7bd784dc-3cf5-46af-b1b7-30faccfd4383</requestId>
    <routeTableSet>
        <item>
            <routeTableId>rtb-02cf6277a355f6a69</routeTableId>
            <vpcId>vpc-0dbe445807821e5a8</vpcId>
            <ownerId>(省略)</ownerId>
            <routeSet>
                <item>
                    <destinationCidrBlock>10.0.0.0/24</destinationCidrBlock>
                    <gatewayId>local</gatewayId>
                    <state>active</state>
                    <origin>CreateRouteTable</origin>
                </item>
            </routeSet>
            <associationSet>
                <item>
                    <routeTableAssociationId>rtbassoc-0a22f5c5ac9bf52fc</routeTableAssociationId>
                    <routeTableId>rtb-02cf6277a355f6a69</routeTableId>
                    <main>true</main>
                    <associationState>
                        <state>associated</state>
                    </associationState>
                </item>
            </associationSet>
            <propagatingVgwSet/>
            <tagSet/>
        </item>
    </routeTableSet>
</DescribeRouteTablesResponse>sh-5.2$

DescribeSecurityGroups

セキュリティグループの一覧を表示します。
※セキュリティグループの数が多いので、セキュリティグループIDでフィルタしています。

</DescribeRouteTablesResponse>sh-5.2$ curl "https://ec2.ap-northeast-3.amazonaws.com/?Action=DescribeSecurityGroups&Version=2016-11-15&GroupId.1=sg-035ab51ee395f801e" --aws-sigv4 "aws:amz:ap-northeast-3:ec2" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo
 $CREDENTIALS | jq -r '.Token'`"
<?xml version="1.0" encoding="UTF-8"?>
<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
    <requestId>6c2958a6-2125-4279-aa7a-7c4bf9ec9b7d</requestId>
    <securityGroupInfo>
        <item>
            <ownerId>(省略)</ownerId>
            <groupId>sg-035ab51ee395f801e</groupId>
            <groupName>apc-kan-test-stack2-SecurityGroupEC2-gLim3KcG9leR</groupName>
            <groupDescription>VPC Endpoint</groupDescription>
            <vpcId>vpc-0dbe445807821e5a8</vpcId>
            <ipPermissions/>
            <ipPermissionsEgress>
                <item>
                    <ipProtocol>-1</ipProtocol>
                    <groups/>
                    <ipRanges>
                        <item>
                            <cidrIp>0.0.0.0/0</cidrIp>
                        </item>
                    </ipRanges>
                    <ipv6Ranges/>
                    <prefixListIds/>
                </item>
            </ipPermissionsEgress>
            <tagSet>
                <item>
                    <key>aws:cloudformation:stack-name</key>
                    <value>apc-kan-test-stack2</value>
                </item>
                <item>
                    <key>aws:cloudformation:logical-id</key>
                    <value>SecurityGroupEC2</value>
                </item>
                <item>
                    <key>Name</key>
                    <value>apc-kan-sg-ec2</value>
                </item>
                <item>
                    <key>aws:cloudformation:stack-id</key>
                    <value>arn:aws:cloudformation:ap-northeast-3:(省略):stack/apc-kan-test-stack2/1206b150-1b1f-11f0-b8fa-0635c5a004ad</value>
                </item>
            </tagSet>
            <securityGroupArn>arn:aws:ec2:ap-northeast-3:(省略):security-group/sg-035ab51ee395f801e</securityGroupArn>
        </item>
    </securityGroupInfo>
</DescribeSecurityGroupsResponse>sh-5.2$

DescribeInstances

EC2インスタンスの一覧を表示します。
※EC2インスタンスの数が多いので、インスタンスIDでフィルタしています。

sh-5.2$ curl "https://ec2.ap-northeast-3.amazonaws.com/?Action=DescribeInstances&Version=2016-11-15&InstanceId=i-08c4bec27b91b32fe" --aws-sigv4 "aws:amz:ap-northeast-3:ec2" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`"
<?xml version="1.0" encoding="UTF-8"?>
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
    <requestId>42e443a6-f7ed-40ce-a48c-66cb5a300fea</requestId>
    <reservationSet>
        <item>
            <reservationId>r-0dee8c953f7041ef5</reservationId>
            <ownerId>(省略)</ownerId>
            <groupSet/>
            <instancesSet>
                <item>
                    <instanceId>i-08c4bec27b91b32fe</instanceId>
                    <imageId>ami-08ea1604ee9ff115d</imageId>
                    <instanceState>
                        <code>16</code>
                        <name>running</name>
                    </instanceState>
                    <privateDnsName>ip-10-0-0-39.ap-northeast-3.compute.internal</privateDnsName>
                    <dnsName/>
                    <reason/>
                    <amiLaunchIndex>0</amiLaunchIndex>
                    <productCodes/>
                    <operator>
                        <managed>false</managed>
                    </operator>
                    <instanceType>t3.micro</instanceType>
                    <launchTime>2025-04-17T00:01:44.000Z</launchTime>
                    <placement>
                        <availabilityZone>ap-northeast-3a</availabilityZone>
                        <groupName/>
                        <tenancy>default</tenancy>
                    </placement>
                    <monitoring>
                        <state>disabled</state>
                    </monitoring>
                    <subnetId>subnet-05c637e57e3d7b56a</subnetId>
                    <vpcId>vpc-0dbe445807821e5a8</vpcId>
                    <privateIpAddress>10.0.0.39</privateIpAddress>
                    <sourceDestCheck>true</sourceDestCheck>
                    <groupSet>
                        <item>
                            <groupId>sg-035ab51ee395f801e</groupId>
                            <groupName>apc-kan-test-stack2-SecurityGroupEC2-gLim3KcG9leR</groupName>
                        </item>
                    </groupSet>
                    <architecture>x86_64</architecture>
(省略)
                </item>
            </instancesSet>
            <requesterId>558859346216</requesterId>
        </item>
    </reservationSet>
</DescribeInstancesResponse>sh-5.2$

注意

実行対象のサービスによっては、パラメータにVersionの指定が必要です。
バージョンの指定が無い場合、古いバージョンのAPIが実行されます。

例えば、EC2ではパラメータにバージョンの指定が無かった場合、古いバージョン (2005-10-05) のAPIが実行されます。
古いバージョンのAPIのため、アクションやパラメータが対応していないものがあります。
※DescribeRouteTablesアクションや、DescribeSecurityGroupsアクションのGroupIdパラメータが対応していませんでした。

sh-5.2$ curl -s "https://ec2.ap-northeast-3.amazonaws.com/?Action=DescribeRouteTables" --aws-sigv4 "aws:amz:ap-northeast-3:ec2" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`" | xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Errors>
    <Error>
      <Code>InvalidAction</Code>
      <Message>The action DescribeRouteTables is not valid for this web service.</Message>
    </Error>
  </Errors>
  <RequestID>d1286802-d5fe-4043-b7b6-ba40fee979a3</RequestID>
</Response>
sh-5.2$ 
sh-5.2$ 
sh-5.2$ curl -s "https://ec2.ap-northeast-3.amazonaws.com/?Action=DescribeSecurityGroups&GroupId.1=sg-035ab51ee395f801e" --aws-sigv4 "aws:amz:ap-northeast-3:ec2" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`" | xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Errors>
    <Error>
      <Code>UnknownParameter</Code>
      <Message>The parameter GroupId is not recognized</Message>
    </Error>
  </Errors>
  <RequestID>0b5aed3a-fa08-4a5e-b8e1-10bfdcfe9248</RequestID>
</Response>


また、実行できたとしても、結果が想定通りではない場合があります。
※DescribeInstancesアクションを実行したところ、取得できる情報が大きく異なりました。

sh-5.2$ curl "https://ec2.ap-northeast-3.amazonaws.com/?Action=DescribeInstances" --aws-sigv4 "aws:amz:ap-northeast-3:ec2" --user "`echo $CREDENTIALS | jq -r '.AccessKeyId + ":" + .SecretAccessKey'`" -H "X-Amz-Security-Token: `echo $CREDENTIALS | jq -r '.Token'`"
<?xml version="1.0" encoding="UTF-8"?>
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2005-10-05/">
    <reservationSet>
        <item>
            <reservationId>r-0dee8c953f7041ef5</reservationId>
            <ownerId>(省略)</ownerId>
            <groupSet/>
            <instancesSet>
                <item>
                    <instanceId>i-08c4bec27b91b32fe</instanceId>
                    <imageId>ami-08ea1604ee9ff115d</imageId>
                    <instanceState>
                        <code>16</code>
                        <name>running</name>
                    </instanceState>
                    <dnsName/>
                    <reason/>
                </item>
            </instancesSet>
        </item>
        <item>
(省略)
        </item>
    </reservationSet>
</DescribeInstancesResponse>sh-5.2$

最新のAPIバージョンは、各サービスのAPIリファレンスから確認できます。
S3の最新APIバージョンは2006-03-01でしたので、S3のAPIはほとんど (全く?) 更新されていないようです。
バージョン指定無しでS3が操作できたのも、そのあたりが影響しているのではないかと思います。

まとめ

今回はAWS SigV4を使用してS3とEC2を操作してみました。
バージョン指定が必要というところで少し躓きましたが、AWS SigV4でもAWS CLIと同等の操作ができました。

AWS SigV4を使用すれば、AWS CLIがインストールされていない環境でもAWS APIにアクセスできそうですね!

AWS SigV4は古くから存在するので情報も多いですが、この記事が誰かのお役に立てば幸いです。

お知らせ

APCはAWS Advanced Tier Services (アドバンストティアサービスパートナー) 認定を受けております。

その中で私達クラウド事業部はAWSなどのクラウド技術を活用したSI/SESのご支援をしております。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp