教學課程:搭 AWS Lambda 配 Amazon 簡易通知服務使用 - AWS Lambda

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

教學課程:搭 AWS Lambda 配 Amazon 簡易通知服務使用

在本教學中,您可以使用 Lambda 函數來單 AWS 帳戶 獨訂閱 Amazon 簡單通知服務 (AmazonSNS) 主題 AWS 帳戶。當您將訊息發佈到您的 Amazon SNS 主題時,Lambda 函數會讀取訊息的內容,並將其輸出到 Amazon CloudWatch 日誌。若要完成此自學課程,請使用 AWS Command Line Interface (AWS CLI)。

連接到連接到 CloudWatch 日誌日誌群組的 Lambda 函數的 Amazon SNS 主題

請執行下列步驟以完成本教學課程:

  • 帳戶 A 中,創建一個 Amazon SNS 主題。

  • 帳戶 B 中建立 Lambda 函數,以讀取主題的訊息。

  • 帳戶 B 中建立主題的訂閱。

  • 將訊息發佈到帳戶 A 中的 Amazon SNS 主題,並確認帳戶 B 中的 Lambda 函數會將訊息輸出到 CloudWatch 日誌。

完成這些步驟後,您將學習如何設定 Amazon SNS 主題以叫用 Lambda 函數。您還將學習如何建立 AWS Identity and Access Management (IAM) 政策,為另一個資源提供呼叫 Lambda AWS 帳戶 的權限。

在此教學課程中,您會使用兩種獨立的  AWS 帳戶。這些指 AWS CLI 令透過使用兩個名為 accountA AND 的具名輪廓來說明這一點accountB,每個設定為使用不同的輪廓 AWS 帳戶。若要瞭解如何設定 AWS CLI 使用不同的設定檔,請參閱第 2 版使用AWS Command Line Interface 者指南中的組態和認證檔案設定。請務必為兩個設定檔設定相同 AWS 區域 的預設值。

如果您為兩者建立的 AWS CLI 紀要 AWS 帳戶 使用不同的名稱,或者如果您使用預設紀要和一個具名的設定檔,請依需要在以下步驟中修改 AWS CLI 指令。

必要條件

如果您沒有 AWS 帳戶,請完成以下步驟來建立一個。

若要註冊成為 AWS 帳戶
  1. 打開https://portal.aws.amazon.com/billing/註冊

  2. 請遵循線上指示進行。

    部分註冊程序需接收來電,並在電話鍵盤輸入驗證碼。

    當您註冊一個時 AWS 帳戶,將創建AWS 帳戶根使用者一個。根使用者有權存取該帳戶中的所有 AWS 服務 和資源。作為安全最佳實務,請將管理存取權指派給使用者,並且僅使用根使用者來執行需要根使用者存取權的任務

AWS 註冊過程完成後,會向您發送確認電子郵件。您可以隨時登錄 https://aws.amazon.com/ 並選擇 我的帳戶,以檢視您目前的帳戶活動並管理帳戶。

註冊後,請保護您的 AWS 帳戶 AWS 帳戶根使用者 AWS IAM Identity Center、啟用和建立系統管理使用者,這樣您就不會將 root 使用者用於日常工作。

保護您的 AWS 帳戶根使用者
  1. 選擇 Root 使用者並輸入您的 AWS 帳戶 電子郵件地址,以帳戶擁有者身分登入。AWS Management Console在下一頁中,輸入您的密碼。

    如需使用根使用者登入的說明,請參閱 AWS 登入 使用者指南中的以根使用者身分登入

  2. 為您的 root 使用者開啟多因素驗證 (MFA)。

    如需指示,請參閱《使指南》中的「IAM為 AWS 帳戶 root 使用者啟用虛擬MFA裝置 (主控台)」。

建立具有管理存取權的使用者
  1. 啟用IAM身分識別中心。

    如需指示,請參閱 AWS IAM Identity Center 使用者指南中的啟用 AWS IAM Identity Center

  2. 在IAM身分識別中心中,將管理存取權授與使用者。

    若要取得有關使用 IAM Identity Center 目錄 做為身分識別來源的自學課程,請參閱《使用指南》 IAM Identity Center 目錄中的「以預設值設定使用AWS IAM Identity Center 者存取」。

以具有管理存取權的使用者身分登入
指派存取權給其他使用者
  1. 在 IAM Identity Center 中,建立遵循套用最低權限權限的最佳作法的權限集。

    如需指示,請參閱《AWS IAM Identity Center 使用者指南》中的建立許可集

  2. 將使用者指派至群組,然後對該群組指派單一登入存取權。

    如需指示,請參閱《AWS IAM Identity Center 使用者指南》中的新增群組

如果您尚未安裝 AWS Command Line Interface,請按照安裝或更新最新版本的步驟進 AWS CLI行安裝。

本教學課程需使用命令列終端機或 Shell 來執行命令。在 Linux 和 macOS 中,使用您偏好的 Shell 和套件管理工具。

注意

在 Windows 中,作業系統的內建終端機不支援您常用於 Lambda 的某些 Bash CLI 命令 (例如zip)。若要取得 Ubuntu 和 Bash 的 Windows 整合版本,請安裝適用於 Linux 的 Windows 子系統

創建一個 Amazon SNS 主題(帳戶 A)

第一步:創建 Amazon SNS 主題
若要建立 主題
  • 帳戶 A 中,使用以下 AWS CLI 命令建立 Amazon SNS 標準主題。

    aws sns create-topic --name sns-topic-for-lambda --profile accountA

    您應該會看到類似下列的輸出。

    { "TopicArn": "arn:aws:sns:us-west-2:123456789012:sns-topic-for-lambda" }

    記下您的主題的 Amazon 資源名稱(ARN)。當您新增許可到 Lambda 函數以訂閱主題時,稍後會在教學課程中用上它。

建立函數執行角色 (帳戶 B)

下一步:創建執行角色

執行角色是授與 Lambda 函數存取 AWS 服務和資源之權限的IAM角色。在帳戶 B 中建立函數之前,請先建立一個角色,該角色會授予函數將記錄寫入記錄檔的基本權限。 CloudWatch 我們將在稍後的步驟中新增要讀取 Amazon SNS 主題的許可。

若要建立執行角色
  1. 帳戶 B 中,在IAM控制台中打開角色頁面

  2. 選擇建立角色

  3. 針對信任的實體類型,請選擇 AWS 服務

  4. 針對使用案例,請選擇 Lambda

  5. 選擇 Next (下一步)

  6. 透過下列步驟將基本許可政策新增至角色:

    1. 許可政策搜尋方塊中,輸入 AWSLambdaBasicExecutionRole

    2. 選擇 Next (下一步)

  7. 執行下列動作來完成角色的建立:

    1. 角色詳細資訊下方的角色名稱中輸入 lambda-sns-role

    2. 選擇建立角色

建立 Lambda 函數 (帳戶 B)

下一步:創建函數

建立一個 Lambda 函數來處理您的 Amazon SNS 訊息。函數代碼將每個記錄的消息內容記錄到 Amazon CloudWatch 日誌。

本教學課程使用 Node.js 18.x 執行期,但我們也有提供其他執行期語言的範例程式碼。您可以在下列方塊中選取索引標籤,查看您感興趣的執行期程式碼。您將在此步驟中使用的 JavaScript 程式碼位於JavaScript索引標籤中顯示的第一個範例中。

.NET
AWS SDK for .NET
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使 Lambda. SNS NET。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 using Amazon.Lambda.Core; using Amazon.Lambda.SNSEvents; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] namespace SnsIntegration; public class Function { public async Task FunctionHandler(SNSEvent evnt, ILambdaContext context) { foreach (var record in evnt.Records) { await ProcessRecordAsync(record, context); } context.Logger.LogInformation("done"); } private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context) { try { context.Logger.LogInformation($"Processed record {record.Sns.Message}"); // TODO: Do interesting work based on the new message await Task.CompletedTask; } catch (Exception e) { //You can use Dead Letter Queue to handle failures. By configuring a Lambda DLQ. context.Logger.LogError($"An error occurred"); throw; } } }
Go
SDK對於轉到 V2
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使用 Go 使用 Lambda 消費SNS事件。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package main import ( "context" "fmt" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" ) func handler(ctx context.Context, snsEvent events.SNSEvent) { for _, record := range snsEvent.Records { processMessage(record) } fmt.Println("done") } func processMessage(record events.SNSEventRecord) { message := record.SNS.Message fmt.Printf("Processed message: %s\n", message) // TODO: Process your record here } func main() { lambda.Start(handler) }
Java
SDK對於爪哇 2.x
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使用 Java 使用 Lambda 消費SNS事件。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.SNSEvent; import com.amazonaws.services.lambda.runtime.events.SNSEvent.SNSRecord; import java.util.Iterator; import java.util.List; public class SNSEventHandler implements RequestHandler<SNSEvent, Boolean> { LambdaLogger logger; @Override public Boolean handleRequest(SNSEvent event, Context context) { logger = context.getLogger(); List<SNSRecord> records = event.getRecords(); if (!records.isEmpty()) { Iterator<SNSRecord> recordsIter = records.iterator(); while (recordsIter.hasNext()) { processRecord(recordsIter.next()); } } return Boolean.TRUE; } public void processRecord(SNSRecord record) { try { String message = record.getSNS().getMessage(); logger.log("message: " + message); } catch (Exception e) { throw new RuntimeException(e); } } }
JavaScript
SDK對於 JavaScript (3)
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使 Lambda JavaScript. SNS

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 exports.handler = async (event, context) => { for (const record of event.Records) { await processMessageAsync(record); } console.info("done"); }; async function processMessageAsync(record) { try { const message = JSON.stringify(record.Sns.Message); console.log(`Processed message ${message}`); await Promise.resolve(1); //Placeholder for actual async work } catch (err) { console.error("An error occurred"); throw err; } }

使 Lambda TypeScript. SNS

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { SNSEvent, Context, SNSHandler, SNSEventRecord } from "aws-lambda"; export const functionHandler: SNSHandler = async ( event: SNSEvent, context: Context ): Promise<void> => { for (const record of event.Records) { await processMessageAsync(record); } console.info("done"); }; async function processMessageAsync(record: SNSEventRecord): Promise<any> { try { const message: string = JSON.stringify(record.Sns.Message); console.log(`Processed message ${message}`); await Promise.resolve(1); //Placeholder for actual async work } catch (err) { console.error("An error occurred"); throw err; } }
PHP
適用於 PHP 的 SDK
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使 LambdaPHP. SNS

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 <?php /* Since native PHP support for AWS Lambda is not available, we are utilizing Bref's PHP functions runtime for AWS Lambda. For more information on Bref's PHP runtime for Lambda, refer to: https://bref.sh/docs/runtimes/function Another approach would be to create a custom runtime. A practical example can be found here: https://aws.amazon.com/blogs/apn/aws-lambda-custom-runtime-for-php-a-practical-example/ */ // Additional composer packages may be required when using Bref or any other PHP functions runtime. // require __DIR__ . '/vendor/autoload.php'; use Bref\Context\Context; use Bref\Event\Sns\SnsEvent; use Bref\Event\Sns\SnsHandler; class Handler extends SnsHandler { public function handleSns(SnsEvent $event, Context $context): void { foreach ($event->getRecords() as $record) { $message = $record->getMessage(); // TODO: Implement your custom processing logic here // Any exception thrown will be logged and the invocation will be marked as failed echo "Processed Message: $message" . PHP_EOL; } } } return new Handler();
Python
SDK對於 Python(肉毒桿菌 3)
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使用 Python 使用 Lambda 一個SNS事件。

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 def lambda_handler(event, context): for record in event['Records']: process_message(record) print("done") def process_message(record): try: message = record['Sns']['Message'] print(f"Processed message {message}") # TODO; Process your record here except Exception as e: print("An error occurred") raise e
Ruby
SDK對於紅寶石
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使用紅寶石消耗與 Lambda 的SNS事件。

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 def lambda_handler(event:, context:) event['Records'].map { |record| process_message(record) } end def process_message(record) message = record['Sns']['Message'] puts("Processing message: #{message}") rescue StandardError => e puts("Error processing message: #{e}") raise end
Rust
SDK對於銹
注意

還有更多關於 GitHub。尋找完整範例,並了解如何在無伺服器範例儲存庫中設定和執行。

使用 Rust 使用 Lambda 消耗SNS事件。

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 use aws_lambda_events::event::sns::SnsEvent; use aws_lambda_events::sns::SnsRecord; use lambda_runtime::{run, service_fn, Error, LambdaEvent}; use tracing::info; // Built with the following dependencies: // aws_lambda_events = { version = "0.10.0", default-features = false, features = ["sns"] } // lambda_runtime = "0.8.1" // tokio = { version = "1", features = ["macros"] } // tracing = { version = "0.1", features = ["log"] } // tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] } async fn function_handler(event: LambdaEvent<SnsEvent>) -> Result<(), Error> { for event in event.payload.records { process_record(&event)?; } Ok(()) } fn process_record(record: &SnsRecord) -> Result<(), Error> { info!("Processing SNS Message: {}", record.sns.message); // Implement your record handling code here. Ok(()) } #[tokio::main] async fn main() -> Result<(), Error> { tracing_subscriber::fmt() .with_max_level(tracing::Level::INFO) .with_target(false) .without_time() .init(); run(service_fn(function_handler)).await }
建立函數
  1. 建立專案的目錄,然後切換至該目錄。

    mkdir sns-tutorial cd sns-tutorial
  2. 將範例程 JavaScript 式碼複製到名為的新檔案中index.js

  3. 使用以下 zip 命令建立部署套件。

    zip function.zip index.js
  4. 執行下列 AWS CLI 命令,在帳戶 B 中建立您的 Lambda 函數。

    aws lambda create-function --function-name Function-With-SNS \ --zip-file fileb://function.zip --handler index.handler --runtime nodejs18.x \ --role arn:aws:iam::<AccountB_ID>:role/lambda-sns-role \ --timeout 60 --profile accountB

    您應該會看到類似下列的輸出。

    { "FunctionName": "Function-With-SNS", "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:Function-With-SNS", "Runtime": "nodejs18.x", "Role": "arn:aws:iam::123456789012:role/lambda_basic_role", "Handler": "index.handler", ... "RuntimeVersionConfig": { "RuntimeVersionArn": "arn:aws:lambda:us-west-2::runtime:7d5f06b69c951da8a48b926ce280a9daf2e8bb1a74fc4a2672580c787d608206" } }
  5. 記錄功能的 Amazon 資源名稱(ARN)。稍後在教程中添加許可以允許 Amazon 調用您的函數時,您將需SNS要它。

為函數新增許可 (帳戶 B)

下一步:向功能添加權限

SNS若要讓 Amazon 叫用您的函數,您需要在以資源為基礎的政策聲明中授予其權限。您可以使用 AWS CLI add-permission命令加入這個陳述式。

授SNS予 Amazon 調用您的函數的許可
  • 帳戶 B 中,使用您之前記錄ARN的 Amazon SNS 主題執行以下 AWS CLI 命令。

    aws lambda add-permission --function-name Function-With-SNS \ --source-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \ --statement-id function-with-sns --action "lambda:InvokeFunction" \ --principal sns.amazonaws.com --profile accountB

    您應該會看到類似下列的輸出。

    { "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\": \"arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda\"}}, \"Action\":[\"lambda:InvokeFunction\"], \"Resource\":\"arn:aws:lambda:us-east-1:<AccountB_ID>:function:Function-With-SNS\", \"Effect\":\"Allow\",\"Principal\":{\"Service\":\"sns.amazonaws.com\"}, \"Sid\":\"function-with-sns\"}" }
注意

如果具有 Amazon SNS 主題的帳戶託管在選擇加入中 AWS 區域,則需要在主體中指定區域。例如,如果您正在使用亞太區域 (香港) 區域的 Amazon SNS 主題,則需要指定sns.ap-east-1.amazonaws.com而非主體。sns.amazonaws.com

授予 Amazon SNS 訂閱的跨帳戶許可(帳戶 A)

下一步:授予跨帳戶權限

若要讓帳戶 B 中的 Lambda 函數訂閱您在帳戶 A 中建立的 Amazon SNS 主題,您需要授予帳戶 B 的權限,才能訂閱您的主題。您可以使用 AWS CLI add-permission命令授與此權限。

若要向帳戶 B 授予訂閱主題的許可
  • 帳戶 A 中,執行下列 AWS CLI 命令。使用ARN您之前記錄的 Amazon SNS 主題。

    aws sns add-permission --label lambda-access --aws-account-id <AccountB_ID> \ --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \ --action-name Subscribe ListSubscriptionsByTopic --profile accountA

建立訂閱 (帳戶 B)

下一步:建立訂閱

帳戶 B 中,您現在將 Lambda 函數訂閱到您在帳戶 A 的教學課程開始時建立的 Amazon SNS 主題。 當訊息傳送至此主題 (sns-topic-for-lambda) 時,Amazon 會Function-With-SNS帳戶 B 中SNS叫用您的 Lambda 函數。

若要建立訂閱
  • 帳戶 B 中,執行下列 AWS CLI 命令。使用您在中建立主題的預設區域,以及ARNs適用於您的主題和 Lambda 函數。

    aws sns subscribe --protocol lambda \ --region us-east-1 \ --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \ --notification-endpoint arn:aws:lambda:us-east-1:<AccountB_ID>:function:Function-With-SNS \ --profile accountB

    您應該會看到類似下列的輸出。

    { "SubscriptionArn": "arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda:5d906xxxx-7c8x-45dx-a9dx-0484e31c98xx" }

將訊息發佈至主題 (帳戶 A 和帳戶 B)

下一步:發佈訊息

現在帳戶 B 中的 Lambda 函數已訂閱帳戶 A 中的 Amazon SNS 主題,現在是時候將訊息發佈到您的主題來測試您的設定。若要確認 Amazon SNS 已叫用 Lambda 函數,您可以使用 CloudWatch 日誌來檢視函數的輸出。

若要將訊息發佈到您的主題並檢視函數的輸出
  1. 輸入 Hello World 至文字檔,並儲存為 message.txt

  2. 從您儲存文字檔案的相同目錄中,在帳戶 A 中執行下列 AWS CLI 命令。 使用您ARN自己的主題。

    aws sns publish --message file://message.txt --subject Test \ --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \ --profile accountA

    這將返回一個帶有唯一標識符的消息 ID,表明 Amazon SNS 已接受該消息。Amazon SNS 然後嘗試將消息傳遞給該主題的訂閱者。若要確認 Amazon SNS 已叫用 Lambda 函數,請使用 CloudWatch 日誌檢視函數的輸出:

  3. 帳戶 B 中,開啟 Amazon CloudWatch 主控台的日誌群組頁面。

  4. 為函數 (/aws/lambda/Function-With-SNS) 選擇日誌群組名稱。

  5. 選擇最新的日誌串流。

  6. 如果您的函數有被正確調用,您將會看到類似下方的輸出,顯示您發佈到主題的訊息內容。

    2023-07-31T21:42:51.250Z c1cba6b8-ade9-4380-aa32-d1a225da0e48 INFO Processed message Hello World 2023-07-31T21:42:51.250Z c1cba6b8-ade9-4380-aa32-d1a225da0e48 INFO done

清除您的資源

除非您想要保留為此教學課程建立的資源,否則您現在便可刪除。刪除您不再使用的 AWS 資源,您可以避免不必要的 AWS 帳戶費用

帳戶 A 中,清理您的 Amazon SNS 主題。

刪除 Amazon SNS 主題
  1. 打開 Amazon SNS 控制台的主題頁面

  2. 選擇您建立的主題。

  3. 選擇 刪除

  4. 在文字輸入欄位中輸入 delete me

  5. 選擇 刪除

帳戶 B 中,清理您的執行角色、Lambda 函數和 Amazon SNS 訂閱。

刪除執行角色
  1. 開啟主IAM控台的 [角色] 頁面

  2. 選取您建立的執行角色。

  3. 選擇 刪除

  4. 在文字輸入欄位中輸入角色的名稱,然後選擇 刪除

若要刪除 Lambda 函數
  1. 開啟 Lambda 主控台中的 函數頁面

  2. 選擇您建立的函數。

  3. 選擇 Actions (動作)、Delete (刪除)。

  4. 在文字輸入欄位中輸入 delete,然後選擇 刪除

刪除 Amazon SNS 訂閱
  1. 打開 Amazon SNS 控制台的訂閱頁面

  2. 選取您建立的訂閱。

  3. 選擇 刪除刪除