VPC内のlambdaからSecrets Managerの値を取得し、Slack WebHook URLにリクエストを送る

# 概要

- デフォルトVPC内のap-northeast-1aのデフォルトサブネット内に設置されたlambda関数で下記のことをする。
    - Secrets Managerの値を取得しconsole.logで出力
    - Slack　WebHook URLにリクエストを送信
- 制約として下記がある。
    - デフォルトVPCに紐づくセキュリティグループのインバウンドルールは変更できないものとする。
    - NATゲートウェイは使用しない
    - 自前でプロキシサーバーを作成してAWS PrivateLinkを使うことはしない

# やりたいこと

## 本当はこうしたい

- 本当は下記の様にしたい。

![work__Online_Whiteboard_for_Visual_Collaboration.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/bd9e3c68-835e-72f8-f5c0-6444fc8e42f3.png)

- しかしながらセキュリティグループの設定変更ができないためシークレットマネージャーからのレスポンスや、Slack WebHook URLにリクエストを送ったときのレスポンスを受け取れないためこの方法では実現できない。（制約があるため）

![work__Online_Whiteboard_for_Visual_Collaboration.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/46863752-64e2-ed8a-7c16-70b4a01a4b7d.png)

## こうする

- 下記のようにlambda関数の２つの「機能」を個々のlambda関数Aとlambda関数Bに分割する。

![work__Online_Whiteboard_for_Visual_Collaboration.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/11425d2c-1e50-24d7-95f3-05fa05251b38.png)

- こうすることで問題が解決できそうである。

# 前提

- SlackのWebhook URLを知っていること

# 方法

## Secrets Managerの準備

- 下記の内容を参考に下記の情報で値を登録する。
    - キー名： `API-KEY`
    - 値： `hogefuga`

https://qiita.com/miriwo/items/269c8ae11ea8b5cc7740

## lambda関数B（Slack通知）の作成

- axiosのカスタムレイヤーを用意する。
- 「test-send-request-slack-function-b」関数を作成する。ランタイムはNode.js18とする。
- 下記のコードを記載する。

    ```js
    import axios from 'axios';
    
    export const handler = async(event) => {
    
        const slackUrl = ご自身のSlackのWebhook URL;
    
        const data = {
            text: 'Hello, World for lambda!'
        };
      
        const config = {
            headers: {
                'Content-Type': 'application/json'
            }
        };
      
        const response = await axios.post(slackUrl, data, config)
            .then((response) => {
                console.log(response.data);
            })
            .catch((error) => {
                console.error(error);
            });
          
        return response;
    };
    ```

## lambda関数A（Secrets Managerを取得して出力）の作成

- 下記の内容を参考に「test-get-secrets-manager-function-a」関数を作成する。ランタイムはNode.js18とする。

https://qiita.com/miriwo/items/6324beefb58f99116d0d

- 下記のコードを記載する。

    ```js
    // Use this code snippet in your app.
    // If you need more information about configurations or implementing the sample code, visit the AWS docs:
    // https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-started.html
    
    import {
      SecretsManagerClient,
      GetSecretValueCommand,
    } from "@aws-sdk/client-secrets-manager";
    import { Lambda } from '@aws-sdk/client-lambda';
    
    const region = "ap-northeast-1";
    
    const lambda = new Lambda({
      region: region
    });
    
    const secret_name = "API-KEY";
    
    const client = new SecretsManagerClient({
      region: region,
    });
    
    let response;
    
    try {
      response = await client.send(
        new GetSecretValueCommand({
          SecretId: secret_name,
          VersionStage: "AWSCURRENT", // VersionStage defaults to AWSCURRENT if unspecified
        })
      );
    } catch (error) {
      // For a list of exceptions thrown, see
      // https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
      throw error;
    }
    
    const secret = response.SecretString;
    console.log(secret);
    
    export async function handler(event) {
    
      const functionBArn = 'lambda関数BのARN';
    
      const params = {
        FunctionName: functionBArn,
        InvocationType: 'RequestResponse',
        Payload: JSON.stringify(event),
      };
    
      try {
        // Lambda関数Bを呼び出し、結果を取得
        await lambda.invoke(params);
      
        return true;
      } catch (error) {
        console.error('Error invoking functionB:', error);
        throw error;
      }
    }
    ```

- デフォルトVPCのap-northeast-1aのデフォルトサブネットにlambda関数Aを設置する。
- セキュリティグループはVPCと同じものを割り当てる。
- レイヤーでAWSレイヤーの「AWS-Parameters-and-Secrets-Lambda-Extension」を設定する。
- lambda関数Aのロールに下記のポリシーを割り当てる。
    - SecretsManagerReadWrite
    - AWSLambdaVPCAccessExecutionRole
- lambda関数Aのロールに下記のインラインポリシーを追加する

    ```json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "lambda:InvokeFunction",
          "Resource": "lambda関数BのARN"
        }
      ]
    }
    ```

## VPCエンドポイント用セキュリティグループの作成（関数A → Secrets ManagerのVPCエンドポイント用）

- 下記の情報でセキュリティグループを作成する。
    - セキュリティグループ名：test-get-secrets-manager-vpc-end-point-sg
    - 説明：test-get-secrets-manager-vpc-end-point-sg
    - VPC：デフォルトVPC
    - インバウンドルール
        - タイプ：HTTPS
        - ソース：0.0.0.0/0
    - アウトバウンドルール
        - タイプ：すべてのトラフィック
        - ソース：0.0.0.0/0

## VPCエンドポイント用セキュリティグループの作成（関数A → 関数B）

- 下記の情報でセキュリティグループを作成する。
    - セキュリティグループ名：test-send-request-slack-vpc-end-point-sg
    - 説明：test-send-request-slack-end-point-sg
    - VPC：デフォルトVPC
    - インバウンドルール
        - タイプ：HTTPS
        - ソース：0.0.0.0/0
    - アウトバウンドルール
        - タイプ：すべてのトラフィック
        - ソース：0.0.0.0/0

## VPCエンドポイントの作成（関数A → Secrets Manager）

- 下記の情報でVPCエンドポイントを作成する。
    - 名前タグ：test-get-secrets-manager-vpc-end-point
    - サービスカテゴリ：AWSのサービス
    - サービス名：com.amazonaws.ap-northeast-1.secretsmanager
    - VPC：デフォルトVPC
    - サブネット：ap-northeast-1aのデフォルトサブネット
    - IPアドレスタイプ：IPv4
    - セキュリティグループ：test-get-secrets-manager-vpc-end-point-sg
    - ポリシー：フルアクセス

## VPCエンドポイントの作成（関数A → 関数B）

- 下記の情報でVPCエンドポイントを作成する。
    - 名前タグ：test-send-request-slack-end-point
    - サービスカテゴリ：AWSのサービス
    - サービス名：com.amazonaws.ap-northeast-1.lambda
    - VPC：デフォルトVPC
    - サブネット：ap-northeast-1aのデフォルトサブネット
    - IPアドレスタイプ：IPv4
    - セキュリティグループ：test-send-request-slack-end-point-sg
    - ポリシー：フルアクセス

## 実行

- すべての設定が完了したら、hello-worldテストを作成し、lambda関数Aを実行する。
- lambda関数AのコンソールにSecrets Managerから取得した「hogefuga」が出力されていることを確認する。
- lambda関数Aからlambda関数Bが実行され、Slackに通知が来ることを確認する。

# 参考文献

https://qiita.com/miriwo/items/92bf53b37a6b9a371dc9

https://qiita.com/miriwo/items/bfd8ccca52d216b315a7

https://qiita.com/miriwo/items/269c8ae11ea8b5cc7740

https://qiita.com/miriwo/items/c1606a4292e108425d77

https://qiita.com/miriwo/items/e9084359d4b75b6bffb2