はじめに
OCI Enterprise AI Agents の OCI IAM 型 Hosted Application を、ブラウザから安全に使う最小構成を試しました。
ポイントは次の3つです。
- AIロジックは OCI Enterprise AI Agents の Hosted Application として動かす
- ブラウザは Hosted Application を直接呼ばない
- OCI Container Instance を BFF (Backend for Frontend) として置き、Resource Principal で IAM 署名して Hosted Application を呼ぶ
今回は、OpenAI Responses API と同じ呼び出し形式を OCI Generative AI の OpenAI互換エンドポイントで使う最小デモです。responses.create() によるテキスト入力・テキスト出力だけを使用します。File Search、Code Interpreter、Function Calling、MCP Calling、Conversations API はこの最小版では使いません。
注意: 本記事は検証環境向けです。公開する場合は、後述するブラウザ利用者の認証、レート制限、最小権限化を必ず追加してください。
構成
Browser
│ HTTP(S)
▼
OCI Container Instance
├─ HTML を配信
└─ POST /api/chat
│ Resource Principal で OCI Request Signing
▼
OCI Enterprise AI Agents Hosted Application(OCI IAM 型)
└─ POST /chat
│ Resource Principal
▼
OCI Generative AI Responses API
ブラウザは通常の POST /api/chat だけを呼びます。OCI IAMの署名はContainer Instance内で行うため、フロントエンドはOCI固有の認証処理を意識しません。
Hosted Application の IAM 型エンドポイントは hostedApplicationsIam を含み、標準の OCI リクエスト署名で呼び出します。OCI公式ドキュメント
ディレクトリ構成
oci-iam-hosted-app-demo/
├── hosted-agent/ # OCI Enterprise AI Agents に載せるイメージ
│ ├── app.py
│ ├── Containerfile
│ └── requirements.txt
└── web-proxy/ # OCI Container Instance に載せるイメージ
├── app.py
├── Containerfile
├── requirements.txt
└── static/index.html
1. Hosted Application 側:最小の AI アプリ
hosted-agent/app.py です。/health と /ready は OCI のヘルスチェック用、/chat がアプリの機能です。
import os
import httpx
from fastapi import FastAPI
from openai import OpenAI
from oci_openai import OciResourcePrincipalAuth
from pydantic import BaseModel
REGION = "us-ashburn-1"
PROJECT_OCID = "ocid1.generativeaiproject.oc1.iad.ama...<masked>"
MODEL_ID = "xai.grok-4.3"
app = FastAPI()
class ChatRequest(BaseModel):
message: str
def responses_client() -> OpenAI:
return OpenAI(
base_url=f"https://inference.generativeai.{REGION}.oci.oraclecloud.com/openai/v1",
api_key="not-used",
project=PROJECT_OCID,
http_client=httpx.Client(auth=OciResourcePrincipalAuth()),
)
@app.get("/health")
def health():
return {"status": "healthy"}
@app.get("/ready")
def ready():
return {"status": "ready"}
@app.post("/chat")
def chat(request: ChatRequest):
response = responses_client().responses.create(
model=MODEL_ID,
instructions="You are a concise Japanese assistant.",
input=request.message,
)
return {"answer": response.output_text}
ここで使っている OciResourcePrincipalAuth() は、Hosted Application 実行時に OCI が投入する短期トークンを利用します。APIキーをコンテナイメージや環境変数に保存しません。
requirements.txt:
fastapi
uvicorn[standard]
openai
oci-openai
httpx
Containerfile:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8080
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
OCI Responses API は OpenAI SDK 形式で responses.create() を使えます。このサンプルで使うResponses APIの機能は、テキスト入力からテキスト応答を生成することだけです。リクエストは OCI の OpenAI互換エンドポイントに送られ、認証・実行・データ管理はOCIで行われます。OCI Responses API
Hosted Applicationのデプロイ設定で環境変数を渡す方法は、今回の検証では起動失敗の原因切り分けが難しかったため使用していません。上記の固定値は検証用です。記事やリポジトリを公開する際は、Project OCIDなどの値を必ずマスクし、実運用では環境変数、OCI Vault、またはデプロイ設定で管理してください。
2. Container Instance 側:HTML配信と IAM 署名プロキシー
ブラウザが OCI IAM のリクエスト署名を作ることはできないため、Container Instance が /api/chat を受けて Hosted Application を呼びます。
web-proxy/app.py:
import os
import httpx
from fastapi import FastAPI
from oci_openai import OciResourcePrincipalAuth
from pydantic import BaseModel
HOSTED_AGENT_URL = os.environ["HOSTED_AGENT_URL"].rstrip("/")
app = FastAPI()
class ChatRequest(BaseModel):
message: str
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/api/chat")
def chat(request: ChatRequest):
# Container Instance 自身の Resource Principal でリクエスト署名する。
with httpx.Client(auth=OciResourcePrincipalAuth(), timeout=90) as client:
response = client.post(
f"{HOSTED_AGENT_URL}/chat",
json={"message": request.message},
)
response.raise_for_status()
return response.json()
HOSTED_AGENT_URL の設定
Container Instance の作成画面または編集画面で、Environment variables(環境変数) を追加します。
| Key | Value |
|---|---|
HOSTED_AGENT_URL |
OCI Enterprise AI Agents の Application詳細画面で払い出された IAM型 API Endpoint から、末尾の /<custom_path> を除いた値 |
たとえばApplication詳細画面で次の値が表示された場合:
https://inference.generativeai.<region>.oci.oraclecloud.com/20251112/
hostedApplicationsIam/<hosted-application-ocid>/actions/invoke/<custom_path>
Container Instance に設定する値は次のとおりです。
https://inference.generativeai.<region>.oci.oraclecloud.com/20251112/
hostedApplicationsIam/<hosted-application-ocid>/actions/invoke
<custom_path> と /chat は設定しません。プロキシーのコードが HOSTED_AGENT_URL の末尾に /chat を連結して呼び出します。設定変更後はContainer Instanceを再作成、または変更を適用して新しいリビジョンを起動します。
HTMLは static/index.html を同じコンテナから配信すればよく、ブラウザは同一オリジンの /api/chat を呼びます。これにより CORS 設定も最小化できます。
3. IAM:Dynamic Group と Resource Principal
Container Instance では、実行時に Resource Principal が使えます。静的な秘密鍵や ~/.oci/config は不要です。
Container Instance 用 Dynamic Group
OCI Console の Identity & Security → Dynamic Groups で作成します。
ALL {
resource.type = 'computecontainerinstance',
resource.compartment.id = '<コンテナインスタンスのコンパートメントOCID>'
}
computecontainerinstance が Container Instance のリソースタイプです。公式のDynamic Group例
IAMポリシーはOCI公式手順を参照する
IAMポリシーは、コンパートメント構成、使うモデル、OCIRの配置先、デプロイ方式で必要な最小権限が変わります。そのため、この記事では検証環境向けの広すぎるポリシー文を掲載せず、以下のOCI公式ページを設定の正とします。
| 設定対象 | 参照するOCI公式ページ |
|---|---|
| Hosted Application/Deployment の Dynamic Group、OCIR読み取り、脆弱性スキャン結果の読み取り | Permissions for Deploying Applications |
| OCI Responses API を Resource Principal で呼ぶためのIAM認証 | OCI Generative AI QuickStart - Set Up Authentication |
| Generative AI のリソースタイプとIAMポリシーの粒度 | IAM Policies for OCI Generative AI |
| Container Instance をDynamic Groupに含めるMatching Rule | OCI Container Instances のDynamic Group例 |
| IAM型Hosted Applicationのエンドポイント形式と呼び出し方法 | Using Applications |
OCI IAM型の Hosted Application は、標準OCI IAMのリクエスト署名とIAMポリシーで認可されます。まず上記の公式ページに従って必要な権限を設定し、検証が通った後にコンパートメント・リソースタイプ・操作を絞り込みます。
4. Podmanで2つのイメージをビルドしてOCIRへpush
Apple Silicon Macでも OCI向けに linux/amd64 を指定します。
podman machine start
# Hosted Application用
podman build --platform linux/amd64 \
-t iad.ocir.io/<namespace>/hello-hosted-agent:test \
-f hosted-agent/Containerfile hosted-agent
# Web / Container Instance用
podman build --platform linux/amd64 \
-t iad.ocir.io/<namespace>/hello-web-proxy:test \
-f web-proxy/Containerfile web-proxy
OCIRにログインします。ユーザー名はテナンシの表示名ではなく、Object Storage Namespace を含む形式です。Identity Domainを利用する場合は <namespace>/<identity-domain>/<username> です。
podman login iad.ocir.io -u <namespace>/<identity-domain>/<username>
Password: が表示されたら、OCI Auth Token を貼り付けます。Auth Tokenをシェルスクリプト、Dockerfile、Gitに保存しません。
podman push iad.ocir.io/<namespace>/hello-hosted-agent:test
podman push iad.ocir.io/<namespace>/hello-web-proxy:test
新規リポジトリへのpushで403になる場合は、コンソールでリポジトリを先に作成するか、repos の作成・更新権限を確認します。OCIRのリポジトリ権限
5. OCIコンソールでデプロイ
Hosted Application
- OCI Generative AI の Applications で Application type に OCI IAM を選択
- Artifact に
hello-hosted-agent:testを指定 - コンテナのポートを
8080に設定 -
/healthと/readyが成功することを確認 - 表示される API endpoint を控える
Container Instance
- イメージに
hello-web-proxy:testを指定 - コンテナポートを
8080として公開 - 環境変数
HOSTED_AGENT_URLを追加。KeyはHOSTED_AGENT_URL、ValueはHosted Application詳細画面のIAM型 Endpointから/<custom_path>を除いた値 - ブラウザから
http://<public-ip>:8080/を開く
ネットワークでは、Container Instanceへの TCP 8080 inbound と、OCI APIおよびインターネットへの TCP 443 outbound を許可します。実運用ではContainer Instanceを直接公開せず、Load Balancer / API Gateway + WAFを入口にする構成がよいです。
動作確認
ブラウザ画面からメッセージを送ると、次の経路で応答が返ります。
Browser
→ Container Instance /api/chat
→ Resource Principal署名
→ IAM型 Hosted Application /chat
→ OCI Responses API
→ Browser
最低限の確認は以下です。
curl http://<container-instance-public-ip>:8080/health
curl -X POST http://<container-instance-public-ip>:8080/api/chat \
-H 'Content-Type: application/json' \
-d '{"message":"こんにちは。あなたは何ですか?"}'
まとめ
OCI Enterprise AI Agents の IAM型 Hosted Application は、OCI IAMのリクエスト署名を使えるため、OCI上の実行基盤と組み合わせやすいです。
- Hosted Application:AIロジックと OCI Responses API 呼び出し
- Container Instance:ブラウザ向けのBFFとResource Principalによる署名
- Browser:OCI認証情報を持たず、通常のHTTP APIだけを呼ぶ
次のステップとしては、Responses APIの Function Calling、File Search、MCP Calling をHosted Applicationに追加すると、同じ構成のまま業務エージェントへ拡張できます。