curlでAmazon Bedrock APIを呼び出してみた

# はじめに

みなさん、こんにちは。Amazon BedrockのAPIを呼び出すのにAWS CLIやAWS SDKを使うことが多いと思います。  
UbuntuのEC2インスタンスは、初期設定だとAWS CLIやAWS SDKがインストールされていません。  
今回は、初期設定の状態でAmazon BedrockのAPIを呼び出すことができるか試してみました。

# 前提

- バージニア北部リージョンを使用
- UbuntuのEC2インスタンスを作成
- AmazonBedrockFullAccessポリシーが追加されたロールをEC2にアタッチ
- EC2にはパブリックIPを付与しない
- EC2への接続はEC2 Instance Connectエンドポイントを使用
- EC2のセキュリティグループのインバウンドルールはEC2 Instance Connectエンドポイント用セキュリティグループからのSSHを許可
- EC2のセキュリティグループのアウトバウンドルールはすべてのトラフィックを許可
- Amazon BedrockでClaudeモデルの利用申請および有効化済み

# 構成図
下図のような構成で実施しました。  
なお、本記事ではEC2 Instance Connectエンドポイントの設定についての説明は割愛します。

![EC2-Bedrock構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2369414/b56baf46-82f8-e6bb-df33-d36fce4c2380.png)

# APIを呼び出すための準備

APIを呼び出す手段として、curlを使用します。  
curlでAWSのAPIを呼び出す場合は署名が必要となります。  
アクセスキー(アクセスキーID、シークレットアクセスキー)を使用して署名を作成します。詳細については、[AWS Identity and Access Management ユーザーガイド]をご参照ください。

[AWS Identity and Access Management ユーザーガイド]: https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_aws-signing.html

curlでは[`--aws-sigv4`というオプション]でリクエストに署名をつけることができるようになりました。今回はこのオプションを使用します。

[`--aws-sigv4`というオプション]: https://curl.se/docs/manpage.html#--aws-sigv4

## 認証情報の取得

IMDSv2を使用してEC2インスタンスのメタデータを取得[^1]し、EC2にアタッチされているロールのクレデンシャル情報を`credential.json`ファイルに保存します。  
保存したクレデンシャル情報を一時的なセキュリティ認証情報として使用します。

[^1]: https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html

```shell
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/`
curl -s -H "X-aws-ec2-metadata-token: ${TOKEN}" http://169.254.169.254/latest/meta-data/iam/security-credentials/${ROLE_NAME}/ > credential.json
```

## 変数の設定

curlコマンドのオプションに渡しやすくするため、EC2インスタンスのクレデンシャル情報を変数に保存します。  
`credential.json`ファイルのJSONデータから`AccessKeyId`、`SecretAccessKey`、`Token`を抽出します。  
JSONデータの抽出は、jqコマンドを使用すれば楽にできますが、Ubuntuの初期設定ではjqコマンドがインストールされていないので、awkを使ってデータを抽出します。

```shell
AWS_ACCESS_KEY_ID=$(awk 'match($0, /"AccessKeyId" *: *"([^"]*)"/, a){print a[1]}' credential.json)
AWS_SECRET_ACCESS_KEY=$(awk 'match($0, /"SecretAccessKey" *: *"([^"]*)"/, a){print a[1]}' credential.json)
AWS_SESSION_TOKEN=$(awk 'match($0, /"Token" *: *"([^"]*)"/, a){print a[1]}' credential.json)
```

Signature V4のオプションを指定するため、アクセス先のリージョンとサービスを変数に保存します。

```shell
REGION=us-east-1
SERVICE=bedrock
```

基盤モデルのモデルIDを変数に格納します。今回は、Claude v2を使用します。

```shell
MODEL_ID=anthropic.claude-v2
```

# Amazon Bedrock APIを呼び出す

curlを使用して生成AIに質問してみます。

## コマンド

```shell
curl -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" \
  --aws-sigv4 "aws:amz:${REGION}:${SERVICE}" \
  --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
  -H "Accept: */*" -H "Content-Type: application/json" \
  --data '{"prompt": "\n\nHuman:日本の首都はどこですか？\n\nAssistant:", "max_tokens_to_sample": 1024}' \
  https://bedrock-runtime.${REGION}.amazonaws.com/model/${MODEL_ID}/invoke
```

### コマンドオプション補足

HTTPリクエストヘッダ`X-Amz-Security-Token`にセッショントークンを追加[^2]します。  

[^2]: https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp_use-resources.html#RequestWithSTS

`--aws-sigv4`オプションで署名を使用するプロバイダ/リージョン/サービスを指定し、`--user`オプションで一時的なセキュリティ認証情報のアクセスキーIDとシークレットアクセスキーを指定します。  

さらに、HTTPリクエストヘッダとHTTPリクエストボディに以下を指定します。

#### HTTPリクエストヘッダ

- Accept: \*/\*
- Content-Type: application/json

#### HTTPリクエストボディ

基盤モデルにClaudeを使用するため、次のパラメータをJSON形式でリクエストボディとして指定します。

|パラメータ          |内容                                            |
|:-------------------|:-----------------------------------------------|
|prompt              |"\n\nHuman:"と"\n\nAssistant:"で挟んだプロンプト|
|max_tokens_to_sample|トークンの最大数(Claude v2の場合、最大4096)     |

Amazon BedrockAPIのアクセス先のエンドポイントは次の形式で指定します。

::: note info
https\://bedrock-runtime.<リージョン>.amazonaws.com/model/<モデルID>/invoke
:::

## 実行結果

completion(回答)が出力されました。

```console
{"completion":" 東京が日本の首都です。","stop_reason":"stop_sequence","stop":"\n\nHuman:"}
```

# おわりに

本記事では追加でソフトウェアをインストールしない条件で確認しましたが、いかがでしたでしょうか？  
企業では、ソフトウェアをインストールするのに承認が必要な場合もあると思います。  
今回の記事が初期設定でも手軽にAmazon Bedrockを試したいときの参考になれば幸いです。

---

- AWS は、米国その他の諸国における Amazon.com, Inc. またはその関連会社の商標です。
- Ubuntuは、Canonical Ltd.の登録商標です。
- その他、本資料に記述してある会社名、製品名は、各社の登録商品または商標です。