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

オリジナルアプリ【BIKKE!!】README

本記事について オリジナルアプリ【BIKKE!!】がようやくRails+Puma+Docker+AWS(ECR,ECS.EC2,RDS,S3,Route53,VPC)でデプロイが完了しました。 そこで私のアプリの全貌を記載したREADMEを公開させていただきます。 アプリ名 BIKKE!! 概要 「ライダーにしか分からないことがある。」がコンセプトです。 乗ったことのあるバイク、所有するバイクのレビューを共有することができます。 また、レビューを今後のバイク選びの参考とすることができます。 バイク探しをしたい人、自分のバイクを共有したい人、バイクメーカーで働く人などバイクに携わる全ての人に価値を提供します。 本番環境 URL 非公開 ログイン情報 ゲストログイン機能を設けています。 トップページのヘッダーより、ワンクリックでゲストユーザーとしてログインが可能です。 ゲストユーザーは、レビューの投稿、検索、コメント、お気に入り登録といった機能が実行できます。 ※アカウント情報の編集・削除機能は実行できません。 制作背景 私自身ライダーであり、バイクが大好きです。 バイクの乗り換え、新規バイクの購入を検討する際、インターネットで検索しても、結果はバイクのスペックなどあくまでもカタログ上の数値であったり、 メディアが共有する専門的なインプレッション記事などがほとんです。 私はそこに課題を感じました。 なぜなら、バイクの良さとは乗ってみないと分からないことが多々あると考えているからです。 「ライダーにしか分からないことがある。」バイクの良さも悪さも、全てがバイク探しの重要なリソースです。 そんなバイク探しの指南となるアプリケーションを作成したいと考えたことが、本アプリケーションの制作背景となります。 DEMO トップページ(検索機能・レビュー一覧表示・ログイン機能) ・トップの写真には、ロード時に文字が浮き上がるようなアニメーションを付与しました。 ・ログイン画面もありますが、トップページからもログインができるようフォームを設置しています。 ・トップ中央に検索機能のコンポーネントがあります。 ・トップ下部にレビュー一覧が、スクロールによりふわっと浮き上がるアニメーションで表示されます。 ・レビューの一覧表示はページネーション機能を用いてコンパクトにまとめました。 また、ページネーションはBootstrapを用いてより見やすく、かつAjax通信により素早くページ切り替えが可能です。 新規登録画面 ・トップページヘッダーより遷移します。 ・必要な情報は「メールアドレス」「パスワード」「ニックネーム」のみとシンプルに仕上げました。 ・エラーメッセージは日本語化しております。 ・パスワードには正規表現のバリデーションを設け、セキュアにエラーメッセージを返します。 ・登録が完了すると、フラッシュメッセージでユーザーに登録が完了したことをアナウンスします。 ・ヘッダーにニックネームが表示されるようになります。 ログイン画面/ログアウト ・トップページヘッダーの「Log out」ボタンよりワンクリックでログアウトが可能です。 また、フラッシュメッセージでユーザーにログアウトが完了したことをアナウンスします。 ・トップページヘッダーの「Sign in」ボタンよりログイン画面に遷移します。 ・ログインに必要な情報は「メールアドレス」と「パスワード」のみです。 ・エラーメッセージは日本語化しています。 ・ログインに成功すると、トップページにリダイレクトされ、フラッシュメッセージでユーザーにログインが成功したことをアナウンスします。 ・トップページのヘッダーにニックネームが追加されます。 ・トップページ写真部分にあるログインフォームからも、ログインが可能です。 マイページ画面(ユーザーページ画面)・アカウント情報編集機能 ・トップページヘッダーに表示された、ニックネームをクリックし遷移します。 ・マイページ画面には、そのユーザーが投稿したレビューやお気に入りしたレビューを一覧で閲覧することができます。 ・表示されるレビュー一覧は、アニメーションで表示されます。 ・マイページ画面に遷移したユーザーが本人である場合、アカウント情報編集ボタンが表示されます。 ・マイページに遷移したユーザーが本人である場合、アカウント情報の編集が可能です。 ・メールアドレスやパスワード、ニックネームの変更が可能です。 ・変更を行わない項目は空白にすることで、そのまま保存されます。 ※ゲストユーザーはアカウント情報の編集は不可能です。 レビュー投稿画面 ・トップページヘッダーにあります「Post」ボタンからワンクリックでレビュー投稿画面に遷移します。 ・レビューの入力項目は写真、車種名、年式、排気量、メーカー、車種タイプ、乗り心地、燃費、メンテナンス性、維持費、速度、見た目の満足度、総合評価、レビューテキスト、で構成されています。 ・写真は任意項目で、そのほかは入力必須項目となります。 ・写真は1枚のみ投稿可能で、プレビュー表示されます。 ・車種名、レビューテキストは自由入力、年式は半角4桁入力、排気量、メーカー、車種タイプはActiveHashによるカテゴリー選択、 燃費、メンテナンス性、維持費、速度、見た目の満足度、総合評価はjQueryによる星評価でレビューを投稿します。 ・「投稿する」ボタン押下により、トップページにリダイレクトされ、フラッシュメッセージの案内とともに投稿が完了したことをお知らせします。 ・レビュー一覧に追加で表示されます。 ・一覧表示時に表示される項目は、写真、車種名、総合評価のみです。 レビュー詳細画面(お気に入り機能・コメント機能) ・一覧表示されたレビューからワンクリックでレビュー詳細画面に遷移します。 ・これは「マイページ(ユーザーページ)に表示されるレビュー一覧」、「検索結果として表示されるレビュー一覧」からも同様に、気になるレビューをワンクリックすることで詳細画面に遷移します。 ・詳細画面では、レビュー投稿で入力した全ての項目が表示されます。 ・ユーザーはあらゆる側面から気になるバイクのレビューを確認することができます。 ・レビュー詳細画面が投稿した本人のレビューである場合、「編集」ボタンと「削除」ボタンが表示されます。 ・レビューが投稿した本人のレビューではない場合、「お気に入り」登録ボタンが表示されます。 ・Ajax通信により、ワンクリックで即お気に入りに登録されます。 ・お気に入りしたレビューはマイページから一覧で管理することができます。 ・また、お気に入りの解除もワンクリックで可能です。 ・詳細画面ではコメントを投稿することが可能です。 ・レビュー投稿者に追加で質問がある場合などに便利です。 ・コメント投稿後、フラッシュメッセージで投稿が完了したことをお知らせし、詳細画面にリダイレクトします。 ・コメントは、投稿者、コメント内容、投稿時間で構成され、コメント投稿したユーザー本人である場合、コメント削除ボタンが表示されます。 レビュー編集画面・レビュー削除機能 ・レビュー詳細画面から、「編集」ボタンを押下し、編集画面に遷移します。 ・編集画面は投稿したユーザー本人のみが遷移可能です。URLを直接打ち込んでも他のユーザーは遷移できません。 ・編集画面は投稿した内容を全て保持しています。 ・ActiveHashによるカテゴリーの再選択、jQueryによる星評価の再評価も簡単に行うことができます。 ・詳細画面より「削除」ボタンを押下することで、レビューの削除が可能です。 ・アラートメッセージにより、本当に削除するか確認します。 ・確認時に「OK」ボタンを押下することにより、フラッシュメッセージが削除完了をお知らせします。 検索結果画面 ・トップページに全ての検索機能を設けています。 ・キーワード検索では、該当する車種名に一部分でも文字が含まれている場合、結果を返します。 ・検索結果に表示されるレビューはアニメーションにより、ふわっと表示されます。 ・排気量、メーカー、車種タイプはカテゴリーに該当するものをワンクリックで一覧表示させます。 ・排気量、メーカー、車種タイプ3つの項目を元に絞り込み検索も可能です。 ・必要ない項目は「指定なし」の状態で検索から省くことが可能です。 工夫したポイント 常にユーザー視点に立ち、ユーザーが「使いやすい、楽しい」と思えるようなUI/UXを意識して制作しました。 具体的なポイントとして、 ・初めてこのアプリを見ても、直感的に使用方法が理解できる。 ・アニメーションを用いて、視覚的な楽しみを作る。 ・なるべく画面遷移を少なく、ワンクリックで目的地に辿り着けるルーティング作成 ・jQueryやAjax通信により素早いレスポンスを与え、ストレスレスな操作感 などが工夫したポイントです。 苦労したポイント とにかくデプロイの一言につきます。 本アプリはDockerで開発したコンテナを、ECRにプッシュし、ECS(EC2)+VPC+RDS+S3でデプロイしたものに、Freenom+Route53でドメインを設定し本番運用しています。 過去にDockerを用いていないRailsをEC2にてデプロイをしたことがありますが、Dockerをデプロイすることは私にとって非常にハイレベルなものでした。 ネットワーク周りのエラー、接続されてもローカルでは出なかったRailsエラーにも悩まされました。 まずはDockerを再度基本から学び直し、そしてAWSでどのようにデプロイしたものが外部アクセスできるのか、学習に励み、その結果デプロイすることができました。 この経験は私の中でも非常に自信につながるものであり、引き続き学習に努め、より自分のものへと吸収していきたいと考えています。 使用技術(開発環境) サーバーサイド:Ruby on Rails フロントサイド:HTML, CSS, JavaScript, jQuery, Bootstrap テスト:RSpec インフラ:Docker, AWS(ECR+ECS+EC2+S3+VPC+S3+Route53), Freenom エディタ:VScode 課題・今後実現したい機能 レスポンシブデザイン化 現時点ではブラウザでのみしか表示が適応しておらず、スマホやタブレットサイズでも快適にアプリが使用できるレスポンシブデザイン化は必須と考えます。 具体的にはCSSにメディアクエリを用いて実装予定です。 アカウント削除機能 退会する機能が未実装であります。退会するまでのフローチャートをシンプルにして実装予定です。ただし、この機能はワンクリックでアカウントが削除されないように注意すべき点であると考えます。 検索機能の充実化 現在検索機能はトップページに集約されています。今後は検索結果ページにも検索機能を追加実装する予定です。 理由は、ユーザーが一度検索を行い、欲しい情報が得られなかった場合、少し範囲を広げて検索する行動が予測され、都度トップページに戻るのは煩わしいと考えるからです。 CI/CDパイプライン作成、デプロイの自動化 現在は下記の流れで手動デプロイを行っております。 ①ECRにイメージをプッシュ ②ECS・EC2インスタンスにSSH接続し、コンテナを再起動 特に手間があるわけでもなく、またローカルで動作をしっかり吟味した上でデプロイを行いたいので、性に合ってはいるのですが、今後はエンジニアで働くことをイメージして、CI/CDパイプラインによりgitからの自動デプロイが出来たらと考えています。 DB設計 ER図 usersテーブル Column Type Options email string null: false, unique: true encrypted_password string null: false nickname string null: false Association has_many :reviews has_many :comments has_many :likes reviewsテーブル Column Type Options bike string null: false year integer null: false displacement_id integer null: false maker_id integer null: false type_id integer null: false recommend float null: false comfort float null: false fuel float null: false maintenance float null: false cost float null: false speed float null: false look float null: false content text null: false user references null: false, foreign_key: true Association belongs_to :user has_many :comments has_many :likes commentsテーブル Column Type Options text text null: false user references null: false, foreign_key: true review references null: false, foreign_key: true Association belongs_to :user belongs_to :review likesテーブル Column Type Options user references null: false, foreign_key: true review references null: false, foreign_key: true Association belongs_to :user belongs_to :review
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

新卒エンジニア研修【2ヶ月間でやったこと】

ベストベンチャー100に選ばれている企業に勤めております。 新卒研修の振り返りで2ヶ月間(4~5月)でやったことを残します。 4月第1週 総合職研修 - PDCA - タスク管理 - ビジネスマナー 4月第2週 開発手法 スクラム開発 1スプリントを繰り返す開発手法 1スプリントは、スプリントプランニング、デイリースクラム、スプリントレトロスペクティブ、スプリントレビュー クラウドネイティヴ クラウド技術を最大限活かそうという考え方 開発スピードの向上、属人化を防ぐ、品質向上などの利点がある 開発ステージについて ローカル開発環境 テスト環境(プログラムが動くかどうかの確認) ステージング環境(本番環境の検証のための環境) 本番環境 Laravel環境構築 Docker for M1 Mac、Workbenchのインストール PHP基本構文、DB、 4月第3週 [チーム・個人]におけるKPI(key performance indicator)について 目標を達成するために必要なアクティビティ べロシティ →ストーリーポイント(タスクの難易度)をどれくらいこなしたか デプロイ回数 →お客さんにどれだけデリバリーできたか サーバー応答速度 → ブラウザの速度 工数・工期予実達成率 開発フローについて テスト設計 テストケース作成 単体テスト 結合テスト 総合テスト UAT (User Acceptance Testの略) 目標設定 基本的には上長がこの1年間で期待していることを目標に定めた。 サービス全体像の理解やサービスアーキテクチャの理解、他部門からの依頼処理など ソフトウェアのテスト技法 の輪行開始 テストファーストな考え方を知る。 バグが出て修正する時間の方が勿体無い。 良いコードとは。 可読性 保守・運用のしやすさ 昔は少ないコード、処理速度に重点を置いていた(CPUやメモリの関係) - ブラックボックステスト(要件定義署や仕様書に合っているか確認するテスト手法) 同値クラステスト 境界値テスト -ディシジョンテーブルテスト ペア構成テスト 状態遷移テスト ドメイン分析テスト ホワイトボックステスト(パスや処理の流れなどプログラム内部に沿ったテスト手法) 制御フローテスト データフローテスト テストの終了条件 テストログ、テスト不具合レポート エビデンス、ログを示す、再現手順がしっかりと書かれているかが大事。 xdebugを入れてPHPUnitを実行 正直、テストに関しては実際に作成&実践してみないと実感がわかない。 Dockerコマンド docker-compose build docker-compose up docker-compose down docker-compose exec アプリ名 シェル Laravel ディレクトリ構造 MVCモデル artisan コマンド 4月第4週 CI/CDについて CI(各開発者の作業結果を自動的に統合、単体テストや結合テストの自動化) CD(開発物を素早くユーザに供給する) AWSについて ELB ECS Lambda Cloudwatch S3 DynamoDB ECR Fargate Athena QuickSight GAS(Google Apps Script)環境構築 Golang デバッグ環境構築 5月第1週 Google チャットbot開発。新規入会者数を決まった時間に通知する。 使用した技術 Golang, CloudWatch、Lambda、APIGateway、DynamoDB  所感 静的言語型付け言語を初めて触った。構造体やポインタの概念など改めて勉強になった。Golangの醍醐味である並列処理などは行っていないので、暇があったらやってみたい。 5月第2週 記念日Slack通知bot開発 スプレッドシートから記念日を取得し、Slackに通知する。 要件定義から、運用計画、デモまで行った。 使用した技術 - GAS、SlackAPI 所感 開発したBotが初めて動いた時(エンジニアの誕生日を祝った)はとても嬉しかった。今後も社内で運用していくので、より良いサービスに改築していきたい。 5月第3週~4週 Github活動見える化 リポジトリ情報(プルリクやレビュー情報など)を大量に取得し、Amazon QuickSightでデータの可視化を行う。 使用した技術 - Golang、ECS、ECR、Fargate、athena、QuickSight、Github API 所感 チームや個人の貢献度を測るための指標づくりの一環として開発を行った。ビッグデータ の取得やBIツールを使った分析方法を学べたのはよかった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sec3 【VPC】ネットワークを構築しよう

ハンヅオンで進めているUdemyの教材内容をまとめておきます。 Sec3 【VPC】ネットワークを構築しよう 12. AWSのネットワークを学ぼう リージョン AWSの各サービスが提供されている地域のこと、AWSのサービス使用する場合には、まずリージョンを選ぶ必要がある アベイラリティゾーン 複数のデータセンターを束ねたもの、リージョン内にいくつかの独立したアベイラティゾーンがある。例えば、1つのアベイラビリティティゾーンが災害で利用できなくった場合に備え、データセンターを独立させ、いくつかに分割してある。 VPC:Vurtual Private Cloud AWS上に仮想ネットワークを作成できるサービス。 リージョンを選択し、アベイラビリティゾーンに跨って作成する。リージョンに対してVPCを構え、その中をサブネットで分割する。例えば、プライベートサブネットやパブリックサブネットなど、利用目的に合わせて分割する。このようにVPCをサブネットで分割する事を「冗長性を高める」といい、AWSのベストプラクティス。 13, 14ネットワークのIPアドレスを決めよう IPアドレス ネットワーク上の機器を識別する住所。32ビットの整数値。 パブリックIPアドレス インターネットを使用する際のIPアドレス。世界中で一意性を補償する必要がある為、ICANNという団体が管理しており、プロパイダーがその貸し出し窓口を担う(AWSもその一つ)。 プライベートIPアドレス インターネット上で使用されないIPアドレス、規定の範囲内からアドレスから選択する。 15. VPCを作成しよう VPCを設定 サブネットでVPCを分割する ルーティングを設定 16. サブネットを作成しよう VPCだとIPアドレスの範囲が大きから、サブネットで小さくする分割することで扱いやすくする。分割する2つの利点。アベイラリティゾーンを分けて配置する事で、災害などに対して耐障害性が上がる。セキュリティ上の理由で、アクセスを限定する 17. ルーティングの設定 今回の目的 パブリックサブネットからインターネットに接続できる様にする。ゆくゆくはパブリックサブネットにはWebサーバーを設置する。その為にルーティングを設定する。 IPアドレスはインターネットの住所...インターネット上でどこにいるか分かる → では、どのデバイスがどのIPアドレスと結びついているか? = ルーターが管理している。 ルーターがIPアドレスを管理し、ネットワークとネットワークがIPアドレスを通じて接続する(ルーティング)。 VPCに対して、ルートテーブルが紐づいている。 ルートテーブルは、宛先のIPアドレスと次のルーター(AWSではターゲットと言う)という書式で設定。 パブリックサブネットのIPアドレスをルートテーブルに設定する事で、パブリックサブネットをインターネットに接続させる。 そしてそれ以外の宛先は、インターネットゲートウェイ(VPCとインターネットを繋げる仮想のルーター)へ指し示す。こいつも新規で作成する必要がある。 18. ネットワーク設計のポイント これまでハンヅオンで進めてきたインターネット設計に関する注意点の紹介。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS クライアントVPN OpenVPNのvpnux Clientを使って接続する

1. vpnux Client をダウンロードする こちらから最新のソフトをダウンロードします。現時点では vpnux Client Standard Edition 2.3 です。 2. 証明書を作成する 以下を参考にサーバー証明書・サーバー秘密鍵は Certificate Manager にインポートし、クライアント証明書・クライアント秘密鍵はローカルの適当なフォルダにダウンロードします。 3. クライアントVPNエンドポイントを作成する サーバー証明書・クライアント証明書は、いずれも手順2で Certificate Manager にインポートしたものを選択します。 以下のように設定します。 作成後、「関連付け」で、エンドポイント作成時に選択した VPC 内の適当なサブネットを選択します。 関連付けが完了すれば、エンドポイントが使用可能になります。この関連付けが完了するまで、かなり時間がかかります。3 ~ 10 分程度かかると思います。 4. vpnux Client を使ってエンドポイントに接続する 設定ファイルをダウンロードします。 設定ファイルを開き、 remote cvpn-endpoint-xxxxxx.prod.clientvpn.ap-northeast-1.amazonaws.com 443 となっている部分を編集します。cvpn-endpoint-xxxxxx の前に a. を追加します。編集後は以下のようになります。 remote a.cvpn-endpoint-xxxxxx.prod.clientvpn.ap-northeast-1.amazonaws.com 443 a. の部分は任意で問題ありません。この任意の文字列を追加しなければ、以下のエラーにより接続に失敗します。 RESOLVE: Cannot resolve host address: cvpn-endpoint-xxxxxx.prod.clientvpn.ap-northeast-1.amazonaws.com:443 () 原因はドキュメントに記載されています。 Client VPNエンドポイントの設定ファイルには、remote-random-hostnameというパラメータがあります。このパラメーターは、DNSキャッシュを防ぐために、クライアントがDNS名の前にランダムな文字列を付加することを強制します。 次に vpnuxClient.exe を開きます。 プロファイルを選択します。 インポートを選択し、設定ファイルを選択します。 編集を選択します。 「証明書認証(PKI)を使用」にチェックを入れます。証明書・秘密鍵はそれぞれ手順2でダウンロードしたものを選択します。その後、保存を選択します。 プロファイルに今インポートした設定ファイルを選択し、接続をクリックします。 隠れているインジケーター(デスクトップ右下にある ^ のマーク)をクリック → vpnux Client を右クリック → 表示をクリックの順に操作すると、以下の画面がウィンドウが表示され、接続できたことが確認できます。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TerraformでIAM ユーザーに初期パスワードを埋め込む方法

はじめに Terraformで"aws_iam_user"リソース単体では 初期パスワードを設定する項目がないためパスワードも追加してあげようと思い設定しました。 公式リファレンスはこちら 前提条件 今回は以下のバージョンでやってみました。 そこまでバージョン意識しなくても出来そうですが割と新しいものを採用しています。 Terraformバージョン:1.0.0 AWSプロバイダー:provider registry.terraform.io/hashicorp/aws v3.45.0 aws cli:aws-cli/2.1.19 今回の肝は、実行環境にAWS CLIがインストールされている事です。 注意点 実際は"aws_iam_user_login_profile"リソースから初期パスワードを作成できるが 以下の手順の通り私にとっては複雑でした。また鍵作成ができるものがどこかにインストールされていないといけない気がします。 公開鍵作成ツールをダウンロード 鍵作成 作成した鍵をエンコード tfファイルに入れる 公式リファレンスはこちら 参考になったQiitaの記事 何をするのか Terraformの"Provisioner"の"local-exec"を使うパワー系プレーですね。 local-execとは local-execとは、tfリソースを作成した後にコマンドを実行してくれる機能です。 今回の場合だと、aws_iam_userリソースを作った後に、aws iam create-login-profileで作成したリソースにパスワードの埋め込みをしています。 公式リファレンス iam.tf resource "aws_iam_user" "test" { name = var.iam_user_name # ここの部分で指定している provisioner "local-exec" { command = "aws iam create-login-profile --user-name ${aws_iam_user.test.name} --password ${var.password} --profile ${var.profile}" } } variable.tf variable "iam_user_name" {} variable "password" {} variable "profile" {} terraform.tfvars iam_user_name = "Terraform" # この部分で入れたいパスワードを指定する password = "Admin1qaz2wsx" profile = "xxxxxxxxxx" 終わりに 実行環境にAWS CLIが必要ですが、EC2(Amazon Linux)で構築している場合はデフォルトでインストールされているかと思いますし、融通が効くかと思います。 ただし、IAM ロールでiam:CreateProfileが必要だと思いますが。(そもそもIAMユーザー作っている時点でその辺りのロール周りも許可してそうですが、補足です。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ユーザー毎に視聴の可否が異なる動画ファイルをCloudFrontで配信する方法の考察

はじめに AWSインフラ的には「有料会員はすべての動画を見ることができて、なおかつ動画が CDN にキャッシュされているウェブサイトを作る」ことは比較的簡単に実現できる。 具体的には、 CloudFront の署名付き Cookie を用いて、ログイン時に特定パス以下 (例: /private/* ) を閲覧可能にするための署名付きCookieを埋め込み、以降のアクセスで利用する ユーザーがログインした状態の JWT トークンを持ち、リクエスト時にCloudFrontの Lambda@Edge や CloudFunction でJWTトークンを検証する などの方法がある。 一方、例えば「会員登録は無料だが、個々の動画を都度購入する」タイプのシステムを作ろうとすると、「この会員はこの動画を見てよいか?」という部分を判断する必要がある。 ここでは、動画ファイルは CloudFront にキャッシュされ効率的に配信したいが、その一方で、会員別にファイルダウンロードの可否をシステムレベルで判断する実装に関してを考察する。 基本方針 今回のシステム要件として、以下を考える。 配信動画ファイルはLIVEではなく、VOD配信の固定動画ファイルを配信すること メジャーなブラウザ・OSでブラウザ上で動画を閲覧できる動画フォーマットであること (当たり前だが) URLを外部にコピーした場合、そのリンクを踏んでも権限のないユーザーが動画を見ることはできないこと 動画ファイルを CloudFront で極力キャッシュし、オリジン側への負荷を減らすこと ユーザーが抜け道を使って動画ファイルをダウンロードすることは対処しない いわゆる商用の DRM プラットフォームを使っての動画の保護は行わない が、可能な限り対処はしたい TL; DR 暗号化されたHLS形式の動画を配信し、鍵ファイルの配信パスだけを Lambda@Edge でユーザー認証することでシステム全体の負荷を減らし、CDNキャッシュを利用しつつも、許可のある人のみが動画を再生できるウェブサイトを作成できる。 基本的な仕組みが理解できれば、それを実現するための手段はプロジェクトごとにカスタマイズして使うこともできる(ただ1つの方法のみが解決策というわけではない) CloudFront によるアクセス制御の技術比較 CloudFront のアクセス制御には 署名付きCookie や 一時URL (Presigned URL) を使うことが有名であるが、今回の場合には以下のようにうまく使えない。 一方で、Lambda@Edge を使う方法には可能性がある。 署名付き Cookie 以下の理由により、CloudFront の署名付き Cookie を使うことはあきらめた。 CloudFront による署名付きCookie (カスタムポリシー) は便利だが、ポリシーとして 1つのパスしか保持できない 。 なので、/private/* 以下のような指定はできるが、/private/001/* AND /private/002/* みたいな方式は無理 CloudFront による署名付きCookie (パス指定で識別) を使うことはできるが、Cookie であることが問題 最大で4KB程度の容量しかない Cookie で保持できる Key/Value の組がブラウザによって異なる (最小が20以上が保証されているが、50個程度のブラウザもある) さらに、数を再現なく増やしていくとブラウザ独自のアルゴリズムに基づいて、Cookie が削除されることもある (セッションクッキーが消えてログインできなくなることも...) 一時 URL (Presigned URL) これは URL が知られてしまうと、そのURLを使ってダウンロードができてしまう。 なので、URLのコピペに非常に弱いという欠点がある。 有効期限を極力短くすることで暫定的に対処は可能だが、例えば分割ダウンロードをしたい場合や、HLSフォーマットのように動画が分割されたファイルになっている場合は相性が悪い。 Lambda@Edge によるビュワーリクエスト 「ユーザーからのアクセスがあったタイミング」で「このURIをユーザーに開示しても良いか」をLambda@Edge のプログラムによって判断することができる。 特にビューワーリクエストは「CDNに到達する直前」の通信に対して起動し、状況が悪ければ CDN に通信を届かせることなくエラーレスポンスを返すことができる。 言い換えると、CDNにデータがキャッシュされていても、そのキャッシュにアクセスさせないようなガード判定を行うことができる。 また、Lambda@Edge ではかなり柔軟にプログラムを書いて動かせるだけでなく、AWSのリソースにアクセスすることすら可能 である。 そのため、例えばマスターデータを DynamoDB に置いておき、その内容を読み込んで処理を分岐させることも可能になっている。 まとめ この要件を解決するため、動画の保護は Lambda@Edge のビュワーリクエストによって行う ビュワーリクエスト内でユーザー個別のDB (DynamoDB) にアクセスして、認証を行う という方針で実装を考えていく。 ただし、この方法では以下のように 「アクセス集中」「レイテンシー」の問題があることを認識しておかなくてはいけない。 アクセス集中:(何も工夫しないと)アクセスの都度 DynamoDB にアクセスが発生するため大量アクセスがあるとDynamoDBのスロットルが限界を迎えて、ユーザーにコンテンツを提供できない場合があることを考慮する必要がある。 特に動画が分割されたファイル形式 (HLS形式など) の場合、1つの動画を再生する度にアクセスは分割ファイル数分発生することに注意 レイテンシー: CloudFront は全世界対象で、Lambda@Edge のコードは各エッジロケーションにコピーされて実行される。 そのため、Lambda@Edge の実行場所は全世界であり、例えば ap-northeast-1 リージョンのテーブルを1つだけ用意した場合、アメリカからのアクセスでは「アメリカのエッジローケーション⇒日本のDynamoDBへのアクセス」が発生し、CloudFront によるキャッシュが上手く活かされない低速のレスポンスとなることが想定される。 そのため、必要に応じて DynamoDB のテーブルを複数リージョンに用意するなどのレイテンシーを小さく抑える工夫をする必要がある。 配信動画の形式 動画の暗号化強度や DRM の考え方などは以下が参考になった。 また、AWS MediaConvert で 暗号化された HLS 形式の動画ファイル を作成できることが分かった。 これは、先の問題と組み合わせても、非常に都合のいい形式なので、これを採用することとした。 都合がいい理由は以下の通り。 動画ごとに異なる鍵を採用し この鍵の取得リクエストのみ認証をかけるようにする 暗号化HLS形式のファイルは .m3u8 ファイル内に復号化用の鍵へのリンクを保持している HLS形式の動画を再生する場合、複数回のダウンロードは発生するが、鍵へのアクセスは1度のみ に限定されるので、アクセス回数が少なくなり、レイテンシーの影響も小さくなる 例え動画の .ts ファイル (HLS形式で分割された動画の実体) へアクセスできても、鍵がなければ正常に動画を再生できないため、個別の .m3u8 や .ts ファイルをURLベタ打ちでダウンロードされても問題ない 実際はこの部分を署名付きCookieで簡易保護するとなおよい システム構成図 以上を考えて、システム全体の構成をまとめると以下のようになる。 このシステムでは S3 バケット(Video Bucket) は Web Hosting として 公開せず、すべて CloudFront 経由で公開することを想定している。 Application 部分は管理システムであり、ここでは動画のアップロードや鍵・ユーザーの管理、MediaConvertのジョブ生成などを行うことを想定している。 また、この図ではあくまで概念のみを示している。 実際には S3 へのアップロードをイベントトリガーとした Lambda によって MediaConvert によるジョブの実行を開始しても良いし、/keys/* 以下を Lambda@Edge + DynamoDB で処理しているが、このパスだけをオリジンサーバーへと送って、その「鍵を取得する部分のみ、アプリケーションで制御する」としても良い。 そのあたりは個別のプロジェクトにあった形で処理してもらえばよいと思う。 そのため、この構成図を元にしつつ、自分たちのプロジェクトに都合の良いようにパーツを構成していくことができる。 Media Convert の設定 Media Convert ではS3に動画をアップロードしておき、そのパスを指定することで動画形式の変換を行うことができる。 暗号化 HLS 形式に変換するジョブを作るときに悩んだ点についてを以下にメモする。 Media Convert の変換にかかる料金 設定の中に PRO とラベルがあるものがあってそのあたりで「これ使ってどれぐらい料金に差が出るの…?」と思ったが、Media Convert には「Basic階層」と「Professional階層」があり、それぞれで変換にかかる料金が異なる。 しかし、これは歴史的経緯のようなもので「単純なものは安価でできる BASIC が後から追加された」と考えるぐらいで良さそう。 主に「出力動画の解像度」と「Basic/Pro」のどちらを使ったかで料金が決まる。 上記の価格には単位が抜けていて、単位は「毎分」である。 Pro階層 (※暗号化HLSはProの料金になる) で 30FPS / 4K 解像度の動画を出力した場合、1パスでの変換にかかる時間は 0.0136USD/分 となる (※記事執筆の2021年6月12日現在)。 もし、30秒の動画をこの価格帯で変換した場合、その変換にかかる料金は 0.0136 * 0.5 = 0.0068 USD となる。 ジョブにかかった時間でなく、動画の長さに依存する課金体系となっている ことは覚えておくと良いだろう。 より詳細な料金体系を知るには以下が参考になった。 HLS AES暗号化に使う鍵ファイルと設定 HLS で AES 暗号化を選ぶには、Management Console から 出力に Apple の HLS 形式を選び、DRM 暗号化で「暗号化方法: AES128」「キープロバイダーのタイプ: 静的キー」を選ぶ。 その後に「動画を暗号化するためのキー」を「静的キーの値」に入力する。 具体的には、暗号化に使う 128bit (16byte) を 16進数で表記した32文字。 極端な話、00000000000000000000000000000000 でもOK。 「URL」には「鍵が記載されたファイルをダウンロードできるURL」を入力する。 ここに入力したURLは エンコード後の .m3u8 ファイルにそのまま書き出される。 このファイルは 静的キーで入力した値がバイナリ形式で保持された16 bytesのファイル でなければならない。 例えば、バイナリ形式の鍵ファイルは openssl rand 16 > aes128.key で生成可能であり、xxd -p aes128.key で16進数出力を得ることができる。 CloudFront の Lambda@Edge 処理 必要な各種設定 前準備として、アクセス許可を判断する DynamoDB のテーブルを1つ作っておく。 ここでは東京 (ap-northeast-1) リージョンに hls-aes-auth-test テーブルを作って、以下のデータを登録した。 ui がテーブルのハッシュキー、keyname がテーブルのレンジキーである。 その後、CloudFront に /keys/* と * の2つの Behaviors 登録する。 これらのアクセスはすべて S3 Bucket オリジンに流すように設定している。 そして、/keys/* の Behavior に以下の関数による Lambda@Edge を実行するように指定する。 hls-key-auth.py #!/usr/bin/python # -*- coding: utf-8 -*- ''' リクエスト許可があるかを Lambda@Edge のレベルでチェックします。 ''' import boto3 TABLENAME = 'hls-aes-auth-test' HASH_KEY = 'ui' RANGE_KEY = 'keyname' dynamodb = boto3.session.Session( region_name='ap-northeast-1').client('dynamodb') def _error_response() -> dict: return { 'status': '401', 'statusDescription': 'Unauthorized', 'body': 'Authentication Failed', } def _parse_cookie(headers) -> dict: """ Cookie を dict 形式に parse して返します """ if 'cookie' not in headers: return {} cookies = {} cookie_text = headers['cookie'][0]['value'] for _cookie in cookie_text.split(';'): cookie = _cookie.strip() ts = cookie.split('=') if len(ts) < 2: continue cookies[ts[0].lower()] = ts[1] return cookies def _has_item(uid: str, keyname: str): """ Dynamoに閲覧可能情報が保持されているかをチェック """ if (not uid) or (not keyname): return False try: res = dynamodb.get_item( TableName=TABLENAME, Key={ HASH_KEY: {'S': uid}, RANGE_KEY: {'S': keyname} } ) return 'Item' in res except Exception as err: return False def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] headers = request['headers'] # Cookie からログイン中のユーザーIDを取得 cookies = _parse_cookie(headers) uid = cookies.get('uid') # パスからアクセスするキー情報を取得 uri = request['uri'] if not _has_item(uid, uri): return _error_response() return request コードでは、Cookie から uid の項目を取得して、アクセスユーザーを特定する。 その後、/keys/* 以下にアクセスした URI が指定する鍵へのアクセス権限がテーブル上に存在しているかをチェックしている。 仮に権限がない場合は CDN に届かせることなく 401 レスポンスを返す。 動作確認 ここでは、hls.js のサンプルを参考にして以下のような実装を行った。 MediaConvertによる動画は /videos/0001/ 以下に出力している。 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>テスト</title> </head> <body> <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> <h1>テスト動画0001</h1> <video id="video"></video> <script> var video = document.getElementById('video'); var videoSrc = '/videos/0001/underwater.m3u8'; if (Hls.isSupported()) { var hls = new Hls(); hls.loadSource(videoSrc); hls.attachMedia(video); } // HLS.js is not supported on platforms that do not have Media Source // Extensions (MSE) enabled. // // When the browser has built-in HLS support (check using `canPlayType`), // we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video // element through the `src` property. This is using the built-in support // of the plain video element, without using HLS.js. // // Note: it would be more normal to wait on the 'canplay' event below however // on Safari (where you are most likely to find built-in HLS support) the // video.src URL must be on the user-driven white-list before a 'canplay' // event will be emitted; the last video event that can be reliably // listened-for when the URL is not on the white-list is 'loadedmetadata'. else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoSrc; } </script> </body> </html> Cookie の値が全くない状態でこのページにアクセスすると、鍵ファイル (0001.key) のダウンロードに失敗する。結果として、動画は再生できない。 一方、Cookie に uid=example という値を埋め込んで再度アクセスしてみると、今度はちゃんと鍵ファイル /keys/0001.key がダウンロードできるので、正常に動画が再生できる。 また、テーブルには example と /keys/0001.key の組み合わせしかデータが存在しない。 そのため、ほぼ同様だが、鍵ファイルを /keys/0002.key に変換したページを見ようとすると、例え Cookie に uid=example が入っていても鍵ファイルのダウンロードに失敗し、動画を見ることができなくなる。 Lambda@Edge のビュワーリクエストによって失敗した場合、例え CloudFront のエッジロケーションにキャッシュされているコンテンツであってもリクエスト実施者にはキャッシュ内容を返答しない ため、Lambda@Edge が許可しないユーザーに鍵がダウンロードされることはない。 構造上、動画の本体である .m3u8 や .ts ファイルは URL さえ知っていればダウンロードできることはできるが、その実体は暗号化されている。 結果、鍵がないと動画を閲覧することができない。 また、ここでは Cookie を使っているが、Cognito + JWT トークンを使っていればログイン中のユーザーIDが JWTトークンをデコードすることで取得できるため、Cookieではなくこれを利用しても良い。 この周りのユーザー識別技術に何を採用するかはプロダクトの事情で決めるのが良いだろう。 記事のまとめ 最初に提示した要件を以下の通り解消した。 配信動画ファイルはLIVEではなく、VOD配信の固定動画ファイルを配信すること メジャーなブラウザ・OSでブラウザ上で動画を閲覧できる動画フォーマットであること ユーザーが抜け道を使って動画ファイルをダウンロードすることは対処しない いわゆる商用の DRM プラットフォームを使っての動画の保護は行わない が、可能な限り対処はしたい ⇒ 暗号化HLS形式を利用し、固定動画ファイルを配信している。 また、hls.js を使うことでメジャーなブラウザでの動画再生を可能とした (当たり前だが) URLを外部にコピーした場合、そのリンクを踏んでも権限のないユーザーが動画を見ることはできないこと ⇒ 動画のファイルこそ頑張ればダウンロードできるものの、動画に暗号化が施されているため、鍵がないと動画が再生できない 動画ファイルを CloudFront で極力キャッシュし、オリジン側への負荷を減らすこと ⇒ Lambda@Edge のビューワーリクエストタイミングで判断することで、CDNキャッシュの仕組みを利用でき、例え正常なコンテンツがキャッシュされている状態でアクセスがあったとしても、不正なアクセスを弾くことができる ⇒ 鍵のみを認証対象とすることで、動画そのものへのアクセスに認証を行わなくても権限のあるユーザーのみが動画再生を可能とした。 結果として、Lambda@Edge の実行回数が減り、システム認証の負荷・ファイルアクセスのレイテンシーを十分減らしている ちなみに、他の方法としては HLSファイルの .m3u8 ファイルを Lambda@Edge で書き換えて許可のある人にだけ .ts ファイルの一時URLを作成したり 、.m3u8 ファイル内の鍵ファイルのパスを動的に差し替えて鍵を取得してくることで本記事と同じ制限をかける と言った方法もある。 このように、回答は1つではないため、プロジェクトにあった方式を採用するのが良いだろう。 あと、もし可変サイズの動画配信に対応したいのであれば、MediaPackage を挟むことになるとは思うが、鍵配信部分については多分変わらないはずなので、仕組みの流用はきくはずだと思う。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS KMS describe-key --key-id にはエイリアスを指定できる

今までキーIDしか指定できないと思っていた。 aws kms describe-key --key-id 1234abcd-12ab-34cd-56ef-1234567890ab describe-key --key-id [--grant-tokens ] [--cli-input-json ] [--generate-cli-skeleton ] しっかりドキュメントに書いてあった。 For example: Key ID: 1234abcd-12ab-34cd-56ef-1234567890ab Key ARN: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab Alias name: alias/ExampleAlias Alias ARN: arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias --key-id にエイリアスを指定。 aws kms describe-key --key-id alias/mykey 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ピアソンVUEでAWS試験をオンライン受験してみた(事前確認編)

目次 1.はじめに 2.手順 1-はじめに オンライン受験をお勧めしたい理由 AWSの認定資格受験にあたり、キャンペーンが実施されております。 一回受験をしてから感覚を掴み、二回目を本気で受ける作戦ができます。 注意点(抜粋) 以下に、試験を受ける際の注意点や要件についてまとめられています。 個人用のPCで受験することを推奨します。企業のファイアウォール (VPN を含む) のない環境で受験してください。 試験中に第三者が入室してはならないことに注意してください。 使用できるモニターはひとつだけです。 試験中、第三者がウェブカメラに映ることや第三者の声が聞こえてはいけません。 机の上には許可されたアイテム (電卓など) 以外のものをおいてはいけません。 ヘッドホンやヘッドセット(有線または Bluetooth による接続)の使用は、試験認定団体から明示的に許可された場合を除き禁止されています。 その他、以下のシステム要件 項目 内容 OS Windows 10(64 ビット)、macOS High Sierra(10.13)以上 メモリ 4 GB RAM 以上 解像度 1920 x 1080 以上(32 ビット色) ネット回線 安定した回線速度(3 Mbps 上り/下り) 2-手順 ピアソンVUEページアクセス AWSの認定試験ページから、「ピアソンVUE試験の準備」をクリック 自身の受験したい資格をクリック 「自宅または職場のオンライン」をクリック 「システムテスト」をクリック アクセスコードをコピーし、OnVUEをダウンロード OnVUEの展開 OnVUEの実行ファイルを展開し、実行(ダブルクリック) Mac OSXの場合 以下のように、OnVUEからMacOSXへのアクセスを許可する必要がある。 * 入力監視 * カメラ * マイク システムテストの実施 OnVUE起動後、先程コピーしたアクセスコードを入力し、「次へ」 OnVUE上でシステムテストが実行される。全ての項目でチェックが入り問題ないことを確認 「シミュレーションを起動」を選択 アプリケーションを起動している場合、ウィンドウを閉じるように指示がでる。 以降は、キャプチャ機能が制限された中で専用のアプリが起動する。 OnVUEのサンプル試験画面のようなものが起動し、使用上の注意が表示されるので適切な選択を選ぶ。 「You have chosen to end this exam.」のようなメッセージが表示されるので、OnVUEウィンドウを閉じる。 ※機能制限はここまで 以下の画面が表示され、システムテスト完了。 実際の試験の予約 インターネットブラウザを立ち上げ、試験の予約を行う。 3-おわり 実際の試験を受けた際の記録を後日に投稿しようと思います。 ※落ちたら2回目受験の様子も投稿します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS]LambdaからLambdaを呼ぶIAMロール設定とnode.js実装メモ

やりたいこと AWSにてLambda関数を2つ作成する。 1つ目のLambda関数が呼ばれたら、その関数内から2つ目のLambda関数を呼び出す。 1つ目のLambda関数は、2つ目のLambda関数から戻り値が返ってくるまでは終了しない。 Lambda関数用IAMロールとポリシー 下記のIAMロールを作成する。 AWSマネジメントコンソール、IAM設定画面にて、「ロールの作成」を押す。 「AWSサービス」ユースケース「Lambda」を選択し「次のステップ:アクセス権限」を押す。 「ポリシーの作成」を押す。 「JSON」タブを選択し、下記を実装する。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "cloudwatch:*", "logs:*", "lambda:*" ], "Resource": "*" }, { "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*", "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } }, { "Effect": "Allow", "Action": [ "logs:DescribeLogStreams", "logs:GetLogEvents", "logs:FilterLogEvents" ], "Resource": "arn:aws:logs:*:*:log-group:/aws/lambda/*" } ] } 「次のステップ:タグ」を押す。 タグの設定は任意なので、不要ならそのまま「次のステップ:確認」を押す。 任意のポリシー名を記入する。 ここでは下記を入力する。 ポリシー名 LambdaPolicyYamatoSample210612a 説明は空欄のままで問題ない。 「ポリシーの作成」ボタンを押す。 下記の表示にて、ポリシーが作成されたことを確認する。 このポリシー「LambdaPolicyYamatoSample210612a」を、 ロールの作成画面にて割り当てる。 ポリシーのフィルタで「LambdaPolicyYamatoSample210612a」を検索して選択する。 チェックを入れて「次のステップ:タグ」を押す。 タグの追加は任意なので、不要なら「次のステップ:確認」を押す。 任意のロール名で作成する。今回は下記で作成する。ロール名を入力し「ロールの作成」ボタンを押す。 LambdaRoleYamatoSample210612a 下記の表示にて、ロールが作成されたことを確認する。 以上で、ポリシー「LambdaPolicyYamatoSample210612a」が割り当てられたロール「LambdaRoleYamatoSample210612a」が作成された。 このロールをLambda関数に適用する。 Lambda関数の作成 1つ目の関数を作成 AWSマネジメントコンソールのLambda画面にて「関数の作成」を押す。 下記の通り作成する。 「一から作成」を選ぶ。 関数名は任意。今回は yamatoSampleLambdaFunction210612a とする。 ランタイムは Node.js 14.x とする。 アクセス権限は「既存のロールを使用する」を選び、先ほど作成したロール「LambdaRoleYamatoSample210612a」を適用する。 「関数の作成」ボタンを押す。 下記の表示で、Lambda関数が作成されたことを確認する。 2つ目の関数を作成 同様の手順で、2つ目の関数を作成する。 関数名は任意だが、今回は yamatoSampleLambdaFunction210612b とする。 以上で、2つのLambda関数 yamatoSampleLambdaFunction210612a yamatoSampleLambdaFunction210612b が作成された。 各関数にログ出力処理を仕込む それぞれの関数が起動した際、動いたことが分かるように、ログ出力をコードに埋め込む。 各関数の index.js に下記を実装する。 コードを修正したら「Deploy」ボタンを押す。 関数A yamatoSampleLambdaFunction210612a console.log("関数A「yamatoSampleLambdaFunction210612a」が呼ばれました。"); 関数B yamatoSampleLambdaFunction210612b console.log("関数B「yamatoSampleLambdaFunction210612b」が呼ばれました。"); 各関数をテスト実行してログが出力されることを確認する 関数を試しに動かしてみる。「テスト」を押す。 「新しいテストイベントの作成」で、イベントテンプレートは「hello-world」を選択する。 任意のイベント名を入力する。 ここでは yamatoTestEventA とする。 「作成」ボタンを押す。 この状態で「テスト」ボタンを押すと、Lambda関数が実行される。 ログが出力されているかどうか確認する。 「モニタリング」タブを選び、「CloudWatchのログを表示」を押す。 ログストリームのリンクをクリックする。 詳細を確認する。ログが出力されている。 つまり、関数Aが起動すると、ログが出力される、ということが確認できた。 同様の手順で関数Bも動かして、関数Bのログも出力されることを確認する。 以上で、関数AとB、それぞれを動かして、ログが出力されることが確認できた。 関数AからBを呼び出す 関数AからBを呼び出すには、 関数Aの index.js に下記を実装する。 const AWS = require('aws-sdk'); const lambda = new AWS.Lambda(); exports.handler = async (event) => { console.log("関数A「yamatoSampleLambdaFunction210612a」が呼ばれました。"); let payload = { "message":"関数Bへ渡したい文字列があればここに記入する。", } // ペイロードをStringにする。 payload = JSON.stringify(payload); let params = { FunctionName:"yamatoSampleLambdaFunction210612b", InvocationType:"RequestResponse", Payload:payload } let callLambda = ''; try { // Lambda関数Bを呼び出す。 callLambda = await lambda.invoke(params).promise(); } catch (e) { console.log("[ERROR]関数呼び出し失敗!",e) } const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; }; 解説 let params の FunctionName に、呼び出し先のLambda関数名を指定する。 payload で呼び出し先の関数へパラメータを渡すこともできる。 動作確認 「テスト」を押して関数Aを動かし、ログが出力されることを確認する。 関数Aが起動すれば、関数Aが関数Bを呼び出すので、結果として関数Bのログも出力される。 関数Bのログを確認する。たしかに出力されている。つまり関数Aが関数Bを呼び出すことに成功している。 関数Aから関数Bへパラメータを渡して戻り値を返してもらう 関数Aから関数Bを呼び出す際、 引数を渡して、関数Bで受け取り、 何らかの処理をした結果を関数Aに戻す。 その場合、下記の実装にする。 関数A index.js const AWS = require('aws-sdk'); const lambda = new AWS.Lambda(); exports.handler = async (event) => { console.log("関数A「yamatoSampleLambdaFunction210612a」が呼ばれました。"); let payload = { "id": 1234, "name": "Kenichiro-Yamato", "message": "こんにちは。私の名前は大和賢一郎です。関数Aから渡されました。", } // ペイロードをStringにする。 payload = JSON.stringify(payload); let params = { FunctionName:"yamatoSampleLambdaFunction210612b", InvocationType:"RequestResponse", Payload:payload } let callLambda = ''; try { // Lambda関数Bを呼び出す。 callLambda = await lambda.invoke(params).promise(); console.log("関数Bからの戻り値: " + JSON.stringify(callLambda)); } catch (e) { console.log("[ERROR]関数呼び出し失敗!",e) } const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; }; 関数B index.js exports.handler = async (event, body, context) => { console.log("関数B「yamatoSampleLambdaFunction210612b」が呼ばれました。関数Aから次のパラメータを渡されました。"); console.log(JSON.stringify({event: event, body: body, context: context}, null, 2)); const response = { statusCode: 200, message: '関数Aさんへ。私は関数Bです。パラメータ受け取りました。ありがとう。', event: event, }; return response; }; ログは下記の通り。パラメータの受け渡しと戻り値の返しが正常に実行されている。 関数Aのログ 関数Bのログ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2でEmbulkを使ってRDSのMysqlからBigQueryにデータ移行してみた

本記事について 普段よりRDSのMysqlにデータを蓄積しており、溜まったデータを分析したいと思いBigQueryにデータを移そうと考えた時の話です。 Embulkというデータ転送エンジンを用いると、簡単に構築可能で、差分更新などの仕組みにも対応しているということでEC2を使って色々な記事を参考に構築してみました。 自分への備忘も含め、これから導入を考えている人向けにも、ハンズオンでこれだけ見れば再現可能な記事を書こうと思います。 インストール手順 インストール手順を画面ショット付きで解説しようと思います。 まず、今回構築するアーキテクトの構成はこんな感じにシンプルなものを作ります。 VPCのパブリックサブネット内にEC2インスタンスを作成し、その上にEmbulkをインストールします。 プライベートサブネット内にあるRDS MySQLとの通信は外部からは出来ず、 PC内の通信しか通さないようにセキュリティグループを設定します。 今回はRDSは既に構築済という前提で、EC2にEmblukをインストールし、 BigQueryにデータ転送するところまでをハンズオンでやっていきます。 EC2の構築 AWSのマネジメントコンソールよりEC2インスタンスを起動します。 インスタンスサイズは無料利用枠が使える、t2.microを使用、マシンイメージはAmazon Linux 2を用いました。 今回はRDSと接続するので、プライベートネットワークでRDSを構築している場合は、RDSのインバンドルールにEC2のソースを追加しておきましょう。 Embulkのインストール インストールは以下2つのコマンドを入力するだけです。 すごく簡単です。 curl --create-dirs -o bin/embulk -L "http://dl.embulk.org/embulk-latest.jar" chmod +x bin/embulk パスも通しておきましょう #.bashrcにパスを追加 sudo echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc #パスの設定を反映 source ~/.bashrc EmbulkはJavaアプリケーションなので、Javaのインストールが必要です。 Javaがインストールされていないことを確認し、インストールをしてあげましょう。 ## 確認 which java -bash: $: コマンドが見つかりません ## インストール sudo yum install java-1.8.0-openjdk embulkのbundle用環境を作成します。 開発の要件やバージョンの違いに合わせて、bundleで環境を分けて管理するイメージです。 例では「rds-to-mysql-bq」のディレクトリを作成しています。 embulk mkbundle rds-mysql-to-bq 以下のようなディレクトリが作成されれば成功です。 rds-mysql-to-bq ├── embulk │   ├── filter │   │   └── example.rb │   ├── input │   │   └── example.rb │   └── output │   └── example.rb └── Gemfile Embulkのプラグインのインストール 作成されたGemfileの最後に以下の2行を追加します。 vimなどを使ってファイルを編集すると良いでしょう。 # input mysql plugin gem 'embulk-input-mysql' # ouput bq plugin gem 'embulk-output-bigquery' Gemfileを編集したら、bundleコマンドでプラグインをインストールします embulk bundle Embulkの設定ファイルを書く 次はEmbulkの設定ファイルを作成していきます。設定ファイルはyaml形式で書き、ここに転送元や転送先のスキーマ、転送方法、環境情報を保持します。1つのテーブルにつき1設定ファイルを作る形になります。Embulkでは、Liquidというテンプレートエンジンを使うため、ファイル名を{ファイル名}.yaml.liquidの形式で作成します。 今回はm_brandsというテーブルを対象にしたいので、m_brands.yaml.liquid というファイル名で作成します。 in: type: mysql host: {{ env.MYSQL_HOST_NAME }} user: {{ env.MYSQL_USER }} password: {{ env.MYSQL_PASSWORD }} database: test_database table: m_brands out: type: bigquery auth_method: json_key json_keyfile: ./credentials/bq_project.json path_prefix: tmp file_ext: .csv.gz source_format: CSV project: rds-to-biqquery-test dataset: aws_mysql_tables auto_create_table: true table: m_brands formatter: {type: csv, charset: UTF-8, delimiter: ',', header_line: false} encoders: - {type: gzip} INとOUTのパラメータ詳細については各プラグインページを参考 embulk-input-mysql embulk-output-bigquery gcpのクレデンシャルが必要になるので、GCPコンソールから鍵を取得します。 GCPコンソールの「IAMと管理」メニューの「サービスアカウント」ページに移動 「サービスアカウントを作成」よりアカウントを作成する BigQueryの管理者権限を付与 サービスアカンウントの作成後、詳細ページより「新しい鍵を作成」しJSON形式で保存 ローカルに落としたJSONファイルのクレデンシャル情報を.credential/bq_projcet.jsonとしてEC2にコピーします。 環境変数の設定 RDSのMySQLの接続情報を環境変数に設定します export MYSQL_HOST_NAME = sample.xxxxxxxxx4.ap-northeast-1.rds.amazonaws.com #エンドポイント export MYSQL_USER = root #ユーザー名 export MYSQL_USER = password #パスワード printenv | grep MYSQL コマンドで設定内容を確認して問題なければ次へ続きます。 Previewを実行 本実行する前に、これまでの設定が問題なく出来ているかPreviewで確認してみましょう。 ちなみに、MySQLのテーブルに入っているデータはこんな感じです。 スマートフォンの機種と発売日などの情報が入っています。 以下のようなコマンドでPreviewを実行します。-bオプションはbundleフォルダのパスを指定します。 embulk preview -b . m_brands.yaml.liquid いろいろメッセージが流れた後に、ターミナル上で結果セットの確認ができました! 良い感じですね! もし、ここでエラーが出た場合は、後述のエラー対応集をご覧ください。 +-----------------+--------------------------------+----------------------+-------------------------+------------------------------------------------------+------------+---------------------------------------------------------------------+-------------------------+-------------------------+ | brand_id:string | brand_name:string | maker:string | relese_date:timestamp | spec:string | url:string | img_src:string | created_at:timestamp | updated_at:timestamp | +-----------------+--------------------------------+----------------------+-------------------------+------------------------------------------------------+------------+---------------------------------------------------------------------+-------------------------+-------------------------+ | M0000000001 | W-ZERO3 | シャープ | 2005-12-05 00:00:00 UTC | 2005年12月上旬発売|3.7インチ|220g | | https://img1.kakaku.k-img.com/images/productimage/l/31201000830.jpg | 2021-04-04 18:10:13 UTC | 2021-04-04 18:10:13 UTC | | M0000000002 | W-ZERO3 [es] | シャープ | 2006-07-27 00:00:00 UTC | 2006年7月27日発売|2.8インチ|175g | | https://img1.kakaku.k-img.com/images/productimage/l/31201000833.jpg | 2021-04-04 18:10:13 UTC | 2021-04-04 18:10:13 UTC | | M0000000003 | X01HT | HTC | 2006-10-14 00:00:00 UTC | 2006年10月14日発売|2.8インチ|176g | | https://img1.kakaku.k-img.com/images/productimage/l/31102000865.jpg | 2021-04-04 18:10:06 UTC | 2021-04-04 18:10:06 UTC | | M0000000004 | W-ZERO3 [es] Premium version | シャープ | 2006-11-16 00:00:00 UTC | 2006年11月16日発売|2.8インチ|175g | | https://img1.kakaku.k-img.com/images/productimage/l/31201000880.jpg | 2021-04-04 18:10:13 UTC | 2021-04-04 18:10:13 UTC | | M0000000005 | X01NK | NOKIA | 2007-04-26 00:00:00 UTC | 2007年4月26日発売|2.8インチ|144g | いざ実行 実行してBigQueryのテーブルに転送するまで通してみます。 runコマンドを実行して転送処理を行います。 embulk run -b . m_brands.yaml.liquid いろいろメッセージが流れ始めます。。。 1分経たないくらいで全ての処理が終了。 BigQueryの画面を確認してみると... 転送されてたーーーーー!!! 完 エラー対応集 Running Embulk version (0.9.23) does not match the installed embulk.gem version (0.10.31). バージョン関連の問題のようです。エラーメッセージにもある通りGemfileを以下のように編集します #gem 'embulk' ← コメントアウト gem 'embulk', '< 0.10' org.jruby.exceptions.RaiseException: Google::Apis::ClientError BigQueryのロケーションを指定していない場合にエラーが発生するようです。 設定ファイルのOUT句にlocationパラメータを追加してあげれば解決しました。 ~略~ out: type: bigquery auth_method: json_key json_keyfile: ./credentials/bq_project.json path_prefix: tmp file_ext: .csv.gz source_format: CSV project: rds-to-biqquery-test location: asia-northeast1 ← これを追加!!! ~略~
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSs3上でお名前.comで取得した独自ドメインを反映させる手順

何の記事か AWSのS3上で構築したサイトを、お名前.comで取得した独自ドメインにしようと思ったものの、意外と情報がまとまっておらずメモに残そうと思いました。 ※作業として目的を果たすためのメモであり、技術的には正しい理解はできていないかと思いますのでご了承ください。 最終的に参考になった記事 https://deep.tacoskingdom.com/blog/12 https://qiita.com/wannabe/items/17060e244c50d5b467cb やるべき作業 お名前.comとAWS上でそれぞれやるべきことがあります。 AWS上では「S3」「Route53」「CertificateManager」「CloudFront」の4つの設定が必要。 ①お名前.comで独自ドメインの取得 ここは特に迷うことはない。 ②Route53でAWS上に独自ドメインを認識させる ホストゾーンの作成 お名前.comで取得した独自ドメインを入力して作成をクリック 出てくる4つのネームサーバーのアドレスをメモ(お名前.comでの反映作業のため) ③お名前.comでDNSの設定を行う step②で取得した4つのアドレスをお名前.com上で反映させる ④CertificateManger SSL認証をしてくれる お馴染みのLet's Encryptを使う必要なく、AWS上で完結してくれる バージニア北部(us-east-1)リージョンで作業をする。CloudFrontで証明書を使用するには、バージニアである必要があるため。 以下の記事「AWS Certificate ManagerでSSL証明書の発行」の箇所に従う(大変参考になりました) https://deep.tacoskingdom.com/blog/12#part-h2-3 CNAMEの情報が発行されるのでメモ(お名前.comでの反映作業のため) ⑤お名前.comでSSL認証設定を反映させる お名前.com上での該当箇所が探しづらい。。。 DNS>ドメインのDNS設定>ドメイン選択>DNSレコード設定を利用するの「設定する」を選択 以下の記事「お名前ドットコムに外部のCNAMEを設定する」の箇所に従う (大変参考になりました) https://deep.tacoskingdom.com/blog/12#part-h2-3 ⑥CloudFrontでの設定 この記事の「S3にファイルをアップロードして静的サイトを取得したドメインで公開」の箇所に従う (大変参考になりました) https://qiita.com/wannabe/items/17060e244c50d5b467cb 「Create Distribution」をクリックして指示に従う。 「Deployed」となるまで対応。 ⑦Route53でCloudFrontでの設定を定義する wwwをCloudFrontで作成した内容に向ける。 まとめ 作業として1つのサイトで完結できるものがなかったので、本記事にまとめました。 私は参考にした2つの記事の内容を組み合わせて作業をして、SSL認証独自ドメイン運用ができたので、少しでも参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Data Analytics - Specialty 合格記録

この記事 AWS Data Analytics Specialty を取得したので、学習内容や感想を記録します。 about me インフラエンジニア AWS関連のインフラ構築や保守を4年ほど経験しています。 これまでのAWS資格は以下の流れで取得しました。 2019 Solution Architect Associate (7月) SysOps Administrator Associate (9月) Solution Architect Professional (11月) Developer Associate (12月) 2020 DevOps Engineer Professional (3月) Security Specialty(5月) Advanced Networking(10月) 2021 Database Specialty(1月) Data Analytics Specialty(6月) about DAS試験 AWS 認定 データベース – 専門知識 https://aws.amazon.com/jp/certification/certified-data-analytics-specialty/ 試験対策でやったこと 試験ガイドとサンプル問題 まずは、どんな内容の問題が出るのか目を通します。 上記リンクの「試験ガイド」「サンプル問題」です。 どんな問題が出るのか?具体的な対象サービスは?シチュエーションは? といった部分を確認します。 AWS公式ドキュメントによる学習 まず、各サービスについて知る必要があるのでこちらの公式資料で学習です。 https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/ ※Analyticsの主要なサービス部分 何もわからない状態で問題集をやるよりは、 公式ドキュメントで「見たことある」状態にしてから演習すると、Input効率が格段に上がります。 もちろん、やってみてからでも場合(分野)によってはありです。 問題演習 問題集は主にkoiwaclubです。 https://aws.koiwaclub.com/ Udemyもいくつかやりましたが、私が買って解いたものは回答が違っているものもあったので途中でやめました。 どれを使うかしっかり選べば良いかと思いますが、特に英語のものはいくつかやってみてから選んだほうが良いかと思います。 不足していた知識補完 学習前半で、個人的に知識不足だったのは以下でした。 ・Kinesis系サービスのそれぞれの用途 ・各サービスの便利オプション(例:Glueのジョブブックマーク機能や、Redshiftの外部テーブル参照機能とか) ・AthenaやQuicksightでできることやユースケース 最も役に立った書籍 今回、データ分析の分野自体が経験がなく不安だったので、書籍でしっかり学習しようと思い 後半戦は主にこちらの書籍での学習/ハンズオンをやりました。 「AWSではじめるデータレイク: クラウドによる統合型データリポジトリ構築入門」 https://www.amazon.co.jp/dp/491031301X 正直はじめに読むべきだったなと思ったくらい、初級者にも適切な内容だと思います。 データレイク分野は、一体誰が何のために使用するのか? どんな登場人物が出てくるのか? 従来の方法と比べて、AWSクラウドで実装することでどの様なメリットが有るのか? 各AWSサービスはどうやって使うのか?(例えばQuicksightの画面や出来る操作等) この辺がはっきりと理解できる内容でした。 (全分野で出してほしいくらいです。。) 結果&まとめ 点数はギリギリでしたが、無事合格。 試験対策としての学習時間は、45時間程度です。 やはり今回も、場合によっては英語で解いたほうがわかりやすいこともあるのでそちらもおすすめです。 私はテストセンターで受験しましたが、たまたまシステム障害で遅れて試験が始まりました。 復習で必死だったので、個人的には全然問題ありませんでしたが…(笑) 次の試験 いよいよラスト、Machine Learning Specialtyを、CLFと共に取ります。 経験は多少あるので、思い出しながら短期で学習します。 この記事が何かのお役に立てられれば幸いです。 ありがとうございました。 戦いの記録 SAA https://qiita.com/shinon_uk/items/5525178bf98034676b2f SOP https://qiita.com/shinon_uk/items/e60bcb946b49bf5cabda SAP ・勝利編 https://qiita.com/shinon_uk/items/c6b599d1cd3000e84d59 ・敗走編(資料集め) https://qiita.com/shinon_uk/items/ba839ba048ba439cc3ff DVA https://qiita.com/shinon_uk/items/8015953c792ef4bc7223 DOP https://qiita.com/shinon_uk/items/5646d536e649b60b962a SCS https://qiita.com/shinon_uk/items/67fab096f9b85c47de55 ANS https://qiita.com/shinon_uk/items/05f90e2ff6e9c9e732e8 DAS https://qiita.com/shinon_uk/items/996edfa2ceab274c38cb
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amplify + Cognito でハマったポイント

AWS Amplifyでネイティブアプリを作っているのですが、思いのほかハマったので、ポイントをここに書き残します。 ハマり1: 既存のUser Poolを使う場合、WebアプリとNativeアプリの設定が一致していないとエラーになる AmplifyでUser Poolを使う場合、WebアプリとNativeアプリの2つがUser PoolのApp Client Settingsに登録されている必要がありますが、各種設定(Identity Provider, Callback/Signout URLs, OAuth Scopeなど)は2つのアプリで一致させておかないとエラーが発生します。例えば以下のようなエラーが出ます。 The following OAuth properties are not matching: Callback URLs: | web_app | native_app | | ------- | ---------- | | | myapp:// | amplify import auth を実行した際には、設定が一致していなくてもエラーが出ない場合があり、分かりにくいです。その場合は次回amplify pullを実行した際にエラーが出ます。 ハマり2: import authのタイミングでは動的生成コードが更新されない amplify import authを実行しても、動的生成コード(amplifyconfiguration.dart や aws-exports.js など)は更新されないようです。 amplify pushすると更新されます。 ハマり3: Auth.signUpの結果がiOSとAndroidで異なる Email Verificationが必要な場合、結果のオブジェクトにiOSとAndroidで真偽値が逆転しているという恐ろしいプロパティがあります。以下は Flutterでのコード例です。 final result = await Amplify.Auth.signUp(...); print(result.nextStep.signUpStep); // CONFIRM_SIGN_UP_STEP print(result.isSignUpComplete); // iOS は false, Android は true サンプルコードによってはisSignUpCompleteの値を見て条件分岐しているものがあるので、安易に参考にするとAndroidでは動くがiOSでは動かない...という事故が発生します。 2020年の9月には既にIssueがあるようですが、2021年6月現在でも直っていないようです。 ハマり4: Cognito User Pool OnlyにするとAndoridで例外が出る(未解決) Cognito User Pool Only(Identity Pool を使わない)の場合、 Androidでログイン時に例外が出ます。警告なのでログイン自体は出来ているのですが、盛大にスタックトレースが出るのでなにか設定を間違っているのかとしばらく悩みました。iOSでは特に警告は出ません。 W/AWSMobileClient( 7940): Failed to federate tokens during sign-in W/AWSMobileClient( 7940): java.lang.Exception: Federation is not enabled, please check if you have CognitoIdentity configured. W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.AWSMobileClient$10.run(AWSMobileClient.java:1715) W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.internal.InternalCallback.await(InternalCallback.java:115) W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.AWSMobileClient.federatedSignInWithoutAssigningState(AWSMobileClient.java:1668) W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.AWSMobileClient$6$1.onSuccess(AWSMobileClient.java:1200) W/AWSMobileClient( 7940): at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$6.onSuccess(CognitoUser.java:1099) W/AWSMobileClient( 7940): at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$27.run(CognitoUser.java:3098) W/AWSMobileClient( 7940): at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$24.run(CognitoUser.java:2965) W/AWSMobileClient( 7940): at com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.AuthenticationContinuation.continueTask(AuthenticationContinuation.java:147) W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.AWSMobileClient$6$1.getAuthenticationDetails(AWSMobileClient.java:1235) W/AWSMobileClient( 7940): at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.getSession(CognitoUser.java:1032) W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.AWSMobileClient$6.run(AWSMobileClient.java:1185) W/AWSMobileClient( 7940): at com.amazonaws.mobile.client.internal.InternalCallback$1.run(InternalCallback.java:101) W/AWSMobileClient( 7940): at java.lang.Thread.run(Thread.java:919) ハマリ5: 自動生成コードが正しく生成されなくなることがあった これは Cognito とは無関係かもしれませんが、import auth, remove auth, push, pull を繰り返していたら、突然 flutter プロジェクトのはずなのに amplifyconfiguration.dart ではなく aws-exports.js が生成されるようになってしまいました。 amplify init から改めてやり直したところ復旧しましたが、amplify configure project でアプリのフレームワークを再設定しても回復できたかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Webアプリデプロイ方法(AWS EC2編)

目次 1.はじめに 2.前提 3.新規ユーザ作成 4.各種ソフトウェアインストール 5.githubからのアプリクローン 6.アプリのシークレット設定 7.webサーバ設定 8.applicationサーバ設定 9.db設定 10.アプリ起動 11.まとめ 12.参考 はじめに 前回の記事「Webアプリ公開のためのインフラ環境をCloudFormationで構築してみた」を通し、Webアプリデプロイ用のインフラ環境を準備することができました。今回は作成したAWS EC2上に、RailsのWebアプリをデプロイしましたので、大まかな手順を整理します。 前提 前回、CloudFormationで構築した以下のAWS構成にて、EC2上にRailsのWebアプリをデプロイしていきます。 ■ デプロイするWebアプリ 個人的に以下、学習系のWebアプリを開発してみましたので、こちらをデプロイしてみます。 WebアプリURL : https://www.memory-tank.ga/ (PC推奨) Rails:6.0.3 Ruby:2.6.5 概要 効率的なナレッジ蓄積と知識定着を支援するアプリ。 ユーザは様々なWord(単語)や自作の四択問題をカテゴリ別に管理した上で蓄積することができる。 また、蓄積したWordや四択問題はユーザ自身の定着率/正答率に応じて、習得済と未習得の2つのカテゴリに分割して自動管理される。 以降、実際のデプロイの手順を記載していきますが、まずは全体像、大まかな流れをまとめます。 作業概要 内容 新規ユーザ作成  アプリ管理用のOSユーザを作成する 各種ソフトウェアインストール プラグイン/MySQL/Node.js/rbenv/ruby-build/Rubyをインストールする GitHubからのアプリクローン  GitHubからEC2上にアプリをクローン/配置する アプリのシークレット設定  アプリのシークレットを生成し、設定する Webサーバ設定  Nginxの設定ファイルを修正する Applicationサーバ設定  Unicornの設定ファイルを修正する DB設定  DBへのアクセスに関わる設定ファイルを修正する アプリ起動  Nginx/Unicornを起動する 新規ユーザ作成 AWSのEC2インスタンスを作成するとデフォルトユーザ「ec2-user」が使えますが、複数人でアプリを管理していくことを想定し、ここでもう1つの管理用OSユーザを作成しておきます。 EC2へのログイン ローカル環境 #ローカル環境で、EC2インスタンスの秘密鍵が格納されたパスに移動する $ cd ~/.ssh #秘密鍵を指定し、ec2-userでEC2にログインする (yes/noを聞かれるので、yesと入力する) $ ssh -i 秘密鍵の名前.pem ec2-user@EC2のElasticIPアドレス 新規ユーザの作成 EC2 #adduserの後ろに、作成したいユーザのユーザ名を指定する $ sudo adduser ユーザ名 新規ユーザのパスワード設定 EC2 #以下のコマンドを実行後、設定したいパスワードを求められるので入力する $ sudo passwd ユーザ名 新規ユーザのsudo権限を設定 EC2 #visudoファイルを編集する $ sudo visudo 1. 以下の、rootに関する権限の記述箇所を探す   root ALL=(ALL) ALL 2. 「i」を入力して、入力モードに切り替える 3. 1で探した行の下に以下の記述を追記する ※ 新規作成ユーザの権限設定   ユーザ名 ALL=(ALL) ALL 4. 「esc」を押して入力モードを終了する 5. 「:wq」を入力後、エンターを押して編集を完了する 新規ユーザへの切り替えができることの確認 EC2 #以下を実行後、プロンプトの[ec2-user|の表示が新規作成のユーザ名に切り替わればOK $ sudo su - ユーザ名 EC2へSSH接続をするための鍵をローカル環境で作成 ローカル環境 #.sshディレクトリに移動する $ cd ~/.ssh #以下のコマンドでSSHの鍵を作成する $ ssh-keygen -t rsa -------------------------------- #以下のメッセージが表示されるので、「任意の名前_key_rsa」を入力する Enter file in which to save the key ():任意の名前_key_rsa #何もせずにエンターを押す Enter passphrase (empty for no passphrase): #何もせずにエンターを押す Enter same passphrase again: -------------------------------- 秘密鍵/公開鍵が作成されたことの確認 ローカル環境 #lsコマンド実行後、秘密鍵「任意の名前_key_rsa」と公開鍵「任意の名前_key_rsa.pub」が表示されることを確認する $ ls ~/.ssh/config (SSH経由でリモートサーバーに接続する際に利用される設定ファイル)の編集 ローカル環境 #~/.ssh/configファイルを編集する $ vi config 1. 「i」を入力し、入力モードに切り替え、以下を追記する -------------------------------- #Hostの後ろに、先ほど作成した秘密鍵の名前を記載する Host 任意の名前_key_rsa #Hostnameの後ろに、EC2のElastic IPアドレスを記載する Hostname EC2のElastic IPアドレス #ポート番号22番を指定する Port 22 #Userの後ろに、先ほど作成した新規ユーザのユーザ名を記載する User ユーザ名 #IdentityFileの後ろに、先ほど作成した秘密鍵のフルパスを記載する IdentityFile ~/.ssh/任意の名前_key_rsa -------------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する 公開鍵の中身をコピー ローカル環境 #公開鍵の中身をcatコマンドで出力し、全文をコピーする $ cat 任意の名前_key_rsa.pub サーバ側で公開鍵を設定 (先ほど作成したユーザで実施する) EC2 #公開鍵格納用のディレクトリを作成する $ mkdir .ssh #作成したディレクトリのアクセス権限を設定する $ chmod 700 .ssh #作成したディレクトリに移動する $ cd .ssh #公開鍵を記録するファイルを作成する $ vi authorized_keys 1. 「i」を入力し、入力モードに切り替え、以下を追記する ---------------------------------------- ローカル環境でコピーした公開鍵の中身を貼り付ける ---------------------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #公開鍵を記録するファイルのアクセス権限を設定する $ chmod 600 authorized_keys #新規作成ユーザからサインアウトする $ exit #ec2-userからサインアウトする $ exit 新規作成ユーザでのSSH接続確認 ローカル環境 #作成した秘密鍵を指定し、EC2にSSH接続をする $ ssh 任意の名前_key_rsa 無事にログインができたら、最初のステップ「新規ユーザ作成」は完了です。 各種ソフトウェアインストール 次に、Webアプリを動かす上で必要な各種ソフトウェアをインストールしていきます。 Nginxは前回記事のCloudFormationにて、EC2のユーザデータよりインストール済で自動起動設定もしてあります。 サーバのアップデート EC2 #まずはEC2内のソフトウェアをアップデートしておきます。 $ sudo yum update -y 各種プラグインのインストール EC2 #Git/コンパイル用コマンド/コンパイラ/パッチ適用コマンド/OpenSSL用ファイル/Ruby用パッケージ/アプリ開発用ライブラリ $ sudo yum install git make gcc-c++ patch openssl-devel libyaml-devel libffi-devel libicu-devel libxml2 libxslt libxml2-devel libxslt-devel zlib-devel readline-devel MySQL 5.7 のインストール EC2 #MySQL公式のyumリポジトリを追加 $ sudo rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm #MySQLをインストール $ sudo yum install mysql-devel mysql57 mysql57-server $ sudo yum install mysql mysql-server mysql-utilities Node.js 15.5 のインストール EC2 #Node.jsのバージョン管理ツールnvmをインストールする $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash #以下コマンド実行後、プロンプトに「nvm」と表示されることを確認する $ command -v nvm #上記で「nvm」が表示されなかった場合は以下を実行する $ source ~/.bash_profile #Node.jsをバージョン指定でインストールする $ nvm install 15.5.0 rbenvのインストール EC2 #rbenv (rubyのバージョン管理ツール)をインストールする $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv #パスを通す $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile #shims と autocompletion の有効化設定を追記 $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile #設定ファイルを反映させる $ source ~/.bash_profile ruby-build のインストール EC2 #ruby-build (rubyのビルドツール)をインストールする $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build # ~/.rbenv/versions/*/bin/ 以下のファイルを ~/.rbenv/shims/ 以下にコピーする $ rbenv rehash Rubyのインストール EC2 #ローカル環境で開発したアプリのRubyバージョンと同じバージョンを指定し、インストールする $ rbenv install -v 2.6.5 #使用するRubyのバージョンを指定する $ rbenv global 2.6.5 # ~/.rbenv/versions/*/bin/ 以下のファイルを ~/.rbenv/shims/ 以下にコピーする $ rbenv rehash # Rubyのバージョンを表示し、インストールしたものと同じになっていることを確認する $ ruby -v ここまでで「各種ソフトウェアインストール」は完了です。 githubからのアプリクローン 次に、GitHubから、開発したアプリをEC2上にクローンしていきます。 設定ファイルの作成 EC2 #ホームディレクトリに移動 $ cd ~ #gitの設定ファイルを作成する $ vi .gitconfig 1. 「i」を入力し、入力モードに切り替え、以下を追記する -------------------------------- [user] name = gitに登録した自分の名前 email = git登録時の自分のメールアドレス #pull、pushのための設定 [url "github:"] InsteadOf = https://github.com/ InsteadOf = git@github.com: -------------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する アプリ配置のディレクトリ作成 EC2 #ルートディレクトリに移動 $ cd / #var/wwwディレクトリを作成 $ sudo mkdir var/www #var/www/railsディレクトリを作成 $ sudo mkdir var/www/rails #varディレクトリの所有者を新規作成ユーザにする $ sudo chown ユーザ名 var #varディレクトリに移動する $ cd var/ #www配下の所有者を新規作成ユーザにする $ sudo chown -R ユーザ名 www git接続用の鍵作成 EC2 #ホームディレクトリに移動する $ cd ~ #.sshディレクトリの権限を設定する $ chmod 700 .ssh #.sshディレクトリに移動する $ cd .ssh #sshの鍵を作成する $ ssh-keygen -t rsa -------------------------------- 以下のメッセージが表示されるので、「ec2_git_rsa」と入力する Enter file in which to save the key ():ec2_git_rsa 何もせずにエンターを押す Enter passphrase (empty for no passphrase): 何もせずにエンターを押す Enter same passphrase again: -------------------------------- #lsコマンドを実行後、秘密鍵「ec2_key_rsa」と公開鍵「ec2_key_rsa.pub」が表示されることを確認する $ ls #設定ファイルを作成する $ vi config 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- Host github github.com Hostname github.com User git IdentityFile ~/.ssh/ec2_git_rsa ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #公開鍵の中身をcatコマンドで出力し、全文をコピーする $ cat ec2_git_rsa.pub 公開鍵をGitHubにアップ GitHubの「settings」→ 「SSH and GPG keys」を押下する 「New SSH key」を押下する 「Title」に先ほど作成した公開鍵名、「Key」に先ほどコピーした公開鍵の中身を入力し、「Add SSH key」を押下する EC2 #ターミナルへ戻り設定ファイルの権限を変更しておく $ chmod 600 config GitHubからアプリをクローン EC2 # /var/www/railsディレクトリに移動する $ cd /var/www/rails # アプリをクローンする $ git clone クローンしたいアプリのGitHubのURL #lsコマンド実行後、各自のアプリディレクトリ/ファイルが表示されればOK $ ls #アプリのディレクトリに移動する $ cd アプリ名 #Gemのインストール $ bundle install #「bundle install」で「Could not find 'bundler' 〜」、「To update to the latest version installed on your system, run `bundle update --bundler`.」のエラーが出た場合は以下を実施してからリトライする。 $ gem update bundler ※ アプリのURLはGitHubで「Code」→ 赤枠内のアイコンを押下するとコピーができる ここまでで「githubからのアプリクローン」は完了です。 アプリのシークレット設定 次にアプリのシークレット設定をしていきます。 マスターキーの作成 ローカル環境(開発したアプリのディレクトリ内で実施) #以下を実行し、表示されるマスターキーコピーする $ vi config/master.key 「:q!」を入力後、エンターを押して特に編集をせずに完了する EC2(クローンしたアプリのディレクトリ内で実施) #configディレクトリに移動 $ cd config #マスターキーの作成 $ vi master.key 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- 先ほどコピーしたマスターキーの値 ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する シークレットの作成 ローカル環境(開発したアプリのディレクトリ内で実施) #以下コマンドで表示されたシークレットキーをコピーする $ bundle exec rake secret EC2(クローンしたアプリのディレクトリ内で実施) #アプリのディレクトリ直下に移動する $ cd /var/www/rails/アプリ名 #credentials.yml.encを編集する $ EDITOR=vi bin/rails credentials:edit 1. 「i」を入力し、入力モードに切り替え、以下を編集する ----------------------------- # aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base: 先ほどコピーしたシークレットキーをペースト ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する ここまでで「アプリのシークレット設定」は完了です。 webサーバ設定 次にWebサーバ設定として、Nginxの設定ファイルを編集していきます。 設定ファイル編集 EC2(クローンしたアプリのディレクトリ内で実施) #nginxのディレクトリに移動する $ cd /etc/nginx/conf.d/ #設定ファイルを編集する ※ アプリ名の部分は各自、変えてください。 $ sudo vi アプリ名.conf 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- # log directory #エラーログのパス指定 error_log /var/www/rails/アプリ名/log/nginx.error.log; #アクセスログのパス指定 access_log /var/www/rails/アプリ名/log/nginx.access.log; #unicornとの接続設定 upstream unicorn_server { server unix:/var/www/rails/アプリ名/tmp/sockets/.unicorn.sock fail_timeout=0; } server { listen 80; client_max_body_size 4G; server_name 各自のアプリのドメイン名 keepalive_timeout 5; # Location of our static files root /var/www/rails/アプリ名/public; location ~ ^/assets/ { root /var/www/rails/アプリ名/public; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; if (!-f $request_filename) { proxy_pass http://unicorn_server; break; } } error_page 500 502 503 504 /500.html; location = /500.html { root /var/www/rails/アプリ名/public; } } ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する ここまでで「webサーバ設定」は完了です。 applicationサーバ設定 次にApplicationサーバ設定として、Unicornの設定ファイルを編集していきます。 Unicornのインストール EC2(クローンしたアプリのディレクトリ内で実施) #アプリのディレクトリ直下に移動する $ cd /var/www/rails/アプリ名 #Gemfileを編集する $ vi Gemfile 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- group :production, :staging do gem 'unicorn' end ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #Unicornをインストールする $ gem install bundler $ bundle install 設定ファイルの編集 EC2(クローンしたアプリのディレクトリ内で実施) #設定ファイルを編集する ※ アプリ名の部分は各自、変えてください。 $ vi config/unicorn.conf.rb 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- # set lets $worker = 2 $timeout = 30 $app_dir = "/var/www/rails/アプリ名" $listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir $pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir $std_log = File.expand_path 'log/unicorn.log', $app_dir # set config worker_processes $worker working_directory $app_dir stderr_path $std_log stdout_path $std_log timeout $timeout listen $listen pid $pid # loading booster preload_app true # before starting processes before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end # after finishing processes after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end ----------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する ここまでで「applicationサーバ設定」は完了です。 db設定 次にDBアクセスの設定をしていきます。 dotenv-rails (環境変数を管理するGem)の導入 EC2(クローンしたアプリのディレクトリ内で実施) #Gemfileを編集する $ vi Gemfile 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- gem 'dotenv-rails' ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #dotenv-railsをインストールする $ bundle install #以下コマンドを実行し、表示されるシークレットキーをコピーする $ bundle exec rake secret #.envファイルの作成 $ touch .env #.envファイルの編集 $ vi .env 1. 「i」を入力し、入力モードに切り替え、以下を追記する ----------------------------- SECRET_KEY_BASE=先ほどコピーしたシークレットキー DB_NAME=RDSのDB名 DB_USERNAME=RDSのユーザー名 DB_PASSWORD=RDSのパスワード DB_HOSTNAME=RDSのエンドポイント ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #設定ファイルを反映させる $ source .env #設定した値が表示されることを確認する $ echo $SECRET_KEY_BASE $ echo $DB_NAME $ echo $DB_USERNAME $ echo $DB_PASSWORD $ echo $DB_HOSTNAME database.ymlの編集 EC2(クローンしたアプリのディレクトリ内で実施) #.database.ymlファイルの編集 $ vi config/database.yml 1. 「i」を入力し、入力モードに切り替え、以下の編集をする ----------------------------- production: <<: *default database: <%= ENV['DB_NAME'] %> username: <%= ENV['DB_USERNAME'] %> password: <%= ENV['DB_PASSWORD'] %> host: <%= ENV['DB_HOSTNAME'] %> ---------------------------- 2. 「esc」を押して入力モードを終了する 3. 「:wq」を入力後、エンターを押して編集を完了する #MySQLを起動する $ sudo systemctl start mysqld #マイグレーションを実行する $ bundle exec rake db:migrate RAILS_ENV=production ここまでで「db設定」は完了です。 アプリ起動 以上で、各種設定が完了しましたので、最後にアプリを起動していきます。 各種起動 EC2 #アプリのプリコンパイルをする $ bundle exec rake assets:precompile RAILS_ENV=production #プリコンパイルが正常に終了せず、「yarn」のエラーが発生した場合は以下を実施後にリトライする $ npm install -g yarn $ yarn upgrade #Nginxを再起動する $ sudo systemctl restart nginx #Unicornを起動する $ bundle exec unicorn_rails -c /var/www/rails/アプリ名/config/unicorn.conf.rb -D -E production #Unicornの起動を確認する。以下コマンド実行後、プロセスが3行程度表示されること $ ps -ef | grep unicorn | grep -v grep 稼働確認 ブラウザより独自ドメインにてアクセスをし、無事に画面が表示されることを確認する まとめ 以上で、RailsのアプリをAWS EC2上にデプロイすることができました。アプリのデプロイにはAWS CodeDeployやECSなど、他のサービスも使用できるため、今後はそちらについても学習してみたいと思います。 参考 この記事は以下の情報を参考にして執筆しました。 【画像付きで丁寧に解説】AWS(EC2)にRailsアプリをイチから上げる方法【その3〜サーバー設定とRailsアプリの配置編〜】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS S3エンドポイント インターフェース型でローカルから直接S3にアクセスする

ゲートウェイ型とインターフェース型の違い S3エンドポイントには、ゲートウェイ型とインターフェース型があります。インターフェース型は PrivateLink とも呼ばれます。ゲートウェイ型ではエンドポイントを作成するとルートテーブルにルートが追加されます。一方インターフェース型では、エンドポイントのネットワークインターフェースが作成され、プライベートアドレスが割り当てられます。つまり、両者の大きな違いはエンドポイントを通る際にIPアドレスの変換が起こるかどうかだと認識しております。間違い等ございましたらご指摘頂けますと幸いです。 Amazon S3 のゲートウェイエンドポイント Amazon S3 のインターフェイスエンドポイント Amazon S3 パブリック IP アドレスを使用する VPC のプライベート IP アドレスを使用する オンプレミスからのアクセスできない オンプレミスからアクセスできる 別のリージョンからアクセスできない 別の AWS リージョンからのアクセスできる S3エンドポイントを作成する 「エンドポイントの作成」をクリックします。 フィルターのテキスト部分に「s3」と入力し、エンターを押します。表示される2つのエンドポイントのうち、タイプが「Interface」となっているものを選択します。 VPC と AZ(アベイラビリティゾーン) を選択します。 セキュリティグループを選択します。ここでは VPC のデフォルトのセキュリティグループを選択しています。 ポリシーを設定します。ここではフルアクセスを選択しています。なお、このポリシーはエンドポイント作成後に変更することができます。 「エンドポイントの作成」をクリックします。 S3にアクセス --endpoint-url には以下のDNS名のいずれも利用することができます。 PS C:\WINDOWS\system32> aws s3 --region ap-northeast-1 --endpoint-url https://bucket.vpc-endpoint-id-o16cnn3y.s3.ap-northeast-1.vpce.amazonaws.com cp C:\Users\user\Documents\test_upload.txt s3://bucket-name/ upload: ..\..\Users\user\Documents\test_upload.txt to s3://bucket-name/test_upload.txt ポリシーを設定 次にポリシーを設定してエンドポイントを経由しているか確認してみます。私の環境ではポリシーを設定してから反映されるまで少し時間がかかりました。 { "Id": "Policy1623456633533", "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1623456631884", "Action": "s3:GetObject", "Effect": "Allow", "Resource": "arn:aws:s3:::bucket-name/*", "Principal": "*" } ] } 以下のようにオブジェクトをダウンロードすることができました。 PS C:\WINDOWS\system32> aws s3 --region ap-northeast-1 --endpoint-url https://bucket.vpc-endpoint-id-o16cnn3y.s3.ap-northeast-1.vpce.amazonaws.com cp s3://bucket-name/test_upload.txt C:\Users\user\Documents download: s3://bucket-name/test_upload.txt to ..\..\Users\user\Documents\test_upload.txt 一方、アップロードは Access Denied になり失敗しました。 PS C:\WINDOWS\system32> aws s3 --region ap-northeast-1 --endpoint-url https://bucket.vpc-endpoint-id-o16cnn3y.s3.ap-northeast-1.vpce.amazonaws.com cp C:\Users\user\Documents\test_upload.txt s3://bucket-name/ upload failed: ..\..\Users\user\Documents\test_upload.txt to s3://bucket-name/test_upload.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied エンドポイントを作成したユーザーでも使用するためには明示的な許可が必要だということがわかりました。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】AWSのSESを使って本番環境でメールを送信する(aws-sdk-rails)

前提条件 macOS: Big Sur Ver11.2.3 Rails: 6.1.1 Ruby: 2.6.5 AWS: EC2(デプロイ),Route53(ドメイン取得),ACM(証明書取得) 前提条件に至るまで 固定IPアドレスに紐付いたドメインを取得し、取得したドメインにアクセスするとページが表示されるまで持っていくには、以下の記事のとおりでOK! 【初心者向け】AWSのサービスを使ってWebサーバーをHTTPS化する やりたいこと EC2上にデプロイしたRailsアプリケーションの本番環境で自由にメールを送信できるようにすること(Deviseのパスワード設定とか etc...)。 そのためにAWSのサービスのうち、SESを利用することにします。 手順(概要) ①AWS SESの設定 ②AWSのCSに制限解除のメールを送る(sandboxによる送信制限の解除) ③IAMユーザーの設定 ④Railsの設定 そして、上記の③までの設定については以下の方の記事が大変参考になりました。ありがとうございます! 【AWS】Amazon SESを用いてRuby on Railsのdeviseでメールを送信する ※なお、自分はすでにIAMユーザーを作成していたため、既存のIAMユーザーに「AmazonSESFullAccess」というインラインポリシーを後から追加する、といった方法で実装しました。まだIAMユーザーを作成していない方は上記のQiita記事の通りで良いのかと思います。 ④以降については、今回はAmazonが提供する正式なGemを使用したため、上記記事とは方法が少し異なります。 それでは、手順④以降について以下で具体的に見ていきます。 手順(詳細:Railsの設定) ①Gemのインストール Gemfileに以下を記述 # AWSのSESを使ってメールを送信するためにインストール gem 'aws-sdk-rails', '~> 3.6', '>= 3.6.1' そして、ターミナルで「bundle install」します。 ②AWSの初期設定ファイルを作成 以下のディレクトリにファイルを新規に作成します。 「aws.rb」としておきます。 config/initializers/aws.rb creds = Aws::Credentials.new( ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'] ) Aws::Rails.add_action_mailer_delivery_method(:aws_sdk, credentials: creds, region: 'ap-northeast-1') config.action_mailer.delivery_method = :aws_sdk 2〜3行目は環境変数になっているので、ターミナル上で設定されているか確認しておくこと。 (私の場合はS3に画像を保存していたため、すでに設定済みでした。) ちなみに、後でEC2上でも別途設定する必要があるので、忘れないよう注意! ③環境設定用ファイルを編集 開発環境と本番環境の設定を変更します。 config/environments/development.rb (中略) config.action_mailer.default_url_options = { host: '取得したドメインのフルURL' } config.action_mailer.delivery_method = :aws_sdk (中略) config/environments/production.rb config.action_mailer.default_url_options = { host: 'https://www.takeoutgohan.net/' } config.action_mailer.delivery_method = :aws_sdk ④Deviseの初期設定ファイルを編集(導入していなければとばしてOK) config/initializers/devise.rb (中略) # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. config.mailer_sender = 'noreply@あなたのドメイン(hoge.netなど)' (中略) ⑤メールの送信元ドメインの変更 Deviseの設定に合わせ、送信元アドレスのドメインを書き換えます。 app/mailer/application_mailer.rb class ApplicationMailer < ActionMailer::Base default from: 'noreply@あなたのドメイン(hoge.netなど)' layout 'mailer' end ⑥AWSのSESコンソール上の設定を行う ⑤までを行ったところ、メールは送れているものの受信ボックスに届いていないという状態になりました。 調べたところ、メールの信頼性を確保するため追加の設定をすれば良さそう! ということでSESコンソール上で以下の設定を行いました。 DKIMの設定 AWSにルートユーザーでログインし、SESのコンソールに移動。 左メニューの「Domains」から該当のドメインを選び、DKIMの設定を行う。 MAIL FROM Domainの設定 AWSにルートユーザーでログインし、SESのコンソールに移動。 左メニューの「Domains」から該当のドメインを選び、一番下の「MAIL FROM Domain」の設定を行う。 今回は、「mail」とだけ入力して作成しました。 最後に 以上で設定は完了になります。お疲れさまでした。開発環境でメールが実際に届くか確認しましょう(私は自分のGmailアドレスに送りました)。 また、本番環境にデプロイしたあとはEC2上でAWSの環境変数が設定されているか確認し、Webサーバー(Unicorn)を再起動してからサイトに再度アクセスすると良いと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ECS Execを使って Fargateのコンテナにアクセスする

はじめに 本記事では、ECS Exec の機能を使って、稼働中の Fargate のコンテナにアクセスする時の簡易な手順について、記載しています。 アクセスする Fargate のコンテナ周りの環境は、下図になります。 ECS Execは、SSM エージェントのバイナリを、下図のようにコンテナにバインドマウントして、Systems Manager (SSM) の Session Manager 経由で、アクセスできるようにしているようです。 引用:Github での Proposal 前提条件 Fargate のコンテナサイド ECS サービスを実行するプラットフォームのバージョンが1.4.0 以降であること。 Fargate のコンテナが Systems Manager (SSM) のエンドポイントに接続できること。 アクセスするクライアントサイド ECS Exec コマンドを実行するための AWS CLI がインストールされていること。 AWS CLI 対応バージョン v1 1.19.28 以降 v2 2.1.31 以降 AWS CLI 用の Session Manager plugin がインストールされていること。 参考: AWS CLI バージョン 1 のインストール、更新、およびアンインストール AWS CLI バージョン 2 のインストール、更新、およびアンインストール (オプション) AWS CLI 用の Session Manager plugin をインストールする ECS Exec を有効にする 下記コマンドで、AWS CLI が対応するバージョンか確認します。 $ aws --version aws-cli/1.19.92 Python/3.7.4 Darwin/18.7.0 botocore/1.20.92 下記コマンドで、Session Manager plugin がインストールされているか検証します。(下記のメッセージが出力されていれば、OKです。) $ session-manager-plugin The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. アクセスするタスク(コンテナ)の IAM ロール に下記のSSM エージェントの実行用のポリシーをアタッチします。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", "ssmmessages:OpenDataChannel" ], "Resource": "*" } ] } 下記コマンドで、ECS サービスの ECS Exec を有効にします。 $ aws ecs update-service --region ap-northeast-1 --cluster [クラスター名] --service [サービス名] --enable-execute-command ##出力結果 { "service": { 省略 "enableExecuteCommand": true } } 下記コマンドで、ECS サービスの ECS Exec が有効になったことを確認します。( true と出力されていれば OK です ) $ aws ecs describe-services --region ap-northeast-1 --cluster [クラスター名] --services [サービス名] | jq '.services[].enableExecuteCommand' true 有効にしたサービス上で、新しく起動したタスクに対してのみ ECS Exec は使用できます。 サービスを更新するなどして、タスクを再デプロイして下さい。 Fargate のコンテナにアクセス ECS Exec を有効にしたサービス上で起動した タスク ID を確認します。 下記コマンドで、Fargate のコンテナにアクセスします。(Starting session...と出力されれば OK です) aws ecs execute-command --region ap-northeast-1 --cluster [クラスター名] --task [タスク ID] --container [コンテナ名] --interactive --command "/bin/sh" The Session Manager plugin was installed successfully. Use the AWS CLI to start a session. Starting session with SessionId: ecs-execute-command-07cfe2faxxxxxxxxxxxxxxxxx Systems Manager (SSM) の Session Manager 上でも接続されていることを確認できます。 詳細な使用方法 より詳細な使用方法は、下記が参考になります。 New – Amazon ECS Exec による AWS Fargate, Amazon EC2 上のコンテナへのアクセス デバッグに Amazon ECS Exec を使用する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS クライアントVPN 2要素認証 秘密鍵にパスワードを付加する

初めに 現在 AWS クライアント VPN には 3 つの認証方法があります。 クライアント証明書による相互認証 Active Directory によるユーザー認証 SAML によるユーザーフェデレーション認証 今回、相互認証のみで2要素認証ができないか調べてみました。 その結果、OpenVPN によるクライアント秘密鍵のパスワードによる認証を追加可能であることがわかりました。記事の内容に間違い等ございましたらご指摘頂けると幸いです。 パスワード入力画面 証明書・秘密鍵を作成する こちらを参考に進めます。 パスワードを付加するにあたって、手順と異なるのは以下の部分です。 5.クライアント証明書とキーを生成します。 クライアント証明書とクライアントプライベートキーは、クライアントを設定するときに必要になるため、必ず保存してください。 クライアント証明書と秘密鍵を作成するとき、以下のようにドキュメントにある nopass を消してコマンドを実行します。 ./easyrsa build-client-full client 以下のようにパスワードを設定できます。Enter PEM pass phrase の部分です。 $ ./easyrsa build-client-full client Using SSL: openssl OpenSSL 1.0.2k-fips 26 Jan 2017 Generating a 2048 bit RSA private key ....+++ ..........+++ writing new private key to '/home/ec2-user/easy-rsa/easyrsa3/pki/easy-rsa-3613.TxeBqP/tmp.LVMVQ9' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- 後は手順通りです。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon Linux環境でSupervisorを使ってLaravel Queueを動作させる方法

この記事は私自身のmediumにも記載されています。 Laravel Queue work with supervisor on AWS EC2 1. Supervisorをインストールする Amazon レポジトリーにはsupervisorが入っておりません。 なのでepelレポジトリーを使ってインストールする必要があります。 sudo yum --enablerepo=epel install supervisor 2. supervisorをスタート sudo service supervisord start Redirecting to /bin/systemctl start supervisord.serviceこのメッセージが表示されたらインストール成功です。 3. supervisor設定ファイル修正 supervisorにworkerを追加するため、設定ファイルを修正します。 sudo vi /etc/supervisord.conf 下記を追記しましょう。 [program:worker] command=php /project-home/artisan queue:work process_name=%(program_name)s_%(process_num)02d numprocs=2 autostart=true autorestart=true user=root redirect_stderr=true stdout_logfile=/project-home/storage/logs/worker.log worker.logファイルをログパスに追加することを忘れないでください。 touch /project-home/storage/logs/worker.log 4. supervisor設定ファイルの読み込み 修正された設定ファイルを読み込ませるため、下記コマンドを実行します。 sudo supervisorctl reread 正しく入力したら、このようなメッセージが表示されます。 worker: available 5. supervisor再起動 設定を適用させるためにsupervisorを再起動しましょう。 sudo service supervisord restart workerが動作されているのか確認しましょう。 sudo supervisorctl status 下記のようなメッセージが表示されます。pidとuptimeは私のメッセージと違うはずです。 worker:worker_00 RUNNING pid 1043936, uptime 0:00:10 worker:worker_01 RUNNING pid 1043937, uptime 0:00:10 6. supervisorをインスタート再起動時にスタートするように設定する sudo chkconfig supervisord on 終わり!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む