AWSアカウントA内のLambda関数から**、AWSアカウントB**内にあるLambda関数を呼び出す方法の備忘録です。
もともとのゴールは、アカウントA内のAmazon Lexボットから、アカウントB内のLambda関数を直接呼び出すことでした。
しかし現状無理そうなので、アカウントA内の(プロキシ)Lambda関数を経由して、間接的にアカウントBの(本命)Lambda関数を呼び出すことにしました。
##概要
Lexボットがある、呼び出し側のAWSアカウントをアカウントA(ID:999999999999)、呼び出される本命Lambda関数がある側のAWSアカウントを**アカウントB(ID:000000000000)**とします。
アカウントA内に作成するプロキシLambda関数が、アカウントB内の本命Lambda関数を呼び出すには、アカウントBの側でアカウントAのアクセスを許可する必要があります。
セットアップ全体の流れは次のとおり。
- アカウントB内に、本命Lambdaの実行権限を持つIAM Roleを作成
- アカウントA内に、上記のRoleと連携するRoleを作成
- アカウントA内で、このRoleの下にプロキシLambda関数を作成
- プロキシLambda内で、Roleの権限を行使して本命Lambdaを実行
- (おまけ)LexボットがプロキシLambda関数を呼び出すようにする
##Step 1:アカウントB内に IAM Roleを作成
まずアカウントB側で、本命Lambdaを実行できる権限を持つ、アカウントA用のIAM Roleを作成します。
アカウントB(ID:000000000000、本命Lambda側)上で、AWS管理コンソールのメニューから IAM > Access management > Rolesを開きCreate roleボタンをクリック。
Select type of trusted entityセクションでAnother AWS accountを選択し、Account ID欄にアカウントAのIDを入力。アカウントAがこのロールを担う主体となります。
Next: Permissionsをクリック。
Attach permissions policiesセクションでは、このロールが持つ権限としてAWSLambdaRoleポリシーを選択し、次に進みます。
Tagsセクションでは、必要であればタグを指定して次に進みます。
次のReviewセクションで、Role name欄に任意のロール名を入力して、Create roleボタンをクリック。
ロールが新規作成されます。
作成されたロールを開き、ロールのRole ARNを控えておきます。(Step 2と3で使用する)
##Step 2:アカウントA側にもロールを作成
次はアカウントA側に、Step 1で作成したロールと連携するロールを新規作成します。
アカウントA(ID:999999999999、LexボットとプロキシLambda側)上で、AWS管理コンソールのメニューから IAM > Access management > Roles を開き、Create roleボタンをクリック。
Select type of trusted entityセクションでAWS service、Choose a use caseセクションではLambdaを選択。
Attach permissions policiesセクションで、Create policyボタンをクリック。
新しいブラウザーウィンドウ(またはタブ)が開きます。JSONタブに移動し、下記のようなインラインポリシーを作成します。
インラインポリシーのテキストはこちら↓。
Resourceの値として、Step 1で作成したロールのARNを指定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::000000000000:role/myIntegrationLambda" //アカウントBで作成したロールのARN
}
]
}
Tagsセクションは、必要であればタグを指定して次に進みます。
次のReview policyセクションで、Name欄に任意のポリシー名を入力し、Create policyボタンをクリック。
インラインポリシーが新規作成されます。
このウィンドウ(またはタブ)を閉じて、手続き途中だったCreate roleのウィンドウに戻ります。
Create roleのブラウザーウィンドウに戻り、Attach permissions policiesセクションで、ロールに付与するポリシーを選択します。
ここではAWSLambdaBasicExecutionRoleと、今作成したインラインポリシーを選択。
AWSLambdaBasicExecutionRoleはアカウントA内のLambdaを実行する権限、インラインポリシーはStep 1で作成した、アカウントB側のロールを執行する権限を付与するポリシーです。
Tagsセクションでは、必要であればタグを指定して、次に進みます。
次のReviewセクションで、Role name欄に任意のロール名を入力してCreate roleボタンをクリック。
アカウントA側のロールが新規作成されます。
##Step 3:アカウントA側で(アカウントB内の本命Lambdaを呼び出す)プロキシLambdaを作成
アカウントA(ID:999999999999)のAWS管理コンソールで、Lambdaを開き、Create functionボタンをクリック。プロキシLambda関数を新規作成します。
Author from scratchを選び、Function name 欄に任意の関数名を入力。
RuntimeはNode.js 14.xを選択し、Change default execution roleセクションをクリックして開く。
Change default execution roleセクションでは、Step 2で作成したロールを指定するのでUse an existing roleを選択します。
Existing roleのドロップダウンリストで、Step 2で作成したロールを選びます。
このロール選択により、プロキシLambdaがアカウントBの本命Lambdaを実行できる権限を持ちます。
Create functionボタンをクリックして、Lambda関数を新規作成します。
##Step 4:プロキシLambda内で、Roleの権限を行使して本命Lambdaを実行
本命Lambda関数を呼び出して実行するプロキシLambda関数のコードを書きます。
Lambda関数の画面では、上部右側に、その関数のARNが表示されています。プロキシLambdaのコード内で、本命LambdaのARNが必要になるので、予めアカウントB内の本命Lambdaから取得しておきます。
index.jsに、下記のコードを入力します。
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', //アカウントAの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", //アカウントAの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には、アカウントBにある本命lambda関数のARNを指定します。
Deployボタンでコードをデプロイします。
##Step 5:(おまけ)LexボットがプロキシLambda関数を呼び出すようにする
LexボットのインテントがプロキシLambda関数実行できるよう、FulfillmentセクションでStep 3、4のプロキシLambda関数を指定します。
まず、Step 4の最後でコードをデプロイしたあと、Versionsタブに移動します。
Publish new versionボタンをクリックして新しいバージョンを作成します。
バージョンを発行することで、LexボットがIntentのFulfillmentにこのlambda関数を利用できるようになります。
アカウントA上で、AWS管理コンソールのメニューからAmazon Lexをクリックして移動し、Lambda関数を実行させたいIntentを開きます。