Lambda関数内で、別AWSアカウントのLambda関数を呼び出す


**AWSアカウントＡ**内のLambda関数から**、AWSアカウントＢ**内にあるLambda関数を呼び出す方法の備忘録です。

もともとのゴールは、アカウントＡ内のAmazon **Lexボット**から、アカウントＢ内のLambda関数を直接呼び出すことでした。

しかし現状無理そうなので、アカウントＡ内の（プロキシ）Lambda関数を経由して、間接的にアカウントＢの（本命）Lambda関数を呼び出すことにしました。



##概要

Lexボットがある、**呼び出し側**のAWSアカウントを**アカウントＡ（ID：999999999999）**、**呼び出される**本命Lambda関数がある側のAWSアカウントを**アカウントＢ（ID：000000000000）**とします。

アカウントＡ内に作成するプロキシLambda関数が、アカウントＢ内の本命Lambda関数を呼び出すには、アカウントＢの側で**アカウントＡのアクセスを許可**する必要があります。

セットアップ全体の流れは次のとおり。

1. アカウントＢ内に、本命Lambdaの実行権限を持つIAM Roleを作成
1. アカウントＡ内に、上記のRoleと連携するRoleを作成
1. アカウントＡ内で、このRoleの下にプロキシLambda関数を作成
1. プロキシLambda内で、Roleの権限を行使して本命Lambdaを実行
1. （おまけ）LexボットがプロキシLambda関数を呼び出すようにする

##Step 1：アカウントＢ内に IAM Roleを作成
まずアカウントＢ側で、本命Lambdaを実行できる権限を持つ、アカウントＡ用のIAM Roleを作成します。


**アカウントＢ**（ID：000000000000、本命Lambda側）上で、AWS管理コンソールのメニューから **IAM > Access management > Roles**を開き**Create role**ボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/646e4b73-8a0b-bf09-92df-4f52df388181.png)

Select type of trusted entityセクションで**Another AWS account**を選択し、Account ID欄に**アカウントＡのID**を入力。アカウントＡがこのロールを担う主体となります。
**Next: Permissions**をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/6a9d0b00-02b9-dd04-fd09-f300d580a12f.png)

Attach permissions policiesセクションでは、このロールが持つ権限として**AWSLambdaRole**ポリシーを選択し、次に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/79b5a63c-059a-d0fb-cbbc-2a2c2f79a78c.png)

Tagsセクションでは、必要であればタグを指定して次に進みます。

次のReviewセクションで、**Role name**欄に任意のロール名を入力して、**Create role**ボタンをクリック。
ロールが新規作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/0b17a2cf-dda0-65c5-acee-b847c9ddcbb2.png)


作成されたロールを開き、ロールの**Role ARN**を控えておきます。（Step 2と3で使用する）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/b20f01a0-eb6a-bc89-66a7-3bfc9f8ac857.png)

##Step 2：アカウントＡ側にもロールを作成
次はアカウントＡ側に、Step 1で作成したロールと連携するロールを新規作成します。

**アカウントＡ**（ID：999999999999、LexボットとプロキシLambda側）上で、AWS管理コンソールのメニューから **IAM > Access management > Roles** を開き、**Create role**ボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/646e4b73-8a0b-bf09-92df-4f52df388181.png)

Select type of trusted entityセクションで**AWS service**、Choose a use caseセクションでは**Lambda**を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/343df985-40b0-994d-8e50-fc6ff45abcdb.png)

Attach permissions policiesセクションで、**Create policy**ボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/a5e08323-4adf-41f7-e14b-848bd27b671a.png)

新しいブラウザーウィンドウ（またはタブ）が開きます。**JSON**タブに移動し、下記のようなインラインポリシーを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/a52453c3-bec8-bd01-14f0-3a3eb615919b.png)

インラインポリシーのテキストはこちら↓。
**Resource**の値として、**Step 1で作成したロールのARN**を指定します。

```json:AssumeRolePolicy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::000000000000:role/myIntegrationLambda" //アカウントＢで作成したロールのARN
        }
    ]
}
```

Tagsセクションは、必要であればタグを指定して次に進みます。

次のReview policyセクションで、**Name**欄に任意のポリシー名を入力し、**Create policy**ボタンをクリック。
インラインポリシーが新規作成されます。
このウィンドウ（またはタブ）を閉じて、手続き途中だったCreate roleのウィンドウに戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/549abfa5-d610-40d3-a5c4-4ad96fac33da.png)

Create roleのブラウザーウィンドウに戻り、Attach permissions policiesセクションで、ロールに付与するポリシーを選択します。
ここでは**AWSLambdaBasicExecutionRole**と、**今作成したインラインポリシー**を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/cc15c7ab-b3fc-4361-021a-b45f89a89a06.png)
AWSLambdaBasicExecutionRoleはアカウントＡ内のLambdaを実行する権限、インラインポリシーはStep 1で作成した、アカウントＢ側のロールを執行する権限を付与するポリシーです。

**Next: Tags**ボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/a1f5f360-ee16-9357-777a-0af93989b109.png)

Tagsセクションでは、必要であればタグを指定して、次に進みます。

次のReviewセクションで、**Role name**欄に任意のロール名を入力して**Create role**ボタンをクリック。
アカウントＡ側のロールが新規作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/0bf81319-8353-f2a0-107f-995e9aa128f4.png)

##Step 3：アカウントＡ側で（アカウントＢ内の本命Lambdaを呼び出す）プロキシLambdaを作成
**アカウントＡ**（ID：999999999999）のAWS管理コンソールで、**Lambda**を開き、**Create function**ボタンをクリック。プロキシLambda関数を新規作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/1b569848-69a8-082e-c642-502d1f6d0cc6.png)

**Author from scratch**を選び、**Function name** 欄に任意の関数名を入力。
**Runtime**はNode.js 14.xを選択し、**Change default execution role**セクションをクリックして開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/40622835-d2d6-f70d-7229-1a7ff945e106.png)

Change default execution roleセクションでは、Step 2で作成したロールを指定するので**Use an existing role**を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/44ce1c2b-921d-269a-3d79-7346195ea662.png)

**Existing role**のドロップダウンリストで、**Step 2で作成したロール**を選びます。
このロール選択により、プロキシLambdaがアカウントＢの本命Lambdaを実行できる権限を持ちます。
**Create function**ボタンをクリックして、Lambda関数を新規作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/251cfef7-4a80-33b5-2f63-ce8970988d1e.png)

##Step 4：プロキシLambda内で、Roleの権限を行使して本命Lambdaを実行
本命Lambda関数を呼び出して実行するプロキシLambda関数のコードを書きます。

Lambda関数の画面では、上部右側に、その関数のARNが表示されています。プロキシLambdaのコード内で、本命LambdaのARNが必要になるので、予めアカウントＢ内の本命Lambdaから取得しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/da239ded-93d4-3d50-1c20-888c52821525.png)
index.jsに、下記のコードを入力します。

```javascript:ProxyLambda
const aws = require('aws-sdk');
     
"use strict";
 
 
// --------------- Main handler -----------------------
  
// Route the incoming request based on intent.
// The JSON body of the request is provided in the event slot.
exports.handler = async (event, context, callback) => {
        console.log("Started");
        const lexPost = JSON.stringify(event);
        console.log(lexPost);
       
 
        var sts = new aws.STS({apiVersion: '2011-06-15'});
        var stsParams = {
            RoleArn: "arn:aws:iam::000000000000:role/myIntegrationLambda", //Step 1で作成したロールのARN
            DurationSeconds: 3600,
            RoleSessionName: "assumeRoleSession"
        };
     
        const stsResults = await sts.assumeRole(stsParams).promise();
        console.log("STS Result: ", stsResults);
         
        var lambda = new aws.Lambda({
            region: 'ap-northeast-1', //アカウントＡのlambdaがあるリージョン
            accessKeyId: stsResults.Credentials.AccessKeyId,
            secretAccessKey:stsResults.Credentials.SecretAccessKey,
            sessionToken: stsResults.Credentials.SessionToken
        });
     
     
        console.log("Got new Lambda");
           
        const params = {
            FunctionName: "arn:aws:lambda:ap-northeast-1:000000000000:function:myMainLambda", //アカウントＡのlambdaのARN
            InvocationType: "RequestResponse",
            Payload: JSON.stringify(event)
        };
        console.log("Params: ", params);
           
        const res = await lambda.invoke(params, (err, data) => {
            let res = data;
            if (err) {
              console.log("呼び出し失敗");
              console.log(err);
              callback(err, err);       
            } else {
              console.log("呼び出し成功");
              console.log("response:", res);
              callback(null, JSON.parse(res.Payload));
            }
        }).promise();
           
};
```

- 18行目のRoleArnには、Step 1の最後で控えたARNを指定します。
- 37行目のFunctionNameには、アカウントＢにある本命lambda関数のARNを指定します。

**Deploy**ボタンでコードをデプロイします。

##Step 5：（おまけ）LexボットがプロキシLambda関数を呼び出すようにする
LexボットのインテントがプロキシLambda関数実行できるよう、FulfillmentセクションでStep 3、4のプロキシLambda関数を指定します。

まず、Step 4の最後でコードをデプロイしたあと、**Versions**タブに移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/2533b142-9c94-da2a-1c2b-74a821b76c0a.png)

**Publish new version**ボタンをクリックして新しいバージョンを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/5c5ca25f-1fad-132f-fa11-3e5b2d0440df.png)

バージョンを発行することで、LexボットがIntentのFulfillmentにこのlambda関数を利用できるようになります。

**アカウントＡ**上で、AWS管理コンソールのメニューからAmazon Lexをクリックして移動し、Lambda関数を実行させたいIntentを開きます。

IntentのFulfillmentセクションで、プロキシLambda関数を指定し、Intentを保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/973ab3cb-0049-8b30-bb4e-229eaa7c4a9c.png)