

# 建置您的第一個已驗證代理程式
<a name="identity-getting-started-cognito"></a>

此入門教學課程將逐步引導您使用 Amazon Bedrock AgentCore Identity 從頭開始建置完整的已驗證代理程式，並協助您開始在代理程式應用程式中實作身分功能。您將了解如何設定開發環境、使用 Cognito 建立身分驗證基礎設施、將代理程式部署到 AgentCore 執行期，以及測試完整的身分驗證工作流程。

在本教學課程結束時，您將擁有完全部署的代理程式，可透過 OAuth2 流程驗證使用者、安全地取得存取權杖，並示範完整的身分管理生命週期。您的代理程式將在具有適當 IAM 許可的 AgentCore 執行期上執行，建立測試實驗室環境，您可以在其中示範和測試整合功能。

**Topics**
+ [先決條件](#identity-quick-start-prerequisites)
+ [步驟 1：建立 Cognito 使用者集區 （選用）](#identity-quick-start-cognito)
+ [步驟 2：建立登入資料提供者](#identity-quick-start-credential-provider)
+ [步驟 2.5：將回呼 URL 新增至 OAuth 2.0 授權伺服器](#identity-update-credential-provider)
+ [步驟 3：建立啟動 OAuth 2.0 流程的範例代理程式](#identity-quick-start-agent)
+ [步驟 4：將代理程式部署到 AgentCore 執行期](#identity-quick-start-deploy)
+ [步驟 5：叫用代理程式](#identity-quick-start-invoke)
+ [清除](#identity-quick-start-cleanup)
+ [安全最佳實務](#identity-quick-start-security)

## 先決條件
<a name="identity-quick-start-prerequisites"></a>

開始前，請確保您具備以下條件：
+ 具有適當許可 AWS 的帳戶
+ 已安裝 Python 3.10\+
+ 已安裝的最新 AWS CLI `jq` 
+ 已安裝 Node.js 18\+ （適用於 AgentCore CLI)
+  AWS 已設定的登入資料和區域 `aws configure` ()

本教學課程需要您擁有 OAuth 2.0 授權伺服器。如果您沒有，步驟 1 將使用 Amazon Cognito 使用者集區為您建立一個。如果您的 OAuth 2.0 授權伺服器已設定用戶端 ID、用戶端秘密和使用者，您可以繼續進行步驟 2。此授權伺服器將充當資源登入資料提供者，代表授權代理程式傳出 OAuth 2.0 存取字符。

### 安裝 SDK 和相依性
<a name="identity-quick-start-install"></a>

建立本指南的資料夾、建立 Python 虛擬環境，並安裝 AgentCore SDK 和 AWS Python SDK (boto3)。

```
mkdir agentcore-identity-quickstart
cd agentcore-identity-quickstart
python3 -m venv .venv
source .venv/bin/activate
pip install bedrock-agentcore boto3 strands-agents pyjwt
```

也請使用下列內容建立 `requirements.txt` 檔案。這稍後將由 AgentCore 部署工具使用。

```
bedrock-agentcore
boto3
pyjwt
strands-agents
```

## 步驟 1：建立 Cognito 使用者集區 （選用）
<a name="identity-quick-start-cognito"></a>

本教學課程需要 OAuth 2.0 授權伺服器。如果您沒有可用於測試的 ，或者如果您想要將測試與授權伺服器分開，此指令碼將使用您的 AWS 登入資料來設定 Amazon Cognito 執行個體，供您做為授權伺服器使用。指令碼將建立：
+ Cognito 使用者集區
+ 該使用者集區的 OAuth 2.0 用戶端和用戶端秘密
+ 該 Cognito 使用者集區中的測試使用者和密碼

刪除 Cognito 使用者集區 AgentCoreIdentityQuickStartPool 也會刪除相關聯的 client\_id 和使用者。

您可以選擇將此指令碼儲存為 create\_cognito.sh，然後從命令列執行，或將指令碼貼到您的命令列。

```
#!/bin/bash

REGION=$(aws configure get region)

# Create user pool
USER_POOL_ID=$(aws cognito-idp create-user-pool \
  --pool-name AgentCoreIdentityQuickStartPool \
  --query 'UserPool.Id' \
  --no-cli-pager \
  --output text)

# Create user pool domain
DOMAIN_NAME="agentcore-quickstart-$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 5)"
aws cognito-idp create-user-pool-domain \
  --domain $DOMAIN_NAME \
  --no-cli-pager \
  --user-pool-id $USER_POOL_ID > /dev/null

# Create user pool client with secret and hosted UI settings
CLIENT_RESPONSE=$(aws cognito-idp create-user-pool-client \
  --user-pool-id $USER_POOL_ID \
  --client-name AgentCoreQuickStart \
  --generate-secret \
  --allowed-o-auth-flows "code" \
  --allowed-o-auth-scopes "openid" "profile" "email" \
  --allowed-o-auth-flows-user-pool-client \
  --supported-identity-providers "COGNITO" \
  --query 'UserPoolClient.{ClientId:ClientId,ClientSecret:ClientSecret}' \
  --output json)

CLIENT_ID=$(echo $CLIENT_RESPONSE | jq -r '.ClientId')
CLIENT_SECRET=$(echo $CLIENT_RESPONSE | jq -r '.ClientSecret')

# Generate random username and password
USERNAME="AgentCoreTestUser$(printf "%04d" $((RANDOM % 10000)))"
PASSWORD="$(LC_ALL=C tr -dc 'A-Za-z0-9!@#$%^&*()_+-=[]{}|;:,.<>?' < /dev/urandom | head -c 16)$(LC_ALL=C tr -dc '0-9' < /dev/urandom | head -c 1)"

# Create user with permanent password
aws cognito-idp admin-create-user \
  --user-pool-id $USER_POOL_ID \
  --username $USERNAME \
  --output text > /dev/null

aws cognito-idp admin-set-user-password \
  --user-pool-id $USER_POOL_ID \
  --username $USERNAME \
  --password $PASSWORD \
  --output text > /dev/null \
  --permanent

# Get region

ISSUER_URL="https://cognito-idp.$REGION.amazonaws.com/$USER_POOL_ID/.well-known/openid-configuration"
HOSTED_UI_URL="https://$DOMAIN_NAME.auth.$REGION.amazoncognito.com"

# Output results
echo "User Pool ID: $USER_POOL_ID"
echo "Client ID: $CLIENT_ID"
echo "Client Secret: $CLIENT_SECRET"
echo "Issuer URL: $ISSUER_URL"
echo "Hosted UI URL: $HOSTED_UI_URL"
echo "Test User: $USERNAME"
echo "Test Password: $PASSWORD"

echo ""
echo "# Copy and paste these exports to set environment variables for later use:"
echo "export USER_POOL_ID='$USER_POOL_ID'"
echo "export CLIENT_ID='$CLIENT_ID'"
echo "export CLIENT_SECRET='$CLIENT_SECRET'"
echo "export ISSUER_URL='$ISSUER_URL'"
echo "export HOSTED_UI_URL='$HOSTED_UI_URL'"
echo "export COGNITO_USERNAME='$USERNAME'"
echo "export COGNITO_PASSWORD='$PASSWORD'"
```

## 步驟 2：建立登入資料提供者
<a name="identity-quick-start-credential-provider"></a>

登入資料提供者是您的代理程式存取外部服務的方式。建立登入資料提供者，並使用授權伺服器的 OAuth 2.0 用戶端進行設定。

如果您使用自己的授權伺服器，請從授權伺服器設定環境變數 `ISSUER_URL` 、 `CLIENT_ID` 和 `CLIENT_SECRET`及其適當的值。如果您使用先前的指令碼來建立 Cognito 的授權伺服器，請將輸出中的 EXPORT 陳述式複製到終端機，以設定環境變數。

此登入資料提供者將由代理程式的程式碼使用，以取得存取權杖以代表您的使用者採取行動。

**Example**  

1. 如果您有 AgentCore CLI 專案，您可以使用 CLI 新增登入資料提供者。CLI 會在部署期間建立提供者。

   ```
   agentcore add credential \
     --name AgentCoreIdentityQuickStartProvider \
     --type oauth \
     --discovery-url "$ISSUER_URL" \
     --client-id "$CLIENT_ID" \
     --client-secret "$CLIENT_SECRET"
   ```

   當您`agentcore deploy`在步驟 4 中執行 時，將會建立登入資料提供者。請注意部署輸出中的回呼 URL。

1. 

   ```
   #!/bin/bash
   # please note the expected ISSUER_URL format for Bedrock AgentCore is the full url, including .well-known/openid-configuration
   OAUTH2_CREDENTIAL_PROVIDER_RESPONSE=$(aws bedrock-agentcore-control create-oauth2-credential-provider \
     --name "AgentCoreIdentityQuickStartProvider" \
     --credential-provider-vendor "CustomOauth2" \
     --oauth2-provider-config-input '{
       "customOauth2ProviderConfig": {
         "oauthDiscovery": {
           "discoveryUrl": "'$ISSUER_URL'"
         },
         "clientId": "'$CLIENT_ID'",
         "clientSecret": "'$CLIENT_SECRET'"
       }
     }' \
     --output json)
   
   OAUTH2_CALLBACK_URL=$(echo $OAUTH2_CREDENTIAL_PROVIDER_RESPONSE | jq -r '.callbackUrl')
   
   echo "OAuth2 Callback URL: $OAUTH2_CALLBACK_URL"
   ```

## 步驟 2.5：將回呼 URL 新增至 OAuth 2.0 授權伺服器
<a name="identity-update-credential-provider"></a>

若要防止未經授權的重新導向，請將從 [CreateOauth2CredentialProvider](https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_CreateOauth2CredentialProvider.html) 或 [GetOauth2CredentialProvider](https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_GetOauth2CredentialProvider.html) 擷取的回呼 URL 新增至您的 OAuth 2.0 授權伺服器。

如果您使用先前的指令碼建立具有 Cognito 的授權伺服器，請將輸出的 EXPORT 陳述式複製到終端機，以設定環境變數，並使用 OAuth2 憑證提供者回呼 URL 更新 Cognito 使用者集區用戶端。

```
#!/bin/bash
aws cognito-idp update-user-pool-client \
    --user-pool-id $USER_POOL_ID \
    --client-id $CLIENT_ID \
    --client-name AgentCoreQuickStart \
    --allowed-o-auth-flows "code" \
    --allowed-o-auth-scopes "openid" "profile" "email" \
    --allowed-o-auth-flows-user-pool-client \
    --supported-identity-providers "COGNITO" \
    --callback-urls "$OAUTH2_CALLBACK_URL"
```

## 步驟 3：建立啟動 OAuth 2.0 流程的範例代理程式
<a name="identity-quick-start-agent"></a>

在此步驟中，我們將建立啟動 OAuth 2.0 授權流程的代理程式，以取得代表使用者的字符。為求簡化，客服人員不會代表使用者實際呼叫外部服務，但會向我們證明已取得代表測試使用者的同意。

### 客服人員代碼
<a name="identity-quick-start-agent-code"></a>

建立名為 `agentcoreidentityquickstart.py` 的檔案，並儲存此程式碼。

```
"""
AgentCore Identity Outbound Token Agent

This agent demonstrates the USER_FEDERATION OAuth 2.0 flow.

It handles the OAuth 2.0 user consent flow and inspects the resulting OAuth 2.0 access token.
"""

from bedrock_agentcore.runtime import BedrockAgentCoreApp
from bedrock_agentcore.identity import requires_access_token
import asyncio
import jwt
import logging

app = BedrockAgentCoreApp()

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def decode_jwt(token):
    try:
        decoded = jwt.decode(token, options={"verify_signature": False})
        return decoded
    except Exception as e:
        return {"error": f"Error decoding JWT: {str(e)}"}

class StreamingQueue:
    def __init__(self):
        self.finished = False
        self.queue = asyncio.Queue()

    async def put(self, item):
        await self.queue.put(item)

    async def finish(self):
        self.finished = True
        await self.queue.put(None)

    async def stream(self):
        while True:
            item = await self.queue.get()
            if item is None and self.finished:
                break
            yield item

queue = StreamingQueue()

async def handle_auth_url(url):
    await queue.put(f"Authorization URL, please copy to your preferred browser: {url}")

@requires_access_token(
    provider_name="AgentCoreIdentityQuickStartProvider",
    scopes=["openid"],
    auth_flow="USER_FEDERATION",
    on_auth_url=handle_auth_url, # streams authorization URL to client
    force_authentication=True,
    callback_url='insert_oauth2_callback_url_for_session_binding',
)
async def introspect_with_decorator(*, access_token: str):
    """Introspect token using decorator"""
    logger.info("Inside introspect_with_decorator - decorator succeeded")
    await queue.put({
        "message": "Successfully received an access token to act on behalf of your user!",
        "token_claims": decode_jwt(access_token),
        "token_length": len(access_token),
        "token_preview": f"{access_token[:50]}...{access_token[-10:]}"
    })
    await queue.finish()

@app.entrypoint
async def agent_invocation(payload, context):
    """Handler that uses only the decorator approach"""
    logger.info("Agent invocation started")

    # Start the agent task and immediately begin streaming
    task = asyncio.create_task(introspect_with_decorator())

    # Stream items as they come in
    async for item in queue.stream():
        yield item

    # Wait for task completion
    await task

if __name__ == "__main__":
    app.run()
```

**注意**  
如需處理[工作階段繫結](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/oauth2-authorization-url-session-binding.html) 的本機回呼伺服器實作範例，請參閱 [oauth2\_callback\_server.py](https://github.com/awslabs/amazon-bedrock-agentcore-samples/blob/main/01-tutorials/03-AgentCore-identity/05-Outbound_Auth_3lo/oauth2_callback_server.py) 

## 步驟 4：將代理程式部署到 AgentCore 執行期
<a name="identity-quick-start-deploy"></a>

我們將在 AgentCore 執行期託管此代理程式。我們可以透過 AgentCore CLI 輕鬆執行此操作。

從終端機安裝 AgentCore CLI 並建立新的專案：

```
npm install -g @aws/agentcore
agentcore create --name IdentityQuickstart --defaults
```

將您的代理程式指令碼複製到專案的代理程式目錄，取代預設代理程式：

```
cp agentcoreidentityquickstart.py IdentityQuickstart/app/IdentityQuickstart/main.py
```

同時將您的需求檔案複製到代理程式目錄，以確保所有相依性都包含在部署中：

```
cp requirements.txt IdentityQuickstart/app/IdentityQuickstart/
```

然後部署您的專案：

```
cd IdentityQuickstart
agentcore deploy
```

CLI 會合成 AWS CDK 堆疊，並將您的代理程式部署到 AgentCore 執行期。這大約需要 2-3 分鐘。

### 更新代理程式的 IAM 政策，以存取字符保存庫和用戶端秘密
<a name="identity-quick-start-iam-policy"></a>

AgentCore CLI 會在部署期間建立代理程式的執行角色，但該角色不會自動包含權杖保存庫存取的許可。您需要連接其他政策，以允許代理程式在執行時間擷取 OAuth 2.0 權杖。

此指令碼會從 CLI AWS 擷取您的帳戶和區域，從 CloudFormation 堆疊尋找代理程式的執行角色，並連接適當的政策。您可以複製並貼上此指令碼，或將其儲存至檔案並執行。

```
#!/bin/bash

# Get account and region from AWS CLI
AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
REGION=$(aws configure get region)

# Get execution role from CloudFormation stack outputs
EXECUTION_ROLE=$(aws cloudformation describe-stack-resources \
  --stack-name AgentCore-IdentityQuickstart-prod \
  --query "StackResources[?ResourceType=='AWS::IAM::Role'].PhysicalResourceId" \
  --output text | head -1)

echo "Parsed values:"
echo "Execution Role: $EXECUTION_ROLE"
echo "Account: $AWS_ACCOUNT"
echo "Region: $REGION"

# Create the policy document with proper variable substitution
cat > agentcore-identity-policy.json << EOF
{
"Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AccessTokenVault",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:GetResourceOauth2Token",
        "secretsmanager:GetSecretValue"
      ],
      "Resource": ["arn:aws:bedrock-agentcore:$REGION:$AWS_ACCOUNT:workload-identity-directory/default/workload-identity/*",
        "arn:aws:bedrock-agentcore:$REGION:$AWS_ACCOUNT:token-vault/default/oauth2credentialprovider/AgentCoreIdentityQuickStartProvider",
        "arn:aws:bedrock-agentcore:$REGION:$AWS_ACCOUNT:workload-identity-directory/default",
        "arn:aws:bedrock-agentcore:$REGION:$AWS_ACCOUNT:token-vault/default",
        "arn:aws:secretsmanager:$REGION:$AWS_ACCOUNT:secret:bedrock-agentcore-identity!default/oauth2/AgentCoreIdentityQuickStartProvider*"
      ]
    }
  ]
}
EOF

# Create the policy
POLICY_ARN=$(aws iam create-policy \
    --policy-name AgentCoreIdentityQuickStartPolicy$(LC_ALL=C tr -dc '0-9' < /dev/urandom | head -c 4) \
    --policy-document file://agentcore-identity-policy.json \
    --query 'Policy.Arn' \
    --output text)

# Extract role name from ARN and attach policy
ROLE_NAME=$(echo $EXECUTION_ROLE | awk -F'/' '{print $NF}')
aws iam attach-role-policy \
    --role-name $ROLE_NAME \
    --policy-arn $POLICY_ARN

echo "Policy created and attached: $POLICY_ARN"

# Cleanup
rm agentcore-identity-policy.json
```

## 步驟 5：叫用代理程式
<a name="identity-quick-start-invoke"></a>

現在所有設定完成，您可以叫用 代理程式。在此示範中，我們將使用 `agentcore invoke`命令和我們的 IAM 登入資料。使用 IAM 身分驗證時，我們需要傳遞 `--user-id`和 `--session-id`引數。

```
agentcore invoke "TestPayload" --runtime IdentityQuickstart --user-id "SampleUserID" --session-id "ALongThirtyThreeCharacterMinimumSessionIdYouCanChangeThisAsYouNeed"
```

然後，代理程式會將 URL 傳回至您的`agentcore invoke`命令。將該 URL 複製並貼到您偏好的瀏覽器，然後系統會將您重新導向至授權伺服器的登入頁面。`--user-id` 參數是您向 AgentCore Identity 呈現的使用者 ID。`--session-id` 參數是工作階段 ID，長度必須至少為 33 個字元。

**重要**  
`--user-id` 參數使用 `GetWorkloadAccessTokenForUserId` API 路徑，會將 userId 視為不透明字串，而不會針對已驗證的最終使用者身分進行驗證。這適用於您沒有可用 IdP 字符的快速入門和開發案例。對於您擁有識別最終使用者的 JWT 的生產部署，請改用 JWT 型身分驗證路徑 (`GetWorkloadAccessTokenForJWT`)，以驗證字符的發行者、簽章和過期。如需詳細資訊，請參閱[取得工作負載存取字符](get-workload-access-token.md)。

在瀏覽器上出現提示時，輸入授權伺服器上使用者的使用者名稱和密碼，或使用您設定的偏好身分驗證方法。如果您使用步驟 1 的指令碼來建立 Cognito 執行個體，您可以從終端機歷史記錄中擷取。

您的瀏覽器應該重新導向至您設定的 OAuth2 回呼 URL，這會處理[工作階段繫結流程](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/oauth2-authorization-url-session-binding.html) 。確保您的 OAuth2 回呼伺服器提供明確的成功和錯誤回應，以指出授權狀態。

**注意**  
如果您在未完成授權的情況下中斷調用，您可能需要使用新的工作階段 ID ( `--session-id` 參數） 請求新的 URL。

### 除錯
<a name="identity-quick-start-debugging"></a>

如果您遇到任何錯誤或意外行為，代理程式的輸出會擷取在 Amazon CloudWatch logs中。日誌結尾命令會在您執行 後提供`agentcore deploy`。

## 清除
<a name="identity-quick-start-cleanup"></a>

完成後，`agentcore deploy`從您的專案目錄執行 `agentcore remove all` ，然後從中解壓縮已部署的 AgentCore 執行期資源。然後刪除 Amazon Cognito 使用者集區，分離並刪除您建立的 IAM 政策，然後刪除登入資料提供者。

## 安全最佳實務
<a name="identity-quick-start-security"></a>

使用身分資訊時：

1.  **絕不在代理程式程式碼中硬式編碼登入資料** 

1.  針對敏感資訊**使用環境變數或 Amazon SageMaker AI** 

1.  設定 IAM 許可時**套用最低權限原則** 

1.  **定期輪換外部服務的登入**資料

1.  **稽核存取日誌**以監控客服人員活動

1.  針對身分驗證失敗**實作適當的錯誤處理** 