emahiro/b.log

Drastically Repeat Yourself !!!!

Amazon Pinpoint で S3 上のファイルからセグメントを作成する

Overview

Amazon Pinpoint という AWS が提供してるマネージドCRM ツールを使ってセグメント(配信対象)を S3 上のファイルから作成する手順について記載します。

用語の整理

  • セグメント
    • Amazon Pinpoint 上の用語。配信対象を指します。
    • APNS であればデバイストークン、SMS であればメールアドレス、というようにマッピングさせることでモバイル端末に通知を送ることができます。

実装方法

ざっくり S3 にファイル(csv) をアップロードして、そのファイルを元に Pinpoint のセグメント(endpoint) を作成するという流れを考えます。

import の定義は以下に詳細に記載されています。

docs.aws.amazon.com

具体的な実装に関しては以下のようなシーケンスになります。passRole されてる AWS の内部処理については多分こうしてるんじゃないか?という予想です。

import するファイルのサイズが小さい場合、CreateImportJob API の完了後に作成された SegmentID が返ってくることがありますが、大きい場合 Pinpoint 側でも Batch Job が動いていて都度ステータスを確認して Segment の作成確認を行う必要があるので、CreateImportJob を実行したあとに GetImportJob で Segment の作成状況を確認する必要があります。

なお作成状況のステータスについては以下のドキュメントに記載されています。

docs.aws.amazon.com

sequenceDiagram
    participant app
    participant sts
    participant pp as pinpoint
    participant s3
    
app ->> s3: upload csv
s3 -->> app: url
app ->> sts: assumeRole(pinpoint-role)
sts -->> app: cred
app -->> pp: create import job with with cred & s3URL
alt AWS 内部
    pp ->> sts: passRole to import segment role from s3
    sts -->> pp: role
end
pp ->> s3: get file
s3 -->> pp: data
pp ->> pp: import job
pp -->> app: job status
loop if status != completed 
    app ->> pp: get import job status
    pp -->> app: status and segment id
end

利用する API

ファイル形式

今回はCSV を利用します。 セグメントを作成するための CSV のフォーマットは決まっていて ChannelTypeAddress が必須です。

  • ChannelType は APNS や GCM、SMS などになります。
  • Address は Push であればデバイストークン、メールとなればemail アドレスになります。

ハマったところ

Pinpoint -> S3 に触る role を設定する

先結論だけ書いておくと、Amazon Pinpoint に今回説明しているような外部のファイル(今回は S3上)を読み込ませてセグメント(endpoint) を作成する際は 専用のロールが必要になります。詳細は以下の公式ドキュメントに書いてあります。

docs.aws.amazon.com

なお、上記サンプルで書かれてるCLI のPayload だとうまく動かず、以下のようにしました(JSON のテンプレが古そう?)

# 以下の JSON を用意する。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "pinpoint.amazonaws.com"
      }
    }
  ]
}

aws iam create-role --role-name PinpointSegmentImport --assume-role-policy-document file://PinpointImportTrustPolicy.json

# response で以下の結果が返ってきます。
{
    "Role": {
        "Path": "/",
        "RoleName": "PinpointSegmentImport",
        "RoleId": "$RoleID",
        "Arn": "arn:aws:iam::$AppName:role/PinpointSegmentImport",
        "CreateDate": "2024-01-29T15:37:51+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "pinpoint.amazonaws.com"
                    }
                }
            ]
        }
    }
}

# 作った role に AmazonS3ReadOnlyAccess というポリシーをアタッチします。
aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess --role-name PinpointSegmentImport

※ これが最初わからず、以下の記事で AWS の assumeRole から調べ始めました。

dev.classmethod.jp

今回は本業において、とあるアカウントAから別のアカウントBに用意された Pinpoint のリソースを触る、という特殊な方法をベースに考えることになったのはありますが、ある role に Amazon Pinpoint をさわれるポリシーを attach し、その role に assume(変身)して Pinpoint を操作する、というのが基本的な流れになるのは変わりません。

では今回はこの専用ロール(Pinpoint) が S3 上のファイルを指定して Create Import Job を作成するのですが、この 「PinpointがS3上のファイルを指定して」 という部分、ここで結論に記載した専用の role が必要になります。
さらに Pinpoint を触れる role(roleA) が CreateImportJob を発行するときに、この Pinpoint -> S3で触る特別な role に成り代わる( iam.PassRole) 権限がないと、CreateImportJob を発行できません。ここが一番つまづきました。

このため、pinpoint の roleA には S3 を触るための roleB への iam.passRole が許可されてる必要があります。

余談

作成したセグメントを使って Push 通知を配信するには CreateCampaign を利用します。
こちらの手順については別のエントリを書く予定です。