要点
- シミュレータor実機の時刻設定
- iOSの地域設定(言語設定ではないです)を使用するCognitoのリージョンに合わせる。
- テーブル属性のデータ型定義
- DynamoDBで扱えるデータ型(文字列・数値・バイナリ)を意識する。
- DynamoDB側のテーブル定義(属性名・データ型)のとおりにクライアントを実装する。
- 使用するRoleに対する適切なポリシー設定
- CognitoとDynamoDBに関して、必要十分な権限を付与する。
要点を無視した場合の不具合
- シミュレータor実機の時刻設定
-
iOSの時刻設定を誤ると、The security token included in the request is expiredなるExceptionが発生します。(参考: Stackoverflow)
-
iOSの地域設定が使用するCognitoのリージョンに合っていない場合、DynamoDBにアクセスするためのトークンの有効期限が切れたものと(AWS側に)みなされてしまいます。
-
私の場合は、iOS言語設定=日本語、iOS地域設定=デフォルト(アメリカ)、Cognito=東京リージョン、の条件で発生しました。
(Stackoverflowでの質問(抜粋))
Caused by: com.amazonaws.AmazonServiceException: The security token included in the request is expired (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ExpiredTokenException(以下、Answer。重要箇所を太字強調しました)
This looks to me like a clock skew error. If you have left an emulator open for awhile or changed the clock on a phone it is possible the token generated from the SDK does not match what AWS is expecting.
- テーブル属性のデータ型定義
- DynamoDBで定義した属性名orデータ型の通りにクライアント側を実装しないと、Supplied AttributeValue is empty, must contain exactly one of the supported datatypesといったエラーになります。
- DynamoDBにおいては、文字列(NSString)・数値(NSNumber)・バイナリ(NSData)型のみが許されています。
- 普通のRDBMSやCoreDataと同じような感覚で日付(NSDate)なんかを突っ込んでしまうと、上記のようなエラーになってしまいます。
- 使用するRoleに対する適切なポリシー設定
-
CognitoのIdentityPoolIdに紐づくRoleのポリシーに十分な権限が付与されていないと、先ほどの1のExceptionに加えてAccessDeniedExceptionが発生します。(DynamoDBに関するポリシー設定のやり方はこちらに書いてあります)
-
また過剰な権限付与は、IdentityPoolId(で発行したワンタイムトークン)が漏洩した際の不正利用リスク増加につながります。たとえばActionに**dynamodb:***が設定されていると、レコードのCRUDの他に既存テーブルの削除も許してしまいます。さらにResourceの指定がなければ、意図しない別テーブルへのアクセスも実現してしまいます。
(以下、dynamodb:UpdateItemが付与されていないことによるException)
Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=1 "(null)" UserInfo={__type=com.amazon.coral.service#AccessDeniedException, Message=User: arn:aws:sts::(※ユーザID):assumed-role/(※Role名)/CognitoIdentityCredentials is not authorized to perform: dynamodb:UpdateItem on resource: arn:aws:dynamodb:us-west-2:(※ユーザID):table/(※DynamoDBのテーブル名)}