AWS IoT – Authorizing Direct Call

AWS

AWS IoTを使用してエッジデバイスからAWSのリソース、例えばAWS S3にアクセスしたくなることがあります。エッジデバイスからS3にアクセスする方法としていくつかありますが、この記事ではAuthorizing Direct Callという仕組みを使用してAWSリソースにアクセスします。

この記事は、こちらの記事で作成したモノ・証明書を使用するため事前に準備を済ませて下さい。

    Authorizing Direct Calls

    エッジデバイスからAWS S3にアクセスする為に、AWS S3のアクセスを公開設定にしてしまえばエッジデバイスを含む誰からもアクセス可能ですが、公開設定にせず、管理するデバイスからのアクセスを可能とする為に、Authorizing Direct Callsという仕組みを使用します。

    AWS S3へのアクセスを可能にする別の方法として、AWS S3の署名付きURLを使用することもできますが、署名付きURLは有効期限があるため目的に応じて使い分けます。

    Authorizing Direct Callsを利用するために以下の設定を行います。

    1. IAMロールの作成
    2. 作成したIAMロールにS3のファイル取得を許可するポリシーを設定
    3. IAMロールを参照するIoTロールエイリアスを作成する
    4. 証明書を使用して上記で作成したIAMロール権限を付与するためのIoTポリシーを作成する
    5. IoTポリシーと証明書をアタッチする

    IoTデバイスに直接IAMロール権限を付与できないため、IoTロールエイリアスを経由し、IAMロール権限を取得します。それぞれの関係は以下の通りです。

    IAMロールの作成

    IAMロールrole-s3-readを作成します。

    $ cat << EOS > role-s3-read.json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "credentials.iot.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
    EOS
    $ aws iam create-role --role-name role-s3-read --assume-role-policy-document file://role-s3-read.jsonCode language: Bash (bash)

    IAMポリシーの作成

    IAMポリシーpolicy-s3-readを作成し、IAMロールrole-s3-readに設定します。S3バケットxxxxxxxxxx-iot-test-files/以下のファイルを取得可能に設定します。xxxxxxxxxxにはアカウントIDを指定してください。(別の記事でこのバケットを使用するためxxxxxxxxxxはアカウントIDを指定します)

    $ cat << EOS > policy-s3-read.json
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "s3:GetObject"
                ],
                "Effect": "Allow",
                "Resource": "arn:aws:s3:::xxxxxxxxxx-iot-test-files/*"
            }
        ]
    }
    EOS
    $ aws iam put-role-policy --policy-name policy-s3-read --role-name role-s3-read --policy-document file://policy-s3-read.jsonCode language: Bash (bash)

    IoTロールエイリアスの作成

    IoTロールエイリアスiot-role-alias-s3-readを作成し、IAMロールrole-s3-readと紐づけします。

    aws iot create-role-alias --role-alias iot-role-alias-s3-read --role-arn arn:aws:iam::xxxxxxxxxxxx:role/role-s3-readCode language: Bash (bash)

    arn:aws:iam::xxxxxxxxxxxx:role/role-s3-readは適切なアカウントIDに置き換えます。アカウントIDは以下で取得可能です。

    aws sts get-caller-identity|jq -r .AccountCode language: Bash (bash)

    IoTポリシーの作成

    IoTポリシーiot-policy-s3-readを作成

    $ cat << EOS > iot-policy-s3-read.json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "iot:AssumeRoleWithCertificate",
          "Resource": "arn:aws:iot:us-east-1:xxxxxxxxxxxx:rolealias/iot-role-alias-s3-read"
        }
      ]
    }
    EOS
    $ aws iot create-policy --policy-name iot-policy-s3-read --policy-document file://iot-policy-s3-read.jsonCode language: Bash (bash)

    arn:aws:iot:us-east-1:xxxxxxxxxxxxは適切なアカウントIDに置き換えて下さい。

    IoT証明書にIoTポリシーをアタッチ

    IoT証明書にIoTポリシーiot-policy-s3-readをアタッチします。--target arn:aws:iot:us-east-1:xxxxxxxxxxxxx:cert/xxxxxxxxxxxxxこちらの記事で作成した証明書のARNです。

    aws iot attach-policy --policy-name iot-policy-s3-read --target arn:aws:iot:us-east-1:xxxxxxxxxxxxx:cert/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxCode language: Bash (bash)

    動作確認

    まずはクレデンシャルプロバイダーのエンドポイントを調べます。

    $ aws iot describe-endpoint --endpoint-type iot:CredentialProvider
    {
        "endpointAddress": "xxxxx.credentials.iot.us-east-1.amazonaws.com"
    }Code language: Bash (bash)

    取得したクレデンシャルプロバイダーからトークンを取得します。

    $ curl --cert ./certificate.pem --key ./private.key -H "x-amzn-iot-thingname: test-thing" https://xxxxxxxxxxxx.credentials.iot.us-east-1.amazonaws.com/role-aliases/iot-role-alias-s3-read/credentials | jq -r .
    {
      "credentials": {
        "accessKeyId": "ASXXXXXXXXXXXXXXXX",
        "secretAccessKey": "otXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "sessionToken": "IQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "expiration": "2022-12-03T14:14:07Z"
      }
    }Code language: Bash (bash)

    S3にxxxxxxxxxx-iot-test-filesバケットを作成し、確認用ファイルを保存します。(繰り返しにないりますが、xxxxxxxxxxはアカウントIDを指定します)

    aws s3 mb s3://xxxxxxxxxx-iot-test-files
    echo hoge > hoge.txt
    aws s3 cp hoge.txt s3://xxxxxxxxxx-iot-test-files/Code language: Bash (bash)

    取得したトークンを使用してS3からファイルをダウンロードします。

    $ AWS_ACCESS_KEY_ID="ASXXXXXXXXXXXXXXXX" \
    AWS_SECRET_ACCESS_KEY="otXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
    AWS_SESSION_TOKEN="IQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
    aws s3 cp s3://xxxxxxxxxx-iot-test-files/hoge.txt .
    download: s3://xxxxxxxxxx-iot-test-files/hoge.txt to ./hoge.txtCode language: Bash (bash)

    S3へのアクセスはs3:GetObjectしか許可していないため、リスト操作ができないことを確認します。

    $ AWS_ACCESS_KEY_ID="ASXXXXXXXXXXXXXXXX" \
    AWS_SECRET_ACCESS_KEY="otXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
    AWS_SESSION_TOKEN="IQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
    aws s3 ls s3://xxxxxxxxxx-iot-test-files/hoge.txt
    
    An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access DeniedCode language: Bash (bash)

        正しく動作していそうです。

        以上です。

        参照

        ERROR: The request could not be satisfied
        [AWS IoT] 既存の証明書だけでMQTT以外の各種AWSリソ−スにアクセスする (Authorizing Direct Calls) | DevelopersIO
        AWS IoT の Authorizing Direct Callsを使用すると、既存の証明書だけで、AWSリソースにアクセスする事が可能です。