20200918のAWSに関する記事は19件です。

VPCエンドポイントを試してみた

vpcエンドポイントのハンズオンを体験したので、概要と作成方法の記録です。
勉強途中のため一部理解が追いついていない部分がありますが、ご了承ください。

vpcエンドポイントとは

vpcエンドポイントは、グローバルIPを持つAWSサービスに対して、vpc内から直接アクセスするための出口のこと。

オンプレだと、専用線で自社サーバと、別地域のサーバやらストレージを接続するイメージです。(うん百万かかるのに・・・)

今回は、プライベートサブネット内のインスタンスから、S3へ直接アクセスするための、vpcエンドポイントを作成します。

以下の順に進んでいきますので、よろしくお願いいたします。
間違っている箇所があればコメントで教えていただけると大変助かります:pray_tone1:

利用環境

今までに作成したVPCやサブネット、インスタンスをそのまま利用しました。
下図の赤線ルートでS3へアクセスできることが目的です。(黒線はVPCエンドポイントを使用しない場合のアクセス例)

vpcエンドポイント利点.png

S3の作成

今までS3は作成してこなかったため、最初にS3の作成を行います。
AWSマネジメントコンソールから「S3」と検索し、「S3マネジメントコンソール」に移動します。

img 2020-09-15 19.19.14.png

S3マネジメントコンソールに移動したら、「バケットの作成」を選択します。
私はいくつかバケットを作成しているのでバケット名が表示されていますが、初回であれば何も表示されません。

img 2020-09-15 19.19.25.png

S3バケットに名前をつけたら、今回は他に設定をしないので「作成」を選択します。
S3バケット名は一意の値である必要があるため、日付等を名前の後に付与すると良いようです。

img 2020-09-15 19.20.07.png

IAMロールの作成・インスタンスの割当

続いて、インスタンスがS3へアクセスするためのIAMロールを作成します。
(S3を作成しただけでは使えません!!まずはインスタンスがS3へアクセスできるよう権限設定をします)

AWSマネジメントコンソールから「IAM」と検索し、「IAMマネジメントコンソール」に移動します。
IAMマネジメントコンソールの左ペイン、「ロール」を選択し、「ロールの作成」を選択します。

img 2020-09-15 19.45.49.png

ユースケースは「EC2」を選択し「次のステップ」を選択します。

img 2020-09-15 19.46.05.png

「AmazonS3FullAccess」を選択し、「次のステップ」を選択します。
※「ポリシーのフィルタ」で「S3」を入力すると良きです。

img 2020-09-15 19.46.22.png

設定しなくても大丈夫ですが、「Name」キーの設定を行いました。

img 2020-09-15 19.47.15.png

「ロール名」、「ロールの説明」を入力し、「ロールの作成」を選択します。
※ロール名は先ほどの「Name」キーと同様の値にしています。ロールの説明は適当でも大丈夫です。

img 2020-09-15 19.47.45.png

ここまでで、S3へのアクセス権を持った、IAMロールの完成です。

続けて、作成したIAMロールをインスタンスへ割り当てます。

「EC2マネジメントコンソール」に移動して、インスタンスを選択後、「アクション」、「インスタンスの設定」、「IAMロールの割り当て/置換」を選択します。

なお、インスタンスが停止していると割り当てに失敗しますので、起動状態でお願いします。
下の画面はインスタンスが停止しているので、この後失敗します。

img 2020-09-16 9.11.11.png

先ほど作成したロールを選択して、「適用」を選択します。

img 2020-09-16 9.11.21.png

これでIAMロールに準じたアクセス権限がインスタンスにされたことになります。
今回は、「AmazonS3FullAccess」がインスタンスに付与されたことになります。

また、プライベートサブネット内のインスタンスに割り当てたので、VPCエンドポイントもNATゲートウェイもない今の状態では、S3へは接続できません。

実際にプライベートサブネット内のインスタンスに接続して確認してみます。

# 自分のPCから
$ ssh ec2-user@18.177.121.50 -i my-key.pem

# パブリックサブネットのインスタンスから
[ec2-user@10.0.1.10 ~]$ ssh ec2-user@10.0.2.10 -i DBserver.pem

# プライベートサブネットのインスタンスから
[ec2-user@10.0.2.10 ~]$ aws s3 ls

下図のようにプロンプトが戻ってきませんので、「Ctrl」+「C」でAbortしましょう。

img 2020-09-17 20.28.20.png

VPCエンドポイントの作成・設定

続いてVPCエンドポイントを作成します。

VPCダッシュボードから、左ペインの「エンドポイント」を選択します。

img 2020-09-17 20.51.42.png

「S3」でフィルタをかけて、表示されたサービスを選択します。

img 2020-09-17 20.53.03.png

vpcは自身で作成したvpcを選択します。

img 2020-09-17 20.53.13.png

プライベートサブネットに属しているルートテーブルを選択します。

img 2020-09-17 20.53.23.png

ポリシーは変更せず、「エンドポイントの作成」をすると完成です!!
先ほどと同様の手順で確認をしてみると。。。

img 2020-09-17 20.54.46.png

「aws s3 ls」コマンドで応答が帰ってこなかったため、以下コマンドを使用しています。

$ aws s3 ls --region ap-northeast-1

少し補足

VPCエンドポイントには2種類あり、今回使用したのは無料のGateway型です。
Privatelink型は有料だそうです。

名前 実装方法
Gateway型 エンドポイントポリシーをルートテーブルに設定することで直接アクセスする
Privatelink型 サブネットがエンドポイント用のIPを持ち、それをDNSが名前解決することでルーティングする

参考文献

最後までお付き合いいただきありがとうございました:couplekiss:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS SOA】認証情報レポートの備忘録

はじめに

SOAの試験にあたって、IAM認証情報レポートに関する問題が問題集で出題された。SAAでは見なかったもので、備忘録としてIAM認証情報レポートとは何かを簡単に記載したい。

認証情報レポートとは?

ユーザーと、ユーザーの各種認証情報 (パスワード、アクセスキー、MFA デバイスなど) のステータスが示された認証情報レポートを生成し、ダウンロード可能。
認証情報レポートがどこから入手できるかで、IAMから取れるということを覚えておこう。

入手方法

IAM>認証情報レポートを開き、レポートをダウンロードを押すとレポートが出る。
スクリーンショット 2020-09-18 18.36.02.png

参考
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_getting-report.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Elastic Beanstalk に swap 設定(永続化も忘れずに)

AWS Elastic Beanstalk のウェブコンソールではメモリ容量はインスタンスタイプ設定でできるものの swap 設定はできません。
なので、ebextension に書くことで設定します。

swapを設定するところまではネットに転がっていたのですが、永続化まで考慮に入れている記事がなかったのでこの記事を書きました。
swaponコマンドで実行したものは再起動すると設定が巻き戻ってしまうので、fstabファイルに設定を書いておきます。

書き方

アプリケーションのトップディレクトリに.ebextensionsディレクトリを作成し、その中に swap.config とでも名前をつけて以下の内容を配置します。

ebextensions/swap.config
commands:
  000_create_file:
    test: test ! -e /swapfile
    command: dd if=/dev/zero of=/swapfile bs=1M count=1024 && chmod 600 /swapfile
  001_mkswap:
    command: mkswap /swapfile
    ignoreErrors: true
  002_swapon:
    command: swapon /swapfile
    ignoreErrors: true
  003_fstab:
    test: test `grep -c swap /etc/fstab` -eq 0
    command: echo "/swapfile  swap   swap    defaults   0 0" >> /etc/fstab

ステップ順に軽い解説をしておきます

  • 000_create_file
    • /swapfile という名前の0埋めされたファイルを作ります
    • swapはメモリの拡張のためにファイルを使う方式なので、ストレージサイズがタイトな場合には予め増量しておいた方が良いと思います。筆者の環境ではサーバに8G、使用中4G程度あったので、2Gのスワップを割り当てると残りがかなりタイトになってしまう状態でした
    • test ! -e /swapfile はファイルがなかったら作るためのshellコマンドです
  • 001_mkswap
    • ファイルを元にswap領域を作成します
    • ignoreErrors しないとすでに転換が済んでいる場合にエラーが出るので入っています
  • 002_swapon
    • スワップ領域を使用します
  • 003_fstab
    • 以下に記述

fstabに記述がすでにある場合には次のデプロイで書き込む必要がないので、存在チェックをしています。

test `grep -c swap /etc/fstab` -eq 0

grep -c swap /etc/fstabがfstabファイルに存在するswapと書かれている行数で、-eq 0はそれが0行であることをチェックしています

fstab の中身は最終的に以下のようになります。

[ec2-user@ip-172-31-26-7 ~]$ cat /etc/fstab
#
LABEL=/     /           ext4    defaults,noatime  1   1
tmpfs       /dev/shm    tmpfs   defaults        0   0
devpts      /dev/pts    devpts  gid=5,mode=620  0   0
sysfs       /sys        sysfs   defaults        0   0
proc        /proc       proc    defaults        0   0
/swapfile  swap   swap    defaults   0 0

おまけ

ebextension はデプロイしないといけないので動作確認の負荷が高いです。
test コマンドの実行などは手元環境で試した方が楽です。

こちらのebextensionの内容の確認をしたいケース。

  003_fstab:
    test: test `grep -c swap /etc/fstab` -eq 0
    command: echo "/swapfile  swap   swap    defaults   0 0" >> /etc/fstab

以下のようにシェルのワンライナーでだいたい確認することができます。

if test `grep -c swap /etc/fstab` -eq 0 ; then echo "/swapfile  swap   swap    defaults   0 0" >> /etc/fstab; fi
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSのまずはやっておくべきセキュリティ対策

AWSのまずはやっておくべきセキュリティ対策として、基本的なことだが 大事なことなのでまとめておこうと思います。

AWS Identity and Access Management

IAMによる認証

  • rootユーザには、強力なパスワードと多要素認証(MFA)を設定
  • 基本的には、rootユーザを使用しない
  • rootユーザのAccess Keyが発行されていた場合は削除する
  • IAMユーザのパスワードポリシーには強力なものを設定
  • IAMユーザのパスワードやAccess Key/Secret Access Keyは定期的にローテーションする
  • 認証情報の利用状況はIAMのCredential Report機能で定期的に確認

IAMによる権限設定

  • 全てのアクセスはデフォルトで拒否(Deny)となっているため、必要な権限のみ明示的に許可(Allow)設定を行う
  • アクセス権限の優先度は 暗黙的なDeny(デフォルトDeny) < 明示的なAllow < 明示的なDeny
  • IAMポリシーは最小限のアクセス権を付与

監査

  • AWS CloudTrailによる証跡取得を行う
    • 誰が、いつ、どのような操作(AWS Console、CLI、API等)したかを記録
    • AWS CloudTrail自体の料金は無料
  • AWS ConfigによるAWSリソースの設定を記録し評価を行う
    • AWSリソースの変更履歴、構成情報を管理
  • AWS Config RulesでAWSリソースがあるべき状態になっているかを自動評価
    • 例)Security GroupでSSHをフルオープンにしていないか
    • 例)公開状態になっているS3はないか
    • 例)全てのIAMユーザでMFAが有効になっているか

IAMロール

  • EC2にはIAMロールを利用する
    • AWSサービスに対してAWS操作権限を付与し、IAMユーザの認証情報をOSやアプリに持たせる必要がなく、認証情報の漏洩リスクを低減
    • 自動的に認証情報(Access Key/Secret Access Key)がローテーションされる
    • 認証情報はAWS Security Token Service(STS)により生成
  • IAMロールを使えるものは全てIAMロールを利用
  • オンプレからAWSリソースを操作する場合等、致し方ない場合のみIAMユーザを利用
  • IAMユーザやアクセスキーは共有しない
  • git-secretsを使用しクレデンシャル情報の漏洩防止

S3 Access Management

  • 必要以上に公開範囲の広いポリシーやACLを設定しない
    • EC2やAWSサービスからのアクセスはIAMロールで行う
  • 外部へ開放されているバケットを定期的にチェックする
    • AWS Trusted Advisor
    • AWS IAM Access Analyzer(Access Analyzer for S3)

発見的統制

  • 各種AWSサービスのログを有効化する
    • CloudTrail:誰が、いつ、どのような操作(AWS Console、CLI、API等)したかを記録
    • VPC Flow Logs:VPCのネットワークインタフェース間のIPトラフィックをキャプチャ
    • Lambda:Lambda Functionに関するエラー出力、標準出力等のログを収集
    • CloudWatch Logs Agent:EC2上で動作するOS、ミドルウェア、アプリケーション等のログをCloudWatchへ収集

データ保護

  • 保存時のデータ暗号化(Encryption at Rest)
    • サーバサイド暗号化(SSE)ではAWS Key Management Service(KMS)キーを使用し暗号化
    • クライアントサイド暗号化(CSE)ではKMSでCustomer Master Key(CMK)を使用し暗号化
  • 通信の暗号化(Encryption in Transit)
    • SSL通信を利用
    • AWS Certificate Managerで証明書を発行(無料)、自動管理
    • CloudFrontとELB間をHTTPSにし、ELBをSSH Terminationとする
  • DB接続情報やクレデンシャル等はセキュアに保管する
    • AWS Systems Manager Parameter Store
    • AWS Secrets Manager
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSのやっておくべきセキュリティ対策

AWSのやっておくべきセキュリティ対策として、基本的なことだが 大事なことなのでまとめておこうと思います。

AWS Identity and Access Management

IAMによる認証

  • rootユーザには、強力なパスワードと多要素認証(MFA)を設定
  • 基本的には、rootユーザを使用しない
  • rootユーザのAccess Keyが発行されていた場合は削除する
  • IAMユーザのパスワードポリシーには強力なものを設定
  • IAMユーザのパスワードやAccess Key/Secret Access Keyは定期的にローテーションする
  • 認証情報の利用状況はIAMのCredential Report機能で定期的に確認

IAMによる権限設定

  • 全てのアクセスはデフォルトで拒否(Deny)となっているため、必要な権限のみ明示的に許可(Allow)設定を行う
  • アクセス権限の優先度は 暗黙的なDeny(デフォルトDeny) < 明示的なAllow < 明示的なDeny
  • IAMポリシーは最小限のアクセス権を付与

監査

  • AWS CloudTrailによる証跡取得を行う
    • 誰が、いつ、どのような操作(AWS Console、CLI、API等)したかを記録
    • AWS CloudTrail自体の料金は無料
  • AWS ConfigによるAWSリソースの設定を記録し評価を行う
    • AWSリソースの変更履歴、構成情報を管理
  • AWS Config RulesでAWSリソースがあるべき状態になっているかを自動評価
    • 例)Security GroupでSSHをフルオープンにしていないか
    • 例)公開状態になっているS3はないか
    • 例)全てのIAMユーザでMFAが有効になっているか

IAMロール

  • EC2にはIAMロールを利用する
    • AWSサービスに対してAWS操作権限を付与し、IAMユーザの認証情報をOSやアプリに持たせる必要がなく、認証情報の漏洩リスクを低減
    • 自動的に認証情報(Access Key/Secret Access Key)がローテーションされる
    • 認証情報はAWS Security Token Service(STS)により生成
  • IAMロールを使えるものは全てIAMロールを利用
  • オンプレからAWSリソースを操作する場合等、致し方ない場合のみIAMユーザを利用
  • IAMユーザやアクセスキーは共有しない
  • git-secretsを使用しクレデンシャル情報の漏洩防止

S3 Access Management

  • 必要以上に公開範囲の広いポリシーやACLを設定しない
    • EC2やAWSサービスからのアクセスはIAMロールで行う
  • 外部へ開放されているバケットを定期的にチェックする
    • AWS Trusted Advisor
    • AWS IAM Access Analyzer(Access Analyzer for S3)

発見的統制

  • 各種AWSサービスのログを有効化する
    • CloudTrail:誰が、いつ、どのような操作(AWS Console、CLI、API等)したかを記録
    • VPC Flow Logs:VPCのネットワークインタフェース間のIPトラフィックをキャプチャ
    • Lambda:Lambda Functionに関するエラー出力、標準出力等のログを収集
    • CloudWatch Logs Agent:EC2上で動作するOS、ミドルウェア、アプリケーション等のログをCloudWatchへ収集

データ保護

  • 保存時のデータ暗号化(Encryption at Rest)
    • サーバサイド暗号化(SSE)ではAWS Key Management Service(KMS)キーを使用し暗号化
    • クライアントサイド暗号化(CSE)ではKMSでCustomer Master Key(CMK)を使用し暗号化
  • 通信の暗号化(Encryption in Transit)
    • SSL通信を利用
    • AWS Certificate Managerで証明書を発行(無料)、自動管理
    • CloudFrontとELB間をHTTPSにし、ELBをSSH Terminationとする
  • DB接続情報やクレデンシャル等はセキュアに保管する
    • AWS Systems Manager Parameter Store
    • AWS Secrets Manager
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DiscordのWebhooksをurllib経由でたたいて簡単自動発言ボット作成

概要

AWS Lambda の Python 3.7 ランタイムを使ってDiscordのWebhook URL を叩くと 403 でうまいこと叩けずに困った。

原因を調べたらどうやらUAをチェックしているらしく、UAが urllib だとNG。( 試しに使った curl はOK )

Discordのライブラリを入れればいいんだろうけど、Lambdaという都合上、ほか依存ライブラリ追加したくない。

UAをcurlに偽装することでうまいこと叩けた。よかったよかった。

反省

  • うまくいくパターンとだめなパターンの差分はHTTPヘッダをみよ。
  • APIがコケる場合にはちゃんとステータス値とレスポンスボディとマニュアルをみよ。

参照

Python3のスクリプトでjsonをPOSTする - Qiita

詳細

What is Webhooks

Discordにおいて、なにかあったら自動で特定のチャンネルにメッセージを送りたい。

なんでも Webhookってのが作られるらしく、それならシンプルにJSONをポストするだけでそういうことができる。
(本当はDMを送りたかったんだけど、そっちはAPI経由になってだるそうなんでヤメ)

How to get Webhook URL

たぶん管理者権限がいる。

  1. チャンネルの右側に表示されているギアをクリック
  2. 左のメニューから「連携サービス」をクリック
  3. 「ウェブフック」とあるのでそこの「詳細」 or 「ウェブフックを確認」をクリック
  4. 「新しいウェブフック」をクリック、ポストされるときの名前を指定し、チャンネルを指定
  5. 「ウェブフックURLをコピー」をクリックすればOK

試す

とりあえず POST はオオゴトなんでまずは GET から。curlを使って試す。

$ curl -v https://discordapp.com/api/webhooks/xxxxxxxx
略
< HTTP/2 200
略
{"type": 1, "id": "xxxx", "name": "xxxxx", "avatar": null, "channel_id": "xxxxxx", "guild_id": "xxxxxx", "application_id": null, "token": "xxxxxx"}

OK。エンドポイントが正しくあることは確認できた。

POSTを試す。

$ curl -v -X POST -H "Content-Type: application/json" -d '{"content":"ふぁらおからウェブフック経由のポストで参上"}' https://discordapp.com/api/webhooks/xxxxxxxx

でOK。

Pythonのコードから試す

以下で試せばOK。試しに urllib.request.Request の第3パラメータの User-Agent を削除してみてほしい。それだと弾かれてしまう。

    url = "https://discordapp.com/api/webhooks/xxxxxxxx"
    method = "POST"
    headers = {"Content-Type" : "application/json"}
    obj = {"content" : "ふぁらおからウェブフック経由のポストで参上"}
    json_data = json.dumps(obj).encode("utf-8")
    request = urllib.request.Request(
        url,
        json_data,
        {"User-Agent": "curl/7.64.1", "Content-Type" : "application/json"},
        method
    )
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")
        print(response_body)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Copilotとecspressoの違いを調べてみた

結論

  • 下記「背景」のようなケースの場合は、ecspressoまたは類似ツールを使ったほうが事故は少ない
  • コンテナやAWSやっていき勢、PoCなど速度が必要なケースはAWS Copilotを使ってみて慣れていくのはアリ
  • というより、双方のツールは目指すところが全然違うので比較対象として論じること自体にちょっと無理がある

前提

本稿で記載している「ECS」は「ECS on Fargate」であり、「ECS on EC2」ではありません。
双方のツールを軽く触れて書いた記事なので、細かい機能について把握していないものもあると思います。

背景

これまでいくつかのAWSを使用したプロジェクトのインフラ管理にTerraformをオールインワンツールとして採用してきました。
しかし、システムの規模が大きくなるにつれてTerraformではどうしても取り回しの鈍さが出てくるケースが増えてきたため、アプリケーションレベルのデプロイコントロールはECSに特化したCLIに乗り換えたほうが良いのでは…と思い至り、調査した結果を記事にしました。

ECSとは

ECS is 何?という方は、AWSの中の人として大人気なトリ先生のスライドを見るといいです。
https://pages.awscloud.com/rs/112-TZM-766/images/A-1.pdf

※本稿では触れないCLIツールも上記スライド内でPros/Consが紹介されています

AWS Copilotとは

AWS ECS CLIの後継サービスでAWS謹製。
デフォルトでモダンかつプロダクションレディなインフラ構築をサポートしてくれるらしい。

リポジトリ

https://github.com/aws/copilot-cli

特徴

  • VPC、サブネット、ロードバランサー、デプロイパイプライン、ストレージなどのクラウドリソースを管理できる
  • 上記の細かい設定はデフォルトでいい感じになっているらしい
  • 生きたOSSプロジェクトなので気になる点はIssueやPRを出せる
  • 単一バイナリ
  • 本番や開発など環境ごとの設定をマニフェストファイルとしてYAMLで管理できる
  • Dockerfileだけあればアプリケーションを最低限実行するために必要なものをインタラクティブにデプロイしてくれる
  • ECS Service Discoveryを比較的簡単に使用できる
  • 内部的にCloudFormationのコードを生成しているためAWSに関する対応が幅広い
  • サイドカー構成は現時点では事前定義された構成(FireLens)しか使用できなさそう
  • 既存のリソースはVPC周りしかインポートできなさそう
  • リポジトリにWikiはあるが、限定的な情報しか書いてないので使うなら手探りになりそう

ecspressoとは

面白法人カヤック社が開発したECSデプロイツール。
飲み物の「エスプレッソ」からもじったとのこと。
ECSサービスやECSタスクのコントロールに特化しているため、AWS CLIなどを使って頑張るより手軽にデプロイ操作をコントロールできる。
いくつかのCI/CDツールとの親和性もあるため、CI/CD自動化にも組み込みやすく、小規模なサービスならこれだけで事足りるケースも多い。
利用者も一定数いるため、初期導入についてはググれば十分な情報を得ることができる。

リポジトリ

https://github.com/kayac/ecspresso

特徴

  • タスク定義を含めて開発用リポジトリで管理できる
  • みんな大好きGolang製
  • 生きたOSSプロジェクトなので気になる点はIssueやPRを出せる
  • 単一バイナリ
  • サイドカー構成のデプロイも可能
  • go-configと併用すると環境変数の展開もできる
  • ツールで出来ることが限定されているので開発者が軽い気持ちで使っても大事故が起こりにくい

比較一覧表

No 項目 AWS Copilot ecspresso
1 ALBの作成
1 NLBの作成
1 ECSクラスターの作成
1 ECSサービスの作成
1 ECSタスク定義の作成
1 ECSタスクのスケーリング操作
1 ECSタスクのロールバック
1 Fargate Spot
1 Blue/Green Deploy対応 ?
1 サイドカーのデプロイ
1 brew install
1 Task Execution IAM Roleの管理
1 Task IAM Roleの管理
1 DRY RUN
1 YAML
1 Github Actions連携
1 Circle CI連携
1 Codeシリーズ連携
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

APIとは

見てくださった方々に正しい情報を伝えられるように頑張りますが、初投稿なので細かい所は大目に見てくださいっ。

定義

APIとは「Application Programming Interface」の頭文字を取ったものです。
「Application」→アプリケーション、ソフトウェア
「Programming」→プログラム
「Interface」→「何か」と「何か」を繋ぐもの
以上を大雑把に言うと「アプリケーション、ソフトウェアとプログラムを繋ぐもの」ということになります。
例えるなら、パソコンと周辺機器をつなげるUSBも役割的には同じ役割です。
APIの場合ソフトウェア同士をつなげます。つまり、APIを使うと異なるソフトウェアやサービス間で認証機能を共有したり、チャット機能を共有したり、片方から数値データを取り込み、別のプログラムでそのデータを解析したりできるようになります。

メリット

・アプリケーションの開発時間やコストの削減が可能
・セキュリティの向上
・最新情報を簡単に取得できる

他にもあると思いますが、以上がAPIの利点と言えます。

アプリケーションの開発時間やコストの削減が可能

APIを使うことによって自分で1からプログラムを組む必要がなくなり、プログラムの開発時間を省略できるようになります。開発になれていないエンジニアでも簡単にアプリケーション開発が可能になります。

セキュリティの向上

色々な世の中のサービスの中で会員登録時にGoogleアカウントやFaceboolアカウントと連携することで登録できたという経験があると思いますがこれはAPIのおかげでできています。
この連携により簡単に会員登録できるようになる他に、自社でセキュリティレベルの高い会員登録システムを入れるよりも、すでにあるセキュリティレベルの高い会員システムを導入する方がユーザーも安心してサービスを使うことができます。

最新情報を簡単に取得できる

APIを使えばそれぞれの最新情報をこちら側から取得しなくても取得、利用できるようになります。
例えば、自分のサイトでAmazonや楽天などの商品を売っている場合、販売価格や商品情報が変わった時にも自動で変更されるようになります。

WEBAPI

WEBAPIとはweb上に公開されていて、外部から呼び出して利用することができるAPIです。

WEBAPIの例

・Amazon
・Facebook
・Twitter
・Google
・ぐるなび
・楽天
・Yahoo

一般的には企業のwebサイトから登録をしてAPIを取得します。各々のAPIの使い方は今回また別の機会で紹介できたらなと思います。

WEBAPIを使うにあたって

実際にAPIを使うときには注意点があります。
・APIキー(アクセスキー)
・APIシークレットキー
この2つを使うときに取得するのですがAPIキーはログインの際のID名にあたる部分、APIシークレットはパスワードのようなものです。なので大切に管理しなければなりません。この2つが第三者や外部に漏れてしまうと情報を買い替えられたり、勝手に送金や出金をされてしまう場合もあります。なのでパスワードや他の権利関連のものは大切に管理しましょう。

終わりに

https://data.wingarc.com/what-is-api-16084/4
https://www.internetacademy.jp/it/programming/javascript/how-to-use-web-api.html

こちらのサイトを参考にさせていただきました。
簡単になりましたが大体APIとはこんな感じなんだなと思っていただければ幸いです。
詳しい各々のAPIの紹介はこちらの方が紹介しているQiitaが分かりやすくておすすめです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Systems Managerを用いてEC2上のコマンドを動かしてみた

こんにちは。streampackのfadoです。厳しい暑さが続いておりますがみなさん、いかがお過ごしでしょうか。まだまだ油断は禁物ですのでうがいと手洗いを忘れないようにしましょう。さて、今回は表題にも書きました通り、AWS Systems Managerを利用し、AWS Lambda及びAmazon API Gatewayと連携したシステムでAmazon EC2インスタンス上でコマンドを実行させる方法を簡単に説明していきたいと思います。

注意事項

  • Linuxコマンド及びAWS Lambda,Amazon API Gateway,AWS Systems Managerの知見がある方を対象にしています。
  • AWS LambdaはPython3で記載しています。
  • ffmpegのRTMP送信先はAWS Elemental MediaLive -> AWS Elemental MediaPackageにしていますがスコープ外ですのでセットアップ等は割愛させていただきます。

リソース

  • Amazon EC2 (以下 EC2)
  • AWS Systems Manager(以下 SSM)
  • AWS Lambda (以下 Lambda)
  • Amazon API Gateway(以下 API Gateway)
  • AWS IAM (IAM ロールとIAM ポリシー)

手順

EC2

  • OSはAmazon Linux 2を使っています。AWS Systems Managerエージェントとffmpegが動く環境であればどのOSでも問題ありません。
  • AmazonSSMManagedInstanceCoreポリシーがアタッチされたIAM ロールを対象EC2インスタンスにつけます。 AmazonSSMManagedInstanceCoreEC2インスタンスがSSMのメイン機能を取り扱えるように許可してくれるポリシーです。
  • 例ではffmpegコマンドを利用しますので事前にインストールしておきましょう。
  • 動画はフリー素材を使っています。

SSM

AWS Systems Managerコンソールにて「インスタンスとノード」 -> 「マネージドインスタンス」のタブで対象EC2インスタンスが登録されていることを確認します。表示に出ていない場合はEC2にアタッチされているロールにAmazonSSMManagedInstanceCoreポリシーが漏れている可能性があります。
スクリーンショット 2020-09-18 1.59.28.png

Lambda

LambdaIAM ロールAWS Systems Managerssm:SendCommandssm:ListCommandInvocationsアクションを利用しているのでこの二つのアクションが含まれるポリシーを付けます。LambdaIAM ロール専用のポリシーにしたいので、インランポリシーでの作成になります。

関数コードは次の通りです。

lambda_handler.py
import boto3
import time
import json

apigw = boto3.client('apigateway')
ssm = boto3.client('ssm')

## 対象インスタンスを定義
instance_id = ['i-XXXXXXXXX']

## 実行するコマンドを定義
start_cmd = "/usr/local/bin/ffmpeg -re -stream_loop -1  -i /home/ec2-user/media/bbb_sunflower_1080p_30fps_normal.mp4 -c:v copy -c:a aac -flags +loop-global_header -f flv rtmp://XX.XX.XX.XX:1935/test/live < /dev/null > /tmp/ffmpeg.log 2>&1 &"
stop_cmd = "/usr/bin/killall ffmpeg"

def lambda_handler(event, context):
    try:
        ## API GatewayのURL pathによって実行するコマンドを区別
        api_path = event['path']
        if "start" in api_path:
            cmd_to_execute = {'commands': [start_cmd]}
        elif "stop" in api_path:
            cmd_to_execute = {'commands': [stop_cmd]}
        else:
            return "No matches,exiting..."

        ### send-commandを実行
        response = ssm.send_command(
            DocumentName = "AWS-RunShellScript",
            InstanceIds = instance_id,
            Comment = 'Executing ffmpeg command...', 
            TimeoutSeconds = 600, 
            Parameters = cmd_to_execute
        )
        command_id = response['Command']['CommandId']

        ## send_commandのCommandIdid値が取得できるまで数秒かかることもあるため5秒間隔をおく
        time.sleep(5)

        ## ステータスを取得
        list_invocations = ssm.list_command_invocations(
            CommandId = command_id,
            Details = True
            )

        ### Api Gatewayに渡すレスポンスを定義
        body = list_invocations['CommandInvocations'][0]['Status']

        return { 
            'statusCode': 200,
            'headers': {'Content-Type': 'application/json'},
            'body': body
            }

    except Exception as e:
        raise e

詳細な説明は省きますが上記はAPI Gatewayから送られてきたURLを判別し、対象EC2インスタンスに対しstartまたはstopコマンドの実行命令を送ります。コマンド実行が成功ならSuccess,失敗ならFailedのレスポンスが戻ってくる流れとなっています。

API Gateway

次のように設定します。リソース名は分かりやすいものにしましょう。
尚、メソッドはGETではなくPOSTにします。APIのURLを叩くだけで実行されないようにするためです。

プロトコル メソッド リソース名
REST POST /start
REST POST /stop

メソッドを設定する際に「Lambda プロキシ統合の使用」にチェックを入れます。これはAPI Gatewayが受信リクエストをLambda関数の入力eventパラメータにマッピングさせるためです。

スクリーンショット 2020-09-18 0.20.30.png

検証

startコマンド

1.設定したstart用APIでPOSTメソッドを用いて実行します。「Success」レスポンスが返ってきたら問題なくコマンドが実行されたことになります。「Failed」レスポンスの場合は、EC2インスタンスのamazon-ssm-agent.logをご確認ください。

$ curl -X POST https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/ffmpeg/start
Success

2.EC2インスタンス上でffmpegプロセスが起動できていることを確認できました。

$ ps axu|grep ffmpeg
root      3119  9.9  1.0  91388 21100 ?        S    01:23   0:00 /usr/local/bin/ffmpeg -re -stream_loop -1 -i /home/ec2-user/media/bbb_sunflower_1080p_30fps_normal.mp4 -c:v copy -c:a aac -flags +loop-global_header -f flv rtmp://54.249.218.4:1935/test/live
ec2-user  3121  0.0  0.1 110536  2236 pts/0    S+   01:23   0:00 grep --color=auto ffmpeg

3.配信が問題なくできていることも確認できました。
(配信はスコープ外なのでできていなくてもffmpegプロセスさえ動いていれば問題ありません)

スクリーンショット 2020-09-18 1.39.23.png

stopコマンド

1.設定したstop用APIでPOSTメソッドを用いて実行します。「Success」レスポンスが返ってきたら問題なくコマンドが実行されたことになります。「Failed」レスポンスの場合は、EC2インスタンスのamazon-ssm-agent.logをご確認ください。

$ curl -X POST https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/ffmpeg/stop
Success

2.EC2インスタンス上でffmpegプロセスが起動できていることを確認できました。

$ ps axu|grep ffmpeg
ec2-user  3108  0.0  0.1 110536  2236 pts/0    S+   01:22   0:00 grep --color=auto ffmpeg

SSMからのコマンド実行に問題がないかEC2インスタンスのログでも確認することができます。

/var/log/amazon/ssm/amazon-ssm-agent.logの一部

  },
  "documentStatus": "Success",
  "documentTraceOutput": "",
  "runtimeStatus": {
    "aws:runShellScript": {
      "status": "Success",
      "code": 0,
      "name": "aws:runShellScript",
      "output": "",
      "startDateTime": "2020-09-17T16:08:17.477Z",
      "endDateTime": "2020-09-17T16:08:17.488Z",
      "outputS3BucketName": "",
      "outputS3KeyPrefix": "",
      "stepName": "",
      "standardOutput": "",
      "standardError": ""
    }

結論

AWS Systems Manager,AWS LambdaAmazon API Gatewayを活用すればEC2インスタンス上でコマンドを簡単に実行させることができます。今回は単純な処理を例に挙げて説明しましたが踏み込んだコマンドを実行するスクリプトを用意すればさらに高度な処理ができ、かつその実行結果を表示させることも可能です。それではまた次回!

参考文献

https://aws.amazon.com/jp/systems-manager/
https://aws.amazon.com/jp/lambda/
https://aws.amazon.com/jp/api-gateway/
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

しくじり / id_rsaを上書きしてしまった話

AWS C9でアプリケーション開発を行う際、SSH接続がgithubとEC2インスタンスでこんがらがった話。

C9上でgit管理している場合
githubをリポジトリとしてssh接続する際は~/environment/.sshフォルダに置いておくと思う(当時無知識だったため、そのままid_rsaという名前にした)
ここで登録する際に名前を例えばid_rsa_githubなどに変更するか、もしくはディレクトリを切ってgithubを指定しておけば後々詰まることもなかっただろう

そして開発がある程度終了し
EC2インスタンスに接続するためのid_rsaを同じフォルダに上書きしてしまっていた

今までgithubにssh接続出来ていたものが、突然Permission denied (publickey).と怒られるようになる

上書きしてしまったのものは仕方ないので、こういった場合はgithubのssh接続を再登録すればOK
その際、ちゃんとディレクトリを切るなり、ファイル名を変更するなりして
.ssh/configファイルの中のパスを指定してあげましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon SESの1日の送信制限を引き上げる方法

SESを利用していて、これからも同じようなことがありそうなので忘れないようにまとめておきます。

SESとは?

SESとはAmazon Simple Email Serviceの略で、デベロッパーが任意のアプリケーションでメールを送信できるようにするメール配信サービスです。

特徴としては、従量課金制導入コストが低い等が挙げられています。

また、SESには無料枠があり月62000通までは無料で使用できます(EC2からメールを送信する場合)。

詳しい料金設定は以下を参考にして下さい。
SESの料金について

1日の送信制限の上限を上げたい

SESを利用する場合、デフォルトで送信できるメールの数が制限されいています。

なので大勢のユーザーに一斉にEメールを送りたいが、この申請をしていないと1日の送信制限に引っかかってしまい、送信できないなんてことが起きてしまいます。

なので以下に手順をまとめていきます。

1. AWSマネジメントコンソールにサインイン

2. 左上のサービスからSES(Simple Email Service)の設定画面へ
Screen Shot 2020-09-17 at 11.03.44 PM.png

3. Sending Statisticsを押し、 Your Amazon SES Sending Limitsの
Sending Quotaを確認

ここで現在の1日あたりの送信クォータが確認できます。
※画像では既に上限を引き上げているため50000となっていますが、デフォルトは200となっています。
Screen Shot 2020-09-17 at 11.29.07 PM.png

4. 上限を引き上げたい場合は、右上のサポートからサポートセンターへ
Screen Shot 2020-09-17 at 11.09.30 PM.png

5. 真ん中のオレンジの「ケースの作成」ボタンを押す
Screen Shot 2020-09-17 at 11.09.58 PM.png

6. サービス制限の緩和を押す
Screen Shot 2020-09-17 at 11.11.13 PM.png

7. 下に入力欄が出てくるので必要な項目を入力
ここで入力する項目は、以下になります。
・AWSアカウントID
・送信制限の引き上げをリクエストする AWS リージョン
・制限タイプ:希望する一日あたりの送信クォータ or 希望する最大送信レート
・新しい制限値
・Eメールメッセージタイプ(システム通知など該当するものを選択)
・ウェブサイトURL(必須ではないが、あったほうがいい)
・申請理由の説明

項目の入力が完了したら送信。

ここまで終えれば基本的に24時間以内にAWSから返答があります。

まとめ

覚えといて損はないし、1回やってみると案外あっという間に終わったのでいい経験だった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Slash Commandsで自分が使用している端末のグローバルIPは取得できるのか【API Gateway + Lambda(Go)】

はじめに

こんにちは。先月AWS ChatbotからRDSを操作していて、とても簡単にSlackから実行できて感動したので、第2弾です!今回はSlackから自分のグローバルIPを取得できるのかを、試してみました!

結論

残念ながら、Slackから自分のグローバルIPは取得できませんでした。

Slackで自分のグローバルIPを取得するべく、Slash CommandsというSlackのapiと、AWSのAPI Gateway、Lambdaを使って試みたので、その過程について備忘録です。

方法検討

自分のグローバルIPを取得して、それを引数としてLambdaを実行したかったので、AWSを使う方針で進めていきます。

調査したところ、SlackからLambdaを実行する方法を2つ見つけました。

  • API Gatewayを使う方法(Slash Commandsの作成)
  • AWS Chatbotを使う方法

API Gatewayはアクセス元のグローバルIPを取得できるというのを知ったので、今回はAPI Gatewayを使う方法(Slash Commandsの作成)で実装することにしました!

構成図

構成は下図の通りです。
ちなみに、Slash commandsは3000ms以内に応答を返す必要があるので、処理時間が長いものに関しては先にSlackに応答を返す必要があるみたいです。今回はアクセス元IPを返すだけなので、こちらの構成で実装しました。
参考:https://api.slack.com/interactivity/slash-commands

Slash_commands.png

やってみる

Lambda関数の作成

今回はチャンネルを識別し、指定チャンネルから実行されていれば、アクセス元のグローバルIPを返すというLambda関数を作りました。

チャンネルを識別する意図としては、Slash Commandsは、ワークスペース内の全チャンネル、全DMで使えるもので、チャンネルを指定することができません。今回作成するSlash CommandsはグローバルIPを返すだけなので、どこで実行できても問題はないのですが、実際には指定したプライベートチャンネルのメンバーのみしか実行できないようにしたかったので、実行チャンネルを識別し、実行権限があるのかを判断する処理を入れています。

IAMロール

特別必要な権限はないので、基本的なLambdaアクセス権限をアタッチしたロールを使用します。

Slackから送られるデータと構造

Slackから送られるデータと構造は下記の通りです。
※ Valueは削除しています。本来はそれぞれ値が入っています。
※ 後述のAPI Gatewayのマッピングテンプレートを使用した場合の構造です。

{
  "querystring":{
    "api_app_id":"",
    "channel_id":"",
    "channel_name":"",
    "command":"",
    "response_url":"",
    "team_domain":"",
    "team_id":"",
    "text":"",
    "token":"",
    "trigger_id":"",
    "user_id":"",
    "user_name":""
  },
  "source_ip":""
}

ソースコード

package main

import (
    "github.com/aws/aws-lambda-go/lambda"
    "os"
)

type MyEvent struct {
    Querystring Querystring `json:"querystring"`
    SourceIp string `json:"source_ip"`
}

type Querystring struct {
    ChannelId string `json:"channel_id"`
}

/**************************
    処理実行
**************************/
func run(event MyEvent) (interface{}, error) {
    // os.Getenv()でLambdaの環境変数を取得
    if event.Querystring.ChannelId == os.Getenv("channelId") {
        return event.SourceIp, nil
    }
    res := "実行権限がありません。"
    return res, nil
}

/**************************
    メイン
**************************/
func main() {
    lambda.Start(run)
}

API Gatewayの作成

API Gatewayの作成を行います。
POSTメソッドを作成し、先ほど作成したLambda関数を紐付けます。

そして、マッピングテンプレートの設定をしていきます。
[統合リクエスト]をクリックします。

スクリーンショット 2020-09-06 23.39.41.png

最下部にあるマッピングテンプレートを開き、リクエスト本文のパススルーはテンプレートが定義されていない場合 (推奨)を選択します。そして、[マッピングテンプレートの追加]をクリックします。

スクリーンショット 2020-09-06 23.45.21.png

[マッピングテンプレートの追加]を押したら出てくるテキストボックスにapplication/x-www-form-urlencodedを入力、保存します。

テンプレートの入力フォームが出てくるので、下記のマッピングテンプレートを貼り付け、[保存]をクリックします。

スクリーンショット 2020-09-06 23.43.58.png

【マッピングテンプレート】

#set($rawAPIData = $input.path('$'))
## escape any quotes
#set($rawAPIData = $rawAPIData.replace('"', '\"'))

## first we get the number of "&" in the string, this tells us if there is more than one key value pair
#set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())

## if there are no "&" at all then we have only one key value pair.
## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
## the "empty" kv pair to the right of the ampersand will be ignored anyway.
#if ($countAmpersands == 0)
 #set($rawPostData = $rawAPIData + "&")
#end

## now we tokenise using the ampersand(s)
#set($tokenisedAmpersand = $rawAPIData.split("&"))

## we set up a variable to hold the valid key value pairs
#set($tokenisedEquals = [])

## now we set up a loop to find the valid key value pairs, which must contain only one "="
#foreach( $kvPair in $tokenisedAmpersand )
 #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
 #if ($countEquals == 1)
  #set($kvTokenised = $kvPair.split("="))
  #if ($kvTokenised[0].length() > 0)
   ## we found a valid key value pair. add it to the list.
   #set($devNull = $tokenisedEquals.add($kvPair))
  #end
 #end
#end

{
"querystring" : {
#foreach( $kvPair in $tokenisedEquals )
  ## finally we output the JSON for this pair and append a comma if this isn't the last pair
  #set($kvTokenised = $kvPair.split("="))
  #if($kvTokenised.size() == 2 && $kvTokenised[1].length() > 0)
    #set($kvValue = $kvTokenised[1])
  #else
    #set($kvValue = "")
  #end
  #if( $foreach.hasNext )
    #set($itemDelimiter = ",")
  #else
    #set($itemDelimiter = "")
  #end
 "$kvTokenised[0]" : "$kvValue"$itemDelimiter
#end
},
"source_ip" : "$context.identity.sourceIp"
}

最後にリソースのデプロイを行い、発行されたURLをコピーしておきます。

スクリーンショット 2020-09-07 0.17.36.png

Slash Commandsの作成

Slack appの作成

Slack apiからSlack appを作成していきます。

[Create New App]をクリックするとAppの作成画面に遷移します。

スクリーンショット 2020-09-05 13.26.37.png

ここで、Slack Appの名前Appを実行したいワークスペースを選択します。
そして、[Create App]をクリックするとSlack Appが完成します。

スクリーンショット 2020-09-05 13.27.43.png

Slash commandsの作成

Appの設定ページに移動して、Slash commandsを作成します。

左側のメニューから[Slash commands]を選択し、[Create New Commands]をクリックします。

スクリーンショット 2020-09-05 13.28.36.png

次に、Slackから送信するコマンド名前述のAPI Gatewayで取得したリクエストURL説明文の3つを入力します。今回は、/get_ipというコマンド名を設定しました。

スクリーンショット 2020-09-05 13.44.48.png

今回は引数を入力しないのでヒントは入れませんでしたが、引数など入力時の補足がある場合はUsage Hintに入力しておきます。Escape channels, users, and links sent to your appにチェックを入れることで、引数にユーザ名を入れる時に、ユーザ名だけではなくユニークなユーザIDも送ることができ、アカウントを識別できるそうです。今回はアカウントの識別は不要なので、チェックは入れませんでした。

それぞれ入力完了後、[Save]をクリックすると、Slash commandsが完成します。

Botの名前設定

このままAppのインストールに進むと、(App名)にはインストールするボットユーザーがありません。というエラーが出て、Appをインストールできなかったので、Appの設定ページから、Botを作成します。

ちなみに、App名が小文字英数字の場合は、自動でBotが設定されるみたいので、初期値が入っていればこのフローは不要です。わたしはIP取得マンというApp名にしていたためボットユーザが作られなかったのだと思われます。

左側のメニューから[App Home]を選択し、Your App's Presence in Slackの[Edit]をクリックします。

スクリーンショット 2020-09-06 18.19.39.png

Botの表示名ユーザ名を入力して[Add]をクリックすると、Botの名前が設定されます。

スクリーンショット 2020-09-06 18.19.51.png

Appのインストール

いよいよAppのインストールです。

左側のメニューから[Install App]を選択し、[Install App to Workspace]をクリックします。

スクリーンショット 2020-09-06 18.20.06.png

作成したAppが指定したワークスペースにアクセスするのを許可すると、グローバルIPを取得するコマンドの完成です。

実行結果

実行方法

今回作成したコマンド/get_ipをメッセージとして送信します。

スクリーンショット 2020-09-13 19.22.55.png

指定チャンネルから実行した場合

指定チャンネルから実行した場合のレスポンスは次の通りです。

スクリーンショット 2020-09-06 19.13.55.png

IPアドレスが返ってきました!!!

ただ、自分のグローバルIPを調べてみると・・・違う。。
これはSlackのグローバルIPアドレスですね。。。

残念ながら、自分のグローバルIPアドレスを取得することはできませんでした。

指定外のチャンネルから実行した場合

ちなみに、指定外のチャンネルから実行した場合のレスポンスは次の通りです。

スクリーンショット 2020-09-06 19.13.45.png

これで、実行チャンネルを識別し、指定チャンネル外からは実行できないことが確認できました!

おわりに

結果、SlackからグローバルIPを取得することはできませんでしたが、SlackのIPは取得することができました。ただ、実行する度に違うIPアドレスが返ってくることも確認できました。今回とは関係ないですが、Slackは複数のグローバルIPアドレスを持っていることがわかりました。

前回に引き続き、SlackからLambdaを実行してみましたが、AWS Chatbotと比較してSlash commandsの良いところは個人DMで使えるというところかなと感じました。反対に、Slash commandsの場合は処理時間が3000msを越えるものは、まず応答を返すようにしないといけないところは少し面倒かな、、と思いました。

今回は、残念な結果に終わってしまったので、また違う方法を考えます。SlackからグローバルIPを取得するいい方法があるよっていう方いらっしゃいましたら、教えていただけると嬉しいです!

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS ECS ~ demo

1.CloudFormation で環境を準備する

入力する箇所は、次のとおりで他の内容はデフォルトとする。

キー バリュー
スタックの名前 任意
MasterUserName 任意(後でDBで使う。)
MasterUserPassword 任意(後でDBで使う)
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "VPC Template For Multi-AZ",
  "Parameters": {
    "MasterUserName": {
      "Description": "RDS master user name",
      "Type": "String"
    },
    "MasterUserPassword": {
      "Description": "RDS master user password",
      "Type": "String"
    }
  },
  "Resources": {
    "VPC": {
      "Type"       : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock"          : "10.0.0.0/16",
        "InstanceTenancy"    : "default",
        "EnableDnsSupport"   : "true",
        "EnableDnsHostnames" : "false",
        "Tags"               : [ { "Key": "Name", "Value": "SimplechatVPC" } ]
      }
    },
    "eip": {
      "Type"       : "AWS::EC2::EIP",
      "Properties" : { "Domain" : "vpc" }
    },
    "subnetPub1": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.0.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Public-Subnet-1" } ]
      }
    },
    "subnetPub2": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.1.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Public-Subnet-2" } ]
      }
    },
    "subnetPrv1": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.2.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Private-Subnet-1" } ]
      }
    },
    "subnetPrv2": {
      "Type"       : "AWS::EC2::Subnet",
      "Properties" : {
        "CidrBlock"        : "10.0.3.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Private-Subnet-2" } ]
      }
    },
    "Nat": {
      "Type"       : "AWS::EC2::NatGateway",
      "Properties" : {
        "AllocationId"     : { "Fn::GetAtt" : ["eip", "AllocationId"] },
        "SubnetId"         : { "Ref" : "subnetPub1" }
      },
      "DependsOn"  : "eip"
    },
    "IGW": {
      "Type"       : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags"             : [ { "Key": "Name", "Value": "Simplechat-IG" } ]
      }
    },
    "RouteTablePublic": {
      "Type"           : "AWS::EC2::RouteTable",
      "Properties"     : {
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Public-RT" } ]
      }
    },
    "RouteTablePrivate": {
      "Type"           : "AWS::EC2::RouteTable",
      "Properties"     : {
        "VpcId"            : { "Ref": "VPC" },
        "Tags"             : [ { "Key": "Name", "Value": "Private-RT" } ]
      }
    },
    "gw": {
      "Type"           : "AWS::EC2::VPCGatewayAttachment",
      "Properties"     : {
        "VpcId"             : { "Ref": "VPC" },
        "InternetGatewayId" : { "Ref": "IGW" }
      }
    },
    "subnetRoutePub1": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePublic" },
        "SubnetId"         : { "Ref": "subnetPub1" }
      }
    },
    "subnetRoutePub2": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePublic" },
        "SubnetId"         : { "Ref": "subnetPub2" }
      }
    },
    "subnetRoutePrv1": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePrivate" },
        "SubnetId"         : { "Ref": "subnetPrv1" }
      }
    },
    "subnetRoutePrv2": {
      "Type"           : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties"     : {
        "RouteTableId"     : { "Ref": "RouteTablePrivate" },
        "SubnetId"         : { "Ref": "subnetPrv2" }
      }
    },
    "routePublic": {
      "Type"           : "AWS::EC2::Route",
      "Properties"     : {
        "DestinationCidrBlock"  : "0.0.0.0/0",
        "RouteTableId"          : { "Ref": "RouteTablePublic" },
        "GatewayId"             : { "Ref": "IGW" }
      },
      "DependsOn"      : "gw"
    },
    "routePrivate": {
      "Type"           : "AWS::EC2::Route",
      "Properties"     : {
        "DestinationCidrBlock"  : "0.0.0.0/0",
        "RouteTableId"          : { "Ref": "RouteTablePrivate" },
        "NatGatewayId"          : { "Ref" : "Nat" }
      },
      "DependsOn"      : [ "Nat" , "subnetRoutePrv1", "subnetRoutePrv2" ]
    },
    "LoadBalancerSecurityGroup": {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription": "simplechat_lb_sg",
        "GroupName" : "simplechat_lb_sg",
        "VpcId": { "Ref" : "VPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : "80",
            "ToPort" : "80",
            "CidrIp" : "0.0.0.0/0" }
        ]
      }
    },
    "WebServerSecurityGroup": {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription": "simplechat_web_sg",
        "GroupName" : "simplechat_web_sg",
        "VpcId": { "Ref" : "VPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : "80",
            "ToPort" : "80",
            "SourceSecurityGroupId" : { "Ref" : "LoadBalancerSecurityGroup" } }
        ]
      }
    },
    "RDSSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "simplechat_db_sg",
        "GroupName" : "simplechat_db_sg",
        "VpcId" : { "Ref" : "VPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp",
            "FromPort" : "3306",
            "ToPort" : "3306",
            "SourceSecurityGroupId" : { "Ref" : "WebServerSecurityGroup" } }
        ]
      }
    },
    "DbSubnetGroup": {
      "Type": "AWS::RDS::DBSubnetGroup",
      "Properties": {
        "DBSubnetGroupName": "simplechat_db_subnet",
        "DBSubnetGroupDescription": "simplechat_db_subnet",
        "SubnetIds": [ {"Ref": "subnetPrv1"}, {"Ref": "subnetPrv2"} ]
      }
    },
    "DBParameterGroup": {
      "Type": "AWS::RDS::DBParameterGroup",
      "Properties": {
        "Description": "simplechat parameter group",
        "Family": "mysql5.7",
        "Parameters": {
          "character_set_client": "utf8mb4",
          "character_set_connection": "utf8mb4",
          "character_set_database": "utf8mb4",
          "character_set_results": "utf8mb4",
          "character_set_server": "utf8mb4",
          "collation_connection": "utf8mb4_bin",
          "collation_server": "utf8mb4_bin"
        }
      }
    },
    "DbInstance": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "DBInstanceIdentifier": "simplechat-ecs-db",
        "Engine": "MySQL",
        "EngineVersion": "5.7.22",
        "AllocatedStorage": "5",
        "MasterUsername": { "Ref": "MasterUserName" },
        "MasterUserPassword": { "Ref": "MasterUserPassword" },
        "DBInstanceClass": "db.t2.micro",
        "DBSubnetGroupName": { "Ref": "DbSubnetGroup" },
        "DBParameterGroupName": { "Ref": "DBParameterGroup" },
        "VPCSecurityGroups": [ { "Ref": "RDSSecurityGroup"} ]
      }
    },
    "ALB" : {
      "Type" : "AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties" : {
        "LoadBalancerAttributes" : [
          { "Key" : "access_logs.s3.enabled", "Value" : "false" },
          { "Key" : "deletion_protection.enabled", "Value" : "false" },
          { "Key" : "idle_timeout.timeout_seconds", "Value" : "60" }
        ],
        "Name" : "simplechat-alb",
        "Scheme" : "internet-facing",
        "SecurityGroups" : [
          { "Ref": "LoadBalancerSecurityGroup" }
        ],
        "Subnets" : [ {"Ref": "subnetPub1"}, {"Ref": "subnetPub2"} ],
        "Tags" : [
          {"Key": "Name", "Value": "simplechat-alb" }
        ]
      }
    },
    "Cloud9Env": {
      "Type": "AWS::Cloud9::EnvironmentEC2",
      "Properties": {
        "Name": "simplechat_cloud9_env",
        "Description": "simplechat_cloud9_env",
        "AutomaticStopTimeMinutes": "1440",
        "InstanceType": "t2.micro",
        "SubnetId": { "Ref": "subnetPub1" }
      }
    }
  }
}

2.Dockerイメージを登録する


2-1.Amazon ECR にリポジトリを作成する

適当なリポジトリ名で、リポジトリを作成する。(設定はデフォルト)

2-2.Amazon ECR にDockerイメージを登録する

【「1.CloudFormation で環境を準備する#」】で、cloud9でsimplechat_cloud9_env が作成されているので、「Open IDE」を選択し、次のとおりappを展開する。

wget https://ecs-for-aws-summit-online.workshop.aws/simplechat_app.tar.gz

tar zxvf simplechat_app.tar.gz

cd simplechat_ecs_app/

Amazon ECRから「プッシュコマンドの表示」をクリックし、後は手順どおり、ログイン→ビルド→タグ付け→プッシュする。

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin .dkr.ecr.us-east-1.amazonaws.com

docker build -t simplechat .

docker tag simplechat:latest .dkr.ecr.us-east-1.amazonaws.com/simplechat:latest

docker push .dkr.ecr.us-east-1.amazonaws.com/simplechat:latest

3.Dockerコンテナの作成

3-1.クラスターの作成

「AWS Fargate」を指定。(他の設定はデフォルト)

3-2.タスク定義

次のとおり入力していく。
キャプチャ100.PNG

イメージは先程作成したAmazon ECRのリポジトリのURIを指定する。ポートマッピングは80にする。
キャプチャ200.PNG

環境変数を設定する。

キー バリュー
DB_HOST RDSインスタンスのURI
DB_USER 【1.CloudFormation で環境を準備する】で指定したもの
DB_PASS 【1.CloudFormation で環境を準備する】で指定したもの

キャプチャ300.PNG

3-3.サービス

次の通り入力する。
スクリーンショット 2020-09-17 20.08.50.png

デプロイメントはローリングアップデート
スクリーンショット 2020-09-17 20.09.31.png

次の通りVPCやALBを指定する。
スクリーンショット 2020-09-17 20.13.03.png
スクリーンショット 2020-09-17 20.14.18.png
スクリーンショット 2020-09-17 20.15.13.png

今回AutoScallingは特に設定しない。
スクリーンショット 2020-09-17 20.16.56.png

「RUNNING」になったらOKです。
スクリーンショット 2020-09-17 20.21.06.png

4.アプリケーションの確認と修正

ALBのDNS名にアクセスして、アプリケーションを色々触ってみる。

そのあと、Cloud9を開き、アプリケーションの適当な箇所を修正し、「File」から「Save」。その内容が反映されるか確認する。

【2-2.Amazon ECR にDockerイメージを登録する】の手順と同様にログイン→ビルド→タグ付け→プッシュする。
※実際はAmazon ECRのリポジトリにおいて「タグのイミュータビリティ」を「有効にする」に設定し、イメージ更新毎に一意のタグを付けるようにする。
※「タグのイミュータビリティ」→ 有効にすると同じタグを上書きができなくなる。

今回は、ECSのサービスで「新しいデプロイの強制」のチェックボックスをオンにだけ変更し、更新する。
スクリーンショット 2020-09-17 20.36.25.png

タスクは2つになるはずですがしばらくすると、1つになります。(ローリングアップデート)

最後にalbのDNSにアクセスし、変更が反映されたか確認する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS SAA合格体験記

AWSの合格体験記
 たくさんありますよね。
何番煎じかわかりませんが、
 これから受ける人の役に立てれば
  いいと思っています。


AWS SAAとは

  • AWS Solutions Architect -Associateの略
  • 主にAWSを構築する人向け
  • 運用者向けはSysOpsAdministrator
  • 開発者向けはDeveloper

こんな感じのすみ分け
image.png


なぜSAAを取ろうと思った

  • AWSの知識をちゃんと身に着けたい
  • EC2やS3,VPCといった基本的なサービスを学ぶので、範囲も広く体系的に学べそう
  • 内外的にAWSを知っている人という保証が欲しかった

勉強期間

  • 3ヶ月強ぐらい(結構長い)
  • 平日の毎朝毎晩と土曜日(日曜日は休みたかった)

勉強方法

次のudemyの教材を中心に勉強
書籍は参考書として活用


使った教材

udemy

  • これだけでOK! AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座(SAA-C02試験対応版)
  • 【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問)

問題に関しては3回ぐらい解いて90%ぐらいまで正答率を上げた

書籍

※2018年に試験がupdateしているので古すぎるものは注意


感想(勉強)

  • AWSの知識はもちろんインフラそのものの知識がなかったのでそこから学べた
  • udemyのハンズオンを行ったので実際の経験としても身についた(NATゲートウェイを削除し忘れて高額な請求が来たことも思い出)
  • とって終わりではなく、活かしていかないともったいない(本当にそう)

感想(試験)

  • 個々のサービスは分かっていてもまず、問題文で何を求められているか理解するのに時間がかかった
  • udemyの問題集ほど細かいところは聞かれなかった印象
  • 受験料15,000円はちょっと高い
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS QuickSight ~ demo

2つのCSVファイルをjoinする

エディションは「Enterprise」を利用してください。
tempsnip1.png

必要項目を入力します。”Enable autodiscovery of…”にチェックすることを忘れない。
tempsnip2.png

「ファイルのアップロード」から、CSVファイルをSPICE領域にアップロードする。
tempsnip3.png

特定の列を基準にJOINするため、「データを追加」よりもう一つのcsvファイルをアップロードする。
tempsnip4.png

2つの円のようなアイコンを選択し、JOINする列を指定し、結合タイプはInnerを指定する。
※InnerはONで指定した条件が、結合する両方のテーブルにマッチするレコードのみを返します。
tempsnip5.png

これで2つのCSVファイルが、結合されました。

データタイプを変更する

自動的にInt(整数)型で認識されているものを、String型(文字列)に変更する。
tempsnip6.png

視覚化

「保存して視覚化」後、SPICEに取り込んだデータを可視化していきます。
左からフィールドをDrag & Dropすることでそのフィールドのデータをもとに可視化が行われます。
キャプチャ7.PNG

ML(機械学習)インサイトの機能

与えられたデータから予測値をだすことができます。「予測を追加」から行えます。
tempsnip8.png

結果は次のとおり。
キャプチャ9.PNG

ドリルダウン

X軸に3つの項目(A B C)、Y軸に1つの合計の値があったとします。
「ドリルダウン」を利用すると、AのBの値というように視覚化することが可能になります。
スクリーンショット 2020-09-12 17.38.49.png

コントロールとフィルタ

フィルタするためのコントロールを作成し、その作成したコントロールでフィルタを作成していきます。
例えば●月●日〜●月●日までの合計や平均とか。

「パラメータ」は次の通り作成していく。
スクリーンショット 2020-09-12 17.52.38.png

作成すると、続いてパラメータの接続先を選択するダイアログが出るので、「コントロール」を選択します。
スクリーンショット 2020-09-12 17.57.03.png

次の通り開始日のコントロールを追加。
スクリーンショット 2020-09-12 17.58.47.png

同じ要領で終了日のコントロールも追加。
スクリーンショット 2020-09-12 18.04.26.png

これで開始日と終了日のコントロールが作成できたので、「フイルタ」を次の条件で作成していく。
スクリーンショット 2020-09-12 18.08.48.png

後は好きにフイルタの日付を変更して、グラフが変わるか確認して見るだけ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSの関連記事まとめ

自分用のまとめです。


構築


最適化


セキュリティ


コスト削減


バックアップ


便利ツール


HowTo


CI/CD

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS] マネジメントコンソールのLambdaの管理画面からStep Functionsのワークフローを確認できるようになりました

Launch

9/17に、「AWS Lambda adds console support for visualizing AWS Step Functions workflows」ということで、LambdaのコンソールでStep Functionsのワークフローのビジュアライズ機能がLaunchされました。

Lambdaの管理画面

メニュー蘭に「Step Functions state machines」の項目があります。
lambda1.png

Step Functions state machinesのメニューを選択すると、上部にStep Functionsの使い所のようなものが説明されていて、その下にState machineの一覧があります。
今回は、「[AWS] Step Functionsで遊んでみる(SAM + Lambda) Part.3(分岐編)」のものをDeoloyしてあります。
lambda2.png

State machineのリンクを選択すると、そのステートマシンのいつものグラフが表示されます。
lambda.png

そして、その下に、ステートマシンから呼び出しているLambdaが一覧表示されます。
今回はシンプルな例なので1つしかないですが、このステートマシンで使用しているLambdaと、どのStepで使用しているかが一目でわかるようになりました。
lambda4.png

まとめ

これまで、Step Functionsの管理画面から、ARNを確認しながら追う必要がありましたが、その必要がなくなりました。
ステートマシンで複数のLambda関数を呼び出しているケースでは、Lambda間の相関がわかりやすくなったのではないでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】CloudFrontのBehaviorsを使った分岐でハマったところ

とりあえずメモレベルで残す

装飾とかまとめはまた別途書きます。

やりたかったこと

Route53に登録したホストゾーンのドメインに対して、URLから判定してS3かAPIGatewayに飛ばす

  • Default (*)の場合はS3(Staticページ)に飛ばす
  • /api/*の場合はAPIGatewayに飛ばす

ハマったところ

  • APIGatewayのStageがdevを設定
  • CloudFrontのOriginsに設定したAPIGatewayの設定のOrigin Path/devを設定
  • CloudFrontBehaviorsPath Patternには/api/*されていた
  • <cloud front path>/api/*でAPI叩いたら"message": "Missing Authentication Token"が返ってきた

原因

  • 上記の設定だと、APIGatewayの/api/dev/Stageにアクセスしようとするため、リソースがないと言われる
    • CloudFrontのBehaviorsPath Patternに設定する値と、APIGatewayのStageが一致している必要がある
    • CloudFrontのOriginsに設定したAPIGatewayの設定のOrigin Pathの値は設定しない

対応

  • APIGatewayのStageにapiを追加
  • CloudFrontのBehaviorsPath Pattern/api/*を設定
  • CloudFrontのOriginsOrigin Pathの設定値はなし

参照ページ

“Missing Authentication Token” — CloudFront/APIG Troubleshooting

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Route53 親ドメインを移行しないでEC2にサブドメイン設定

やりたいこと

一つドメインを持ってるのですが、それは別なサイトに使ってるので、サブドメインでやりたいなーとおもった

前提

EIPと紐付いているEC2がある
EC2はnginx導入済み

下記記事の続き
https://qiita.com/ntm718/items/f896c8e4fb801777954b

ドメイン取得済み
ちなみにお名前ドットコム(DNS設定するだけなのでどこでも良いですが)

1.サブドメインのRoute 53ホストゾーンを作成します。

ホストゾーンの作成を選択

注意
ホストゾーン1つにつき、0.50 USD/月発生します(50円ほど)

スクリーンショット 2020-09-16 0.48.31.png

ドメイン名につけたいサブドメインを含むドメイン名を入力
test部分がサブドメイン
パブリックホストゾーンのまま、作成

スクリーンショット 2020-09-16 1.09.28.png

作成するとネームサーバーが振られます
このNS値を、現在の親ドメインのDNSレコードに追加します

スクリーンショット 2020-09-17 23.56.25.png

DNS設定

登録している親ドメインのDNS設定できるページに行きます
自分の場合、お名前ドットコムなので下記のような画面です

スクリーンショット 2020-09-18 0.01.17.png

そして、レコードに
- サブドメイン
- Type: NS
- TTL: 900 (キャッシュ時間なので増やしても良い)

で入力し、
VALUEに、Route53の手順で作成された、タイプNSnsから始まる値を入力します
NSは4レコードなのでVALUEだけ4レコードを追加します

スクリーンショット 2020-09-18 0.02.29.png

スクリーンショット 2020-09-18 0.10.23.png

お名前ドットコムの場合DNSレコード設定用ネームサーバー変更確認を選択せず、設定まで行き完了です

EC2と紐付け

AWS Route53の作成したホストゾーンにレコードを追加します
レコード作成を選択

スクリーンショット 2020-09-18 0.32.20.png

シンプルルーティングで次へ

スクリーンショット 2020-09-16 2.27.39.png

シンプルなレコードを定義を選択し、
- レコード名: 空欄
- 値/トラフィックのルーティング先: レコードタイプに応じた~~
- 値: EIPのパブリックIPv4
- レコードタイプ: A

スクリーンショット 2020-09-16 2.30.32.png

作成後、サブドメインホストゾーンに戻り、レコードをテストするを選択

スクリーンショット 2020-09-18 0.32.20.png

レスポンス取得を押し、EIPのパブリックIPが返却されたらOK

スクリーンショット 2020-09-18 0.41.07.png

nginx設定

server_nameの設定する

EC2にssh接続し

sudo vi /etc/nginx/nginx.conf

server_nameの箇所を、サブドメイン含むドメインを入力

再起動して、反映させる

sudo systemctl restart nginx

確認

ブラウザでドメイン入力、表示されたら成功
https ではなく http で確認しましょう(SSLがまだの場合)

感想

netlifyでブログをサブドメインで運用しており、そのときにドメインのDNSを移しているのに気づかずハマり、SSLしてないからhttpなのに、httpsにして少し溶かしてしまいましたが、簡単な構成だと楽にできますね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む