CloudShell・Cloud9でのSNS作成

# はじめに
私は大学卒業後に新卒でITとは無縁のアナログな会社に営業として6年勤務後に現在のSESに未経験から転職して1年ほど。

経験した言語はPython・C#・Js
インフラの仕事をしたい訳ではなかったが、知識がなさすぎてやばいと思い個人的に勉強を始めAWSにたどり着いた。
目的がないと続かないと性格なので何やら流行っているAWS認定試験を合格を目指そうと思い以下を合格済み
・クラウドプラクティショナー　
・ソリューション・アーキテクト・アソシエイト　

現在はAWSエンジニアとして転職できるように勉強している。


# この記事を書いた理由

オンラインでの勉強会に参加した際に
**アウトプットするまでが勉強**
という言葉から記事を書くというアウトプットをすることにした。
学んだことの復習をします。

アウトプット経験の少なさとそもそも学歴がないので文章力のかけた内容となる可能性もあると思いますがご理解のほどよろしくお願いします。
間違い、最善の策等のご指摘は喜びます。

# 内容について
[connpass](connpass)でJAWS-UG CLI専門支部でCLIハンズオンイベントで学んだことのアウトプット
イベント内での作業手順と同等の内容となっている部分も多くあると思います。
今回はタイトル通りSNSを作成し、自身のメールアドレスにSNSを飛ばすところまで実施する。

# 作業環境
・OSとバージョン
Amazon Linux release 2 (Karoo)
・シェルとバージョン
GNU bash, バージョン 4.2.46(2)-release (x86_64-redhat-linux-gnu)
・AWS CLIのバージョン
aws-cli/1.20.56 Python/3.7.10 Linux/4.14.246-187.474.amzn2.x86_64 botocore/1.21.56

CloudShellとCloud9を使用します。

# そもそもSNSとは
` ・モバイルプッシュ通知やSMS送信など様々なメディアに対応した分散型フルマネージド通知サービス
・発信する側をパブリッシャー・受信する側をサブスクライバーと言い、Pub/Subモデルとも呼ばれている。
・発信する側受信する側へのメッセージをプッシュする一方通行
・Kinesis Data Firehose、SQS、Lambda、HTTP、E メール、モバイルプッシュ通知、モバイルテキストメッセージ (SMS) などのサポートされたエンドポイントを使用して SNS トピックにサブスクライブし発行されたメッセージを受信できる。
・基本料金、前払いは必要なく完全な従量課金制
・モバイルプッシュ通知は100万件まで、SMSは100件まで、Eメールは1,000件まで無料利用枠で送信をすることができる。
・１つのメッセージを多数のサービスが並列非同期処理ができ1対多の関係 `

# SQSとの違い

` SQSはマネージド型のメッセージキューイングサービスで、マイクロサービス、 分散システム、およびサーバーレスアプリケーションの切り離しとスケーリングが可能
・非同期式サービス対サービス通信の一つの形で、サーバレス及びマイクロサービスで使われる
・送信側はキューと呼ばれる場所にメッセージを保存
・受信者はポーリングをして、キューがあれば取得する
・メッセージを最大14日保存可能
・処理・削除されるまでは保存される(受信されてもキューに残り、自動的に削除されない)
・各メッセージは１つの受信者によって1回だけ処理される1対1の関係
・サービスや機能の間に依存性を分離させ、拡張性と安定性が高いシステムを構築 `

# AWS CloudShell・Cloud9とは
CloudShell・・・AWSを操作するためのコマンドラインツール(あの黒い画面のやつです)

Cloud9・・・ブラウザのみでどのマシンからでもコードを記述、実行、デバッグできる、クラウドベースの統合開発環境 (IDE) 

# 作業手順
以下CloudShellで実施
インスタンスプロファイルのIAMロールへのIAMポリシーのアタッチ (AmazonSNSFullAccess)
目的・・・インスタンスプロファイルにアタッチされているIAMロールに
IAMポリシー(AmazonSNSFullAccess)をアタッチする

１、インスタンスプロファイル名を指定
```
IAM_INSTANCE_PROFILE_NAME='handson-cloud9-instance-profile' 
```

２、IAMポリシー名を指定
```
IAM_POLICY_NAME='AmazonSNSFullAccess'
```

３、設定値の確認
```
cat << END
IAM_INSTANCE_PROFILE_NAME:"handson-cloud9-instance-profile"
       IAM_INSTANCE_PROFILE_NAME="${IAM_INSTANCE_PROFILE_NAME}"
IAM_POLICY_NAME:"AmazonSNSFullAccess"
       IAM_POLICY_NAME="${IAM_POLICY_NAME}"

END
```

４、IAMロール名の取得
```
IAM_ROLE_NAME=$( \
  aws iam get-instance-profile \
    --instance-profile-name ${IAM_INSTANCE_PROFILE_NAME} \
    --query 'InstanceProfile.Roles[].RoleName' \
    --output text \
) \
  && echo ${IAM_ROLE_NAME}
//(出力結果)　handson-cloud9-environment-role
```

５、IAMポリシーのARNを取得
```
IAM_POLICY_ARN=$( \
  aws iam list-policies \
    --scope AWS \
    --max-items 1000 \
    --query "Policies[?PolicyName==\`${IAM_POLICY_NAME}\`].Arn" \
    --output text \
) \
  && echo "${IAM_POLICY_ARN}"
// (出力結果) arn:aws:iam::aws:policy/AmazonSNSFullAccess
```

６、　設定値の確認
```
cat << END

  # IAM_ROLE_NAME:"handson-cloud9-environment-role"
    IAM_ROLE_NAME="${IAM_ROLE_NAME}"
  # IAM_POLICY_ARN:"arn:aws:iam::aws:policy/AmazonSNSFullAccess"
    IAM_POLICY_ARN="${IAM_POLICY_ARN}"

END
```

７、IAMポリシーをアタッチ
```
aws iam attach-role-policy \
  --role-name ${IAM_ROLE_NAME} \
  --policy-arn ${IAM_POLICY_ARN}
```

８、完了確認(インスタンスプロファイル"handson-cloud9-instance-profile"がアタッチされているIAMロールにIAMポリシー"AmazonSNSFullAccess"がアタッチされている)

```
aws iam list-attached-role-policies \
  --role-name ${IAM_ROLE_NAME} \
  --query "AttachedPolicies[?PolicyName == \`${IAM_POLICY_NAME}\`].PolicyName" \
  --output text
//AmazonSNSFullAccess
```

以下からCloud9で実施
# 目的・・・メールアドレス登録用の一時ファイル
"${HOME}/environment/tmp-handson-cli-sns-novice/mail_address.tmp"を作成

１、メールアドレスの指定
```
MAIL_ADDRESS="<事前に用意したメールアドレス>"
```

2. 一時ファイル用ディレクトリの指定
```
DIR_TMP="${HOME}/environment/tmp-handson-cli-sns-novice"
```
２、ディレクトリが存在することを確認し、存在しない場合は作成
```
ls -d ${DIR_TMP} > /dev/null 2>&1 \
  || mkdir -p ${DIR_TMP}
```

3、 一時ファイルファイル名の指定
```
FILE_TMP="${DIR_TMP}/mail_address.tmp" \
  && echo ${FILE_TMP}
```

４、設定値の確認
```
cat << END

  # 1. MAIL_ADDRESS:"<通知先メールアドレス>"
       MAIL_ADDRESS="${MAIL_ADDRESS}"
  # 2. DIR_TMP:"${HOME}/environment/tmp-handson-cli-sns-novice"
       DIR_TMP="${DIR_TMP}"
  # 3. FILE_TMP:"${HOME}/environment/tmp-handson-cli-sns-novice/mail_address.tmp"
       FILE_TMP="${FILE_TMP}"

END
```

５、一時ファイルを作成
```
cat << END

  # MAIL_ADDRESS:"<通知先メールアドレス>"
    MAIL_ADDRESS="${MAIL_ADDRESS}"
  # FILE_TMP:"${HOME}/environment/tmp-handson-cli-sns-novice/mail_address.tmp"
    FILE_TMP="${FILE_TMP}"

END
// MAIL_ADDRESS='<通知先メールアドレス>'
```

６、完了確認
```
ls ${FILE_TMP}
// ${HOME}/environment/tmp-handson-cli-sns-novice/mail_address.tmp
```

# SNSトピックを構築する

１、リージョンの指定
```
export AWS_DEFAULT_REGION='ap-northeast-1'
```

２、SNSトピック名
```
SNS_TOPIC_NAME='handson-cli-sns-novice-topic'
```

３、設定値の確認
```
cat << END

  # 0. AWS_DEFAULT_REGION:"ap-northeast-1"
       AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}"

  # 1. SNS_TOPIC_NAME:"handson-cli-sns-novice-topic"
       SNS_TOPIC_NAME="${SNS_TOPIC_NAME}"

END
```

４、SNSトピックを作成
```
cat << END

  # SNS_TOPIC_NAME:"handson-cli-sns-novice-topic"
    SNS_TOPIC_NAME="${SNS_TOPIC_NAME}"

END
```
```
aws sns create-topic \
  --name ${SNS_TOPIC_NAME}
// {
//  "TopicArn": "arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:handson-cli-sns-novice-topic"
//}

```
５、SNSトピック"handson-cli-sns-novice-topic"が存在する事を確認
```
aws sns list-topics \
  --query "Topics[?contains(TopicArn, \`${SNS_TOPIC_NAME}\`)].TopicArn" \
  --output text
```

# SNSトピックへのメールアドレス登録
目的・・・SNSトピック"handson-cli-sns-novice-topic"にメールアドレス"<通知先メールアドレス>"を登録
１、リージョンの指定
```
export AWS_DEFAULT_REGION='ap-northeast-1'
```
２、SNSトピック名を指定
```
SNS_TOPIC_NAME='handson-cli-sns-novice-topic'
```
３、SNS通知プロトコル名を指定
```
SNS_SUBSCRIPTION_PROTOCOL='email'
```
４、通知先エンドポイント
```
DIR_TMP="${HOME}/enviroment/tmp-handson-cli-sns-novice"
FILE_TMP="${DIR_TMP}/mail_address.tmp" && echo ${FILE_TMP}
// ${HOME}/environment/tmp-handson-cli-sns-novice/mail_address.tmp
```
５、一時ファイルの読み込み
```
source ${FILE_TMP}
```
６、通知先エンドポイントを指定
```
SNS_SUBSCRIPTION_ENDPOINT="${MAIL_ADDRESS}" \ 
&& echo ${SNS_SUBSCRIPTION_ENDPOINT}
// 通知先メールアドレス
```
７、設定値の確認
```
cat << END

  # 0. AWS_DEFAULT_REGION:"ap-northeast-1"
       AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}"

  # 1. SNS_TOPIC_NAME:"handson-cli-sns-novice-topic"
       SNS_TOPIC_NAME="${SNS_TOPIC_NAME}"
  # 2. SNS_SUBSCRIPTION_PROTOCOL:"email"
       SNS_SUBSCRIPTION_PROTOCOL="${SNS_SUBSCRIPTION_PROTOCOL}"
  # 3. SNS_SUBSCRIPTION_ENDPOINT:"<通知先メールアドレス>"
       SNS_SUBSCRIPTION_ENDPOINT="${SNS_SUBSCRIPTION_ENDPOINT}"

END
```
８、SNSトピックのARNを取得する
```
SNS_TOPIC_ARN=$( \
  aws sns list-topics \
    --query "Topics[?contains(TopicArn, \`${SNS_TOPIC_NAME}\`)].TopicArn" \
    --output text \
) \
  && echo ${SNS_TOPIC_ARN}
// arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:handson-cli-sns-novice-topic
```

９、設定値の確認
```
cat << END

  # SNS_TOPIC_ARN:"arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:handson-cli-sns-novice-topic"
    SNS_TOPIC_ARN="${SNS_TOPIC_ARN}"
  # SNS_SUBSCRIPTION_PROTOCOL:"email"
    SNS_SUBSCRIPTION_PROTOCOL="${SNS_SUBSCRIPTION_PROTOCOL}"
  # SNS_SUBSCRIPTION_ENDPOINT:"<通知先メールアドレス>"
    SNS_SUBSCRIPTION_ENDPOINT="${SNS_SUBSCRIPTION_ENDPOINT}"

END
```
１０、SNSトピックにメールアドレスを登録
```
aws sns subscribe \
  --topic-arn ${SNS_TOPIC_ARN} \
  --protocol ${SNS_SUBSCRIPTION_PROTOCOL} \
  --notification-endpoint ${SNS_SUBSCRIPTION_ENDPOINT}
// "SubscriptionArn": "pending confirmation"
```

登録したメールアドレスに"AWS Notification - Subscription Confirmation"という標題のメールが届いているのを確認する。

１１、完了確認
目的・・・SNSトピック"handson-cli-sns-novice-topic"にプロトコル"email"のエントポイント(メールアドレス)"<通知先メールアドレス>"が存在する事を確認する

```
aws sns list-subscriptions-by-topic \
  --topic-arn ${SNS_TOPIC_ARN} \
  --query "Subscriptions[?Endpoint == \`${SNS_SUBSCRIPTION_ENDPOINT}\`].Endpoint" \
  --output text
// 通知先のメールアドレス
```

１２、SNSトピック"handson-cli-sns-novice-topic"に登録されているエントポイント"<通知先メールアドレス>"のサブスクリプションARNが存在する。("PendingConfirmation"ではない。)」ことを確認
```
aws sns list-subscriptions-by-topic \
  --topic-arn ${SNS_TOPIC_ARN} \
  --query "Subscriptions[?Endpoint == \`${SNS_SUBSCRIPTION_ENDPOINT}\`].SubscriptionArn" \
  --output text
// arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:handson-cli-sns-novice-topic:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

# 参考にしたサイト
参加したイベント
・https://jawsug-cli.connpass.com/
コマンド
・https://awscli.amazonaws.com/v2/documentation/api/latest/index.html
JMESPath
・https://dev.classmethod.jp/articles/aws-cli-query-jmspath-tostring-grep/
・https://qiita.com/qtatsunishiura/items/fdd5e7f251299a90cd8c#%E9%80%9A%E5%B8%B8%E3%81%AEjmespath%E5%BC%8F%E3%81%A7%E5%A4%89%E6%95%B0%E5%B1%95%E9%96%8B%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88