読者です 読者をやめる 読者になる 読者になる

水深1024m

技術的なメモとか日記的なもの

AWS で作るシステムのセキュリティ考

AWS アカウントを複数人で使ってシステムを作っていく時に、 セキュリティの面からやるべきことについて。 主に Web アプリケーションを想定した内容ですが、特に書いてあることは特殊ではないと思います。 各所の Blog にも記事書かれてますが思っていることをつらつらと書いてみます。 なんか変なこと言ってたらご指摘ください。

参考: AWSのセキュリティが気になるなら読んでおくべきAWSセキュリティのベストプラクティス - yoshidashingo

はじめに (AWS アカウントと IAM ユーザ)

前提というか用語の話。

  • AWS アカウント
    • アカウント作成時のメールアドレス、パスワードでログインして使うユーザ
  • IAM ユーザ
    • AWS アカウントから発行できる、ユーザ名とパスワードでログインして使うユーザ

AWS アカウント周り

AWS アカウント (ルートユーザ) で作業できないようにする

AWS アカウントは Linux で言う root ユーザみたいなものなので、アカウント内全てのリソースにアクセス可能です。 構築運用面で最初に IAM ユーザを作成する時以外、アカウントで作業する必要があることはほとんどないです。

  • 操作用の IAM ユーザを作る
  • AWS アカウントに紐付いてる Access Key とか証明書を消す
  • AWS アカウントに MFA を設定する

あとは、重要なシステムのあるアカウントであれば MFA のハードウェアキー買って設定して 金庫にでも突っ込んでおくと良いです。

IAM ユーザを使う人ごとに分割する

IAM を使うと、作業者個人単位で専用のユーザを持てるので、これを使いまわす必要はどこにもないです。 使う人それぞれに IAM ユーザを作成して、必要に応じて権限設定して使いましょう。 CloudTrail 使えば大体の操作は後からトラックできるようになります。 例えばいわゆる Admin な人たちにはほぼ全権を渡しておいて、そうでない人には Describe 系の API だけ渡すとかの切り分けをしておきます。 IAM にも MFA が設定できるので、好みに応じてハードウェア買うかスマートフォンにアプリ入れて MFA を有効化しておきましょう。 アクセスキーとシークレットキーはいずれにせよそれなりに死守する必要があることに気をつけてください。 Mac な人なら envchain 使うとなお良いと思います。

OS X キーチェーンから環境変数をセットするツールを作りました - クックパッド開発者ブログ

難点はユーザ数が増加していくと管理するのが難しくなるところでしょうか。ここはまだうまい解が分からないところです。。。

アプリにキーを埋めない

例えば EC2 で特定の S3 バケットにファイルアップロードするアプリとかバッチを動かす時など。 一昔前まではそのアプリ用の IAM ユーザ発行してキー埋めたりすることもあったと思いますが、 キー埋めないで IAM Role for EC2 Instance 使いましょう。

Amazon EC2 の IAM ロール - Amazon Elastic Compute Cloud

AWS SDK 使える環境であれば大体の実装ではキーの取得とローテーションへの追随もやってくれます。 サーバ設定もデプロイも自動化したけどキーの配布どうしよう、みたいな問題はこれで大体解決するのでは。 難点は今のところインスタンス"起動"時にしかロール指定できないこと。Stop/Start じゃダメです。 イミュータボーでディスポーザボーなインフラをお持ちの各位であればそんな難しいことではないのでは。

Unix アカウント周り

IAM アカウントは分離していても EC2 インスタンスのユーザは ec2-user や ubuntu ユーザを共有して使っている方も多いと思います。 が、インスタンスを扱うユーザが多くなるのであれば、OS レイヤでの権限分離もちゃんとやる必要があります。 Chef とか Puppet で管理する手もあるんですが、ユーザ情報を変更するたびに全台への apply が必要なのも厳しい感じがします。 ここを分離したいのであれば今のところはおとなしく LDAP を使うのが良いでしょう。 OpenSSH を使っていると、ちょっと前まではパッチ当てない限り公開鍵認証にするために LDAP ユーザであっても 対象のインスタンスに事前に公開鍵を配布しておく必要があったのですが、 OpenSSH 6.2 から LDAP 側に保持している公開鍵を読む、みたいなことができるようになったので、ここも心配する必要がなくなりました。

ref. OpenSSH 6.2を使って公開鍵認証もLDAPで行いたい。 - Qiita

ただし LDAP サーバが壊れると全てが崩壊するので、cloud-init で作成されるユーザと EC2 のキーペアは無効化せずに あくまでキーペアを共有しない (これも金庫とかに放り込んでおく) だけに留めておいたほうが良いかもしれません。

暗号化

AWS の例えば S3 や EBS にはサーバサイド暗号化 (SSE) という機能がついてます。 暗号化鍵の管理を AWS 側がやってくれて、使う側としては透過的にデータを暗号化できる機能です。 透過的にというのは要は、API 越しにデータ送信する時は平文で、送信後格納されるタイミングで暗号化されて、 読み出しの際は復号されたデータが降ってくるというやつです。 これを有効化するだけで全てのデータが暗号化されて最高便利という機能に見えるのですが、 API の認証が通れば復号化されたデータが降ってくるので、実際に権限外のアクセスから保護できるケースはそんなに多くないです。 例えば AWS 側の管理者が悪意を持ってアクセスしてきたり、AWSAPI のバグで他人のオブジェクトにアクセスできたり、 AWS がセキュリティペーパーに書いてある通りじゃなく使い終わった HDD を適当に捨てていた場合なんかには保護できるかもしれませんが、 それよりも開発者の誰かがアクセスキーを Github に visible な状態で突っ込んでいたり、メールアドレスとパスワードを使いまわしていて AWS アカウントにログインされたりして死ぬ可能性のほうが遥かに高いんじゃないでしょうか。 というわけで暗号化については"それで守れる範囲"をちゃんと考えた上で、必要な場合はちゃんと実装したほうが良いでしょう。 例えば S3 を例に挙げると、 AWS SDK for Java, .NET, Ruby には S3 にアップロードする際クライアントサイドで任意のキーを渡して暗号化してからアップロードできるようになっています。 これは API がどうこうという話ではなく完全にクライアントサイドで暗号化しています。

Protecting Data Using Client-Side Encryption - Amazon Simple Storage Service

あるいは鍵を AWS に渡して暗号化してもらう SSE-C というのもあります。

Protecting Data Using Server-Side Encryption with Customer-Provided Encryption Keys (SSE-C) - Amazon Simple Storage Service

完全な SSE より、R/W に実際の鍵が必要な分保護できるケースはもちろん増えますが、端的には "暗号鍵を渡すことと引き換えに暗号化処理をオフロードする"というものなので、 暗号化を考えた時にこれがしっくりくるケースってあるのかなーと感じています。

EBS でも、AWS サイドで暗号化の手段が用意されています。

Amazon EBS Encryption - Amazon Elastic Compute Cloud

副次的な効果として、スナップショットを public にしたりアカウントをまたぐことが仕組み上できなくなりますので、 この効果だけ欲しいという方には良いのかも。そもそもの懸念については S3 のものと大差ないと考えています。 自前で暗号化やるのであれば、パートナーが提供してるソフトウェア使う手もありますし、 Linux であれば dm-crypt 使っても良いと思います。

ここだけ長くなっちゃいましたが、要は何を何から守るのかちゃんと考えて実装しようよというだけの話です。

ロギング/監視

オンプレ環境との大きな違いを挙げるとすれば、AWS 上ではコアスイッチでミラーポートを使ってネットワーク監視するみたいなことが難しいので、 基本的に各インスタンス上で監視を行う必要がある点でしょうか。 トレンドマイクロの DeepSecurity とかはそういったアプローチだと思います。

AWS API 周りであれば前述の CloudTrail を使うのが一番良いんじゃないでしょうか。 全サービスをカバーしているわけではないということに留意する必要がありますが。 ファイルは S3 に json で吐かれるので、MongoDB なり ElasticSearch に突っ込んで検索可能にしておくと トラブルシューティングの時などにも捗るとおもいます。 ログを S3 に置いておくのであれば、そのバケットのアクセス権をちゃんと設定するのは必須として、MFA Delete も有効化しておきましょう。

MFA Delete - Amazon Simple Storage Service

おわり

正直粒度もバラバラでまとまらないですが、ざっと書いてみました。 AWS 固有のことが(アカウントとか)それなりにはありますが、その他はこれまで普通にやられてきたことと大差ないと思います。 ここでカバーしていない内容も多々ありますが、そういうのも徐々に書いていきたいです。

完全にオフトピックですが、イミュータブルインフラとかテスト駆動インフラみたいな話って セキュリティ運用とも相性が良いよなあと最近考えています。 例えば Heartbleed なんかが記憶に新しいですが、ミドルウェア脆弱性があってバージョンアップしないとなんて時も パッチしたミドルウェアの検証は(もちろんカバレッジによりますが) Serverspecinfrataster で可能ですし、 実際の入れ替え作業も、既存のサーバを止めてバージョンアップするのではなく新しい構成のサーバを起動して入れ替えるだけで良ければ、かかる労力はかなり小さくなるでしょう。

最近の Web インフラ界隈の流れにうまいこと乗りつつ、より便利でセキュアな環境を作りたいですね。 以上です。

触って試す AWS MFA

相次ぐパスワードリスト攻撃もあり、いわゆる MFA (Multi-Factor Authentication) が使えるサービスが増えてきました。 AWS でもデバイスによる MFA ができるようになっています。 この仕組みとかについて書きます。 AWS について主に書いていますが他のサービスで使われているものも大体同じ (少なくとも GitHub とかは) はずです。

AWS MFA で使われている仕組み

IAM の FAQ でも書かれていますが、 AWS で使うことができるのは TOTP (Time-based One-Time Password Algorithm) です。 アルゴリズムの説明は こちら などがわかりやすかったです。 TOTP の RFC もそんなに分量ないので読んでみると良いと思います。 ざっくり言うと TOTP がしているのはすごく単純なことで、

  • 認証を行う側と認証される側で同じ鍵を共有しておく
  • お互いが同じ鍵を用いて同じ計算方法でワンタイムパスワードを生成する。生成時、変化する要素として現在時刻が使われる

これだけです。鍵の共有時を除けば認証する側とされる側で通信する必要がないので、 スマートフォンを MFA デバイスにしている場合それがオンラインである必要はありません。

ちょっとコード書くとその様子を眺めることができるので後述します。

ハードウェア MFA とバーチャル MFA

AWS の MFA ではハードウェア MFA デバイスとバーチャル MFA デバイスの2種類が使えるようになってます。

ハードウェア MFA

AWS の場合、ハードウェア MFA は専用のベンダーが一社あり ここ から購入します。 現在は小さい USB メモリみたいなものとカード型のものを選ぶことができますが、 カード型の方は日本から買えないようです。無念。

ベンダーのページに記載されていますが、これらも Time-based との記載がありますので TOTP が使われているものと思われます。 使っているアルゴリズムは同じですが、ハードウェア MFA とバーチャル MFA の違いは鍵の共有方法にあります。 若干推測ですがハードウェア MFA の場合、ベンダーはハードウェアのシリアルナンバーとそれに紐づく鍵を何らかの安全な方法で AWS 側に渡しているはずです。 そのため、このハードウェアを購入して AWS アカウントに使おうとすると、シリアルナンバーを入力するよう求められます。 このシリアルナンバーは実際の生成に使われるわけではなく、入力するとそれに紐づく鍵が AWS 側で呼び出されて、 以降その seed を元にワンタイムパスワードを計算するようになるという仕組みです。 また、このハードウェアには耐タンパー性がありますので、外から鍵を盗みとられるという可能性も少ないと思います。

バーチャル MFA

ハードウェア MFA の他にバーチャル MFA を選択することもできます。多くの人はこちらを使っていると思います。 バーチャル MFA の場合もパスワードの生成方法はハードウェアと全く同様ですが、スマートフォンアプリ (Google Authenticator, Amazon MFA) など 専用ハードウェアではないものの上で生成を行うところが差異です。 また鍵の共有方法も違います。ハードウェア MFA の場合鍵は予め AWS 側に渡っていますが、 バーチャル MFA の場合 AWS 側で生成した鍵を手元のデバイスで受け取る必要があります。 手段は多くの場合2通りで、QR コードを使うか鍵を手で入力します。

QR コードには、アカウントの名前や鍵, 認証の種類 (TOTP or HOTP) が含まれています。 Google Authenticator の wiki に詳しい説明が載っているので興味のある方はご参照ください。

キーを手動で入力する場合は、アカウントの名前などは情報として含まれないため手動で入力する必要があります。 また、鍵が格納されるのは結局スマートフォン上の記憶領域なので、その安全性はそのアプリや端末のセキュリティレベルによるというところが ポイントかと思います。

自分でやって観察してみる

ruby だと ROTP という gem があって、この OTP 周りの処理をやってくれます。 コード読んでみると実際どういう処理をやる必要があるのか見えてくると思います。 https://github.com/mdp/rotp

require 'rotp'
key = ROTP::Base32.random_base32
totp = ROTP::TOTP.new(key)
puts key
puts totp.now

こんなコードを書くと、16文字の base32 で生成されたキーと、それを元に生成したパスワードが返ってきます。

$ ruby rotp.rb 
amxz5qyc54sap3qp
271576

ここで生成されたキーを Google Authenticator に入力してみます。 サービスを新規追加する画面から、手動で入力 を選択し、アカウント(適当な名前) とキー (生成されたキー) を入力します。 時間ベース (TOTP) にチェックが入っていることを確認して完了ボタンを押すと、他のサービスに並んでパスワードが表示されると思います。

では、コード側でも生成されたキーでパスワードを生成するようにしてみます。

require 'rotp'
totp = ROTP::TOTP.new("amxz5qyc54sap3qp")
puts totp.now

これで totp.now を watch -n 1 とかで Google Authenticator といっしょに眺めてみると、 お互い大体同じタイミングで値が切り替わるのがわかるとおもいます。

手元で OTP を生成して AWS 認証してみる

注: 大体どんな感じで MFA が動いてるのか観察するためにやっているので、Web アプリ置いて生成させてこれでデバイス要らず便利〜みたいなことはやらないほうが良いと思います。

IAM で適当なユーザを作って MFA を有効にします。(実際の値は雑に消しました)

f:id:kani_b:20140706173554p:plain

ぱっと見切り替わるように見えないのですが、この画面で "Show secret key for manual configuration" をクリックすると 設定用のキーが出てきます。これを先ほどのコードで使うようにします。

f:id:kani_b:20140706173612p:plain

require 'rotp'
totp = ROTP::TOTP.new("your_mfa_key")
puts totp.now

これで6桁のワンタイムパスワードが出力されるようになったと思います。watch -n 1 ./rotp.rb とかしておくと時間経過とともに変化していくはずです。 出力されたワンタイムパスワード2つ (最初に出力されたものと次に出力されたもの) を入力するとアクティベーションが完了します。

実際にログインしようとしてみると、コード側で生成されたワンタイムパスワードが使えることが確認できます。 面白いですね。

その他

さっきも書いた通り、QR コードは鍵やその他の情報をやりとりするだけのものなので、 同じ鍵を持つデバイスを複数個作ることができます。 つまり同じ QR コードをスキャンしておけば iPhone と併用している Android とかもう使わなくなったスマートフォンなどを MFA デバイスのバックアップとして持っておくことが可能です。 その分鍵がある場所が増えることになるのでユースケースによりますが。

MFA はもはや使わない理由が特に無いので、心当たりのある人は今すぐ有効にしましょう。

AWS Casual Talks#2 で発表してきた

開催からもう一週間経って今更感しかないのですが、 AWS Casual Talks#2 という勉強会で AWS CloudTrail の話をしてきました。

AWS Casual Talks#2 on Zusaar

アレなタイトルですみませんでした。。。

CloudTrail の話と言いつつ、前半1/3くらいを Heartbleed ネタに使ってしまいましたが ちょうどホットな話題だったのと、AWS 周辺でこの話してる人あまりいないなあと思っていたので つい入れてしまいました。

30分もの枠で対外発表するのは初めてだったので正直かなり緊張していました。 終わってみると、喋り方や話のまとめ方など色々反省点が多いなあと思いつつ、楽しかったです。

CloudTrail についてもうちょっと

スライド中に、ログを取るために HTTP Proxy をかますことを考えた、みたいなことを書いてるのだけど、 そうするとその Proxy を通さないリクエストはロギングできなくなる、 つまり例えば IAM でリクエスト元 IP とかを Proxy のものに縛っていたとして、 リクエスト元 IP が違う (= Proxy 使ってない) リクエストは当然ロギングできないわけで、 やっぱり API に対してのログとは言えないなあと思っていました。

AWS の怖いところの一つとして、目に見えているもの以外の部分が見えにくいということを かなり感じていたので、ネタではなく CloudTrail さんには一日も早く太平洋を渡ってきてほしいなあと願っています。

iwas について

iwas という CloudTrail のログをパースして IAM の変更履歴を記録するものを作ってみました。

kanny/iwas · GitHub

CloudTrail のログ通知を SNS 経由で SQS に吐くようにしてあげると使えます。

IAM の変更履歴って、権限変更の記録というセキュリティの面から見ても 個人的にはかなり必要なものだと思っていて、IAM に実装されないのかなーとずっと思っているのですが、 そういう気配がなかったので作りました。

ちなみにネーミングは IAM (I am) の変更履歴を取るので I was ... にしていて、 個人的にはこのネーミングだけで行ける!!!!!とか思っていたのですが、 なんというか、社会は厳しかったです。

同梱している iam-export.rb は IAM のポリシを json ファイルにエクスポートします。 当初は aws-sdk for ruby の current 版を使ってたのですが、IAM Role の扱いに対応していなくて、 開発は aws-sdk-core (v2) にシフトしているようだったので、まだ pre ではありますがこちらを使ってみました。

が、中身を見ればわかるように正直全くプロダクションクオリティではありません。。。 すでにいくつか考慮漏れを見つけているので、近いうちに直して環境構築方法とともにきちんと公開しようと思います。

さいごに

次は EC2/VPC 上のインスタンス運用でのセキュリティとか、そういう話をする機会があればと思います。 というか AWS 系の勉強会は数あれど、その中で運用におけるセキュリティとかに焦点を当てたものって あまりなさそうなので、今度やってみたいですね。

というわけで、主催してくださった @con_mame さん、 会場提供してくださった AWS さん、他の発表者の方々、聞いてくださった方々、ありがとうございました。

AWS Game Day Japan 2014 に参加した

JAWS DAYS 2014 の前日に開かれた、 Game Day Japan 2014 に参加してきました。 AWS Game Day Japan 2014 Spring (Tokyo) - JAWS DAYS 2014 | Doorkeeper

Game Day そのものの詳細はクラスメソッドさんの Blog 記事が詳しいと思います。 すごく大雑把に言うと AWS で構築したシステムを全力で攻撃して全力で修復するというものです。

『JAWS DAYS 2014』開催前告知 #11 対戦型システム信頼性向上策体感イベント『GAME DAY』は前日3/14(金)、4箇所(東京/大阪/名古屋/仙台)同時開催!! #jawsdays #jawsug | Developers.IO

過去にも行われたようですが僕は今回が初参加でした。 Game Day そのものに興味はあったので今年もやるという噂をききつけてエントリー。 全会場で50人いかなかったら中止って書いてあって、平日ということもあり開催されるのかなーとちょっと不安でしたが 無事開催されることになって嬉しかったです。

会場に着いて説明のち、早速チーム分け。 チームメイトは @moomindani さんと @nginks さん。 自己紹介しつつまずはコミュニケーションツールを作る。 Google Docs だけでなんとかなるかと思ったけどチャットが欲しかった(声でバレるから)ので Skype も併用することにしました。

構築と防御

まず最初は構築フェーズ。EC2 と SQS を使ったシステムを手順に沿って作っていきます。 去年と同じだったらしいんだけど、どうせ問題変わるだろうと思って何ら予習しなかったので 2回目でーすって人が手挙げてたりして冷や汗ものでした。 構築はチームのお二人に任せつつ、防御周りのことをしたり構築を手伝ったり。 やったことはこんな感じ

  • CloudTrail を有効化してログを他アカウントの S3 バケットに投げるように
  • SQS の Dead letter queue を有効化して変なキューは自動で流せるように
  • piculet でセキュリティグループの状態をコードとして保持
  • 自作の IAM エクスポートスクリプトで IAM の構造とかを保持 (今回は IAM のみ触れないのであまり意味はないけど、読みやすいように)

などなど。色々考えましたがすっと手が動かないなーという反省。。。

EC2 が実行するワーカーに OS コマンドインジェクションを見つけて (去年も全く同じだったらしいけど) パッチ当てようか迷ったのだけど、 コード読んでたのが終了3分前くらいで間に合いませんでした。。。 あと CloudTrail のログを他アカウントに出すのは反則かなーと思ったけど、実際有効なんじゃないかなーと思ってやってみました。 ほんとは loggly の free account から読めるようにしてたんだけど、インポートがなぜかうまくいってなかったので諦めることに。 ちまちま作っていた自作のパーサと JSONView でなんとかしていました。

攻撃・修復

どんな攻撃があったかは ijin さんの Blog にほとんど記載されてるのでそちらをご参照ください。

AWS Game Day Japan 2014春を開催してきた - @ijin

相手に渡すアカウントは IAM の操作のみができない Power User Template だけを入れたアカウントだったので、 事実上ほとんどなんでもできる状態。 リソース全消しなどではなくバレにくく修復しにくい攻撃が評価されるとのことで、 事前に考えていた攻撃としては S3 の Bucket Policy 周り、Auto Scaling, OS コマンドインジェクション、VPC のネットワーク機能あたりを 攻めようと考えていたのですが、

攻撃用アカウントをもらってざっと目を通すとまさかの VPC 使わない (EC2-Classic) 環境…………

これで考えてた攻撃をかなり潰されてヒーという感じでした。その発想はなかった。。。

修復はだいたいできたものの、AutoScaling の Scheduled Action に仕込まれた攻撃を修復しきれず。 CloudTrail は多くのチームが壊しにかかったようですが、うちのチームは S3 Bucket を外に出していたこともあり無傷。 これについては後述。 1チームが複数チームから攻撃されるというアクシデントなどもありつつも修復フェーズおわり。

結果発表

結果、ほとんどのサービスに加えて Management Console も壊した (表示を触りまくった?) チームが優勝。 うちは厳しいんじゃないかしらと思ってたけどなんと地方賞(仙台賞)をいただきました。 どこ攻撃されたかわからないような攻撃が多かったのが評価対象だったようです。やったー。

感想

限られた時間でシステム作って修復するというのはなかなか難しく、 改めて思ったのは"正しい状態を保持して比較し続ける"ことの重要性でした。 例えばコードにエクスポートしていたセキュリティグループへの攻撃は、変更把握も修復も一発でしたし。

CloudTrail は正直 SQS や AutoScaling 周りへの攻撃がメインだった今回、あまり威力を発揮する場面はなかったかなーという印象。 ただ、リージョンが US だったこともあり、CloudTrail 環境下で作業をしていくとこういうログが取れるのかーというものが 手に入ったのは大きいと思いました。 Management Console も実際は各操作で API を呼んでいるので、相手がどんな順番でシステムの概要を把握していったのかある程度想像できたり。

IAM の Power User template では IAM の変更のみが禁止されてますが、監査という点から考えると CloudTrail への変更も デフォルトで禁止してほしいところです。。。

また、ログの保存場所について自分の考えを確認できたのも良かったです。 CloudTrail しかり ELB しかり、AWS への操作のログが徐々に取得できるようになってきてますが、 確実なログ運用のためには全く違うアカウント管理下にあるバケットへの格納など、どうやっても手がとどかない場所に保持しておくのは 一つの運用として良いのかなーと思いました。

色々と勉強になりました。次回も参加したいです。 運営の皆様、チームメイトの皆様、参加された皆様、ありがとうございました。

仮想化方式(HVM と PV)についてまとめ

EC2 における仮想化方式や kernel の扱いにはいくつか種類があって、 カスタマイズ (パフォーマンスチューニングなど) をする上で必要になることがあります。 C3 インスタンスや I2 インスタンスの登場で、それらがより重要になってきた感があるので一度まとめてみます。 * この記事は基本的Linux についてまとめています

大前提

世に出ている仮想化基盤はいくつかありますが EC2 に使われているのは Xen です。 ただし ハードウェアサポートの追加、インスタンスタイプに応じた各 VM リソースの割り当て方、 ネットワークの扱いなど、 Xen そのものに相当なカスタマイズが行われていることは想像に難くないと思います。 (とか言って API から上だけで実現されていたらそれはそれで面白いですね)

仮想化方式

PV (paravirtual)

EC2 ではサービス開始当初から PV (paravirtual, 準仮想化) 環境でインスタンスの提供を行っています。 paravirtual での起動方法は2種類提供されています。

AKI, ARI を使う方式

EC2 側であらかじめ用意された kernel (AKI) と initrd (ARI) を利用して起動し、 最後にルートデバイスとしてユーザが選択したボリュームをマウントします。 つまり、ルートデバイスの /boot に kernel が含まれていようと、利用される kernel は AKI のものになります。 この方式で起動する場合、ユーザ側で作成するルートデバイスに kernel 本体や initrd が不要になります。 つまり /boot が無くても起動に問題無いはずです。

PV-GRUB を使う方式

UPK (User Provided Kernel) などとも呼ばれています。EC2 では後発で提供されるようになりました。 EC2 における PV-GRUB についてはこのへんXen における PV-GRUB についてはこのへんにドキュメントがあります。 PV-GRUB 用 AKI を指定しておくと、ユーザが指定したルートデバイス内に含まれる kernel を使って起動できるというものです。 PV-GRUB は、ユーザが提供したルートデバイス内に存在する grub.conf を読みに行き、その内容を使って起動します。 grub.conf のパスは固定しておく必要がありますし、kernel を置いておく必要があるので、/boot が必要になってきますが、 ルートデバイスに grub がインストールされている必要はありません。

PV, PV-GRUB ともに、ルートデバイス内に適切にファイルが配置されてさえいれば起動します。 なので AMI をゼロから作る際に、適当な AMI で起動して EBS をアタッチし、 ファイルを流し込めば起動できるようになるんですね。

HVM

クラスタインスタンスがリリースされた際に HVM (Hardware-assited VM) という方式がサポート(というか必須)されました。 その頃だとあまり馴染みのなかった HVM AMI ですが、先日 C3, M3, I2 インスタンスがリリースされた時にこの方式がサポート(もしくは必須)されるようになっており、 一般の利用者にも関係のあるものになってきています。

HVM の場合、起動シーケンスは物理マシンに OS をインストールした場合と何ら変わりません。 ルートデバイスにあるブートローダから、デバイス内に含まれる kernel を起動していきます。 つまり、ブート領域 (GPT or MBR) とブートローダ (grub など) が必要になります。 そのため、既存の PV AMI を HVM 環境で使うためには、ファイルを流した EBS に対して grub をインストールしないといけません。 (ちなみに grub-install は Xen の仮想デバイスに対応していないので grub コマンドからインストールする必要があります) ゼロから作るのであれば、がんばって EBS マウントしたりするより手元の VMware とかでサクッと作ってディスクイメージにした上で dd したほうが早いかもしれません。 事故には気をつけたいですね。

HVM は完全仮想化などと言われているので特にモジュールなど必要なさそうに見えますが、実際はそうではありません。 試しに C3 インスタンスや I2 インスタンスで HVM AMI を起動してみると、Xen のモジュールが色々ロードされていることに気づくと思います。 これは PV on HVM driver と言われているもので、HVM 環境下ではオーバーヘッドが発生しやすい I/O などを PV の時と同様にホスト OS 側のサポートを受けつつ処理できるようにするドライバです。 ドキュメントにもありますが、このドライバは kernel 2.6.36 でマージされて 2.6.37 で改善が入っていますので、新しい kernel を使えるならそれ以上のバージョンを使うと良いです。 RHEL6 (CentOS6) の kernel は 2.6.32 ですが、2.6.36 のドライバがバックポートされているため問題なく利用できるようです。

ハードウェアサポートの利用

HVM AMI を使う必要のあるインスタンスでハードウェアサポートを提供しているものがあります。 代表的なのは C3, I2 インスタンスの SR-IOV による 10G NIC サポート (実帯域が 10G というわけではない) だと思います。 オリジナルの AMI を使う場合、こういったハードウェアサポートを有効にするドライバなどを忘れずロードできるようにしましょう。

使い分けや注意事項

インスタンスがどの方式をサポートしているかのマトリクスはこちら。 古いインスタンスタイプは PV しかサポートしていないので選択の余地はないとして、 新しい C3, M3 インスタンスは PV と HVM の両方をサポートしています。 (I2 インスタンスは HVM 必須です) 個人的には、 PV と遜色無いパフォーマンスが出るのであれば HVM が使えるインスタンスではもう PV AMI 使う理由は無いかなーと思っているのですが、 きちんと計測が必要ですね。 問題になってくるのは同一の AMI を PV, HVM で使いたい時でしょうか。メンテナンスしなきゃいけない AMI が倍になるので。

EC2 のドキュメントでもインスタンスに利用されている CPU やハードウェアサポートが明記されるなど、 インスタンスが稼働している環境そのものを意識することが増えてきました。 今後はどうなっていくのでしょう。EC2 でも使えるハードウェアが色々増えていくと楽しそうですね。

cloudpack night #7 に参加しました / EC2 における AES-NI の話

先日行われた cloudpack night #7 に参加しました。 http://www.zusaar.com/event/978005
主催された cloudpack の id:yoshidashingo さんのまとめはこちら。 http://d.hatena.ne.jp/yoshidashingo/20130826/1377527798

新卒入社5ヶ月目、社会人なりたてのぺーぺーではあるのですが、 僭越ながら若手 LT 枠で発表させていただきました。

EC2 環境における AES-NI の性能について紹介しました。
AES 暗号化するならインスタンスをよく見たほうが良いですよ、という話です。
LT の資料だとうまくまとまらない気がしたので記事という形でまとめておきます。

AES-NI とは

詳細はここで説明するよりググったほうが良いです。
一言で言うと AES 暗号の CPU サポートで、Intel CPU の Westmere (2010年前半) 世代から載るようになったのでそれなりに日が経ってはいます。
OpenSSL(たぶん 1.0.0e~) では既に利用できるようになっています。

EC2 における AES-NI

結論から言うと、EC2 においても AES-NI を利用することができますが、1点だけ落とし穴が存在します。
ヘビーに AWS を利用されている方には既知の問題かと思いますが、 同じインスタンスタイプにおいても割り当てられる CPU が違うことがあります。
(この詳細は con_mame さんのエントリに分かりやすくまとめてあります)
もちろん AWS 側でも世代間の差が少なくなるよう、CPU によってインスタンスへの割当時間調整をしていたりするとは思いますが、
ハードウェアサポートについては如何ともしがたいところでしょう。
同じインスタンスタイプのインスタンスで、AES-NI がサポートされているものとそうでないものがあります。

AES-NI の有無によるパフォーマンスの違い

というわけで、どのくらいのパフォーマンス差が存在するのか検証を行いました。
m2.2xlarge (13 ECU) のインスタンス2台、CentOS6 の環境で、 OpenSSL はディストリビューション標準のパッケージを利用しています。
※計算速度の比較にどうして m2.2xlarge? という声もありそうですが、諸事情です
2台のマシンにははそれぞれ knight, padawan という名前をつけておきます。
フェニックス一号にしようかと思ったのですがやめました。

CPU の確認

まず2台の CPU を確認します。/proc/cpuinfo から得られる情報のうち関係ありそうな部分を抜粋してみます。

knight

processor : 0
model name  : Intel(R) Xeon(R) CPU E5-2665 0 @ 2.40GHz
cpu MHz     : 2399.998
flags       : fpu de tsc msr pae cx8 cmov pat clflush mmx fxsr sse sse2 ss ht syscall nx lm rep_good unfair_spinlock pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 x2apic popcnt aes avx hypervisor lahf_lm

padawan

processor : 0
model name  : Intel(R) Xeon(R) CPU           X5550  @ 2.67GHz
cpu MHz     : 2666.760
flags       : fpu de tsc msr pae cx8 sep cmov pat clflush mmx fxsr sse sse2 ss ht syscall nx lm rep_good unfair_spinlock pni ssse3 cx16 sse4_1 sse4_2 popcnt hypervisor lahf_lm

上記のように knight の flags には aes の文字が見えますが padawan にはありません。
このため、padawan (X5550) では AES-NI がサポートされていないものと考えられます。
Intel の Web サイトからも探せるようになっています

OpenSSL での確認

次に OpenSSL 側での状態を確認します。

knight

$ openssl engine -c -t
(aesni) Intel AES-NI engine
 [AES-128-ECB, AES-128-CBC, AES-128-CFB, AES-128-OFB, AES-192-ECB, AES-192-CBC, AES-192-CFB, AES-192-OFB, AES-256-ECB, AES-256-CBC, AES-256-CFB, AES-256-OFB]
     [ available ]

padawan

$ openssl engine -c -t
(aesni) Intel AES-NI engine (no-aesni)
     [ available ]

というわけで、AES-NI が搭載された knight 側でのみ aesni モジュールでサポートできる 暗号化モードが表示されています。 これで、knight が AES-NI を利用でき、padawan はそうではない、ということが分かります。

OpenSSL ベンチマークオプションでの計測

openssl には speed オプションという暗号化モードのスループットを計測できるオプションがあります。
これを knight, padawan でそれぞれ実行しました。
暗号化モードとして AES256 (CBC モード) を利用して計測し、 同時に、AES-NI の有無以外での差がないか調べるため 3DES のスループットも計測しました。

結果

下記グラフのような結果が出ました。

f:id:kani_b:20130902022357p:plain

グラフに載せ忘れてしまったのですが、単位は kbytes/s です。
256 bytes の暗号化スループット値を抜粋していますが、どのサイズでも開きは大体同じでした。
AES-256-CBC では knight が padawan に約5倍以上の性能差をつけています。
逆に 3DES では padawan のほうが knight のスループットを若干上回っています。
上に書いた CPU 情報を見ると padawan のほうがクロック周波数は若干高いので、 ハードウェアサポート無しでは単純にクロック周波数の高い padawan が速かったということでしょうか。
3DES を使ったときの性能を見る限り CPU 自体の処理性能として knight と padawan に それほど差はなさそうなので、AES-NI の有無による効果と言ってよさそうです。

ファイルの暗号化

ではこれが実用上どのくらいの差になるのかということで、 ほんの軽い程度ではありますが、ディスクI/Oを伴う暗号化速度を計測してみました。
80MB くらいの圧縮済みログを使います。
(暗号化したログを S3 に置いておくとかよくあるパターンだと思うので)
EBS ではなく ephemeral disk にファイルを置いて計測しました。

結果

下記グラフのような結果が出ました。

f:id:kani_b:20130902022419p:plain

またしてもグラフに載せ忘れているのですが単位は sec です。
1ファイルの暗号化に5秒くらいの差がつくとなると、 大量のファイルを暗号化しながら処理するような環境では全体の処理時間に かなりの影響を与えるのではないでしょうか。

まとめ

EC2 でも AES-NI の恩恵は受けられることが無事確認できました。
実際測定してみると、無視できないレベルで違いがあることが分かります。

AWS をはじめとしたクラウド環境は確かに物理マシンのことを考えなくて便利〜となりがちなのですが、 仮想マシン側から見える、"その向こう"の環境に思いを馳せておくと、 こういう細かい点で得できるんじゃないかなと思います。
AWS 側の物理環境もどんどん更新されているでしょうし、 使う側としてはぜひハードウェアサポートも含めた全力を引き出したいところです。

会そのものも、発表は正直だいぶ緊張したのですが、興味を持っていただけた方もいたようで良かったです。その後の懇親会も楽しかったです。
というわけで、楽しい場を提供してくださった cloudpack さん、ありがとうございました:)

追伸: 社会人になりました

学業を共にした Macbook を破壊してから早いもので半年が過ぎました。
冒頭で触れましたが昨年度で大学生を終えて社会人にクラスチェンジしました。
今のところサーバを dd で破壊したりはしていません。
社会人として、うっかりでマシンを破壊しない慎重さを身につけるべく日々がんばっています。
今後ともよろしくお願い致します。

dd と僕

自分のメインマシンこと MacBook ProSSDUbuntu インストールディスクを dd して破壊した。

正直書くのも憚られる話で、お前来年から本当に職業エンジニアになれんのって話なのだけど、
本当にクリティカルな状況下でやらかさないよう戒めとしてまとめることにした。
びっくりするほどレベルの低い話。

修士論文の提出も終わり、さてやっと研究室のサーバ環境を更新できるぜぐへへ、
とか思いながらとりあえず転がっていた HP MicroServer に Ubuntu を入れ、
作業用ストレージにしようとしていた。
自宅でも MicroServer を使っていたのでさくさくっと HDD を突っ込み、MicroServer には光学メディアドライブがないので USB メモリからインストールしようといつものようにインストールイメージをダウンロード。
光学メディアのないマシンにインストールを行う方法で代表的なものは、USB メモリ経由で行う方法か PXE ブートだろう。
以前作ってコメントアウト一行の解除で有効化できるようにしてあった PXE + TFTP 環境を使っていれば惨事は防げたと思う。
しかし僕は MBP に USB メモリを差し込み、いつものように dd で書き込みを行った。
行なってしまった。しかも sudo で。

一応それなりのサイズだし、USB2.0 経由なので書き込みにある程度時間がかかるはず。
だが実行のち、プロンプトが一瞬で戻ってきた。
「うおーずいぶん早いな、こんなもんだったっけ」とか思いつつ、ホームディレクトリに戻ろうと cd を入力してリターンキーを押す。
その瞬間ターミナルがグリッチした。
正確には、プロンプトの中にテキストカーソルがめり込んだ。
しかもリターンキーを叩くたびにめり込む箇所が変わる。なんだこれは。
えっ、と思いながら ls してみると、そこに表示されるリストの日本語は全て化け、サイズ表示さえもおかしなことになった。
はー、何かの拍子で LANG か文字コードが変わったりした?でもそんなことは一切してない、と思いながら echo $LANG したが、返ってくるのは ja_JP.UTF-8 という表示。
正直に言うと、最初にターミナルがグリッチした瞬間、自分が何をやったのか直感的には理解していたと思う。信じたくなかったけど。

もうこの段階で、ターミナルに残っていたコマンド履歴を見て、自分がしでかしたことを把握していた。既にパニック状態。
全てのアプリケーションはディスクアクセスした瞬間にクラッシュする。Chrome のタブさえ開けない。
システム領域はたぶんがっつり上書きされていて、メモリに乗っている部分だけが生きている状態なんだろうなと思った。
唯一使えたのは、起動したままのターミナルと夜フクロウくらいだった。
そのメモリ上の夜フクロウから最後に書き込んだのが下記。この投稿直後に夜フクロウもクラッシュした。

凄まじいやらかしどころではなく、既に勝負はついていた。
ターミナルは生きているからまだファイルを移すことくらいはできるのでは、と思い
scp を試したら、最初の1ファイルが転送できたので少しテンションが上がった。
しかし次の瞬間に OS がフリーズした。
決着はついた。僕にできることはマシンの電源を切り、再び投入し、リンゴマークの後に表示される駐車禁止みたいなマークを眺めるだけだった。
その時の僕の様子は下記の tweet に詳しく記載されている。

その日はもう何もできなかった。
小一時間ほど "どうしようBot" と化したあと、研究室の納会があったため偉大な先生方の前で先ほどの事象を報告し、「えっ論文のファイルは???」「論文本体は無事なんですがソースコードが…」みたいなやり取りをして、酒を飲みまくって寝た。

家に帰ってきて一応 Time Machine の日付を見たが、最後のバックアップは8月であった。
(家では基本的に MBP を断続的にしか使わないこともあり、中断されることが多かった)
その後しばらくの間はこの MBP について何かやる気が全く起きず、データ救出を試みたのは数日後。
とりあえず開腹して SSD を取り出し、testdisk をかける。
Deeper Search で複数パーティションが検出され、おおおーとテンションが上がったのもつかの間、
それは Lion がインストール時に作成する非常用ブートパーティションの残骸であった。
既に何をする気力も残っていないので、そのまま放置して、時間ができたら mountain lion でも入れなおすかーということになった。

事態が動いたのは最近。やっと OS を入れなおすくらいに気分が回復し、
mountain lion をダウンロードしてインストールをはじめる。
ここであることに気づいた。

「インストール時と全く同じセクタ、同じサイズでクイックフォーマットしてインストールすれば、インストール後に削除ファイル回復系のツールで取り出せるのでは???????」

全く大したことではないのだがそれなりに現実味があることもあり、久々にテンションが上がった。
はやる気持ちで OS をインストールし、PhotoRec をかけてみる。
ものすごい勢いでファイルがヒットしまくる。
ここまでくるとテンションは上がりっぱなしで、7割くらい理由不明な勝利の予感を感じていた。
対象ファイル数が膨大なだけに、探すのには骨が折れそう(PhotoRec ではファイルツリーやファイル名までは再現されない)だが、この中に修士課程を共に過ごしたファイルがあるというだけで元気が出る。

一日くらいかけてサーチが完了した。数万件のファイルがヒットして復元されている。
最初のディレクトリを探す。うーんアプリケーション関連のファイルしかなさそうだ。しかし Omnigraffle の内部ファイルっぽいものなど、かつて自分が使っていた環境にあったものがそこにはあり、この調子なら自分のユーザディレクトリ下にあったファイルが見つかるのも時間の問題だろう。
どうやれば早いかな、plist ファイルとか結構あるけど捜索対象ではないし消してしまうか、日本語を含むファイル探せば早いかな、etc....


自分でホームディレクトリに FileVault (暗号化) をかけていてどう頑張っても復旧が無理ということに気づくまで、そう時間はかからなかった。


かくして、僕の MBP は修士課程2年間を共に戦った頃の記憶を全て失い転生した。
dd するときは指差し確認。人間はミスをせずにはいられない生き物ですね。
おしまい。


追記
この話を大学関係のちょっとアレな友人たちとしていたところ、
犯罪者っぽいTシャツを作ってくれた。いい友人に囲まれて幸せです。
http://clubt.jp/product/249779.html
大事なオペレーションをする日にはこのTシャツを着ようと思う。

追記2
ブックマークコメントで「バックアップ取ってないのがそもそもの問題」というご指摘を多数いただきました。
全くもってその通りなのですが、被害状況についてちょっと盛っちゃった感があるので追記しておきます。
実際のところ、本文にもありますが"8月までは TimeMachine でバックアップが取れていた"という状態で、
2年間のうち半分以上くらいは救い出せそうな気配です。(実際のところこれから先使うファイルが無さそうなのでリストアしてませんが、モノ自体はそれなりに堅牢なストレージにあります)
自宅外で使うことがほとんどで、自宅でもバックアップが完了する前に出かけてしまうことが多々あったので
クラウドストレージにでも突っ込んでおくべきでしたね。反省。
他にも、プレゼンに使うファイルだとか、そういうものは別なサーバに移してあったりもするので
被害数としては正直そんなに多くないかもなーと思っています。むしろ"やっちまった"ことへの精神的なダメージが。
お仕事として触るものは当然2重3重4重くらいまでバックアップは考えるもので、
心配性なので(説得力0だけど)管理していたサーバのバックアップ状況とかをモニタしたりしているものですが、
自分の環境となるとまーそんなに大したものないしなーと思ってしまう節がありました。失ってから気づくパターンですね。

論文そのものはもちろん git で自分のローカル以外の場所で管理していたので被害はなく、
実験しながら書き換えていたソースコードとか置いていたデータに被害がという感じでした。
まあ、バックアップは取れていて大前提ということは間違いないですね。
ということで、追記でした。ふげー。