Amazon EKS Pod Identity を利用すると Amazon EKS の Pod 単位で簡単に IAM ロール権限を与えることができます。このブログでは Amazon EKS Pod Identity を利用して Amazon Bedrock アクセスするアプリケーションを実行する例をご紹介します。
Amazon EKS Pod Identity の開始方法や詳細につきましては以下のブログをご確認ください。
ブログ:Amazon EKS Pod Identity は、Amazon EKS クラスター上のアプリケーションの IAM 許可を簡素化します
前提条件
- このブログでは、既存の Amazon EKS クラスター を使用します。
- Amazon Bedrock は 東京リージョン ( ap-northeast-1 ) で anthropic.claude-instant-v1 のモデルが有効化している状態とします。
- Amazon EKS Pod Identity の Add-on が既存の Amazon EKS クラスター にインストールしている状態とします。
- 本手順で公開するアプリケーションは
0.0.0.0:80
でパブリックに公開されますので、必要に応じてセキュリティグループを利用してアクセス制限を行ってください。
- 特に本番環境で利用する上では Amazon EKS のセキュリティベストプラクティスをご確認の上デプロイを行ってください。
Amazon Bedrock アクセスするアプリケーションの実行
まずは IAM ロール権限がない状態で以下のソースコードで実行されるアプリケーションを build して Amazon EKS 上で実行し、Amazon Bedrock アクセスできないことを確認します。
コンテナイメージの作成
Amazon Bedrock アクセスするアプリケーションのコードの例 ( app.py )
import streamlit as st
import boto3
import json
st.title("Bedrock Chat")
# Bedrock Runtimeサービス用のクライアント
bedrock = boto3.client(
service_name='bedrock-runtime',
region_name='ap-northeast-1')
def format_chat_history(messages):
formatted_history = ""
for message in messages:
# ユーザーかアシスタントかに応じてロールを設定
role = "Human:" if message["role"] == "user" else "Assistant:"
# メッセージを整形して追加
formatted_history += f"{role} {message['content']}\n"
return formatted_history
# チャット履歴の初期化
if "messages" not in st.session_state:
st.session_state.messages = []
# アプリ再実行時にチャットメッセージを表示
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# ユーザー入力の受け取り
if prompt := st.chat_input("What is up?"):
# ユーザーメッセージをチャットメッセージコンテナに表示
with st.chat_message("user"):
st.markdown(prompt)
# ユーザーメッセージをチャット履歴に追加
st.session_state.messages.append({"role": "user", "content": prompt})
# 対話履歴を整形してモデルの入力用に準備
chat_history = format_chat_history(st.session_state.messages)
# アシスタントの応答をチャットメッセージコンテナに表示
with st.chat_message("assistant"):
message_placeholder = st.empty()
full_response = ""
# 整形された対話履歴と新しいユーザー入力をモデルに送信
body = json.dumps({
'prompt': chat_history + 'Human: ' + prompt + '\n\nAssistant:',
'max_tokens_to_sample': 1000,
"stop_sequences": ["\n\nHuman:"],
"anthropic_version": "bedrock-2023-05-31"
})
accept = 'application/json'
contentType = 'application/json'
model_id = 'anthropic.claude-instant-v1'
response = bedrock.invoke_model_with_response_stream(
body=body, modelId=model_id, accept=accept, contentType=contentType)
stream = response.get('body')
for event in stream:
chunk = event.get('chunk')
if chunk:
# 取得したチャンクを追加し、Streamlitに表示
full_response += json.loads(chunk.get('bytes').decode()
)["completion"]
message_placeholder.markdown(full_response + "▌")
message_placeholder.markdown(full_response)
# アシスタントの応答をチャット履歴に追加
st.session_state.messages.append(
{"role": "assistant", "content": full_response})
Dockerfileの例
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app.py /app
RUN adduser --disabled-password --gecos '' streamlit
USER streamlit
EXPOSE 8501
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
requirements.txtの例
boto3==1.29.4
botocore==1.32.4
streamlit==1.28.2
Amazon EKS Pod Identity 使用する場合、 AWS SDK は 一定以上のバージョンが必要になります。
以下のようにディレクトリにソースコードを配置してコンテナ image を build し Amazon EKS から利用できる コンテナレジストリー に push を行います。
$ tree
.
├── app.py
├── Dockerfile
├── requirements.txt
このブログでは Amazon ECR を利用した手順をご紹介します。
以下の手順では事前に Amazon ECR 上に llm-app
というプライベートレジストリが作成が必要です。
# ご自身のAWSアカウントIDを設定
export AWS_ACCOUNT_ID=XXXXXXXXXXXX
# 認証トークンを取得し、レジストリに対して Docker クライアントを認証
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
# Docker イメージを構築
docker build -t llm-app:sample .
# リポジトリにイメージをプッシュできるように、イメージにタグ付けを行う
docker tag llm-app:sample ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/llm-app:sample
# イメージをプッシュ
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/llm-app:sample
Amazon EKS 上での実行
以下の manifest ファイルのようにしてアプリケーションを実行します。
この手順では sample-app
という Namespace
を作成し、Service
は type: LoadBalancer
を利用してアプリケーションを公開します。
※Amazon EKS でロードバランサーを取り扱う場合は AWS Load Balancer Controller の利用を推奨します
Namespace の manifest ファイルの例
apiVersion: v1
kind: Namespace
metadata:
name: sample-app
Deployment の manifest ファイルの例
※ Deployment のコンテナイメージはご自身のコンテナレジストリのイメージに変更してください。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: llm-app
name: llm-app
namespace: sample-app
spec:
replicas: 1
selector:
matchLabels:
app: llm-app
template:
metadata:
labels:
app: llm-app
spec:
containers:
# ご自身のコンテナレジストリのイメージに変更してください
- image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/llm-app:sample
name: sampleapp
Service の manifest ファイルの例
apiVersion: v1
kind: Service
metadata:
name: llm-app-lb
namespace: sample-app
spec:
type: LoadBalancer
selector:
app: llm-app
ports:
- protocol: TCP
port: 80
targetPort: 8501
アプリケーションを実行すると以下のようなアプリケーションが実行されます。
しかしながら、 Amazon Bedrock への IAM ロール権限が無いため画面のように AccessDeniedException
となるはずです。
アプリケーション へ Amazon Bedrock へのアクセス権限を追加する
Amazon Bedrock へのアクセス権限を持つ IAM ロールを作成し、 Amazon EKS 上で実行されている Pod に IAM ロールの追加を行います。
Amazon Bedrock へのアクセス権限を持つ IAM ロールの作成
IAM ロールの作成からユースケースで EKS – Pod Identity を選択し、 AmazonBedrockFullAccess の許可ポリシーを追加したロールを作成します。
Amazon EKS Pod Identity を利用して IAM ロールと ServiceAccount のアソシエーションを行う
以下の manifest ファイルのようにして ServiceAccount を作成し、Amazon EKS Pod Identity を利用して IAM ロールと ServiceAccount のアソシエーションを行います。アソシエーションは AWS Management Console 、もしくは CLI を利用して行うことができます。
ServiceAccount の manifest ファイルの例
apiVersion: v1
kind: ServiceAccount
metadata:
name: bedrock-sa
namespace: sample-app
CLI を利用したアソシエーションの例
※ —role-arn ではご自身で作成した IAM ロールの arn を指定してください。
# IAM ロールと ServiceAccount の association
aws eks create-pod-identity-association \
--cluster-name <CLUSTER_NAME> \
--role-arn arn:aws:iam::XXXXXXXXXXXX:role/eks-pod-identity-bedrock \
--namespace sample-app \
--service-account bedrock-sa
# association の確認
eksctl get podidentityassociation --cluster <CLUSTER_NAME>
ASSOCIATION ARN NAMESPACE SERVICE ACCOUNT NAME IAM ROLE ARN
arn:aws:eks:ap-northeast-1:XXXXXXXXXXXX:podidentityassociation/develop/a-zxckaesu4um17oi7e sample-app bedrock-sa arn:aws:iam::XXXXXXXXXXXX:role/eks-pod-identity-bedrock
アプリケーションへ ServiceAccount を追加する
IAM ロールと ServiceAccount のアソシエーションが完了したら、あとはアプリケーションが定義されている Pod へ ServiceAccount の追加を行うだけです。 Deployment に serviceAccountName を追加し、 先程の手順でIAM ロール とアソシエーションした ServiceAccount を指定します。
Deployment の manifest ファイルの例
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: llm-app
name: llm-app
namespace: sample-app
spec:
replicas: 1
selector:
matchLabels:
app: llm-app
template:
metadata:
labels:
app: llm-app
spec:
# serviceAccountName を追加
serviceAccountName: bedrock-sa
containers:
# ご自身のコンテナレジストリのイメージに変更してください
- image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/llm-app:sample
name: sampleapp
アプリケーションを更新すると以下の様に、Amazon Bedrock へのアクセス権限が追加されていることがわかります。
Amazon EKS Pod Identity の良さを感じて頂いたのではないでしょうか。
まとめ
- このブログでは、 Amazon EKS 上で動作するアプリケーションに対して、Amazon EKS Pod Identity を利用して Amazon Bedrock への IAM ロール 権限を追加する方法をご紹介しました
- Amazon EKS Pod Identity を利用して ServiceAccount との IAM ロールのアソシエーションを行うと、 ServiceAccount を Pod に指定するだけで、 IAM ロールベースのアクセス権限を簡単に付与することができます。
- サービスアカウントの IAM ロール (IRSA) と比較すると、 IAM ロールに Amazon EKS クラスター毎に信頼ポリシーを更新する必要がなく、複数のクラスターから IAM ロールを簡単に再利用できます。また ServiceAccount にアノテーションを付与する必要がないためよりシンプルな構成にすることができます。
このブログが皆様の Amazon EKS を利用したビジネスにお役立ちできれば幸いです。
作者情報
ソリューションアーキテクト 瀧田 直斗 (Takita Naoto)
中堅中小企業様を中心に技術的な側面からお客様のビジネスを支援させて頂いております。