SORACOM Kryptonを使ってDynamoDBのテーブルをScanする

# はじめに

IoTデバイスとAWS間で通信を行う場合は、デバイスにIAMのアクセスキーとシークレットキーを埋め込み、利用するのが一般的かと思います。

その場合、デバイスに不正アクセスされた場合や、盗難されると、認証情報を不正に利用される可能性があります
その影響として、当てている権限にもよりますが、データを盗まれたり、EC2立てられてマイニングに使用されたりするかもしれません。

そのため、認証情報を盗まれるのは避ける必要がありますが、かと言って認証情報を使わないわけにもいきません。

そこで登場するのが [SORACOM Krypton](https://soracom.jp/services/krypton/) です


## SORACOM Krypton

SORACOM Krypton(以下 Krypton)は、ざっくり説明すると、
クラウドサービスを使いたいときに、認証情報を取得する機能です。

kryptonを利用することによって、セキュリティ性が向上します。
なぜなら、デバイスに認証情報を持たせなくてもよくなるからです。

説明は一度、[公式](https://soracom.jp/services/krypton/)の「セルラー回線を使用したプロビジョニング」に記載がある図を見ていただいたほうがわかりやすいと思います

流れとしては、認証が必要な処理をクラウドに対して行いたい場合、まずkyrptonに対してリクエストを送ります。
kryptonは、あらかじめ登録されている情報を元に、クラウドから認証情報等を取得し、レスポンスとして返します。

そうすることによって、デバイス側は、認証情報を持つ必要はなくなります。
kryptonいいですね！

## DynamoDBのデータを取得

kryptonでは、何パターンか認証情報を取得する方法がありますが、今回は
[Cognito](https://aws.amazon.com/jp/cognito/)から期限付き認証情報を取得して、DynamoDBのデータ取得を行います。

基本的には以下の手順に近いです。
https://dev.soracom.io/jp/start/krypton_cognito/

ステップ3までは同じなので、公式を参照してください。

ステップ4以降はnode.jsでしかサンプルが用意されていません。
nodeがよければ、そのまま公式の手順で進めてください。(S3からファイルをダウンロードする内容ですが...)

今回はpythonを使用したいのでサンプルがないのと、公式と同じことをしても面白くないので、DynamoDBのデータを取得するようにしています。

以下はKryptonが提供しているAPIのリファレンスです
https://dev.soracom.io/jp/krypton/api/

最初に説明したようにCognitoから期限付きの権限を取得してDynamoDBへのアクセスを行うので、使うAPIとしては

**/v1/provisioning/aws/cognito/open_id_tokens**

となります。

また、エンドポイントについては

>Krypton プロビジョニング API("/v1/provisioning/*") のエンドポイントはプロビジョニングのための認証方法によって異なります。
>SORACOM Air のセルラー回線を使用した認証の場合
https://krypton.soracom.io:8036
SORACOM Endorse による SIM 認証
https://g.api.soracom.io

と記載があり、今回はSORACOM Air のセルラー回線を使用した認証を行うので、
https://krypton.soracom.io:8036
となります。

2点あわせると今回実装するURLができます
https://krypton.soracom.io:8036/v1/provisioning/aws/cognito/open_id_tokens

ここまで準備が整ったら、あとは以下のソースコードを実行するだけです。

## ソースコード

```
# -*- coding:utf-8 -*-
# モジュール

import json
import boto3
from boto3.session import Session
import subprocess
import logging
import traceback

LOG_DIR = "/var/log/"
LOG_FILE = LOG_DIR + "get_dynamo_data.log"
LOG_FORMAT = "[%(asctime)s %(levelname)s] %(message)s"

logging.basicConfig(filename=LOG_FILE, level=logging.INFO, format=LOG_FORMAT)
logger = logging.getLogger("logger")

cognito = boto3.client("cognito-identity", region_name="ap-northeast-1")
cmd = "curl -X POST -H content-type: application/json https://krypton.soracom.io:8036/v1/provisioning/aws/cognito/open_id_tokens"


# kryptonからtokenを取得する
def getToken():
    token = subprocess.Popen(
        cmd, stdout=subprocess.PIPE, shell=True
    ).stdout.readlines()[0]
    token_str = token.decode("UTF-8")

    return json.loads(token_str)

# tokenを使用してcognitoから期限付きのcredentialを取得し、DynamoDBからデータを取得する
def getDynamoData(tokens):
    resp = cognito.get_credentials_for_identity(
        IdentityId=tokens["identityId"],
        Logins={"cognito-identity.amazonaws.com": tokens["token"]},
    )
    secretKey = resp["Credentials"]["SecretKey"]
    accessKey = resp["Credentials"]["AccessKeyId"]
    token = resp["Credentials"]["SessionToken"]

    session = Session(
        aws_access_key_id=accessKey,
        aws_secret_access_key=secretKey,
        aws_session_token=token,
        region_name="ap-northeast-1",
    )
    dynamo = session.resource("dynamodb")
    table = dynamo.Table("test_table")
    response = table.scan()

    return response["Items"]

if __name__ == "__main__":
    try:
        logger.info("start dynamo data ...")
        tokens = getToken()
        dynamo_data = getDynamoData(tokens)
        logger.info(dynamo_data)
    except Exception as e:
        logger.error("exception")
        logger.error(traceback.format_exc())
```

## まとめ

IAMユーザーの権限を適切に設定すれば、認証情報が漏れたとしても、極力被害を抑えられるとは思いますが、
不正なデータをあげられたり、データを盗まれたりする可能性はあります。
めんどくさいからadminでいいやって声は聞こえなかったことにします。

今回紹介したKryptonを使用すれば、万が一の際にも、キーペアは漏れず、不正利用されることは少なくなるでしょう。
最悪なケースでは、プログラムを改変されて、一時トークンを使われることはあるかもしれませんが、できてそこまでです。
Kryptonを使ったほうが確実にセキュアです。

また、上記の明確な利点がありますが、それとは別に精神的な安心を得られるのは、大きなメリットかと思います。

[月額の料金](https://soracom.jp/services/krypton/price/)は高くないと思っているので、安心を買うために、導入を検討してみてはいかがでしょうか

お客さんがいる場合は、こんなセキュリテイ対策をやってるんだよと、説明できるのもいいですね。

より安全にIoTライフを楽しみましょう！