2016年6月29日水曜日

ウェブサイトを HTTPS + CloudFront + S3 の環境に移行したのでその振り返り

先日、Apacheで配信していたWebサイトをS3+CloudFrontの環境に移行しました。そのときにやったことを備忘録としてまとめました。
個人的にハマって悩んだところや大事だなと思ったところは太字にしています。

0. 前提条件

  • 一通り構成を組んだ後でのテストでは、キャッシュがしぶとくてコンテンツ更新後の状況が再現できないことがあるので、Invalidationしまくったり、ブラウザキャッシュを削除しまくったりする必要がある。
  • 適当なテストドメインを用意できると良い。たとえば、 www.example.com について構築しようとしているのであれば、 www2.example.com などをテスト用として確保するとよい。
  • phpやrubyは動きません、Javascriptは動きます、Basic認証はできません、会員登録はできません(phpやrubyが必要なページは動かない)、などの制約事項があるので、非Techの関係者にネゴっとく必要がある。

1. S3の基本的な設定

  • なんでもいいのでバケットを作る。バケット直で自分が持っているドメインを紐付けようと思うなら、ドメイン名と全く同じバケット名(www.example.comのサイトを作りたい場合は、バケット名をwww.example.comにする。ドットは入力できないとエンジニアの直感でなんとなく思いがちだけど、普通に入力できる…。)にする必要があるが、多分不要。(未検証、今回はドメインと同じバケット名にしました…。)
  • 静的ウェブサイトホスティングを有効にする。
  • インデックスドキュメントはindex.html(他任意のファイル名でもOK)、エラードキュメントはerror.html(他任意ry)にする。
  • バケットに、html, access-logs, cf-logs のディレクトリを作成する。htmlがコンテンツ置き場、access-logがS3が直接ロギングするログ置き場、cf-logsがCloudFrontがロギングするログ置き場にする。
  • コンテンツを突っ込んでみて、静的ウェブサイトホスティング用のURLにアクセスして、コンテンツが表示されるかを確認する。

2. CloudFrontの基本的な設定

  • 基本的にはググって出てくるサイトを参考にしてよい。
  • Alternate Domain Names には、テスト用に確保しておいたドメインを入れる
  • Default Root Objectには index.html(もしくは特別な要件があればそれ)を入れる
  • LoggingはOnにして、コンテンツをホストするS3バケットと同じものを指定して、Log Prefixに cf-logs/ を入力する。
  • Origin Domain Name は S3バケット名ではなく、S3バケットの静的コンテンツWebホスティング用のエンドポイントにする。つまり、 www.example.com ではなくて、 www.example.com.s3-website-ap-northeast-1.amazonaws.com にする。
  • Origin Pathを /html にする。
  • Origin Protocol Policy は  HTTP Only にする。それ以外にするとS3内のコンテンツにアクセスできなくなって死ぬ。S3はHTPSをサポートしていない。HTTPSはCloudFrontがなんとかやるので、S3へはHTTPでアクセスさせてよい。
  • Viewer Protocol Policy を Redirect HTTP to HTTPS にする。これで、httpでアクセスしてきた人たちをhttpsに送らせることができる。
  • Object Cachingは明確なキャッシング作戦を用意している場合以外は、デフォルトでよい。
  • Forward HeadersやForward Cookies、Forward Cookiesはとくにそれを使ってやりたいことがなければNoneにする。
  • Compress Objects Automatically は Yesにする。gzip圧縮未サポートの端末はサポートを諦めて速度を取る。

3. DNS

  • CloudFrontのエンドポイントをドメインのCNAMEとして登録する。

4. S3によるリダイレクト

  • リダイレクトはS3の静的ウェブサイトホスティングの項目のところにXMLで入力する。
  • ルールは公式ページ他ググって付ける
  • 404時などにリダイレクトする場合は、エラーステータスによるリダイレクトを行う。書き方は公式ドキュメント参照。
  • 自サイト内でのリダイレクトは、同じドメインに対する別ホストリダイレクトみたいな書き方で定義する。
  • 上記があるため、本番切り替え直前まで、自サイト内リダイレクトには、CloudForntのホスト名を記述する必要がある。
  • なので、テスト用の一時的なドメインがあると便利。

5. CloudFrontによるHTTPS対応

  • SSL証明書はAWS-CLIよりIAMのSSL証明書置き場に送信する。
      aws --profile ebisol iam upload-server-certificate --server-certificate-name 画面に表示させたい証明書名 \
           --path /cloudfront/ \
           --certificate-body file://証明書ファイルのファイルシステム上のフルパス \
           --private-key file://秘密鍵ファイルのファイルシステム上のフルパス \
           --certificate-chain file://中間CA証明書ファイルのファイルシステム上のフルパス
  • ELBの置き場とは別物なので、すでにELB用にSSL証明書を登録してあったとしても、CloudFront用に再度登録する必要がある。
  • 登録できたら、General設定画面の [SSL Certificate]-[Custom SSL Certificate] がクリッカブルになるので、そこを変更する。

6. リリース作業

  • CloudFrontのAlternate Domain Namesをテスト用ドメインから本番用ドメインに変更する。
  • S3に記述したリダイレクトルールのうち、HostNameにテスト用ドメインを記述している箇所を全て本番用ドメインに書き換える。
  • DNSのCNAMEレコードをテスト用ドメインから本番用ドメインに切り替える。
  • 各種ページやリダイレクトルールについて表示確認を行う。変更前の状況が再現される場合は、CloudFrontから /* に対してInvalidationを行い、自分のブラウザのキャッシュも削除して、Invalidationが完了したあと再度確認する。
  • Invalidationが完了するまで確認しない。我慢できない気持ちが高まってくるけど、頑張って我慢する。
  • いろいろ考えると3時間ぐらい時間をネゴって確保しておいた方が良い。
  • あと、もし失敗した場合、2〜3日調査と改善に時間がかかる場合があるということも伝えたほうがいい。

7. AWS Lambda を利用した自動 Invalidation

  • このQiitaの記事内で公開されているLambda関数を自分のAWSでも動かす。(お世話になりました。)
  • ただLambdaにソースをアップロードするだけではだめで、IAMロールとポリシーを作る必要があるし、SNSトピックとサブスクライバも登録する必要がある。でもSNSはそんなに難しくない。
  • IAMロールは s3_CloudFront_Invalidator という名前で作成し、標準で用意されている AWSLambdaExecute というポリシーと、カスタムした CloudFrontInvalidation という自作ポリシーの2つを適用した。
  • CloudFrontInvalidation ポリシーはこんな感じにしたら動いた。
      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Action": [
                      "cloudfront:Get*",
                      "cloudfront:List*",
                      "cloudfront:CreateInvalidation",
                      "iam:ListServerCertificates"
                  ],
                  "Effect": "Allow",
                  "Resource": "*"
              },
              {
                  "Action": [
                      "s3:GetBucketLocation",
                      "s3:GetObject",
                      "s3:GetObjectAcl",
                      "s3:ListBucket",
                      "s3:GetBucketWebsite"
                  ],
                  "Effect": "Allow",
                  "Resource": [
                      "arn:aws:s3:::*"
                  ]
              }
          ]
      }
  • 設定画面で、ConfigurationタブのHandlerが、デフォルトではindex.handler みたいになっていると思うので、jsファイル名に合わせる。 丸パクリでいくなら、「s3-invalidation.handler」を入力する。



2016年6月28日火曜日

ELBのHTTPS暗号化方式から弱い方式を除外する方法

概要


暗号スイートという、暗号化技術の利用セットみたいな概念があります。HTTPS(SSL/TLS)通信では、複数の暗号スイートからクライアントとサーバが利用可能なものを自動で選択して利用します。
しかし、場合によっては、弱い暗号化方式を使われてしまい、セキュリティ強度が下がる場合があります。
また、攻撃者はそのような選択が可能な場合、攻撃プログラムに故意にそういう暗号スイートを選択させるようにしたりします。
今回は、セキュリティ強化のために、ELBが、弱い暗号化方式である3DESを利用しないようにします。

しっかり理解したい方は、解説されている方がいらっしゃいますので、そういうブログや、セキュリティ系の書籍等をご覧ください。


理解してるつもりの SSL/TLS でも、もっと理解したら面白かった話 · けんごのお屋敷 http://tkengo.github.io/blog/2015/12/01/https-details/


手順

  1. ロードバランサーの画面を開きます
  2. 対象のロードバランサータグを選択し、リスナータグを開きます。
  3. HTTPSの行の「暗号」をクリックし、カスタムセキュリティポリシーを選択します。
  4. 「SSL暗号」というリストの中から、「DES-CBC3-SHA」を外します。
  5. 「保存」をクリックすると反映されます。
  6. DESを利用した暗号化方式がリストアップされないことを確認します。
    以下の記事を参考にさせていただきました。
    【小ネタ】cipherscan で対象サイトの SSL cipher suite を確認する
    https://blog.cloudpack.jp/2014/07/29/cipherscan-ssl-cipher-suite/


ELBの暗号設定画面では、暗号化プロトコルも選択できます。
たとえばTLS1.2以外は使わせたくないぜ!という場合には、
同様にカスタムセキュリティポリシーの画面を開き、SSL プロトコル」から

これで、またひとつシステムがセキュアになりました。


2016年6月11日土曜日

条件判定値を引数にそのまま流用できないかを考える

自分向けのプログラミングTipsメモです。大した内容ではありません。
Gistにサンプルコードを書いてみたので、まずそれを貼りたいと思います。


コードは、AWSを操作するための Python版 AWS SDK(Boto3)を利用したプログラムの一部です。
仕事で書いているBoto3プログラムで、こういう場面がありました。
  • 取得した配列のある要素の値がTrueかFalseかで後続で実行する関数の引数を変えたい。
  • 関数の引数にはTrueかFalseを用いる

当たり前といえば当たり前ですが、条件判定しているTureかFalseを、そのまま関数の引数として与えれば、条件判定する必要がないんですよね。
こういう小さな省力化(短いコードで書く努力)を積み重ねることで、一個のサービスが出来上がった時に体感できるような差が生まれるのかなぁなどと思いました。

普段はサーバ管理みたいな仕事が多いので、こういう風にプログラミングに対して自分で「おっ、こうした方がいいじゃん?」みたいな思考ができたこと自体がなんだかとても嬉しくなりました。
こういう気持ちはたとえ小さくてもきちんと表現したり記録しておくことが精神衛生上、そして今後の技術力向上のモチベーション管理上も良いのかなぁと思って、ブログに書いておこうと思った次第です。

こういうTipsがまとまった本とか、あるのかな、普通にありそうだな。
プログラミングをもっと業務でできるようになりたいです。



スマートPythonプログラミング: Pythonのより良い書き方を学ぶ

2016年6月5日日曜日

転職して1年経ったので振り返ってみた2016年5月

今の会社に2015年5月に入社してから1年経ちました。
あっという間だった気もするし、すごく長かった気もします。
自分がどのくらいの仕事をして、何が新しくできるようになったのかを整理したいと思い、箇条書き形式でまとめてみました。
今の会社ではAWSを使っていて、AWSを使ったインフラ全般の構築運用を行うエンジニアとして働いています。
入社前はAWSもEC2をちょっと触ったことがあるぐらいで、インフラの知識もそんなに自信がない状態でした。(今もないですが…w)
AWSエンジニアとしてはまだまだジュニアだと思いますが、1年前には何もできなかったことを考えると、少しはできることが増えてきたなぁと思います。
会社の体制も大分変わり、1年前はエンジニアがCTOとインターンのみでしたが、私の他複数名のエンジニアが採用され、エンジニアチームができ、外部委託している部分を大幅に巻き取って、自分たちのプロダクトを自分たちで責任を持って育てる土壌ができたのかなと思います。

できるようになったこと

日々の設定変更作業

  • Ansibleの初歩的な利用法を学び、初歩的にAnsibleを導入して設定業務が効率化された。
    • サーバ新規構築時のエンジニアのアカウント作成、公開鍵配布、sudo可能化、個人ファイル配布がAnsibleで自動実行できるようになった。
  • Python AWS SDK (Boto3) を利用して、AWSの管理効率化スクリプトを幾つか作成できた。
    • 毎日すべてのEC2のAMIを自動バックアップ
    • 指定した世代より古いAMIとEBS Snapshotを自動削除
    • 各ELBに紐付いているEC2インスタンスの表示名、Public IP、ヘスルステータスを表示
    • ELBに紐付いているサーバを切り離したり、紐付いていいないサーバを接続させる
    • 指定したEC2のAMIを取得し、そのAMIから任意の台数のEC2インスタンスを作成

監視

  • Zabbixを導入し、一元的な監視が可能になった。
  • Zabbixが検知したトリガーをSlackに流し、タイムリーに社内に報告される体制ができた。
  • 一部のエラーに対してはZabbixで検知した障害をトリガーに復旧スクリプトを実行して自動復旧をすることができた。
  • Zabbixのグラフやスクリーン機能を利用することにより、プロダクトマネージャの上司が提携先に性能監視状況を説明することができるようになった。

スケーリング・パフォーマンスチューニング

  • クラウドMSPに連絡しないとサーバがスケールアウト出来ない状況だったが、手元のスクリプトで任意に手動スケールアウトできるようになった。
  • Prefork駆動のAPIサーバをWorker駆動に変更し、サーバ1台あたりの処理量が大幅に増加した(5倍以上)。
  • 多数のサーバの仮想化方式をPVからHVMに変更し、m4などの新しいインスタンスタイプが選択できるようになった。拡張ネットワーキングも自動で適用され、たぶん処理スピードも向上した。
  • と同時に、ステージング環境や開発環境の最小インスタンスサイズにt2.microが選べるようになった。それまでt1しか選べなかった。

開発環境

  • ステージング環境を本番環境と同様の構成にして、コンポーネント間の動作確認がきちんと行えるようになった。
  • ステージング環境のDBのデータを本番と同様にすることができた。
  • Let's Encryptを導入し、ステージング環境のHTTPS接続を無料で実装することができた。

コスト

  • クラウドMSPのパッケージング契約から請求代行に移行し、月額費用の削減が出来た
  • 顧客企業のキャンペーンでバーストして対応した際に、スケールアウトによる追加費用を計測し、社内に共有できるようになった

自分の成果ではないがエンジニアチームができるようになったこと

  • Circle CIを使って、一部の領域で楽勝デプロイができるようになった。GithubのPull RequestをマージしたらCIが実行され、決まったテストを自動で行い、問題ない場合にデプロイされる。
  • リリース時にリリース内容、リリース順序、リリース手順を明記して社内に掲示することができるようになった。
  • アプリケーションの開発を外部に委託していたが巻き取り、自主性の確保とコストダウンを行うことができた。
  • re:dash によるデータ分析を営業などの非Tech系のチームに提供できるようになった

できていないこと、やりたいこと

挙げればキリが無いので、手をつけたところでできていないところをいくつか…。
  • 残っているPV型のEC2インスタンスをすべてHVM型で置き換え
  • 複数役割を持っているEC2インスタンスの完全退役
  • オートスケーリング
  • Zabbixの状態異常検知をトリガーとした自動復旧機能をもっと増やす
  • スポットインスタンスの実践活用
  • インフラ系ドキュメントの充実
  • ログ集約、分析システム(fluentd,ElasticSearch等)の導入


読んだ本について

AWSの本は入社前の休暇に、これらの本を精読しました。今振り返ると2冊しか読んでませんでした…。
それ以降アップデートできていないので、お財布と相談して新しい本を読んでみたいと思います。
でもAWSはネット上にたくさん情報があるから、それが自分で整理さえできれば、本を買わなくてもなんとかなる気もしますが、まぁ「読んだぞ!」という気持ちは大事ですよね。

挑戦意欲を育んでくれたり、達成感をもたらしてくれたりしますので。
ちなみに下の本は発売当時としてはかなり良書だったのかと思いますが、情報が少し古いので、現在の状況との差分を念頭に置きつつ読むか、他の本で代替することをお勧めします。


Amazon Web Services クラウドデザインパターン実装ガイド 改訂版


よくわかるAmazonEC2/S3入門 ―AmazonWebServicesクラウド活用と実践 (Software Design plusシリーズ)