Lambda関数に付与するIAMロールについて | AWS豆知識
DynamoDBへのアクセス許可
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SidDynamoDB",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": [
DynamoDBに作成したテーブルのARN
テーブルに設定したLSIやGSIのインデックスについても個別に指定する
]
}
]
}
S3への許可
ワイルドカードを利用している
s3:*Object → Objectに対する操作すべてということになる
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SidS3ListBucket",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::バケット名"
]
},
{
"Sid": "SidS3ObjectAction",
"Effect": "Allow",
"Action": [
"s3:*Object"
],
"Resource": [
"arn:aws:s3:::バケット名/*"
]
}
]
}
AWS Cognitoの認証機能をAPI Gatewayの呼び出しに利用する | AWSサーバレス構築
参考にするチュートリアル
・英語版チュートリアル(新しめ)
・日本語チュートリアル(古いけど有益)
・Javascriptコードの在り処
また、事前に当ブログ記事「簡易チュートリアル」を参照のこと。
JavaScript
AWS SDK
amazon-cognito-identity.min.js と aws-cognito-sdk.min.js を、公式チュートリアルのコードから拝借する。(ventorフォルダ)
config.js
Cognitoで作成したユーザープールの「プールID」「アプリクライアントID」「リージョン」を入力する。
window._config = {
cognito: {
userPoolId: 'プールID',
userPoolClientId: 'アプリクライアントID',
region: 'リージョン'
},
api: {
invokeUrl: 'APIGatewayでデプロイしたステージのURL'
}
};
cognito-auth.js
ログインIDとパスを入力するinput、ログインボタンをhtmlページ上に用意すること。(login.html参照)
// 認証トークン管理変数。全jsファイル間で共有 var tokenManager = window.tokenManager || {}; // 起動時処理 (function cognitoAuthoMain($) { // ユーザープールの取得 var poolData = { UserPoolId: _config.cognito.userPoolId, ClientId: _config.cognito.userPoolClientId }; var userPool; if (!(_config.cognito.userPoolId && _config.cognito.userPoolClientId && _config.cognito.region)) { return; } userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); if (typeof AWSCognito !== 'undefined') { AWSCognito.config.region = _config.cognito.region; } // === // tokenManager に 関数を設定しておく // サインアウト処理 tokenManager.signOut = function signOut() { userPool.getCurrentUser().signOut(); }; // 認証処理。「check-login-state.js」ファイルにて利用される。 tokenManager.authToken = new Promise(function fetchCurrentAuthToken(resolve, reject) { var cognitoUser = userPool.getCurrentUser(); if (cognitoUser) { cognitoUser.getSession(function sessionCallback(err, session) { if (err) { reject(err); } else if (!session.isValid()) { resolve(null); } else { resolve(session.getIdToken().getJwtToken()); } }); } else { resolve(null); } }); // === // AWS Cognito 認証処理 // ログイン処理 function loginFunc(email, password, onSuccess, onFailure) { var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({ Username: email, Password: password }); var cognitoUser = createCognitoUser(email); cognitoUser.authenticateUser(authenticationDetails, { onSuccess: onSuccess, onFailure: onFailure }); } function createCognitoUser(email) { return new AmazonCognitoIdentity.CognitoUser({ Username: email, Pool: userPool }); } // === // ページ内処理・イベント // ページ読み込み時の処理 $(function onDocReady() { // ログインボタンにイベント追加 let aTag_login = document.getElementById("a_login"); if( aTag_login ) { aTag_login.href = "javascript:void(0);"; aTag_login.onclick = function() { handleLogin(); }; } // ログアウトボタンにイベント追加 let aTag_logout = document.getElementById("a_logout"); if( aTag_logout ) { aTag_logout.href = "javascript:void(0);"; aTag_logout.onclick = function() { handleLogout(); }; } }); // ログインボタン押下時 function handleLogin() { // フォームに入力された値を取得 var email = $('#login_input_email').val(); var password = $('#login_input_password').val(); // 入力チェック if( (email.length == 0) || (password.length == 0) ) { alert('入力されていない項目があります。ご確認ください。'); return; } // === // ログイン処理実行 // 入力された値でログイン判定、成功したならページ遷移 loginFunc( email, password, function loginSuccess() { console.log('Successfully Logged In'); // ログイン成功でトップページへ遷移 window.location.href = topPageUrl; }, function loginError(err) { console.log('Failed Logged In'); alert('ログインに失敗しました。IDとパスワードをご確認ください。'); } ); } // ログアウトボタン押下時 function handleLogout() { // ログアウト処理 tokenManager.signOut(); // アラート表示 alert('ログアウトしました。'); // ログアウトでログインページへ遷移 window.location.href = loginPageUrl; } }(jQuery));
check-login-state.js
// 認証トークン管理変数。全jsファイル間で共有 var tokenManager = window.tokenManager || {}; // 以降のjsにてAPI認証に使われるトークン。 var authToken; // 起動時処理 (function checkLoginStateMain($) { // 認証失敗時に戻すページのURL。今回はログイン画面に戻す想定。 let loginPageUrl = 'login.html'; // === tokenManager.authToken.then(function setAuthToken(token) { if (token) { authToken = token; } else { alert("ページにアクセスするにはログインを行ってください。ログイン画面に移動します。"); window.location.href = loginPageUrl; } }).catch(function handleTokenError(error) { alert(error); window.location.href = loginPageUrl; }); }(jQuery));
call-api.js
「check-login-state.js」にて取得したトークン「authToken」を、API呼び出し時に渡している。
// 認証トークン管理変数。全jsファイル間で共有 var tokenManager = window.tokenManager || {}; // 引数に、Lambdaに渡すJSONデータと、完了時の関数を渡す // completeFuncは、引数にJSONデータを受け取るので、引数を1つ渡せるような関数とする function requestApi( jsonData, completeFunc ) { $.ajax({ method: 'POST', url: _config.api.invokeUrl + '/admin', headers: { Authorization: authToken }, data: jsonData, contentType: 'application/json', success: completeFunc, error: function ajaxError(jqXHR, textStatus, errorThrown) { console.error('Error requesting: ', textStatus, ', Details: ', errorThrown); console.error('Response: ', jqXHR.responseText); alert("データベースサーバーとの通信に失敗しました。"); } }); }
main.js
call-api.js で準備したAPIコール関数を実行する。APIから応答を受けた後の処理も記述している。
(function MainFunction($) {
// Lambda側に渡したいデータをJSON形式で準備
var requestJsonData = {
"Key1": "Value1",
"Key2": "Value2"
};
// Lambda実行完了時の処理
function completeRequest( result ) {
// 引数resultは受け取った時点でJSONデータとして認識できる
// キーを指定してデータを得られる。複数データも配列として指定して取得すれば良い。
// console.log('Response received from API: ', result);
// const responseData = JSON.parse( result );
console.log( result["ReceivedVal1"] );
console.log( result["ReceivedVal2"] );
}
// ページ読み込み時の処理
$(function onDocReady() {
// Lambda実行
requestApi( JSON.stringify(requestJsonData), completeRequest );
});
}(jQuery));
Html
login.html
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>ログインページ サンプル</title> </head> <body> <h1>ログインページ サンプル</h1> <table> <tr><th>ID:</th><td><input id="login_input_email" class="input_text" type="text" required /></td></tr> <tr><th>パスワード:</th><td><input id="login_input_password" class="input_text" type="password" required /></td></tr> </table> <p id="btn_login"><a id="a_login">ログイン</a></p> <!-- javascript --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <!-- Cognito認証 --> <script src="html/js/vendor/aws-cognito-sdk.min.js"></script> <script src="html/js/vendor/amazon-cognito-identity.min.js"></script> <script src="html/js/config.js"></script> <script src="html/js/cognito-auth.js"></script> </body> </html>
index.html
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>AWSチュートリアル簡易版テストページ</title> </head> <body> <div>Hello World</div> <!-- jquery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <!-- 認証処理 --> <script src="js/vendor/aws-cognito-sdk.min.js"></script> <script src="js/vendor/amazon-cognito-identity.min.js"></script> <script src="js/config.js"></script> <script src="js/cognito-auth.js"></script> <script src="js/check-login-state.js"></script> <!-- API呼び出し処理 --> <script src="js/config.js"></script> <script src="js/call-api.js"></script> <script src="js/main.js"></script> </body> </html>
LambdaでDynamoDBにアクセスする記述方法(Python) | AWS豆知識
-
import
-
テーブル取得
-
書き込み
-
読み出し
-
消去
Lambda関数に付与する権限
権限を付与するためにはIAMロールを利用する。
IAMについては「IAM ロール ポリシーについて」を、
実際に付与する権限の書き方例については「Lambda関数に付与するIAMロールについて」を山参照
import
import boto3 from boto3.dynamodb.conditions import Key, Attr
テーブル取得
# dynamoDBオブジェクト
self.dynamodb = boto3.resource('dynamodb')
# テーブル取得
targetTable = self.dynamodb.Table('DynamoDBに存在するテーブル名')
書き込み
# 登録データ
registerData = {
"name": "名前",
"RegisterDate": "登録日"
}
# 値を書き込む
queryResult = targetTable.put_item(
Item = registerData
}
読み出し
# 全件取得 queryResult = targetTable.scan() # DeviceId が DeviceA のものを取得 # Keyに指定している「DeviceId」がパーティションキーである必要がある。 queryResult = targetTable.query( KeyConditionExpression = Key( "DeviceId" ).eq( "DeviceA" ) ) # DeviceId が DeviceA のものを取得(LSI 登録日の昇順で取得) # LSI:ローカルセカンダリインデックス # DynamoDB側で「DeviceId-RegisterDate-index」という名前でインデックスが登録されている queryResult = targetTable.query( IndexName = "DeviceId-RegisterDate-index", KeyConditionExpression = Key( "DeviceId" ).eq( "DeviceA" ) ) # 指定された顧客名の貸出情報を取得(GSI 貸出日時の昇順で取得) # GSI:グローバルセカンダリインデックス # DynamoDB側で「ClientName-RentalDate-index」という名前でインデックスが登録されている queryResult = targetTable.query( IndexName = "ClientName-RentalDate-index", KeyConditionExpression = Key( "ClientName" ).eq( clientName ) )
消去
# 消去
queryResult = targetTable.delete_item(
Key = { "DeviceId": deviceId }
)
# LSIやGSIで設定された2項目でデータを指定して消去
queryResult = targetTable.delete_item(
Key = { "DeviceId": deviceId, "RegisterDate": registerDate }
)
IAM ロール ポリシーについて | AWS豆知識

S3とか、Lambdaとか、サービスには個別に権限を割り当てられます。
例えば、Lambda関数がDynamoDBのデータにアクセスしたい場合、権限を与えていないと拒否されてしまいます。IAMで権限を作成して、それをLambdaに割り当てます。
「ポリシー」と呼ばれるものに権限を構築していきます。ポリシーの記述によってどのサービスのどのアクションを許可するか、細かく指定ができます。
「ロール」と呼ばれるものにいくつかの「ポリシー」を割り当て、その「ロール」を各種AWSサービスに割り当てることで、そのサービスに権限を与えられることができます。
JavaSciptでAWS Gatewayを呼び出す | AWSサーバレス構築 Webページ作成
ロードマップ
-
├ 静的ウェブホスティング : S3
-
├ サーバーレスバックエンド : Lambda
-
├ RESTful API : API Gateway
-
└ Webページ作成 : HTML, JavaScript ← いまココ

公式チュートリアルで参考とするファイル
公式チュートリアルで使われているソースコード
aws-serverless-webapp-workshop(GitHub)
このうち、
・config.js
・cognito-auth.js
・ride.js
を参考にする。
config.js
API GatewayのデプロイURLと、認証を利用する場合にCognitoの情報を保持する構造体データ
複数のJavaScriptファイル間でグローバル変数として振る舞う。
window._config = {
cognito: {
userPoolId: '',
userPoolClientId: '',
region: ''
},
api: {
invokeUrl: 'APIGatewayでデプロイしたステージのURL'
}
};
cognito-auth.js
APIを呼び出す時に認証を必要とさせたいときに利用する。今回の簡易版チュートリアルでは使用しない。
ride.js(call-api.js)
ajaxを利用してAPIを呼び出している。API呼び出し部分だけを抜き出して、新たにJavaScriptファイル「call-api.js」を用意する。
// 引数に、Lambdaに渡すJSONデータと、完了時の関数を渡す // completeFuncは、引数にJSONデータを受け取るので、引数を1つ渡せるような関数とする function requestApi( jsonData, completeFunc ) { $.ajax({ method: 'POST', url: _config.api.invokeUrl + '/testresource', data: jsonData, contentType: 'application/json', success: completeFunc, error: function ajaxError(jqXHR, textStatus, errorThrown) { console.error('Error requesting: ', textStatus, ', Details: ', errorThrown); console.error('Response: ', jqXHR.responseText); alert("データベースサーバーとの通信に失敗しました。"); } }); }
使い方
main.js
call-api.js で準備したAPIコール関数を実行する。APIから応答を受けた後の処理も記述している。
(function MainFunction($) {
// Lambda側に渡したいデータをJSON形式で準備
var requestJsonData = {
"Key1": "Value1",
"Key2": "Value2"
};
// Lambda実行完了時の処理
function completeRequest( result ) {
// 引数resultは受け取った時点でJSONデータとして認識できる
// キーを指定してデータを得られる。複数データも配列として指定して取得すれば良い。
// console.log('Response received from API: ', result);
// const responseData = JSON.parse( result );
console.log( result["ReceivedVal1"] );
console.log( result["ReceivedVal2"] );
}
// ページ読み込み時の処理
$(function onDocReady() {
// Lambda実行
requestApi( JSON.stringify(requestJsonData), completeRequest );
});
}(jQuery));
index.html
これまでに用意したJavaScriptファイルを順番に読み込んで実行させている。
ブラウザのコンソール上にサーバーから送られている文字列が表示されればOK。
本チュートリアルの目的達成。
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>AWSチュートリアル簡易版テストページ</title> </head> <body> <div>Hello World</div> <!-- javascript --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="js/config.js"></script> <script src="js/call-api.js"></script> <script src="js/main.js"></script> </body> </html>
AWS API GatewayでLambda関数を呼び出す | AWSサーバレス構築 RESTful API
ロードマップ
-
├ 静的ウェブホスティング : S3
-
├ サーバーレスバックエンド : Lambda
-
├ RESTful API : API Gateway ← いまココ
-
└ Webページ作成 : HTML, JavaScript

RESTful API とは
REST = 簡易な手順でWebサービスへのアクセスを可能にする仕組みのこと。
RESTful API = REST に則ったAPI
Webページ(html, javascript)とサーバー(Lambda)をつなぐ役目をしているのがAPI Gateway
API作成手順
新規作成
① 4種類あるうちの「REST API」を選択して構築する
② 「新しいAPI」を選択し、API名入力、「エッジ最適化」を選択

リソースの追加
① 「アクション」→「リソースの作成」を選択
② リソース名を入力し、API Gateway CORS を有効にする。例では(testresouceという名前)
③ 作成完了。このリソース名を指定してAPIを呼び出すことになる

メソッドの追加
① 「アクション」→「メソッドの作成」を選択
② メソッドの種類は「POST」
③ 「チェックマーク」を押して確定

④ 統合タイプ「Lambda関数」、「Lambdaプロキシ統合の使用にチェック」、「」で作成した関数を指定
⑤ 関数を呼び出すための権限を Amazon API Gateway に付与するように求められたら、[OK]を選択

デプロイ
① 「アクション」→「APIのデプロイ」を選択
② ステージ名に「prod」を入力
③ APIを呼び出すためのURLが発行される

「発行されたURL + リソース名」でAPIを呼び出せるようになり、APIを呼び出すとそれに紐ついたlambda関数を実行できる。
AWS Lambdaでサーバー側の処理を実装する | AWSサーバレス構築 サーバレスバックエンド
ロードマップ
-
├ 静的ウェブホスティング : S3
-
├ サーバーレスバックエンド : Lambda ← いまココ
-
├ RESTful API : API Gateway
-
└ Webページ作成 : HTML, JavaScript

新規作成
関数を「一から作成」を選択して作成。ランタイムはプログラムを記述する言語を選択するところで、今回はPythonを選択
実行ロールは「基本的なLambdaアクセス権限で新しいロールを作成」を選択すると、Amazon CloudWatch Logs にログをアップロードするアクセス権限を持つIAMロールとポリシーが作成されて、CloudWatchLogsというサービスも自動で登録される。Lambdaの実行ログがCloudWatchに蓄積されるようになる。


記述例
-
lambda_handler関数の引数「event」に、コール元から渡されたjsonデータが含まれる
-
通信で送る場合は文字列データにして送り、受信先でその文字列をデータ型に置き換えて使用する。
import json def lambda_handler(event, context): # 渡されたデータ受け取り event_body = json.loads( event["body"] ) receivedValue1 = event_body["Key1"] receivedValue2 = event_body["Key2"] # 返信するデータを作成(辞書型データ) returnJsonData = { "Name": "Yamada", "ReceivedVal1": receivedValue1, "ReceivedVal2": receivedValue2 } # 返信処理(bodyに辞書型データを文字列型に変換したものをセット) return { 'statusCode': 200, 'headers': { 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'OPTIONS,POST,GET' }, 'body': json.dumps( returnJsonData ) }
returnにある「header」については、オリジン間リソース共有 (CORS)を参照