IoT Coreの証明書を使ってAWSのサービスを利用するための認証情報(アクセスキーIDとシークレットアクセスキー)を発行することができます。 IAMポリシーとうまく組み合わせることで、モノの名前のフォルダー配下だけにアクセスができる構成とすることができます。 設定ファイルをおいてみたりすると実用的ではないでしょうか。

S3
└バケット
  ├デバイス001  ←他のデバイスのフォルダーは見れない
 │ └settiong.json
  ├デバイス002  ←自分のフォルダーは見れる
 │ └settiong.json
  ├デバイス003
 │ └settiong.json
 └デバイス004
   └settiong.json

参考サイト


手順は結構長いですが、必要なリソースは以下のとおりです。

サービス項目内容
IoT Coreモノ
IoT Core証明書
IoT Coreポリシーロールエイリアスに対する__iot:AssumeRoleWithCertificate__アクションが必要
IoT Coreロールエイリアス付与したいIAMロールを指定
IAMポリシー
IAMロール信頼関係として__credentials.iot.amazonaws.com__サービスへの__sts:AssumeRole__アクションが必要
S3バケット

こちらの名称で実施しました。

サービス項目名称
IoT Coreモノthing-3f21f372
IoT Core証明書thing-3f21f372.cert.pem
thing-3f21f372.public.key
thing-3f21f372.private.key
IoT Coreポリシーthing-3f21f372-policy
IoT Coreロールエイリアスs3-bucket-4e8f4765-role-alias
IAMポリシーs3-bucket-4e8f4765-policy
IAMロールs3-bucket-4e8f4765-role-for-iot
S3バケットbucket-4e8f4765

リソース作成

S3

バケットの作成

aws s3api create-bucket \
  --bucket bucket-4e8f4765 \
  --region ap-northeast-1 \
  --create-bucket-configuration LocationConstraint=ap-northeast-1

IAM

IAMポリシーの作成

ポリシー変数の${credentials-iot:ThingName}が、IoTのモノの名前になります。 使えるポリシー変数はこちら。

ポリシー変数
credentials-iot:ThingName
credentials-iot:ThingTypeName
credentials-iot:AwsCertificateId

IAMポリシーのJSONファイルを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::bucket-4e8f4765",
            "Condition": {
                "StringLike": {
                    "s3:prefix": "${credentials-iot:ThingName}/*"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action":[
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:DeleteObject",
                "s3:DeleteObjectVersion"
            ],
            "Resource": "arn:aws:s3:::bucket-4e8f4765/${credentials-iot:ThingName}/*"
        }
    ]
}
aws iam create-policy \
  --policy-name s3-bucket-4e8f4765-policy \
  --policy-document file://s3-bucket-4e8f4765-policy-document.json

IAMロールの作成

信頼関係のポリシードキュメントを作成します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "credentials.iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
aws iam create-role \
  --role-name s3-bucket-4e8f4765-role-for-iot \
  --assume-role-policy-document file://s3-bucket-4e8f4765-role-for-iot-policy-document.json

IAMポリシーをIAMロールにアタッチ

IAMポリシーをIAMロールにアタッチ (999999999999はアカウントIDです)

aws iam attach-role-policy \
  --role-name s3-bucket-4e8f4765-role-for-iot \
  --policy-arn arn:aws:iam::999999999999:policy/s3-bucket-4e8f4765-policy

IoT Core

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

IAMロールに対するエイリアスを作成 (999999999999はアカウントIDです)

aws iot create-role-alias \
  --role-alias s3-bucket-4e8f4765-role-alias \
  --role-arn arn:aws:iam::999999999999:role/s3-bucket-4e8f4765-role-for-iot

モノの作成

aws iot create-thing --thing-name thing-3f21f372

証明書の作成

aws iot create-keys-and-certificate \
  --certificate-pem-outfile "thing-3f21f372.cert.pem" \
  --public-key-outfile "thing-3f21f372.public.key" \
  --private-key-outfile "thing-3f21f372.private.key" \
  --set-as-active

AWS IoT Core ポリシーの作成

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:AssumeRoleWithCertificate",
      "Resource": "arn:aws:iot:ap-northeast-1:999999999999:rolealias/s3-bucket-4e8f4765-role-alias"
    }
  ]
}
aws iot create-policy \
  --policy-name thing-3f21f372-policy \
  --policy-document file://thing-3f21f372-policy.json

証明書にAWS IoT Core ポリシーのアタッチ

aws iot attach-policy \
  --policy-name thing-3f21f372-policy \
  --target "arn:aws:iot:ap-northeast-1:999999999999:cert/5c3453ecc18e5e6b8f3cf89a6c1d68f62a5b08855d13c61b37c987e3442f70f5"

モノに証明書をアタッチ

aws iot attach-thing-principal \
  --thing-name thing-3f21f372 \
  --principal arn:aws:iot:ap-northeast-1:999999999999:cert/5c3453ecc18e5e6b8f3cf89a6c1d68f62a5b08855d13c61b37c987e3442f70f5

リソースの準備は以上です。

認証情報の取得方法

認証情報の取得は、SDKではなく、curlコマンドで行います。(curl以外でももちろん可能です)

エンドポイントの取得

使用するエンドポイントはアカウントごとに異なります。 あとで使うので環境変数に入れておきます。

export endpoint=`aws iot describe-endpoint --endpoint-type iot:CredentialProvider | jq .endpointAddress | tr -d '"'`

認証情報の取得

以下のパラメーターでリクエストを送信します。

パラメータ設定値
—cert証明書ファイル
—keyプライベートキー
x-amzn-iot-thingnameモノの名称。
これだけHTTPヘッダーで指定です
curl --cert ./thing-3f21f372.cert.pem \
  --key ./thing-3f21f372.private.key \
  -H "x-amzn-iot-thingname: thing-3f21f372" \
  https://${endpoint}/role-aliases/s3-bucket-4e8f4765-role-alias/credentials
{
  "credentials": {
    "accessKeyId": "ASIA3.....",
    "secretAccessKey": "fjKhv..........",
    "sessionToken": "IQoJb.....",
    "expiration": "YYYY-MM-DDThh:mm:ssZ"
  }
}

S3へのアクセス

認証情報を環境変数にセット

認証情報を環境変数にセットします。

credentials=`curl --cert ./thing-3f21f372.cert.pem \
  --key ./thing-3f21f372.private.key \
  -H "x-amzn-iot-thingname: thing-3f21f372" \
  https://${endpoint}/role-aliases/s3-bucket-4e8f4765-role-alias/credentials`

export AWS_ACCESS_KEY_ID=`echo $credentials | jq .credentials.accessKeyId | tr -d '"'`
export AWS_SECRET_ACCESS_KEY=`echo $credentials | jq .credentials.secretAccessKey | tr -d '"'`
export AWS_SESSION_TOKEN=`echo $credentials | jq .credentials.sessionToken | tr -d '"'`

S3にアップロード

[cloudshell-user@ip-10-0-129-6 ~]$ aws s3 cp test.txt s3://bucket-4e8f4765/thing-3f21f372/test.txt
upload: ./test.txt to s3://bucket-4e8f4765/thing-3f21f372/test.txt

無事アップロードできました。

ファイルのリスト取得

[cloudshell-user@ip-10-0-129-6 ~]$ aws s3 ls s3://bucket-4e8f4765/thing-3f21f372/
2021-03-28 06:42:12          5 test.txt

他のフォルダーへのアクセスできないことを確認

自分のフォルダー以外はアクセスできません

[cloudshell-user@ip-10-0-129-6 ~]$ aws s3 ls s3://bucket-4e8f4765/thing-xxxxxxxx/

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

バケット直下もアクセスできないことを確認

[cloudshell-user@ip-10-0-129-6 ~]$ aws s3 cp test.txt s3://bucket-4e8f4765/test.txt
upload failed: ./test.txt to s3://bucket-4e8f4765/test.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied