

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 驗證字符 AWS Lambda
<a name="reference-smart-on-fhir-token-validation"></a>

當您在啟用 FHIR 的資料存放區上建立 HealthLake SMART 時，您必須在`CreateFHIRDatastore`請求中提供 AWS Lambda 函數的 ARN。Lambda 函數的 ARN 是使用 `IdpLambdaArn` 參數在 `IdentityProviderConfiguration` 物件中指定。

您必須先建立 Lambda 函數，才能建立啟用 FHIR 的 SMART 資料存放區。建立資料存放區後，就無法變更 Lambda ARN。若要查看您在建立資料存放區時指定的 Lambda ARN，請使用 `DescribeFHIRDatastore` API 動作。

**若要讓 FHIR REST 請求在啟用 FHIR 的資料存放區上在 SMART 上成功，您的 Lambda 函數必須執行下列動作：**
+ 在 1 秒內將回應傳回 HealthLake 資料存放區端點。
+ 解碼用戶端應用程式傳送之 REST API 請求的授權標頭中提供的存取字符。
+ 指派具有足夠許可可執行 FHIR REST API 請求的 IAM 服務角色。
+ 需要下列宣告才能完成 FHIR REST API 請求。如需詳細資訊，請參閱 [必要宣告](reference-smart-on-fhir-authentication.md#server-response)。
  + `nbf`
  + `exp`
  + `isAuthorized`
  + `aud`
  + `scope`

使用 Lambda 時，除了 Lambda 函數之外，您還需要建立執行角色和資源型政策。Lambda 函數的執行角色是 IAM 角色，授予函數存取執行時間所需 AWS 服務和資源的許可。您提供的資源型政策必須允許 HealthLake 代表您叫用您的函數。

本主題中的各節說明來自用戶端應用程式和解碼回應的範例請求、建立 AWS Lambda 函數所需的步驟，以及如何建立 HealthLake 可採用的資源型政策。
+ [第 1 部分：建立 Lambda 函數](#smart-on-fhir-lambda-create)
+ [第 2 部分：建立 AWS Lambda 函數使用的 HealthLake 服務角色](#smart-on-fhir-lambda-service-role)
+ [第 3 部分：更新 Lambda 函數的執行角色](#smart-on-fhir-lambda-service-role-execution-role)
+ [第 4 部分：將資源政策新增至 Lambda 函數](#smart-on-fhir-lambda-invoke-healthlake)
+ [第 5 部分：為您的 Lambda 函數佈建並行](#smart-on-fhir-lambda-function-scaling)

## 建立 AWS Lambda 函數
<a name="smart-on-fhir-lambda-create"></a>

此主題中建立的 Lambda 函數會在 HealthLake 收到對啟用 FHIR 的 SMART 資料存放區的請求時觸發。來自用戶端應用程式的請求包含 REST API 呼叫，以及包含存取字符的授權標頭。

```
GET https://healthlake.region.amazonaws.com/datastore/datastoreId/r4/
Authorization: Bearer i8hweunweunweofiwweoijewiwe
```

本主題中的範例 Lambda 函數會使用 AWS Secrets Manager 來隱藏與授權伺服器相關的登入資料。我們強烈建議不要直接在 Lambda 函數中提供授權伺服器登入詳細資訊。

**Example 驗證包含授權承載字符的 FHIR REST 請求**  
Lambda 函數範例示範如何驗證傳送到啟用 FHIR 之 SMART 資料存放區的 FHIR REST 請求。若要查看如何實作此 Lambda 函數step-by-steps說明，請參閱 [使用 建立 Lambda 函數 AWS 管理主控台](#create-lambda-console)。  
如果 FHIR REST API 請求不包含有效的資料存放區端點、存取字符和 REST 操作，Lambda 函數將會失敗。若要進一步了解必要的授權伺服器元素，請參閱 [必要宣告](reference-smart-on-fhir-authentication.md#server-response)。  

```
import base64
import boto3
import logging
import json
import os
from urllib import request, parse

logger = logging.getLogger()
logger.setLevel(logging.INFO)

## Uses Secrets manager to gain access to the access key ID and secret access key for the authorization server
client = boto3.client('secretsmanager', region_name="region-of-datastore")
response = client.get_secret_value(SecretId='name-specified-by-customer-in-secretsmanager')
secret = json.loads(response['SecretString'])
client_id = secret['client_id']
client_secret = secret['client_secret']


unencoded_auth = f'{client_id}:{client_secret}'
headers = {
  'Authorization': f'Basic {base64.b64encode(unencoded_auth.encode()).decode()}',
  'Content-Type': 'application/x-www-form-urlencoded'
}

auth_endpoint = os.environ['auth-server-base-url'] # Base URL of the Authorization server
user_role_arn = os.environ['iam-role-arn'] # The IAM role client application will use to complete the HTTP request on the datastore

def lambda_handler(event, context):
    if 'datastoreEndpoint' not in event or 'operationName' not in event or 'bearerToken' not in event:
    return {}

    datastore_endpoint = event['datastoreEndpoint']
    operation_name = event['operationName']
    bearer_token = event['bearerToken']
    logger.info('Datastore Endpoint [{}], Operation Name: [{}]'.format(datastore_endpoint, operation_name))

    ## To validate the token
    auth_response = auth_with_provider(bearer_token)
    logger.info('Auth response: [{}]'.format(auth_response))
    auth_payload = json.loads(auth_response)
    ## Required parameters needed to be sent to the datastore endpoint for the HTTP request to go through
    auth_payload["isAuthorized"] = bool(auth_payload["active"])
    auth_payload["nbf"] = auth_payload["iat"]
    return {"authPayload": auth_payload, "iamRoleARN": user_role_arn}

## access the server
def auth_with_provider(token):
    data = {'token': token, 'token_type_hint': 'access_token'}
    req = request.Request(url=auth_endpoint + '/v1/introspect', data=parse.urlencode(data).encode(), headers=headers)
    with request.urlopen(req) as resp:
    return resp.read().decode()
```

### 使用 建立 Lambda 函數 AWS 管理主控台
<a name="create-lambda-console"></a>

下列程序假設您已在啟用 FHIR 的 SMART 資料存放區上處理 FHIR REST API 請求時，建立希望 HealthLake 擔任的服務角色。如果您尚未建立服務角色，您仍然可以建立 Lambda 函數。您必須先新增服務角色的 ARN，Lambda 函數才能運作。若要進一步了解如何建立服務角色並在 Lambda 函數中指定該角色，請參閱 [建立 HealthLake 服務角色以用於用來解碼 JWT 的 AWS Lambda 函數](#smart-on-fhir-lambda-service-role)

**建立 Lambda 函數 (AWS 管理主控台)**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home/functions)。

1. 選擇**建立函數**。

1. 選取**從頭開始撰寫**。

1. 在**基本資訊**下，輸入**函數名稱**。在**執行時間**下，選擇以 Python 為基礎的執行時間。

1. **執行角色** 請選擇 **建立具備基本 Lambda 許可的新角色** 。

   Lambda 會建立函數和[執行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)，此角色會授予函數將日誌上傳至 Amazon CloudWatch 的許可。Lambda 函數會在您叫用函數時擔任執行角色，並使用執行角色來建立 AWS SDK 的登入資料。

1. 選擇**程式碼**索引標籤，然後新增範例 Lambda 函數。

   如果您尚未為 Lambda 函數建立要使用的服務角色，則必須先建立該角色，範例 Lambda 函數才能運作。若要進一步了解如何為 Lambda 函數建立服務角色，請參閱 [建立 HealthLake 服務角色以用於用來解碼 JWT 的 AWS Lambda 函數](#smart-on-fhir-lambda-service-role)。

   ```
   import base64
   import boto3
   import logging
   import json
   import os
   from urllib import request, parse
   
   logger = logging.getLogger()
   logger.setLevel(logging.INFO)
   
   ## Uses Secrets manager to gain access to the access key ID and secret access key for the authorization server
   client = boto3.client('secretsmanager', region_name="region-of-datastore")
   response = client.get_secret_value(SecretId='name-specified-by-customer-in-secretsmanager')
   secret = json.loads(response['SecretString'])
   client_id = secret['client_id']
   client_secret = secret['client_secret']
   
   
   unencoded_auth = f'{client_id}:{client_secret}'
   headers = {
     'Authorization': f'Basic {base64.b64encode(unencoded_auth.encode()).decode()}',
     'Content-Type': 'application/x-www-form-urlencoded'
   }
   
   auth_endpoint = os.environ['auth-server-base-url'] # Base URL of the Authorization server
   user_role_arn = os.environ['iam-role-arn'] # The IAM role client application will use to complete the HTTP request on the datastore
   
   def lambda_handler(event, context):
       if 'datastoreEndpoint' not in event or 'operationName' not in event or 'bearerToken' not in event:
       return {}
   
       datastore_endpoint = event['datastoreEndpoint']
       operation_name = event['operationName']
       bearer_token = event['bearerToken']
       logger.info('Datastore Endpoint [{}], Operation Name: [{}]'.format(datastore_endpoint, operation_name))
   
       ## To validate the token
       auth_response = auth_with_provider(bearer_token)
       logger.info('Auth response: [{}]'.format(auth_response))
       auth_payload = json.loads(auth_response)
       ## Required parameters needed to be sent to the datastore endpoint for the HTTP request to go through
       auth_payload["isAuthorized"] = bool(auth_payload["active"])
       auth_payload["nbf"] = auth_payload["iat"]
       return {"authPayload": auth_payload, "iamRoleARN": user_role_arn}
   
   ## Access the server
   def auth_with_provider(token):
       data = {'token': token, 'token_type_hint': 'access_token'}
       req = request.Request(url=auth_endpoint + '/v1/introspect', data=parse.urlencode(data).encode(), headers=headers)
       with request.urlopen(req) as resp:
       return resp.read().decode()
   ```

### 修改 Lambda 函數的執行角色
<a name="modify-lambda-execution-role"></a>

建立 Lambda 函數之後，您需要更新執行角色，以包含呼叫 Secrets Manager 的必要許可。在 Secrets Manager 中，您建立的每個秘密都有 ARN。若要套用最低權限，執行角色應只能存取 Lambda 函數執行所需的資源。

您可以在 IAM 主控台中搜尋 Lambda 函數，或在 Lambda 主控台中選擇**組態**，以修改 Lambda 函數的執行角色。若要進一步了解如何管理 Lambda 函數執行角色，請參閱 [Lambda 執行角色](#smart-on-fhir-lambda-service-role-execution-role)。

**Example 授予 存取權的 Lambda 函數執行角色 `GetSecretValue`**  
將 IAM 動作新增至`GetSecretValue`執行角色會授予範例 Lambda 函數運作所需的許可。    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:secret-name-DKodTA"
        }
    ]
}
```

此時，您已建立 Lambda 函數，可用於驗證作為 FHIR REST 請求的一部分提供的存取字符，該請求會傳送到啟用 FHIR 的 SMART 資料存放區。

## 建立 HealthLake 服務角色以用於用來解碼 JWT 的 AWS Lambda 函數
<a name="smart-on-fhir-lambda-service-role"></a>

**人物：IAM 管理員**  
可新增或移除 IAM 政策，並建立新的 IAM 身分的使用者。  

**服務 角色**  
 服務角色是服務擔任的 [IAM 角色](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)，可代您執行動作。IAM 管理員可以從 IAM 內建立、修改和刪除服務角色。如需詳細資訊，請參閱《*IAM 使用者指南*》中的[建立角色以委派許可給 AWS 服務](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-service.html)。

JSON Web Token (JWT) 解碼後，Lambda 需要授權，才能傳回 IAM 角色 ARN。此角色必須具有執行 REST API 請求的必要許可，否則會因為許可不足而失敗。

使用 IAM 設定自訂政策時，最好授予所需的最低許可。若要進一步了解，請參閱《*IAM 使用者指南*》中的[套用最低權限許可](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)。

建立 HealthLake 服務角色以在授權 Lambda 函數中指定 需要兩個步驟。
+ 首先，您需要建立 IAM 政策。此政策必須指定您在授權伺服器中提供 範圍的 FHIR 資源存取權。
+ 其次，您需要建立 服務角色。當您建立角色時，您可以指定信任關係，並連接您在步驟 1 中建立的政策。信任關係會將 HealthLake 指定為服務委託人。在此步驟中，您需要指定 HealthLake 資料存放區 ARN 和 AWS 帳戶 ID。

### 建立新的 IAM 政策
<a name="lambda-service-role-part-1"></a>

您在授權伺服器中定義的範圍會決定已驗證使用者在 HealthLake 資料存放區中可存取的 FHIR 資源。

您可以量身打造您建立的 IAM 政策，以符合您定義的範圍。

您可以在 IAM 政策陳述式的 `Action`元素中定義下列動作。對於資料表`Action`中的每個 ，您可以定義 `Resource types`。在 HealthLake 中，資料存放區是唯一支援的資源類型，可在 IAM 許可政策陳述式的 `Resource`元素中定義。

個別 FHIR 資源不是您可以定義為 IAM 許可政策中 元素的資源。


**HealthLake 定義的動作**  

| 動作 | 描述 | 存取層級 | 資源類型 （必要） | 
| --- | --- | --- | --- | 
| CreateResource | 准許建立資源 | 寫入 | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 
| DeleteResource | 准許刪除資源 | 寫入 | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 
| ReadResource | 准許讀取資源 | 讀取 | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 
| SearchWithGet | 准許使用 GET 方法搜尋資源 | 讀取 | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 
| SearchWithPost | 准許使用 POST 方法搜尋資源 | 讀取 | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 
| StartFHIRExportJobWithPost | 准許使用 GET 開始 FHIR 匯出任務 | 寫入 | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 
| UpdateResource | 准許更新資源 | 寫入  | 資料存放區 ARN：arn：aws：healthlakeyour-region：111122223333：datastore/fhir/your-datastore-id | 

若要開始使用，您可以使用 `AmazonHealthLakeFullAccess`。此政策會授予資料存放區中所有 FHIR 資源的讀取、寫入、搜尋和匯出。若要授予資料存放區的唯讀許可，請使用 `AmazonHealthLakeReadOnlyAccess`。

若要進一步了解如何使用 AWS 管理主控台 AWS CLI或 IAM SDKs建立自訂政策，請參閱《[IAM 使用者指南》中的建立](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html) *IAM* 政策。

### 建立 HealthLake 的服務角色 (IAM 主控台）
<a name="lambda-service-role-part-2"></a>

使用此程序來建立服務角色。建立服務時，您也需要指定 IAM 政策。

**建立 HealthLake 的服務角色 (IAM 主控台）**

1. 登入 AWS 管理主控台 並開啟位於 https：//[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 的 IAM 主控台。

1. 在 IAM 主控台的導覽窗格中，選擇**角色**。

1. 然後，選擇 **Create role** (建立角色)。

1. 在**選取信任實體**頁面上，選擇**自訂信任政策**。

1. 接著，在**自訂信任政策**下，更新範例政策，如下所示。**your-account-id** 將 取代為您的帳戶號碼，並新增要在匯入或匯出任務中使用的資料存放區的 ARN。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "sts:AssumeRole",
               "Principal": {
                   "Service": "healthlake.amazonaws.com"
               },
               "Condition": {
                   "StringEquals": {
                       "aws:SourceAccount": "123456789012"
                   },
                   "ArnEquals": {
                       "aws:SourceArn": "arn:aws:healthlake:us-east-1:123456789012:datastore/fhir/your-datastore-id"
                   }
               }
           }
       ]
   }
   ```

------

1. 然後選擇**下一步**。

1. 在**新增許可**頁面上，選擇您希望 HealthLake 服務擔任的政策。若要尋找您的政策，請在**許可政策**下進行搜尋。

1. 然後，選擇**連接政策**。

1. 然後在**角色名稱**下**的名稱、檢閱和建立**頁面上輸入名稱。

1. （選用）接著在**描述**下，為您的角色新增簡短描述。

1. 如果可能，請輸入角色名稱或角色名稱後綴，以協助您識別此角色的用途。角色名稱在您的 AWS 帳戶內必須是獨一無二的。它們無法透過大小寫進行區分。例如，您無法建立名為 **PRODROLE** 和 **prodrole** 的角色。因為有各種實體可能會參照角色，所以您無法在建立角色之後編輯角色名稱。

1. 檢閱角色詳細資訊，然後選擇**建立角色**。

若要了解如何在範例 Lambda 函數中指定角色 ARN，請參閱 [建立 AWS Lambda 函數](#smart-on-fhir-lambda-create)。

## Lambda 執行角色
<a name="smart-on-fhir-lambda-service-role-execution-role"></a>

Lambda 函數的執行角色是授予函數存取 AWS 服務和資源的許可的 IAM 角色。本頁提供有關如何建立、檢視和管理 Lambda 函數執行角色的資訊。

根據預設，當您使用 建立新的 Lambda 函數時，Lambda 會建立具有最少許可的執行角色 AWS 管理主控台。若要管理執行角色中授予的許可，請參閱 *Lambda 開發人員指南*中的[在 IAM 主控台中建立執行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html#permissions-executionrole-console)。

本主題中提供的 Lambda 函數範例使用 Secrets Manager 來隱藏授權伺服器的憑證。

如同您建立的任何 IAM 角色，請務必遵循最低權限最佳實務。在開發片語期間，有時您可能會授予超出必要範圍的許可。在生產環境中發佈您的函數之前，最佳實務是調整政策以僅包含必要的許可。如需詳細資訊，請參閱《*IAM 使用者指南*》中的[套用最低權限](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)。

## 允許 HealthLake 觸發您的 Lambda 函數
<a name="smart-on-fhir-lambda-invoke-healthlake"></a>

因此 HealthLake 可以代表您叫用 Lambda 函數，您必須執行下列動作：
+ 您需要將 設定為`IdpLambdaArn`等於您希望 HealthLake 在`CreateFHIRDatastore`請求中調用之 Lambda 函數的 ARN。
+ 您需要以資源為基礎的政策，允許 HealthLake 代表您叫用 Lambda 函數。

當 HealthLake 在啟用 FHIR 的 SMART 資料存放區上收到 FHIR REST API 請求時，它需要許可來代表您調用資料存放區建立時指定的 Lambda 函數。若要授予 HealthLake 存取權，您將使用以資源為基礎的政策。若要進一步了解如何為 Lambda 函數建立資源型政策，請參閱《 *AWS Lambda 開發人員指南*》中的[允許 AWS 服務呼叫 Lambda 函數](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke)。

## 為您的 Lambda 函數佈建並行
<a name="smart-on-fhir-lambda-function-scaling"></a>

**重要**  
HealthLake 需要 Lambda 函數的最大執行時間少於一秒 (1000 毫秒）。  
如果您 Lambda 函數超過執行時間限制，您會收到 TimeOut 例外狀況。

為了避免發生此例外狀況，建議您設定佈建並行。您可以在增加呼叫前配置佈建並行，來確保所有請求均由具有低延遲的初始化執行個體所提供。若要進一步了解如何設定佈建並行，請參閱 *Lambda 開發人員指南*中的[設定佈建並行](https://docs.aws.amazon.com/ambda/latest/dg/provisioned-concurrency.html) 

若要查看 Lambda 函數的平均執行時間，目前請使用 Lambda 主控台上 Lambda 函數的**監控**頁面。根據預設，Lambda 主控台會提供**持續時間**圖表，顯示函數程式碼處理事件的平均、最短和最長時間。若要進一步了解監控 Lambda 函數，請參閱 [Lambda 開發人員指南中的 Lambda 主控台中的監控函數](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-functions-access-metrics.html#monitoring-console-graph-types)。 **

如果您已為 Lambda 函數佈建並行，並想要監控它，請參閱《*Lambda 開發人員指南*》中的[監控並行](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-concurrency.html)。