20190707のAWSに関する記事は12件です。

【AWS】API Gateway経由でWebアプリにアクセスした際のレスポンスがBase64形式となる

AWS Lambdaなどに構築したWebアプリにAPI Gateway経由でアクセスした際に、既定の設定ではレスポンスがHTMLコンテンツではなくBase64形式となってしまう。

image.png

このような場合は、API Gatewayの設定でAPIの「バイナリメディアタイプ」を追加する必要がある。

解決方法

対象のAPIで[設定]-[バイナリメディアタイプ]で[バイナリメディアタイプの追加]をクリックし、text/htmlまたは*/*を指定して、[変更の保存]をクリック。

image.png

ステージに反映させるためにAPIのデプロイを忘れずに行う。

再度Webアプリにアクセスすると正常にHTMLコンテンツが表示された。

image.png

以上

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

Django + Heroku + AWS S3で画像表示させる方法

概要

Djangoアプリで画像をS3に保存し、アプリに表示させる方法を書いてみます。
想定している処理は、①ユーザーが画像投稿②S3に保存③S3からアプリに画像表示です。

なお、環境はPython 3.7.3Django 2.2になります。

1. AWS設定

1-1. AWS登録

S3を使用するのに、AWSアカウントが必要になりますので、お持ちでない方はAWS Signupからご登録ください。

参照:
AWS アカウント作成の流れ
Amazon S3

1-2. バケット作成

①S3を検索してクリック

s3.png

②バケット作成

s3-02.png

③バケット名とリージョンを選択

s3-03.png

④オプションなし

オプションですが、今回は設定しません

s3-04.png

⑤アクセス権限

こちらの項目を外してください、初期設定ではブロックされてしまいます

s3-05.png

⑥内容を確認して作成

s3-06.png

⑦バケット完成

s3-07.png

1-3. CORS設定

①CORSの設定に移動

作成したバケットをクリックし、「アクセス制限」の「CORSの設定」に移動します

s3-08.png

②CORS構成エディターに追加

下記のように追加してください

CORS
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
   <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

参照:
Cross-Origin Resource Sharing (CORS)
Direct to S3 File Uploads in Python | S3 Setup

1-4. IAM設定

①IAMを検索してクリック

a.png

②ユーザーをクリック

b.png

③ユーザー追加をクリック

c.png

④ユーザー名を入力、プログラムによるアクセスをチェック

d.png

⑤アクセス許可

S3を検索し、AmazonS3FullAccessにチェック

e.png

⑥オプションなし

オプションですが、今回は設定しません

f.png

⑦内容を確認して作成

g.png

⑧IAM設定完了

後ほど、アクセスキーIDシークレットアクセスキーを使いますので、画面を閉じないでください

i.png

参照:IAMとは

2. アプリ設定

2-1. インストール

①django-storagesインストール

terminal
$ pip install django-storages

参照:django-storages | Amazon S3

②boto3インストール

terminal
$ pip install boto3

参照:
Boto 3 Documentation
AWS SDK for Python (Boto3)

2-2. settings.py設定

下記のように追加してください

settings.py
    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'your_app_name',
    'storages', #追加
]

    #追加
    AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
    AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
    AWS_STORAGE_BUCKET_NAME = os.environ['AWS_STORAGE_BUCKET_NAME']

    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
    MEDIA_URL = S3_URL

    AWS_S3_FILE_OVERWRITE = False
    AWS_DEFAULT_ACL = None

2-3. 環境変数

Herokuの環境変数を3つ設定します。

①AWS_ACCESS_KEY_ID②AWS_SECRET_ACCESS_KEYは、IAMユーザーを追加した際に表示された、アクセスキーIDシークレットアクセスキーになります。

③AWS_STORAGE_BUCKET_NAMEは作成したバケット名です。

terminal
$ heroku config:set AWS_ACCESS_KEY_ID="ご自身のアクセスキーIDを記入"
$ heroku config:set AWS_SECRET_ACCESS_KEY="ご自身のシークレットアクセスキーを記入"
$ heroku config:set AWS_STORAGE_BUCKET_NAME="ご自身のバケット名を記入"

参照:
Configuration and Config Vars | Heroku
Django Docs | Deployment checklist

2-4. requirements.txt

インストールしたモジュールをrequirements.txtに追加します。

terminal
$ pip freeze > requirements.txt

2-5. local_settings.py設定

もしlocal_settings.pyを使用している場合は、下記を参考にしてください。

ローカル環境ではMEDIA_ROOTで指定したディレクトリから読み込み、HerokuではS3から読み込むことができます。

settings.py
###
省略
###

DEBUG = False

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'your_app_name',
    'storages',
]

###
省略
###

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

try:
    from .local_settings import *
except ImportError:
    pass

if not DEBUG:
    SECRET_KEY = os.environ['SECRET_KEY']

    AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
    AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
    AWS_STORAGE_BUCKET_NAME = os.environ['AWS_STORAGE_BUCKET_NAME']

    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
    S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
    MEDIA_URL = S3_URL

    AWS_S3_FILE_OVERWRITE = False
    AWS_DEFAULT_ACL = None

    import django_heroku
    django_heroku.settings(locals())

db_from_env = dj_database_url.config(conn_max_age=600, ssl_require=True)
DATABASES['default'].update(db_from_env)
local_settings.py
import os

SECRET_KEY = 'ご自身のSECRET_KEYを記入'

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

DEBUG = True

最後に

Herokuでのデプロイが曖昧でしたら、下記の記事も参考にしてみてください。

DjangoアプリをHerokuにデプロイする方法

以上

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

【参加レポート】AWS Summit Tokyo 2019 Day1にいってきた!

image.png

めちゃくちゃ出遅れましたが、AWS Summit Tokyo 2019 Day1に参加してきましたので、参加レポートを書きたいと思います。

結論から書くと、去年より遥かにグレードアップしている部分が多数あると感じられました。
具体的に何がグレードアップしていたかについては、記事の中でご紹介させていただこうと思います。

AWS Summit Tokyoについて

まずはじめに、AWS Summit Tokyoを知らないという人のために、AWS Summit Tokyoのご説明を致します。

AWS Summit Tokyoは、Amazon Web Serviceが公式で開催しているAWSの祭典です。
IT系のカンファレンスの中では日本最大級の規模になっており、合計 250 以上セッションやデモンストレーション、ハンズオンワークショップを実施しています。

年々、来場者数が増加しているらしく、AWS Summit Tokyo 2019では、初の幕張メッセでの開催となりました。

セッション以外でも、AWSのエキスパートに質問や相談ができるブースや、スポンサー企業のブースなど、様々なコンテンツが用意されています。

より詳しい情報は、公式ページに掲載されておりますので、ご興味のある方はご確認ください。
https://aws.amazon.com/jp/summits/tokyo-2019/

AWS Summit Tokyo 2019のグレードアップポイント!

今回のAWS Summit Tokyo 2019では今までのものと比較しても、大規模にグレードアップしているポイントがいくつもありました。
その中でも、よりすぐりのグレードアップポイントについて、ピックアップしてご紹介したいと思います。

1. 会場がグレードアップ!

まず、大きな変化としては、会場が幕張メッセになったことです。

去年までは、品川プリンスホテルでの開催でした。
品川ということで、職場からのアクセスは大変良かったのですが、セッション会場間の移動が大変だったり、企業ブースがセッション会場と別部屋になっていました。

しかし、幕張メッセでの開催になったことで、企業ブースとセッション会場がシームレスに同じ空間に存在する形になりました。
一部のセッション会場を除いた殆どのセッション会場が同じフロアにあるので、セッション会場の移動がとても楽になりました。

また、DeepRacerのレース会場があったり、

空中にNewRelicさんの広告付きの電車が走るなど、豪華さに拍車がかかっていました!
(写真を取り忘れました... :bow:)

2. アメニティが豪華

スポンサーブースやExpoブースで貰えるアメニティがとても豪華になっていたように感じました。

去年はアンケートに答えると、PCのカメラ部分を隠すウェブカメラカバーがもらえたのですが、今年は冷感タオルと、アイスがもらえました!

認定者ラウンジも、去年は認定者シールを貰えましたが、今年はステンレスボトルと、認定者バッチを貰えました。

僕は毎年チャレンジしていたSIOSさんのくじで、ようやくCoatiマグカップをGetすることができました!

3. セッション

セッションもかなり豪華になっていました!

特に基調講演が始まる際にはダンサーによるオープニングアクトがあるなど、本当にテックカンファレンスなのかを疑うほどの豪華さでした。

基調講演の内容を簡単にまとめると、

  1. 前年同期比で41%の成長
    • クラウドを使う1/2がAWSを選択
  2. AWSのIT人材の育成
    • AWS Loft Tokyo
    • AWS Dev Day
    • AWS Innvocate
    • AWS Educate
  3. クラウドジャーニー
    • Windows対応
    • Redshiftのパフォーマンス10倍
  4. 「全ての開発者に機械学習を」
    • SageMaker
    • DeepRacer
    • トレーニングマテリアルの日本語化

という感じです。
相変わらず、成長率が凄まじいですね...。

去年に引き続き機械学習に力を入れていき、IT人材の育成にも力を入れていくみたいですね (ありがたい...)。

まとめ

去年より遥かにグレードアップし、益々成長を遂げているAWS Summitでした!

次は、6/27にAWS Summit Osaka 2019が開催されます。

そして、来年のAWS Summit Tokyoの会場は横浜だそうです!
(今回もだけど、もはやTokyoじゃないw)

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

EC2とELBで、URLごとに別のサーバにルーティングする

イントロ

EC2で構築したUiPath Orchestrator サーバを、自己署名じゃない証明書でSSLで公開する(Certificate ManagerとELBを使用) のつづきです。
自己署名証明書で動いているIISのOrchestratorサーバを、ELBを用いて正式な証明書を使ったサーバとして公開するところまでをやりました。

残りは、URLが「https://ela.example1.xyz/ 」の時は、Elasticsearchサーバへルーティングする設定の追加です。
cont.png

もろもろ前提などは、前回の記事 をご確認ください。

やってみる

ロードバランサの設定画面で「ルールの表示/編集」をクリック。
e01.png

ルーティングを追加するために上部の「プラス」をクリック。
e02.png

ルールを追加するために「ルールの挿入」をクリック。
e03.png

URLが 「https://ela.example1.xyz/ 」の時だったら を追加するため、プルダウンから「ホストヘッダー...」を選択。
e04.png

「ela.example1.xyz」と入力しチェックマークをクリック。
e05.png

IF(左側)が確定しました。続いてTHEN(右側です) ですが、プルダウンから「転送先」を選択し、転送先のターゲットグループとして前回作成した「ela」を選択。チェックマークをクリックすると、、
e06.png

「アクセス先が ela.example1.xyz だったら、ターゲットグループ ela に転送する」という設定が追加されました。右上の「保存」をクリックします。
e07.png

追加されました!
e08.png

さて https://ela.example1.xyz/ へアクセスしてみると、、表示されましたねーーー。。
e09.png

この Application Load Balancer の ホスト名ベースのルーティング機能によって、一台のロードバランサを使って、様々なサーバにリバースプロキシできるわけですね。とても便利です。
UiPath Orchestrator の構築の観点からも、メインのOrchestratorサーバとElasticsearchサーバを、一台のロードバランサでURLで振り分けできることが確認出来ましたね。

おつかれさまでした。

関連リンク

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

Terraform - リポジトリ構造と活用範囲を考える

はじめに

Terraform に入門すると、最初に簡単な VPC を作成するまでは早いですが、実運用を見越して terraform.tfstate の管理方法について考えたり、効率的なディレクトリ構成について考えたりすると手が止まってしまいます。

入門時期を終えて、書籍『Pragmatic Terraform on AWS』 を読んで Terraform のお作法について学び直したところなので、これまで得た知見を整理するために記事を書いてみます。

書くこと

  • Terraform の使い所
  • Terraform で実装したリポジトリの例とサンプルコード(一部)

書かないこと

  • Terraform の使い方・インストール方法

Terraform の運用方法

Terraform でクラウド環境を構築するだけなら直ぐですが、「構築した環境の上で動作するアプリケーションのライフサイクルについて」や、「AWSアカウント直後から、対象の環境で Terraform を初めて実行するまで」のことを考えると、色々と考えることが多くなります。

実際の構築順序

今回の記事は「Terraformで全ては構築しない」という前提で記載しています。
これを踏まえて、「AWSアカウントを取得して基本設定を終わらせた状態」から「アプリケーションをデプロイする」までをまとめると次の3つのステップが必要になります。

  1. アカウントの基本設定とtfstate保存領域の確保
  2. Terraform によるインフラの構築
  3. Terraform 対応範囲外のインフラ構築(GUI、CUI)

このうち、2) のみが Terraform の実行によって環境を構築するフェーズです。

image.png

1. アカウントの基本設定とtfstate保存領域の確保

AWSアカウントを取得して、本当の直後は次のようなサイトを参考にして設定を行います。

この設定が終わったら、 Terraform で作業を行うために次のような設定を行います。

  1. 作業ユーザの作成
  2. access_key, secret_key の発行
  3. backend 用の S3 Bucket の作成

また、状況に応じて Terraform 実行前にやることとして、以下のようなこともあるかもしれません。

  • Elastic IP の発行(外部IF として固定が必要なものなど)
  • ドメインの取得 と Route 53 の設定
  • ACM を使用した SSL証明書の登録

cf. Multi-account AWS Architecture - Terraform by HashiCorp

ideally the infrastructure that is used by Terraform should exist outside of the infrastructure that Terraform manages.

2. Terraform によるインフラの構築

詳細については、「Module のお作法を整理する」以降の節で記載します。

3. Terraform 対応範囲外のインフラ構築(GUI、CUI)

アプリケーションのデプロイなど、Terraform が構築したシステム・インフラの上にのるリソースのデプロイを行います。

  • Elastic Beanstalk アプリケーション
  • AWS Lambda アプリケーション
  • API Gateway アプリケーション

ただし、この 3) については、自分の中でも悩みの多いところであり、どのように役割分担してゆくか戸惑っている箇所です。

Module のお作法を整理する

まず最初に、Terraform でインフラを構築するにあたって避けては通ることの出来ない module について整理します。

Standard Module Structure

Terraform の公式サイトでは Standard Module Structure ( 標準モジュール構造 ) として次の2つの構成が紹介されています。
cf. Creating Modules - Terraform by HashiCorp

  • minimal recommended module
  • complete example of a module

構造のルール

構造のルールとして次のようなことが記載されています。

  • Root module : リポジトリのルートディレクトリに「Terraform files」を配置しなければならない。
    これがモジュールの primary entrypoint となる。
  • README : Root module と ネストされた moduleは README を配置した方が良い。
    input や output はツールで自動生成できるため、記載する必要はない。
  • LICENSE : Public にモジュール公開するなら、あった方が良い。
  • main.tf, variables.tf, outputs.tf : 最小モジュールとして推奨されるファイル名。空でもあったほうが良い。
  • Variables and outputs should have descriptions. : 全ての variable と output に1~2行の説明を記載しましょう。
  • Nested modules. : module は modules/配下に配置しましょう。module は可能な限り複雑さを排除した振る舞いを記載し、README に用法を記載しましょう。
    Root moduleNested modules を呼ぶ場合、個別のリポジトリにせずに全て1つのリポジトリで管理するようにしましょう。
  • Examples. : module の使用方法を記載した example は examples/ 配下に配置しましょう。
    example には README を配置し、用法のゴールを記載しましょう。

A minimal recommended module

例)最小構成
$ tree minimal-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf

A complete example of a module

例)全体構成
$ tree complete-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│   ├── nestedA/
│   │   ├── README.md
│   │   ├── variables.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   ├── nestedB/
│   ├── .../
├── examples/
│   ├── exampleA/
│   │   ├── main.tf
│   ├── exampleB/
│   ├── .../

Terraform リポジトリの構造を検討する

Terraform によって システムのインフラを構築する際に実装するリポジトリの構造について検討します。

基本コンセプト

検討にあたっての基本コンセプトは次の通りです。

  1. コンポーネント分割
  2. 環境分割
  3. ローカル・モジュール
  4. Backend は AWS S3 で管理

1. コンポーネント分割

書籍『Pragmatic Terraform on AWS』「17.4 コンポーネント分割」という節があります。

ここには次のような記載記載があります。

環境は分かりやすい境界です。ひとつの環境につき、ひとつのtfstate ファイルというのは
素直な考え⽅です。しかし、この考え⽅にはデメリットがあります。ひとつのtfstate ファイ
ルでその環境のすべてのリソースを管理すると、ひとつのミスが全体に影響を与えてしまいま
す。また、Terraform の実⾏にも時間がかかります。そこで、環境を複数のコンポーネントに
分割しましょう。
引用:「KOS-MOS(2019).『Pragmatic Terraform on AWS』v1.0.0, 146-149

また、具体的な例として次のような指針が示されています。

  • 安定度が高いコンポーネントとそれ以外の分離
  • ステートフルなリソース(ストレージやデータストア)の隔離
  • (エンドユーザへの)影響範囲が異なるものの分割
  • 組織のライフサイクルに関わるリソースの分離
  • 関心事の分離

これらの記載を踏まえると、例えば「VPC」「RDS」「EC2」「IAM」といった異なる役割を持つリソースを1つの tfstateファイル で保持することが好ましくないことがわかります。

そのため、今回は記事「terraformはどの単位で分割すべきか - Qiita」を参考にしてコンポーネントの分割を行うことにしました。

2. 環境分割

ここで言う環境とは、Terraform によって構築する対象のサービスが「本番」「検証」「開発」のどの用途で使用されるといった意味で使用します。
この環境の定義の方法は次の2つの方法があります。

  • ディレクトリ分割型
  • workspace型

インターネット上には「ディレクトリ分割型」で環境を定義する例が多く、記事「Terraform 運用ベストプラクティス 2019 ~workspace をやめてみた等諸々~ - 長生村本郷Engineers'Blog」では「workspace型」のデメリットによって「ディレクトリ分割型」に戻したという旨の記載があります。

また、書籍『Pragmatic Terraform on AWS』には、2018 年9 ⽉に⾏われたHashiCorpJapan Meetup において、workspace型の利用者は少数派で、多くのユーザがディレクトリ分割を行っていたとの記載があります。

一方で、workspace型の活用例も確かに存在し、そちらの実例の方が魅力に感じたため、今回は workspace型 を採用することにします。

3. ローカル・モジュール

Module Sources - Terraform by HashiCorp」によると、module block が source として指定出来るものとして次の方法が紹介されています。

今回、この中で使用するのは「Local paths」です。

4. Backend は AWS S3 で管理

これはもう当然の選択ですが、Backend に AWS S3 を指定して terraform.tfsate を管理する方式を採用します。

プロジェクト構成

Standard Module Structure をベースに、前述の基本コンセプトを考慮して設計したディレクトリ構成が以下です。

構成例
$ tree sample-project/
.
├── README.md
├── LICENSE
├── .secret
├── .gitignore
├── ...
├── bin             <--- リポジトリの初期化 
│   ├── init_components.sh
│   ├── init_s3.sh
│   ├── init_s3.bat
│   ├── config/
├── environments/   <--- 環境ごとの変数を定義
│   ├── common
│   │   ├── terraform.tfvars
│   ├── product
│   │   ├── terraform.tfvars
│   ├── staging
│   ├── develop
│   ├── default
├── modules/   <--- Local Module
│   ├── nestedA/
│   │   ├── README.md
│   │   ├── variables.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   ├── nestedB/
│   ├── .../
├── components/   <--- コンポーネント分割した設定群
│   ├── network/
│   │   ├── README.md
│   │   ├── main.tf        <--- 基本となる処理を記載
│   │   ├── variables.tf   <--- variables を記載
│   │   ├── outputs.tf     <--- output ブロックを記載
│   │   ├── backend.tf     <--- リモートステートを記載(terraformブロック、dataブロック)
│   │   ├── provider.tf    <--- provider を記載
│   │   ├── .terraform
│   ├── firewall/
│   ├── iam/
│   ├── s3/
│   ├── datastore/
│   ├── application/
│   ├── operation/
│   ├── .../

Terraform を実際に実行するのは、 components配下にある任意のコンポーネント・ディレクトリの下で実施します。

大雑把な構成図は以下の通りです。

image.png

Sample Code

firewallコンポーネントを例に、コンポーネント配下のコード例を記載します。

backend

リモートステート情報を定義する components/firewall/backend.tf の例は次の通りです。

components/firewall/backend.tf
terraform {
  required_version = "0.12.3"
  backend "s3" {
    region  = "ap-northeast-1"
    encrypt = true

    bucket = "<unique-bucket-name>"
    key    = "firewall/terraform.tfstate"

    profile = "profile-name"
  }
}

data "terraform_remote_state" "network" {
  backend = "s3"

  config = {
    bucket = "<unique-bucket-name>"
    key    = "env:/${terraform.workspace}/network/terraform.tfstate"
    region = "ap-northeast-1"

    profile = "profile-name"
  }
}

terraformブロックの backend を指定すると、以下のような PATH で remote state が作成されます。

unique-bucket-name/env:/${terraform.workspace}/firewall/terraform.tfstate

variables

変数情報を定義するcomponents/firewall/variables.tf の例は次の通りです。

components/firewall/variables.tf
variable "common" {
  type = map(string)

  default = {
    "default.region"  = "ap-northeast-1"
    "default.project" = "project-name"
  }
}

main

基本となる処理を定義するcomponents/firewall/main.tf の例は次の通りです。

components/firewall/main.tf
module "firewall" {
  source = "../../modules/nestedB"

  common = var.common
  vpc    = data.terraform_remote_state.network.outputs.vpc
}

provider

providerを定義するcomponents/firewall/provider.tf の例は次の通りです。

components/firewall/provider.tf
variable "aws_access_key" {
}

variable "aws_secret_key" {
}

provider "aws" {
  version    = "= 2.18.0"
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region     = "ap-northeast-1"
}

terraform.tfvars

環境ごとに定義する変数ファイル environments/common/terraform.tfvars の例は次の通りです。

environments/common/terraform.tfvars
region = "ap-northeast-1"
cidrs = [ "10.0.0.0/16", "10.1.0.0/16" ]
amis = {
  "ap-northeast-1a" = "ami-abc123"
  "ap-northeast-1c" = "ami-def456"
}

workspace

各コンポーネント・ディレクトリ配下に次の4つの workspace を作成します。

command
terraform workspace list
* default
  develop
  product
  staging

AWS CLI profile

backend で指定する AWS S3 にアクセスするための profile 情報を設定します。

.aws/credentials
[profile-name]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Backend用 AWS S3 Bucket 作成スクリプト

AWS CLI を使用して S3 Bucket を作成します。

bin/init_s3.bat
@echo off

set profile_name=%1
set bucket_name=%2

aws s3 mb s3://%bucket_name% ^
  --profile %profile_name%

aws s3api put-bucket-versioning ^
  --profile %profile_name% ^
  --bucket %bucket_name% ^
  --versioning-configuration Status=Enabled

aws s3api put-bucket-encryption ^
  --profile %profile_name% ^
  --bucket  %bucket_name%  ^
  --server-side-encryption-configuration file://config/config-public-access-block.json

aws s3api put-public-access-block ^
  --profile %profile_name% ^
  --bucket %bucket_name% ^
  --public-access-block-configuration file://config/config-public-access-block.json
bin/config/config-public-access-block.json
{
    "Rules": [{
        "ApplyServerSideEncryptionByDefault": {
            "SSEAlgorithm": "AES256"
        }
    }]
}
bin/config/config-bucket-encryption.json
{
    "BlockPublicAcls": true,
    "IgnorePublicAcls": true,
    "BlockPublicPolicy": true,
    "RestrictPublicBuckets": true
}

実行

terraformコマンドを実行する際は以下のようにします。
コマンドを実装するフォルダに注意してください。

command_bash
// 環境変数の設定を確認
export TF_VAR_aws_access_key="AKIAXXXXXXXXXXXXXXXXXX"
export TF_VAR_aws_secret_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo $TF_VAR_aws_access_key
echo $TF_VAR_aws_secret_key

// workspace の選択
terraform workspace select [ default / product / staging / develop ]

// 初期化
terraform init

// Dry run
terraform plan \
-var-file="../../environments/common/terraform.tfvars" \
-var-file="../../environments/$(terraform workspace show)/terraform.tfvars"
command_Powershell
// 環境変数の設定を確認
$env:TF_VAR_aws_access_key="AKIAXXXXXXXXXXXXXXXXXX"
$env:TF_VAR_aws_secret_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$env:TF_VAR_public_key_path=".\.secret\public"
$env:TF_VAR_aws_access_key;
$env:TF_VAR_aws_secret_key;
$env:TF_VAR_public_key_path;
Get-ChildItem env:

// workspace の選択
terraform workspace select [ default / product / staging / develop ]

// 初期化
terraform init

// Dry run
terraform plan `
-var-file="../../environments/common/terraform.tfvars" `
-var-file="../../environments/$(terraform workspace show)/terraform.tfvars"

まとめ

この記事のまとめです。

実現したこと

  1. コンポーネント分割によって、tfstateファイルで管理するリソースを分割
  2. Workspaces を使用して環境(本番、検証、開発)分割
  3. ローカル・モジュールしてリソースを定義
  4. AWS S3 を使用した terraform.tfstate の管理とバージョニング

課題

  1. 一つのリポジトリに複数のコンポーネントを管理する形になっており、terraform initの度に、実行ディレクトリに providerツールがインストールされる。
  2. Module Repogitory が良くわからない。
  3. 全体的に手探り

対策

  1. コンポーネントごとにリポジトリ設計した方が良いのかもしれない。
  2. これは使ってみるしかない。
  3. (悩ましい)

おわりに

記事を書いている途中に v0.11.x から v0.12.x に Terraform のバージョンを上げたら、書いていたコードが全然動かなくなってかなり焦りました。terraform 0.12upgradeコマンドを実行しましたが、万能ではないようです。

さすがにメジャーバージョンがまだ 0系だけあって、破壊的な変更というのがあるのですね。

Terraform が持つコアの機能は素晴らしくイメージも付きやすいものですが、実際に触ってみると HCL の記法や各構築対象サービスのお作法を押さえておく必要があり、最初の壁を乗り越えるまでが大変だという印象を受けます。
また、まだツール自体が成長段階ということもあり、次々の新しい記法やお作法が生まれており、そういった情報を把握して追従することにも一手間が生まれそうです。

ただ、そのコスト以上に、Terraform から得られるメリットの方が大きいため、もっと Terraform について知って行きたいと思います。

参考

今回の記事を作成するにあたって参考にした情報です。

ディレクトリ構造

Terraform の分割単位

State の管理

サンプル

Terraform v0.12.x

AWS S3 for terraform.tfstate

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

TerraformでFargateを扱う際にはまったポイントまとめ

はじめに

Terraformでインフラ構築(AWS)を勉強していて、Fargateを扱う際にはまったポイントをまとめました。

バージョン

  • Terraform v0.12.1

はまったポイント

エラー内容

Error: ClientException: No Fargate configuration exists for given values.

原因

タスク定義でFargate起動タイプを選択している場合、CPU, Memoryは以下の組み合わせから選ばなくてはならないが、

  cpu = 128
  memory = 256

のように設定していた。

CPU value Memory value (MiB)
256 (.25 vCPU) 512 (0.5GB), 1024 (1GB), 2048 (2GB)
512 (.5 vCPU) 1024 (1GB), 2048 (2GB), 3072 (3GB), 4096 (4GB)
1024 (1 vCPU) 2048 (2GB), 3072 (3GB), 4096 (4GB), 5120 (5GB), 6144 (6GB), 7168 (7GB), 8192 (8GB)
2048 (2 vCPU) Between 4096 (4GB) and 16384 (16GB) in increments of 1024 (1GB)
4096 (4 vCPU) Between 8192 (8GB) and 30720 (30GB) in increments of 1024 (1GB)

参考

No Fargate configuration exists for given values
https://code.thebur.net/2018/05/11/no-fargate-configuration-exists-for-given-values/

指定された CPU またはメモリの値が無効
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-cpu-memory-error.html


エラー内容

Error: ClientException: Fargate requires task definition to have execution role ARN to support ECR images.

原因

  • execution_role_arnを指定する必要があった

参考

terraformのmoduleで定義したresouseにアクセスするにはoutputしないとダメ
http://www.mpon.me/entry/2016/12/13/030907

https://github.com/ContainerSolutions/unifi-fargate


エラー内容

Error: InvalidParameterException: Network Configuration must be provided when networkMode 'awsvpc' is specified.

原因

  • network_configurationを設定する必要があった

参考

https://github.com/ContainerSolutions/unifi-fargate


エラー内容

Error: Incorrect attribute value type
Inappropriate value for attribute "subnets": element 0: string required.

解決方法

flattenを用いる

参考

Terraform 0.12 + vpc module v2.2 (Inappropriate value for attribute "subnet_ids": element 0: string required.) #271
https://github.com/terraform-aws-modules/terraform-aws-vpc/issues/271

その他はまったポイント

0.11と0.12での記述の仕方の違い

  • 主に ブロックタイプ (attr { … } という波括弧で記述する属性)と マップ (attr = { key = value } という記述をする属性) ではまりました
  • 参考

タイポ

  • 疲れていると謎のタイポをしています
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS IoT AnalyticsでCSVインポートの処理を作る

AWS IoT Analyticsをあまり利用したことがなかったので、利用した備忘録。ただ色々といじってみたかったので本来のIoT Analyticsの用途からは離れていることは受け入れる感じで。

こんな感じのことをやりたい

こういうのを実現するためにAWS IoT Analyticsは使えるんじゃないかな、と。(向いているとは言っていない)
Overview.png

  1. とあるバケットにCSVファイルが置かれる
  2. CSVファイル配置をトリガとしてLambdaがキックされ、中身をAWS IoT AnalyticsのChannelに送付する。(この際渡す量をAPI側で調整してあげれば、Pipeline内の処理性能はある一定以上は不要になるので、サイジングをシビアに考える必要がない)
  3. あとはStream処理でPipelineの中でやりたい処理を実施する。(今回はDynamoDBへのデータ格納)

Pipeline(AWS IoT Analytics)はVPCの中でLambda処理を動かすことはできないようなので、PipelineのLambdaからVPC内に配置したデータストアへのデータ格納はできないようですが、とりあえずこれができるだけでも色々とメリットを得られるので良さそうです。

  1. Channelはデータの受信したデータをバックアップとして保持しておくことが可能。それを用いてPipeline処理を再度実施することもできる。(例えばPipeline処理を更新したので再度同じデータを通しておく、と言うことも可能。この際データストアに保持されるデータは追加されるのではなく上書きされる仕組みも個人的には嬉しい)
  2. Pipelineを通したデータの一覧をデータセットとして確認することができる。なんならデータセットを利用して他の処理(AWS Batchなどを使った定期的な重めの処理)を実行することも可能。

全体の成果物は以下

とりあえず以降に説明する内容の成果物は以下に保存

https://github.com/kojiisd/aws-iot-csv-importer

データ配置後トリガで起動するLambdaの実装

早速実装に取り掛かります。図で言うところの②のトリガが発生した以降に起動されるLambdaの実装はこんな感じになります。

data_sensor.py
def convert_from_csv_to_json(file_path, bucket_name, header=False):
  df = pd.read_csv(file_path)
  tmp_json ={}

  if header:
    tmp_json = df.to_json(orient='records')
  else:
    tmp_json = df.to_json(orient='values')

  result_json_array = []
  for ele_json in json.loads(tmp_json):
    logger.info(ele_json)
    result_json = {}
    result_tmp_json = {}
    result_tmp_json['s3_bucket'] = bucket_name
    result_tmp_json['data'] = ele_json

    result_json['messageId'] = str(ele_json['account_number'])
    result_json['payload'] = json.dumps(result_tmp_json)
    result_json_array.append(result_json)

  return result_json_array


def send_data_lambda(event, context):

  bucket_str = event['Records'][0]['s3']['bucket']['name']
  bucket = s3_client.Bucket(bucket_str)
  key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
  file_path = TMP_PATH + key

  os.makedirs(os.path.dirname(file_path), exist_ok=True)
  bucket.download_file(key, file_path)

  json_array = convert_from_csv_to_json(file_path, bucket_str, True)

  for json_sub in chunked(json_array, DATA_BATCH_SIZE):
    response = iot_analytics_client.batch_put_message(
       channelName = 'csv_import_sample_channel',
       messages = json_sub
      )

  return 'All data sending finished.'

だいぶ雑なつくりですが、これでChannelに対してCSVデータを送付することができます。今回扱っているデータはElasticsearchのサンプルで使われるデータのaccounts.csvを利用しています。こんな感じのデータです。

accounts.csv
account_number,address,age,balance,city,email,employer,firstname,gender,lastname,state
1,880 Holmes Lane,32,39225,Brogan,amberduke@pyrami.com,Pyrami,Amber,M,Duke,IL
6,671 Bristol Street,36,5686,Dante,hattiebond@netagy.com,Netagy,Hattie,M,Bond,TN
13,789 Madison Street,28,32838,Nogal,nanettebates@quility.com,Quility,Nanette,F,Bates,VA
18,467 Hutchinson Court,33,4180,Orick,daleadams@boink.com,Boink,Dale,M,Adams,MD

これをそれぞれIoT Analyticsに流し込むことになりますが、IoT Analytics側は1データずつ送付されるとそれだけでPipelineの起動数が多すぎになってしまうため、Batch Sizeを調整してまとめてStream処理を走らせられるようにIoT AnalyticsのPipeline部分に設定をしています。

スクリーンショット 2019-07-07 16.52.45.png

これでデータが送られてきた際、Pipelineに100データずつ流し込んでくれるようになります。

Pipelineで呼び出されるLambda処理

無事Channelへのデータ送付がされたら、次にPipeline処理が呼ばれます。このようなコードを書きました。

csv_importer_store.py
def store_data_lambda(event, context):
  logger.info("Start store data: {}".format(event))

  bucket = s3_client.Bucket(event[0]['s3_bucket'])
  key = CONF_PATH
  file_path = TMP_PATH + key
  os.makedirs(os.path.dirname(file_path), exist_ok=True)

  bucket.download_file(key, file_path)
  conf_file = open(file_path, 'r')
  conf_json = json.load(conf_file)

  logger.info(conf_json)
  result_json_array = []
  tmp_json = {}

  for ev in event:
    tmp_json = {}
    for key, value in ev['data'].items():
      if key in conf_json.keys():
        tmp_json[conf_json[key]] = value
    result_json_array.append(tmp_json)

  ddb_table = ddb_client.Table(DYNAMODB_TABLE)

  with ddb_table.batch_writer() as batch:
    for item_json in result_json_array:
      batch.put_item(
        Item=item_json
        )

  return result_json_array

これで実行結果がDynamoDBに格納され、かつIoT Analyticsの時系列DBにも格納されるようになります。

実際に実行してみた結果

実際にCSVファイルをS3に配置して、この処理を通してみました。IoT Analyticsのデータセット部でクエリを発行することで実施結果が確認できました。(もちろんDynamoDBにもデータは入っていました。)

スクリーンショット 2019-07-07 16.58.29.png

DynamoDBにも問題なくデータが格納されています。

スクリーンショット 2019-07-07 17.05.14.png

これで無事に処理を通すことができました。

Pipelineの再処理を実施したくなったら?

もしPippeline内の処理を更新した、などで再度データを流したい場合は、AWS IoT Analyticsでポチポチするだけで実現できます。(もちろんCLIで実施することも可能です)

スクリーンショット 2019-07-07 17.11.26.png

Channelの右側から「メッセージの再処理」を選択します。

スクリーンショット 2019-07-07 17.11.42.png

期間でしか絞れないのが惜しいところですが、ここで期間を指定して、その期間でChannelが受信したメッセージをPipelineに再度流すことができます。

ちなみにCLIの場合はstart-pipeline-reprocessingで実施できます。

まとめ

今回はAWS IoT Analyticsが本来期待されている目的とは少し異なる利用法を試してみましたが、IoT ANayticsが持っているメッセージ再処理などの特徴をうまく利用することで、CSVインポート処理を任せてみることもできそうだ、と言うこともわかりました。様々な活用法があるとは思うので、模索していきたいところです。

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

Zappa利用時のトラブルシューティング集

そもそもZappaとは

Github(英語): https://github.com/Miserlou/Zappa
日本語訳: https://githubja.com/miserlou/zappa

Zappa makes it super easy to build and deploy server-less, event-driven Python applications (including, but not limited to, WSGI web apps) on AWS Lambda + API Gateway. Think of it as "serverless" web hosting for your Python apps.

とのこと。FlaskやDjangoなどのWebアプリケーションフレームワークを利用したPythonアプリをAWS Lambdaへデプロイする際にとても役に立つ。

Zappa利用時のトラブルシューティング集

以下、Zappa利用時に遭遇した事象とトラブルシューティング方法を記載していく。

zappaコマンド(templateなど)を実行するとNoRegionErrorとなる

事象
$ zappa template dev -l ${your-lambda-arn} -r ${your-role-arn}
Calling template for stage dev..
Warning! AWS Lambda may not be available in this AWS Region!
Warning! AWS API Gateway may not be available in this AWS Region!
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
(中略)
botocore.exceptions.NoRegionError: You must specify a region.

==============

Need help? Found a bug? Let us know! :D
File bug reports on GitHub here: https://github.com/Miserlou/Zappa
And join our Slack channel here: https://slack.zappa.io
Love!,
 ~ Team Zappa!
対処法

zappa_settings.json"aws_region": "aws-region-name"を記載する。

zappa_settings.json
{
    "dev": {
        "app_function": "server.app",
        "aws_region": "ap-northeast-1",
        ...
    }
}

zappa templateコマンドを実行するとAttributeError: 'ZappaCLI' object has no attribute 'apigateway_policy'となる

事象
$ zappa template dev -l ${your-lambda-arn} -r ${your-role-arn}                                           
Calling template for stage dev..
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 2779, in handle
    sys.exit(cli.handle())
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 509, in handle
    self.dispatch_command(self.command, stage)
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 553, in dispatch_command
    json=self.vargs['json']
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 666, in template
    policy=self.apigateway_policy,
AttributeError: 'ZappaCLI' object has no attribute 'apigateway_policy'

==============

Need help? Found a bug? Let us know! :D
File bug reports on GitHub here: https://github.com/Miserlou/Zappa
And join our Slack channel here: https://slack.zappa.io
Love!,
 ~ Team Zappa!
対処法

zappaのバージョンを0.47.0に下げる必要がある。

$ zappa -v
0.48.2
$ pipenv install zappa==0.47.0 --skip-lock
Installing zappa==0.47.0…
Adding zappa to Pipfile's [packages]…
✔ Installation Succeeded 
Installing dependencies from Pipfile…
     ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 1/1 — 0

zappa deployupdateコマンドを実行するとStatus check on the deployed lambda failed. A GET request to '/' yielded a 500 response code.となる

事象
$ zappa deploy dev
Calling deploy for stage dev..
Downloading and installing dependencies..
 - markupsafe==1.1.1: Using locally cached manylinux wheel
 - sqlite==python3: Using precompiled lambda package
Packaging project as zip.
Uploading app-dev-1560529924.zip (8.5MiB)..
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████| 8.91M/8.91M [00:00<00:00, 20.6MB/s]
Scheduling..
Scheduled app-dev-zappa-keep-warm-handler.keep_warm_callback with expression rate(4 minutes)!
Uploading app-dev-template-1560529930.json (1.6KiB)..
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.60K/1.60K [00:00<00:00, 24.2KB/s]
Waiting for stack app-dev to create (this can take a bit)..
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:15<00:00,  5.84s/res]
Deploying API Gateway..
Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 500 response code.
対処法

コマンドでのデプロイ時に動作確認としてAPI Gatewayの/リソースに対してGETリクエストが行われるが、そのリクエストに対するLambdaからのレスポンスが500エラーとなっている。
Lambda側の実行ロールの権限やソースコードに問題がないか確認をする。

参考

https://github.com/Miserlou/Zappa/issues/1747

以上

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

Zappa利用時におけるトラブルシューティング集

そもそもZappaとは

Github(英語): https://github.com/Miserlou/Zappa
日本語訳: https://githubja.com/miserlou/zappa

Zappa makes it super easy to build and deploy server-less, event-driven Python applications (including, but not limited to, WSGI web apps) on AWS Lambda + API Gateway. Think of it as "serverless" web hosting for your Python apps.

とのこと。FlaskやDjangoなどのWebアプリケーションフレームワークを利用したPythonアプリをAWS Lambdaへデプロイする際にとても役に立つ。

Zappaによるサーバーレスアプリ開発でのトラブルシューティング集

以下、Zappaによるサーバーレスアプリ開発時に遭遇したトラブル事象とそのシューティング方法を記載していく。

1. zappaコマンド(templateなど)を実行するとNoRegionErrorとなる

事象
$ zappa template dev -l ${your-lambda-arn} -r ${your-role-arn}
Calling template for stage dev..
Warning! AWS Lambda may not be available in this AWS Region!
Warning! AWS API Gateway may not be available in this AWS Region!
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
(中略)
botocore.exceptions.NoRegionError: You must specify a region.

==============

Need help? Found a bug? Let us know! :D
File bug reports on GitHub here: https://github.com/Miserlou/Zappa
And join our Slack channel here: https://slack.zappa.io
Love!,
 ~ Team Zappa!
対処方法

zappa_settings.json"aws_region": "aws-region-name"を記載する。

zappa_settings.json
{
    "dev": {
        "app_function": "server.app",
        "aws_region": "ap-northeast-1",
        ...
    }
}

2. zappa templateコマンドを実行するとAttributeError: 'ZappaCLI' object has no attribute 'apigateway_policy'となる

事象
$ zappa template dev -l ${your-lambda-arn} -r ${your-role-arn}                                           
Calling template for stage dev..
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 2779, in handle
    sys.exit(cli.handle())
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 509, in handle
    self.dispatch_command(self.command, stage)
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 553, in dispatch_command
    json=self.vargs['json']
  File "/root/.local/share/virtualenvs/application-NgYdrrUH/lib/python3.6/site-packages/zappa/cli.py", line 666, in template
    policy=self.apigateway_policy,
AttributeError: 'ZappaCLI' object has no attribute 'apigateway_policy'

==============

Need help? Found a bug? Let us know! :D
File bug reports on GitHub here: https://github.com/Miserlou/Zappa
And join our Slack channel here: https://slack.zappa.io
Love!,
 ~ Team Zappa!
対処方法

zappaのバージョンを0.47.0に下げる。

$ zappa -v
0.48.2
$ pipenv install zappa==0.47.0 --skip-lock
Installing zappa==0.47.0…
Adding zappa to Pipfile's [packages]…
✔ Installation Succeeded 
Installing dependencies from Pipfile…
     ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 1/1 — 0
参考

https://github.com/Miserlou/Zappa/issues/1747

3. zappa deployupdateコマンドを実行するとStatus check on the deployed lambda failed. A GET request to '/' yielded a 500 response code.となる

事象
$ zappa deploy dev
Calling deploy for stage dev..
Downloading and installing dependencies..
 - markupsafe==1.1.1: Using locally cached manylinux wheel
 - sqlite==python3: Using precompiled lambda package
Packaging project as zip.
Uploading app-dev-1560529924.zip (8.5MiB)..
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████| 8.91M/8.91M [00:00<00:00, 20.6MB/s]
Scheduling..
Scheduled app-dev-zappa-keep-warm-handler.keep_warm_callback with expression rate(4 minutes)!
Uploading app-dev-template-1560529930.json (1.6KiB)..
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.60K/1.60K [00:00<00:00, 24.2KB/s]
Waiting for stack app-dev to create (this can take a bit)..
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:15<00:00,  5.84s/res]
Deploying API Gateway..
Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 500 response code.
対処方法

コマンドでのデプロイ時に動作確認としてAPI Gatewayの/リソースに対してGETリクエストが行われるが、そのリクエストに対するLambdaからのレスポンスが500エラーとなっている。
Lambda側の実行ロールの権限やソースコード自体に問題がないか確認をする。

4. zappa deployupdateコマンドを実行するとProvided role 'role_arn' cannot be assumed by principal 'events.amazonaws.com'.となる

事象
$ zappa update dev
Calling update for stage dev..
Downloading and installing dependencies..
 - markupsafe==1.1.1: Using locally cached manylinux wheel
 - sqlite==python3: Using precompiled lambda package
Packaging project as zip.
Uploading app-dev-1560527282.zip (8.5MiB)..
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████| 8.91M/8.91M [00:00<00:00, 23.3MB/s]
Updating Lambda function code..
Updating Lambda function configuration..
Uploading app-dev-template-1560527288.json (1.6KiB)..
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.60K/1.60K [00:00<00:00, 14.9KB/s]
Waiting for stack app-dev to update..
6res [00:09,  1.48s/res]                                                                                                                          
Deploying API Gateway..
Scheduling..
Unscheduled app-dev-zappa-keep-warm-handler.keep_warm_callback.
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
(中略)
cannot be assumed by principal 'events.amazonaws.com'.

==============

Need help? Found a bug? Let us know! :D
File bug reports on GitHub here: https://github.com/Miserlou/Zappa
And join our Slack channel here: https://slack.zappa.io
Love!,
 ~ Team Zappa!
対処方法

Lambda関数の実行ロールとしたいIAMロールの信頼されたエンティティにevents.amazonaws.comを追加する必要がある。

https://console.aws.amazon.com/iam/home より、対象のIAMロールで[信頼関係]タブ-[信頼関係の編集]から、ポリシードキュメントのevents.amazonaws.comを追記し、[信頼ポリシーの更新]をクリック。

以下はポリシードキュメントの編集例。

PolicyDocument_example.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "events.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
参考

https://silvaneves.org/provided-role-cannot-be-assumed-by-principal-eventsamazonawscom.html

以上

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

S3でパブリックアクセス可能なファイルを投稿する

はじめに

久しぶりに AWS で新規アプリケーション開発したらハマった。

2018/11 から S3 のパブリックアクセス機能がリリースされ、一工夫必要になったらしい。
https://aws.amazon.com/jp/blogs/news/amazon-s3-block-public-access-another-layer-of-protection-for-your-accounts-and-buckets/

ではどうすればいいのかという話。

パブリックアクセス機能についてはこちらを参照。
https://dev.classmethod.jp/cloud/aws/s3-block-public-access/

設定手順

下記の3つのいずれかの設定でパブリックアクセス可能なオブジェクトにできる。

公開権限を委任しアップロード時にパブリックアクセスを許可する

権限の委任以外は従来と同じ。

パブリックアクセス設定

  • 新しいアクセスコントロールリスト (ACL) を介して許可されたバケットとオブジェクトへのパブリックアクセスをブロックする
  • 任意のアクセスコントロールリスト (ACL) を介して許可されたバケットとオブジェクトへのパブリックアクセスをブロックする

の 2つをオフにする。

スクリーンショット 2019-07-07 11.45.32.png

あとは、ファイルアップロード時に acl でパブリックアクセスにすればOK。

aws s3 cp [任意のファイル] s3://s3-public-access-test/ --acl public-read

バケットポリシーで許可

下記のポリシーで、s3-public-access-test バケットの public フォルダ以下についてパブリックアクセスを許可している。

パブリックアクセス設定

下記の 2つを許可しておく。

  • 新しいパブリックバケットポリシーを介して許可されたバケットとオブジェクトへのパブリックアクセスをブロックする
  • 任意のパブリックバケットポリシーを介して、バケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする

スクリーンショット 2019-07-07 12.08.06.png

ポリシー

下記のポリシーを「アクセス権限」タブ内のバケットポリシーで設定する。
スクリーンショット 2019-07-07 12.13.36.png

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"AddPerm",
      "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::s3-public-access-test/public/*"]
    }
  ]
}

public ディレクトリ以下にアップロードされたファイルは常にパブリックアクセス許可された状態になる。

aws s3 cp [任意のファイル] s3://s3-public-access-test/public/

バケットポリシー & タグで制御

特定のタグが付与されたオブジェクトについて、パブリックアクセス許可のポリシーを適用する方法。
一括で権限を変更できるので一番スマートかもしれない。

タグの利用には別途料金がかかる。
https://aws.amazon.com/jp/s3/pricing/#S3_Storage_Management_pricing

タグの追加

バケット内の「プロパティ」タブから、タグを追加

key: public-object
value: yes
スクリーンショット 2019-07-07 12.42.38.png

パブリックアクセス設定

[バケットポリシーで許可]と同じ。

ポリシー

設定方法は[バケットポリシーで許可]と同じ。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::s3-public-access-test/*",
            "Condition": {
                "StringEquals": {
                    "s3:ExistingObjectTag/public-object": "yes"
                }
            }
        }
    ]
}

コマンド

cp 時に付与できないようでちょっと面倒。プログラムでアップロードするなら関係ないかも。

# ファイルアップロード
aws s3 cp ~/Downloads/5c886538.jpg s3://s3-public-access-test/public/ --profile=kol 
# タグを付与
aws s3api put-object-tagging --bucket s3-public-access-test --key "public/[任意のファイル]" --tagging 'TagSet={Key=public-object,Value=yes}' 

終わりに

AWS S3 でパブリックアクセス可能なファイルを投稿するための設定方法を記述した。
Techブログを書くなら数ヶ月前の自分に向けて書くと良いとどこかで読んだが、マジで自分に届け。

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

EC2で構築したUiPath Orchestrator サーバを、自己署名じゃない証明書でSSLで公開する(Certificate ManagerとELBを使用)

イントロ

UiPath Orchestrator を構築するにあたって、久しぶりにEC2でSSL証明書を取って環境構築したので、そのときの備忘。

タイトルは UiPath OrchestratorサーバをSSLで公開するってなってますが、実際はOrchestratorに特化した話ではなく一般的なEC2サーバのSSL公開の話って感じです。

前提

  • ドメインを持っている(example1.xyz としました)
  • そのドメインは、AWSのRoute 53で管理している
  • UiPath Orchestratorが、AWS上のEC2で(WindowsサーバのIIS上で)ポート443ですでに動いている
  • 今時点では Orchestratorサーバ(以下Orchサーバ)へは https://[IPアドレス]/ でアクセスしている
  • 保守のためそのEC2サーバへは 443の他RDP(ポート3389)やKibana(ポート5601)も許可している
  • Orchestratorが動くIISサーバは、SSL証明書が自己署名証明書なので、ちゃんとした証明書を用いるようにしたい
  • 監視とか冗長構成とかは、とりあえず今回は省略

記事開始時点を図示するとこんな感じ。
aws0.png

さてさて今回、UiPath Orchestratorを自己署名証明書で構築するところは省略していて、すでに構築済みとしています。そのOrchサーバを自己署名じゃない証明書で公開するのに

  • 証明書を正規に取得して自己署名証明書から置き換え Orchサーバをそのまま外部に「 https://orch.example1.xyz 」などで公開

してもよいのですが、今回は

  • Orchサーバの手前にELB(Elastic Load Balancer)を置いて、AWS上で無料で取得できるSSL証明書を用いる

ことにしました。ELBは特定のネットワークからのポート443,5601への接続のみ許可するモノとします。
図示するとこうです。
aws.png

ほんとはSSLをほどいてルーティングしたい、、

-- 2019/07/07追記 --
ちなみに本当は、ELBでSSLをほどいて IISにはHTTPのポート80で流したかったのですが、UiPath OrchestratorのインストーラがIIS上にSSL付きで構築してくれてしまうのと、さらにはURL Rewrite機能を用いて HTTPアクセスをHTTPSにリダイレクトまでしてくれていて、、、、これらをオフってIIS上にHTTPのOrchestratorを構築する手順が明確ではなかったからです、、、。バインドを80に替えて、URL RewriteをすべてDisableにすれば行けるのかもしれませんが未検証ですorz。
-- 2019/07/07追記 以上 --

-- 2019/07/07追記2 --
バインドをポート80を追加して、URL RewriteをOFFにしてみたのですが、
add02.png

add01.png

おお、Web画面も動くしなんかうまくいってそうな感じ、、、とおもったら、PC上からのロボットトレイからの接続・切断がNGに、、┐('〜`;)┌。。
add03.png

検証はまた後日かな、、、。
-- 2019/07/07追記2 以上 --

やってみる

さて構築の流れとしては、

すればよさそうです。ついでに同じELBを用いて

も入れてみます。

Certificate ManagerでSSL証明書をあらかじめ取得

AWS Certificate Managerを使って無料でSSL証明書を発行する にまとめました。証明書取得まではそれで行けると思います。

ELBの構築(の前のターゲットグループ作成)

ELBは処理を転送するのに、ターゲットグループというEC2インスタンスのグルーピングを用います。今回 Orchサーバのインスタンスをもつグループ「orch」と、あとで使うElasticsearchサーバのインスタンスをもつ「ela」というグループを作成します。先の図のココです。

pic.png

EC2 >> ターゲットグループ を表示して「ターゲットグループの作成」をクリック。
o01.png

今回はELBから、そのままHTTPS(ポート443) で待ち受けているIISサーバに転送するので、プロトコルはHTTPS、ポートは443とします。IISサーバではHTTPで待ち受けている場合は、プロトコルはHTTP、ポートはIISのポート(通常80かな)を設定します。
o02.png

作成が完了したら「閉じる」をクリック。
o03.png

つづいてターゲットグループにOrchサーバを登録するため「編集」をクリックします。
o04.png

Orchestratorサーバを選択して「登録済みに追加」をクリック。待ち受けるポートをインスタンスごとに個別に指定出来ますが、今回はターゲットグループに指定したポートと同じなのでそのままでOK。
o06.png

上に追加されたので、「保存」をクリック。
o07.png

保存されました。
o08.png

同様に、ela のターゲットグループも作ります。違うところは、ELBがHTTPSで受けた後、こちらのターゲットグループにはHTTPでポート5601でルーティングしますので、そのように設定します。
o09.png

ターゲットグループへのElasticsearchサーバの登録も忘れずに。。
o10.png

保存できました。
o11.png

以上で、各ターゲットグループの作成は完了です。

ELBの構築(Application Load Balancerの作成)

つづいて、主役のロードバランサの作成です。
l01.png

Application Load Balancerを選択。
l02.png

今回はHTTPSのみを受け付けるので、HTTPS/443を選択。アベイラビリティゾーンはとりあえず、自分が持ってるサブネットを指定しておきましょう。
l03.png

SSLの設定です。すでにさきほど作成済みであれば、ココに証明書として出てくるはずなのでそれを選択して次へ。
l04.png

ELBが属するセキュリティグループについて、グループはELB用に新規に作成します。このグループは外部からアクセスされるところになるので慎重に。今回はOrchestratorサーバを構築する記事なのであるIPアドレスたちからの接続のみを許可する設定としていますが、広く公開する場合は「任意の場所」を選択しましょう。
l05.png

さて、ルーティングするターゲットグループを指定します。まずはシンプルに、全てのリクエストを「orch」グループにルーティングするように設定します。
のちに「 https://ela.example1.xyz/ 」へのリクエストはSSLをほどいて別のグループ「ela」にルーティングさせますが、あと回しで。
l06.png

インスタンスとポート番号を確認します。
l07.png

最終確認。よければ「作成」をクリック。
l08.png

おお、作成できたようですね。
l09.png

一覧に戻ってみると、確かにELB001というロードバランサが作成できています。下の詳細にDNS名が表示されていますが、このサーバ名がロードバランサに割り振られたサーバ名になります。あとでもっとわかりやすいエイリアスをつけますが、これでアクセスできるようになったということですね。
l10.png

ここまででほぼ、ELBの構築は完了です。

ELBのセキュリティグループ → EC2のグループへの通信許可

つづいて上記のセキュリティグループのリンクをクリックして、ELB側でなくEC2インスタンス達側のセキュリティグループの設定を変更します。
sec.png

このままではELBからの接続が許可されていないことになるので 、ELBのセキュリティグループからEC2側のセキュリティグループへ、HTTPSのためのポート443と、Elasticsearch/Kibanaのためのポート5601 への通信を許可します。また下記のイメージの下から3つめ、元々あったHTTPS/443への直接通信はホントは削除した方がよいでしょう。EC2インスタンス直接アクセスは遮断し、ELBからのアクセスに限定するほうがよいからですね。
l11.png

いったん疎通確認

さてさてELBからのルーティングやセキュリティグループによる通信設定もできたので、いったんブラウザで https://[長いELBのDNS名]/ へアクセスしてみましょう。

l12.png

おなじみのUiPath Orchestrator画面が表示されましたねーー。。今のところ、サーバ名が証明書のCommon Nameと不一致のためSSL的にはエラーになってますが、アクセス自体はできるようになりましたね。

いやー記事にすると長くなりました。。

ELBのサーバ名をAWS Route 53(DNSサービス)で名前解決

さてさて、あとすこし。
先ほどの長ーいELBのサーバ名を、たとえば orch.example1.xyz とか ela.example.xyz などでアクセスできるよう、DNSサービスで名前解決します。

Route 53にアクセスして、該当ホストゾーンの設定画面を開き「レコードセットの作成」をクリック。
d01.png

名前に「orch」、エイリアスを「はい」にするとエイリアス先に、ELBのレコードが選択出来るようになるので、それを選択し「作成」をクリック。
d02.png

レコードが追加されました。簡単ですね。
d04.png

さてさて「 https://orch.example1.xyz/ 」 でアクセスしてみましょう。
d05.png

表示されましたねーー。。
サーバ名がSSL証明書のCommon Name: *.example1.xyz と一致しているため、先ほどのELBのサーバ名の時は発生していた証明書が不正っていうエラーも、今回は出ていない状態になりました!

最後に、ついでに同じ設定で「ela」というサーバ名も追加しておきます。

d06.png

Elasticsearchサーバのルーティングと疎通

ほぼ環境構築は完了です。まだ「 https://ela.example1.xyz へのアクセスは、Elasticsearch/Kibana サーバにHTTPでポート5601へルーティングする」という設定が入ってないのですが、改めて別記事で書こうと思います。

-- 2019/07/07 追記--
別記事書きました :-)
EC2とELBで、URLごとに別のサーバにルーティングする
-- 2019/07/07 追記 以上--

おつかれさまでした。

関連リンク

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

Datadog入門:AWS IAMロール作成とIntegrationのインストール

AWS:IAMロールの作成

1. DatadogのAWS accuntIDを確認する

2. AWS External ID を確認する

  1. Datadogのマイページから [Integrations] - [Integrations]
    image.png

  2. AWSアイコンをクリック
    image.png

  3. [configration]をクリックし、[AWS External ID]を控える
    image.png

3.AWS IAM管理画面 を開く

  1. [ロール]- [ロールの作成]をクリック

  2. [別のAWSアカウント]をクリック

    1. [アカウントID]に、上記で控えた「DatadogのAWS accuntID」を入力
    2. オプション「外部 ID が必要」にチェック
    3. [外部ID]に、上記で控えた「AWS External ID」を入力
    4. [次のステップ:アクセス権限]をクリック image.png
  3. [ポリシーの作成]をクリック
    image.png

4.[JSON]をクリックし、JSONでポリシーを定義。[ポリシーの確認]をクリック
image.png

5.[名前]を入力(例:DatadogAWSIntegrationPolicy)し、[ポリシーの作成]をクリック
image.png

6.ポリシーの作成が完了
image.png

7.先程作成したポリシー名でフィルタしてチェックする。[次のステップ:タグ]をクリック
image.png

8.[次のステップ:確認]をクリック
image.png

9.[名前]を入力(例:DatadogAWSIntegrationRole)し、[ロールの作成]をクリック
image.png

10.ロールが作成されたことを確認
image.png

Datadog:AWS Integrationの設定

  1. Datadogのマイページから [Integrations] - [Integrations]
    1. AWS accuntID を入力
    2. ロール名を入力(例:DatadogAWSIntegrationRole)
    3. [Install Configuration]をクリック
  • 反映まで30~60分程かかるまで待つこと。

以上。

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