2012年10月22日月曜日

SUZ-LAB最前線(VPCのサブネット/ ルーティング/セキュリティ)

スズキです。
SubnetのCIDRの設計方針は下記が最新のものとなります。
(本記事のものは少し古い考え方です)

VPCのSubnetのCIDRの設計方針(一例として)

VPCの設計に関しては、今まで、いろいろと経験し社内でも議論し、
SUZ-LAB(cloudpack)的にも一つのパターンができつつあったので、
このタイミングで形式知にしてみました。(つまりCDPです!)

まずは、百聞は一件に如かず、ということで構成図からです。
まあ、わかる人は、この図だけで、すべてが分かると思います。

余談ですがIaaS(この言葉でAWSをくくるのは嫌なのですが...)で現状ぶっちぎっている
(と勝手に思っている)AWSの、隠れた「ぶっちぎり」要因は下記だと思っています。
  1. プレミアムサポート
  2. シンプルアイコン
(1)のプレミアムサポートのすばらしさは、いろいろなところで言われている話なので、
ここで詳しくは書きませんが、"cloudpack"のお客様へのサポートは、AWSの
プレミアムサポートを、お手本にしています。(まだまだ足元にも及びませんが...)

(2)のシンプルアイコンの凄さは、恥ずかしながら、この時期になるまで
気づきませんでした...

今どういうことが起きているかというと、(初めての)お客様との設計のやり取りが、
下記のような図で、特にアイコンの説明も必要なく、いきなり深いレベルで
できてしまっています。

お互いアイコン(プロダクト)に対する認識の共有ができているため、話が非常に早いのです!
僕らも、アイコンの説明などの付帯資料を作成する必要もありません!
このあたりは、お互いに、かなりの工数削減(この言葉は使いたくないけど)にも
なっていると思います。

シンプルアイコン(とCacoo)がなかったら、CDPが生まれたかどうかも、あやしいところです。


話を戻して、上図の設計方針を説明します。

サブネット

下記の3つの視点でサブネットを設計しています。
  1. Availability Zone
  2. インターネットアクセスに対するルーティング
  3. 配置するコンポーネント(ELB/EC2/RDS)のIPアドレス(任意/固定)

  1. "Availability Zone"ごとに同じ種類のサブネットを配置し、例えば下記のように
    CIDRで各AZを区別できるようにします。
    • A Zone: 10.0.0.0/18
    • B Zone: 10.0.64.0/18
    • C Zone: 10.0.128.0/18
    • (D Zone: 10.0.192.0/18)
    当然、CIDR(ネットワークアドレスやサブネットマスク)はシステム規模によって
    変更するべきです。

  2. インターネットアクセス(IGW)に対するルーティングは下記の3種類とします。
    そして、例えば下記のようにCIDRで各ルーティングの種類を区別できるようにします。
    • Public: 10.0.0.0/23
      インターネット(IGW)へのInbound/Outboundの両アクセスが可能
    • Protected: 10.0.2.0/23
      インターネット(IGW)へのOutboundのみNAT経由でアクセス可能
    • Private: 10.0.4.0/23
      インターネット(IGW)へのアクセスは不可能
    Privateサブネットに配置しているEC2で、インターネットへのOutboundアクセスが
    必要になった場合、そのEC2はProtectedサブネットに再配置することで対応します。

  3. IPアドレスを固定にするコンポーネント(EC2)と、任意のIPアドレスが
    付与されてしまうコンポーネント(ELB/RDS/AS)は、別のサブネットに配置します。
    なぜなら、両コンポーネントを同居させてしまうと、固定で使いたいIPアドレスが、
    任意に付与されるIPアドレスに、先に使われてしまう可能性があるからです。
    • 任意: 10.0.0.0/24
    • 固定: 10.0.1.0/24
    ACT/STBなサーバは3つのAZを使わず、IPアドレス固定のEC2を配置する
    サブネットで、2つのAZのみで構成(EC2を配置)することになります。

ルーティング

上述(サブネット)の通りPublic/Protected/Privateの3種類を用意します。
"Virtual Private Gateway"(VPG)へのVPN接続は、上記の必要なサブネットに
追加するようにして、それ用にサブネットを作成することは行いません。

ほとんどの場合は、PrivateサブネットにVPGをアタッチして、踏み台(Temp)経由で
他のサブネット(Protected/Public)にアクセスする形になると思います。

セキュリティ

アクセス制限方法は、おおまかに下記の5種類方法があると思いますが、
  • Network ACL: サブネットに対するアクセス制限
  • セキュリティーグループ: EC2/ELB/RDSに対するアクセス制限
  • OS: "iptables"や"tcp wrapper"などで制限
  • サーバ: "apache"や"postgresql"などで制限
  • アプリケーション: アプリケーションプログラム内で制限
基本的にセキュリティグループでアクセス制限を行うことにします。

ただし、PublicサブネットとProtected/Privateサブネットに対しては
それぞれ下記のように、必要最低限のアクセス許可を実施しておきます。
  • External Network ACL: 10.0.0.0/23
    Publicサブネットに設定。デフォルト設定(Inbound/Outboundがすべて許可)
    だが、拒否リストで指定IPからのアクセス制限も必要に応じて実施。
  • Internal Network ACL: 10.0.2.0/22
    Protected/Privateサブネットに設定。InboundはVPC内のみアクセス可能。
    Outboundはすべて許可。
とうぜん、VPG経由の他拠点からのアクセスがある場合は、"Netowrk ACL"にしかるべき設定を
実施する必要があります。

CIDRの切り方は、もう少し吟味する必要がありそう...
--------
http://www.suz-lab.com

2012年10月19日金曜日

"tcpflow"でELBの挙動を確認してみる

スズキです。

いままでパケットのモニタリングは下記のように"tcpdump"をりようしていたのですが、
"tcpdump"でPostfixとSESの間のSMTPをのぞいてみる
HTTPに関しては下記の"tcpflow"の方が出力がみやすそうなので、試してみました。
tcpflow -- TCP Flow Recorder
"yum"で簡単にインストールできます。(リポジトリは"rpmforge"です)
# yum -y install tcpflow

そして下記コマンドで80番ポートのモニタリングが始まります。
# tcpflow -cs -i eth0 port 80
tcpflow[4004]: listening on eth0

ちなみに指定しているオプションは下記の通りです。
-c : ファイルに書き出さずコンソールのみに出力
-s : 表示できない文字を"."として出力
-i : モニタリング対象ネットワークインターフェース("eth0"など)を指定
ELB経由のリクエストは次のように出力されます。
010.000.000.113.50471-010.000.000.191.00080: GET /elb.php HTTP/1.1
host: test-419396984.ap-northeast-1.elb.amazonaws.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.3
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ja,en-US;q=0.8,en;q=0.6
Cache-Control: max-age=0
Cookie: SUZLAB=TEST; AWSELB=55FD...
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4
X-Forwarded-For: 219.117.233.241
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Connection: keep-alive

そしてレスポンスは以下のようになります。
010.000.000.191.00080-010.000.000.113.50471: HTTP/1.1 200 OK
Date: Thu, 18 Oct 2012 12:30:49 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.17
Content-Length: 262
Connection: close
Content-Type: text/plain; charset=UTF-8

ELB_IPADDRESS : 10.0.0.113
COOKIE_AWSELB : 55FD...
COOKIE_SUZLAB : TEST
EC2_IPADDRESS : 10.0.0.191
X_FOWARDED_FOR: xxx.xxx.xxx.xxx

テスト対象ファイル(PHP)は下記で利用していたものです。
ELBの挙動確認(Disable Stikiness)
当然ELBのヘルスチェックも下記のように出力されます。
010.000.000.113.29775-010.000.000.191.00080: GET /healthcheck.txt HTTP/1.1
host: 10.0.0.191:80
User-Agent: ELB-HealthChecker/1.0
Accept: */*
Connection: keep-alive

010.000.000.191.00080-010.000.000.113.29775: HTTP/1.1 200 OK
Date: Fri, 19 Oct 2012 02:43:57 GMT
Server: Apache/2.2.15 (CentOS)
Last-Modified: Thu, 18 Oct 2012 12:25:37 GMT
ETag: "20593-c-4cc547c1590bb"
Accept-Ranges: bytes
Content-Length: 12
Connection: close
Content-Type: text/plain; charset=UTF-8

healthcheck

そして、このモニタリングはHTTPのAPI通信のデバッグなどでも、非常に有用です!

HTTPSのモニタリングはOpenSSLと組み合わせればいいのか?
--------
http://www.suz-lab.com

AWS関係の技術ブログを書き続けたらどうなったか?(肩身が狭かった編)

スズキです。

子供が生まれた記念に、このAWS技術ブログが生まれ、書き続け、そして、今どうなったか?
を振り返ってみました。

といっても、そもそも、このブログはIT技術無差別ブログのつもりで書いており
AWS関係に特化してるつもりではありません。
(最近はAWSの仕事が多いので必然的にAWSの記事も多くなっているだけです)

AWS関係の記事(タグがAWSのもの)を書き始めたのは、調べてみると、2008/01/19からで
記事数も400半ばとなっています。

ちなみにAWSタグが初登場の記事は下記でした。(みんな知ってるかー?)
"Amazon Associates Web Service"情報
AWS関係の記事にかかわらず、当初は、自分の作業効率を上げるための一つの試みとして
書いていたと思います。

僕のまわりにいたITエンジニアたちは、僕も含めGoogleで検索して必要な情報を集め、
その情報をもとに、作業している人がほとんど、というか全員でした。
(多分ITエンジニアは、みんな、そんな感じで作業しているんじゃないかと思います)

このようなスタイルで作業していると、作業効率は検索キーワードを選ぶ技術に
左右されてしまうはずです。しかし、この技術は経験的に業界3〜5年目くらいで
大多数の人が頭打ちになっているような気がしています。

このままでは年をとるとともに記憶力が衰え、35歳になったら、"@shouhei"に
定年退職させられてしまうと焦り、より作業効率を上げる方法として下記の方法を
試すことにしました。
作業のためにGoogleで調べたり、実際に試行錯誤して得た情報を
キャッシュすることで、次に同じような作業をするときは、そのキャッシュから
高速に取り出し、以前よりも早く、そして高い質で作業できるようにする。
そして、そのキャッシュ先が「SUZ-LABブログ」です。

よく考えると、これはMemcacheとMySQLの関係に似ているかもしれません。
MySQLのデータがWebページで、Google検索がSQL、キーワードを選ぶ技術が
インデックスで、Memcacheがブログといった感じでしょうか?

初見のものはキャッシュ(ブログ記事)がないので、SQL(Google検索)をつかって、
データベース(Webページ)から必要な情報を取得します。取得したデータは作業用に
加工して、次は、すぐに使えるようにキャッシュ(ブロク記事)として保存します。

対象のIT技術(テーブル)が多くなれば多いほど、情報を取得するのに(Joinが必要となり)
時間がかかるでしょう。
当然スキルが上がるほど、取得時間を短くするためにキーワードの選択(インデックス)を
工夫していくと思います。

そして、データベース(Webページ)からの取得時間が長いキャッシュ(ブログ記事)ほど、
価値があることになります。

しかし、この方法はブログを書くことに結構なコスト(時間)がかかりました。というか
ブログを書く時間までを作業時間とすると、キャッシュ(ブログ記事)が少ない初期は、
当然ヒット率も低いので、逆に、かなりの時間がかかってしまいます。

ということで、実は、作業効率は下がってしまいました。
作業効率が下がるということは、以前より業務のパフォーマンスが下がる、
つまり短期的には見た目、会社への貢献度が下がるので
「ブログなんて書いてないで仕事しろ!」
と、みんなに思われてるんだろうなー、と考えながら書き続けてました。

こんな状況でも書き続けれたのは、僕がCTOというポジションだったからだと思います。
(CTOに「技術ブログを書くな!」と面と向かって言えるスタッフは少ないでしょう)

次は、キャッシュ(ブログ記事)が溜り、ヒット率が高くなりだした時期の話です!
--------
http://www.suz-lab.com

2012年10月13日土曜日

ELBの挙動確認(Enable Load Balancer Generated Cookie Stickiness)

スズキです。

前回、下記のようにCookieによるセッション維持を無効にした場合のELBの挙動を試したので
ELBの挙動確認(Disable Stikiness)
今回は、下記のようにELBが生成したCookieをもとにセッション維持する方法を有効にして
確認してみました。(テスト環境とテスト方法は上記の記事に記載しているものと同じです)


まずは、二つのIPアドレスの一方に対して確認してみます。
# cat /etc/hosts
xxx.xxx.xxx.xxx session-test.suz-lab.com
#yyy.yyy.yyy.yyy session-test.suz-lab.com

普通にアクセスすると、前回同様に一方のAZのEC2に対して交互にアクセスされることが
わかります。
# curl http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
# curl http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.1.193
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
つまり、セッション維持が行われていません。

それでは、ELBが生成したCookieを利用してアクセスしてみます。

まずはELBが生成したCookieを下記のように取得します。
# curl -c cookie.txt http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz

すると下記のようなCookie(AWSELB)が生成されていることがわかります。
# cat cookie.txt 
session-test.suz-lab.com  FALSE  /  FALSE  1350074674  SUZLAB  TEST
session-test.suz-lab.com  FALSE  /  FALSE  1350071373  AWSELB  55FD...
(このCookieに振り分け先EC2の情報が書かれているようです)

そして、次のようにCookieを利用してアクセスしてみます。
# curl -b cookie.txt http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 55FD...
COOKIE_SUZLAB : TEST
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
# curl -b cookie.txt http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 55FD...
COOKIE_SUZLAB : TEST
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
常に同じEC2(10.0.1.135)に振り分けられていることがわかります。

次に、ELBのもう一方のIPアドレスでも確認してみます。
# cat /etc/hosts
#xxx.xxx.xxx.xxx session-test.suz-lab.com
yyy.yyy.yyy.yyy session-test.suz-lab.com

先ほどと同じCookieでアクセスしてみます。
# curl -b cookie.txt http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 55FD...
COOKIE_SUZLAB : TEST
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
# curl -b cookie.txt http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 55FD...
COOKIE_SUZLAB : TEST
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
やはり先程と同じEC2(10.0.1.135)に振り分けられていることがわかります。
また、今度はアクセスしているELB(10.0.1.194)も同じになっています。
(ELBのDNS名に振られたIPアドレスとAZの話はどうなった?)

ちなみに、ELBが生成したCookieをもとにセッション維持する方法は下記のように
動作しています。
期間ベースのセッション維持の有効化

(1)ロードバランサーがリクエストを受け取ると、まずこの Cookie がリクエスト内に
あるかどうかを調べます。

(2)ある場合は、Cookie で指定されたアプリケーションインスタンスにリクエストが
送信されます。

(3)Cookie がない場合、ロードバランサーは、既存の負荷分散アルゴリズムに基いて
アプリケーションインスタンスを選択します。

(4)同じユーザーからの以降のリクエストをそのアプリケーションインスタンスに
バインドするため、応答に Cookie が挿入されます。
図にするとこんな感じでしょうか?


実際にTelnetを使ってアクセスしてみると、Cookieがない場合はELBがHTTPレスポンスで
Cookieをセットするように振舞っていることがわかります。
# telnet session-test.suz-lab.com 80
Trying zzz.zzz.zzz.zzz...
Connected to session-test.suz-lab.com.
Escape character is '^]'.
GET /elb.php HTTP/1.0

HTTP/1.1 200 OK
Cache-control: no-cache="set-cookie"
Content-Type: text/plain; charset=UTF-8
Date: Fri, 12 Oct 2012 20:31:53 GMT
Server: Apache/2.2.15 (CentOS)
Set-Cookie: SUZLAB=TEST; expires=Fri, 12-Oct-2012 21:31:53 GMT
Set-Cookie: AWSELB=55FD...;PATH=/;MAX-AGE=300
X-Powered-By: PHP/5.3.17
Content-Length: 118
Connection: Close

ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
Connection closed by foreign host.

X-Forwarded-Forに複数のIPアドレスがあらわれるパターンがわからない...
--------
http://www.suz-lab.com

ELBの挙動確認(Disable Stikiness)

スズキです。

こんな感じの構成を前提としています。


今回は、ELBのCookieによるセッション維持を無効にして試してみます。


まずは、ELBにふられているIPアドレスの確認です。
# nslookup test-000000000.ap-northeast-1.elb.amazonaws.com
Name: test-000000000.ap-northeast-1.elb.amazonaws.com
Address: xxx.xxx.xxx.xxx
Name: test-000000000.ap-northeast-1.elb.amazonaws.com
Address: yyy.yyy.yyy.yyy
二つふられていることがわかります。

このELB経由で、下記のPHPにアクセスして挙動を確認してみます。
<?php
header("Content-type: text/plain");
print("ELB_IPADDRESS : " . $_SERVER["REMOTE_ADDR"]          . "\n");
print("COOKIE_AWSELB : " . $_COOKIE["AWSELB"]               . "\n");
print("COOKIE_SUZLAB : " . $_COOKIE["SUZLAB"]               . "\n");
print("EC2_IPADDRESS : " . $_SERVER["SERVER_ADDR"]          . "\n");
print("X_FOWARDED_FOR: " . $_SERVER["HTTP_X_FORWARDED_FOR"] . "\n");
if(!isset($_COOKIE["SUZLAB"])) {
  setcookie("SUZLAB", "TEST", time() + 3600);
}
?>
特に、ELB_IPADDRESSとEC2_IPADDRESSの値に注目です。

まずは、二つのIPアドレスの一方に対して確認してみます。
# cat /etc/hosts
xxx.xxx.xxx.xxx session-test.suz-lab.com
#yyy.yyy.yyy.yyy session-test.suz-lab.com

すると、下記のように一方のAZのEC2に対して交互にアクセスされることがわかります。
# curl http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.0.113
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.0.191
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
# curl http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.0.113
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.0.109
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
ただしELBのIPアドレスは同じで、EC2と同じAZのものとなっています。

次に、ELBのもう一方のIPアドレスで確認してみます。
# cat /etc/hosts
#xxx.xxx.xxx.xxx session-test.suz-lab.com
yyy.yyy.yyy.yyy session-test.suz-lab.com

すると下記のように、もう一方のAZのEC2に対して交互にアクセスされることがわかります。
# curl http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.1.135
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
# curl http://session-test.suz-lab.com/elb.php
ELB_IPADDRESS : 10.0.1.194
COOKIE_AWSELB : 
COOKIE_SUZLAB : 
EC2_IPADDRESS : 10.0.1.193
X_FOWARDED_FOR: zzz.zzz.zzz.zzz
そしてELBのIPアドレスも、やはり同じです。ただし先ほどのIPアドレスとは変わっており、
こちらのEC2と同じAZのものとなっています。

ということで、ELBにふられているIPアドレスはAZごとに少なくても一つ用意され、
アクセスされたIPアドレスが所属するAZのEC2に優先的にふられているのでは?
と妄想できます。(ドキュメントに書いてあるかも?)

図にするとこんな感じでしょうか?


ELB間の矢印は、サーバーワークスさんの下記ブログに書かれたELBの挙動
(一方のAZのEC2障害)を考慮したものです。
ELBのローカルIPを2つ取得するケース
なので、負荷テストが難しい...
--------
http://www.suz-lab.com

2012年10月9日火曜日

SESのバウンス情報をSNS(HTTP)で通知してPHPで処理

スズキです。

下記でバウンスメールなどを簡単に発生させる(テストする)ことができるようになりました。

"Amazon SES Mailbox Simulator"を試してみた
その時に、通知をメールだけでなく、SNSでも行えることがわかったので、よく
メルマガ配信機能など作るときに実装するバウンスメールの処理を、このSNSでできないか
試してみました。


上記の記事では、下記のSNSのトピックに通知が行われるようになっており、


その通知先(サブスクリプション)はメールとしていました。

実は、この通知先に次のようにHTTP(S)を利用することも可能です。


登録すると確認メッセージが送信され、そのメッセージ中のURLにアクセスすることで
その通知先が承認されます。


通知先がメールの時は確認メールを受信して本文中のURLをクリックすれば
よかったのですが、HTTP(S)の場合はそうはいかず、確認メッセージは指定した
通知先URLにPOSTで送られて来ます。

なので、通知先URLは下記のようなPHPを配置しておきました。
<?php 
$json = file_get_contents("php://input");
error_log($json);
?>

この状態で上記の確認メッセージをPHPが受信すると、以下のようにエラーログに
出力されます。
[Mon Oct 08 21:41:06 2012] [error] [client 27.0.1.155] {
  "Type"             : "SubscriptionConfirmation",
  "MessageId"        : "0812b051-affc-4fd4-ba19-5f273d85cce2",
  "Token"            : "2336412f37fb687f5d51e6e241d09c81d...",
  "TopicArn"         : "arn:aws:sns:us-east-1:81111815109...",
  "Message"          : "You have chosen to subscribe to t...",
  "SubscribeURL"     : "https://sns.us-east-1.amazonaws.c...",
  "Timestamp"        : "2012-10-08T12:41:06.238Z",
  "SignatureVersion" : "1",
  "Signature"        : "rm9LegteKP4lOljphEMqtliGfv/NO6DvS...",
  "SigningCertURL"   : "https://sns.us-east-1.amazonaws.c..."
}
この"SubscribeURL"にアクセスすると、下記のようなXMLが表示され、


次のように、無事、通知先(サブスクリプション)が有効になります。


そして、ようやくSESでバウンスメールを発生させてみます。


すると、今度はエラーログに下記のようなバウンスメールの情報が出力されることが
わかります。

[Mon Oct 08 22:00:41 2012] [error] [client 27.0.1.155] {
  "Type" : "Notification",
  "MessageId" : "463fbb0b-63ea-4a6d-90c5-33c8686e3bd1",
  "TopicArn" : "arn:aws:sns:us-east-1:811118151095:suz-lab-ses",
  "Message" : "{
    \\"notificationType\\":\\"Bounce\\",
    \\"bounce\\":{
      \\"bounceType\\":\\"Permanent\\",
      \\"reportingMTA\\":\\"dns; a194-13.smtp-out.amazonses.com\\",
      \\"bouncedRecipients\\":[{
        \\"emailAddress\\":\\"bounce@simulator.amazonses.com\\",
 \\"diagnosticCode\\":
   \\"smtp; 5.1.0 - Unknown address error 550-'5.1.1 user unknown' (delivery attempts: 0)\\",
 \\"status\\":\\"5.0.0\\",
 \\"action\\":\\"failed\\"
      }],
      \\"bounceSubType\\":\\"General\\",
      \\"timestamp\\":\\"2012-10-08T13:00:39.000Z\\",
      \\"feedbackId\\":\\"0000013a40768691-29692462-1148-11e2-9...\\"
    },
    \\"mail\\":{
      \\"timestamp\\":\\"2012-10-08T13:00:39.000Z\\",
      \\"source\\":\\"suzuki@suz-lab.com\\",
      \\"messageId\\":\\"0000013a40768169-3ba4f620-da2b-4b4a-95...\\",
      \\"destination\\":[\\"bounce@simulator.amazonses.com\\"]
    }
  }",
  "Timestamp" : "2012-10-08T13:00:40.691Z",
  "SignatureVersion" : "1",  
  "Signature" : "FDNBWbFhc5MXs+2tjw327zXhiKca3GLHbbVEN8vUmLAmnj60...",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleN...", 
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action..."
}
あとは、この情報を、パースして、解析して、データベースに登録して、...
など、いつものバウンスメールの処理ロジックを実行するだけです。

図にすると、こんな感じでしょうか?

  1. メールを送信
  2. バウンスメールが返ってくる
  3. バウンスメールをユーザーに転送 / SNSのトピックに通知
  4. SNSがHTTP(S)でELBにアクセス
  5. ELBがHTTPでEC2にアクセス(ELBで"SSL Termination")
  6. バウンス情報を S3 / RDS / DynamoDB に保存
バウンス情報を処理するEC2は、"Auto Scaling"で必要に応じて増減させることもできます!

でも、SQSを通知先(サブスクリプション)にしたほうが、もっといいかも...
--------
http://www.suz-lab.com

2012年10月8日月曜日

S3のWebサイトのリダイレクト機能をTelnetで確認してみた

スズキです。

先日、下記の通りS3でWebサイトのリダイレクト機能が利用できるようになりました。

【AWS発表】Amazon S3 がウェブサイトのリダイレクト機能をサポート
ということで、リダイレクト機能を利用した場合のHTTPリクエスト/レスポンスを
Telnetで確認してみました。

まずは"Web Site Hosting"機能が有効なS3のバケットに、下記のHTMLを配置します。
<html>
  <head>
    <meta http-equiv="Refresh" content="0; URL=/index.html"/>
  </head>
  <body>Redirect!</body>
</html>
このメタダグを利用した方法は、HTMLレベルでリダイレクトを実現する場合に
よく使われるものだと思います。(JavaScriptで実現する方法もあります)

ちなみに、このファイルのメタデータ(AWSコンソール)は次のようになっています。




実際にTelnetでアクセスすると下記のような結果になります。
# telnet www.suz-lab.com 80
Trying 27.0.1.84...
Connected to www.suz-lab.com.
Escape character is '^]'.
GET /redirect.html HTTP/1.1
Host: www.suz-lab.com
Connection: close

HTTP/1.1 200 OK
x-amz-id-2: rwwJDcMcnLQPmBufmRyvtWdvSaUvfA9LUZHpcaB3zYtSFlgdtaDQOs5zkf7yas+P
x-amz-request-id: 5D4B5DA8D408FBE9
Date: Mon, 08 Oct 2012 10:27:30 GMT
Last-Modified: Mon, 08 Oct 2012 10:18:14 GMT
ETag: "86b349cf988679198ecc5c8ad80319dd"
Content-Type: text/html
Content-Length: 120
Server: AmazonS3

<html>
  <head>
    <meta http-equiv="Refresh" content="0; URL=/index.html"/>
  </head>
  <body>Redirect!</body>
</html>
Connection closed by foreign host.
これでも、メタタグで指定したURLにリダイレクトするはするのですが、
HTTPステータスコード200(OK)となっってしまいます。

できればリダイレクトの場合は、HTTPステータスコード301(Moved Permanently)に
したいところです。

で、S3でWebサイトのリダイレクト機能です。

リダイレクト機能は、下記のように対象ファイルに対してメタデータを設定することで
実現できます。



再度Telnetで確認すると、今度は下記のようになりました。
# telnet www.suz-lab.com 80
Trying 27.0.1.84...
Connected to www.suz-lab.com.
Escape character is '^]'.
GET /redirect.html HTTP/1.1
Host: www.suz-lab.com
Connection: close

HTTP/1.1 301 Moved Permanently
x-amz-id-2: NM3/B9pOI4AMgf9Tb5wWx5LlLlvFyUPAiL4rVrzyBml+pGz1tnYnhTAiJy/kkJ/S
x-amz-request-id: 605B05309A780ADB
Date: Mon, 08 Oct 2012 10:28:49 GMT
Location: /index.html
Content-Length: 0
Server: AmazonS3

Connection closed by foreign host.
HTTPステータスコード301(Moved Permanently)になり、リダイレクトの設定が、
Locationヘッダで行われていることが確認できます。(Bodyはありません)

"Permanent Redirectパターン"に加筆するか...
--------
http://www.suz-lab.com

AWS対応WAF InfoCage SiteShell Skipfish番外編

スズキです。

下記でWAFのインストールと簡単実験まで試してみたので、
AWS対応WAF InfoCage SiteShell インストール編
次は管理サーバをたてた"管理編"を書こうと思ったのですが、その前に、
以前、下記のようにSkipfishでの脆弱性診断を試したのを思い出して、

"skipfish"でWebアプリのセキュリティ診断
調子に乗って、このSiteShellにも仕掛けてみることにしました。

Skipfishのバージョンも、いろいろと上がっていたので、インストール(CentOS6)から
再度、確認です。

まずは、必要なパッケージのインストールです。
# yum -y install openssl-devel
# yum -y install pcre-devel
# yum -y install libidn-devel

次に、下記よりSkipfishのソースをダウンロードして、

Skipfish, version 2.09 beta - web application security scanner 

次のようにビルドします。
# cd /usr/local/src/
# curl -OL http://skipfish.googlecode.com/files/skipfish-2.09b.tgz
# tar xvzf skipfish-2.09b.tgz
# cd skipfish-2.09b
# make

そして早速、作成されたSkipfishのバイナリを下記のように実行します。
./skipfish -LY -W /dev/null -o sql http://localhost/sql.html

ちなみに、そのまま実行すると非常に時間がかかるので、下記で紹介した方法で診断時間の
短縮を行っています。("-V"オプションがなくなってる...)

skipfishを早く終了させるために
実行するとコンソールに下記のように途中経過が出力され、終了すると終了結果も
出力されます。
skipfish version 2.09b by lcamtuf@google.com

  - localhost -

Scan statistics:

      Scan time : 0:00:48.881
  HTTP requests : 14093 (288.3/s), 22499 kB in, 2716 kB out (515.8 kB/s)  
    Compression : 0 kB in, 0 kB out (0.0% gain)    
    HTTP faults : 0 net errors, 0 proto errors, 0 retried, 0 drops
 TCP handshakes : 14093 total (1.0 req/conn)  
     TCP faults : 0 failures, 0 timeouts, 0 purged
 External links : 38 skipped
   Reqs pending : 0          

Database statistics:

         Pivots : 236 total, 234 done (99.15%)    
    In progress : 0 pending, 0 init, 0 attacks, 2 dict       
  Missing nodes : 4 spotted
     Node types : 1 serv, 3 dir, 223 file, 0 pinfo, 4 unkn, 5 par, 0 valll
   Issues found : 9 info, 0 warn, 1 low, 0 medium, 0 high impact
      Dict size : 0 words (0 new), 0 extensions, 0 candidates
     Signatures : 75 total
        
[+] Copying static resources...
[+] Sorting and annotating crawl nodes: 236
[+] Looking for duplicate entries: 236
[+] Counting unique nodes: 51
[+] Saving pivot data for third-party tools...
[+] Writing scan description...
[+] Writing crawl tree: 236
[+] Generating summary views...
[+] Report saved to 'sql/index.html' [0x92d5631c].
[+] This was a great day for science!

レポートは下記のようにHTMLで出力されます。


そしてSiteShellのログには、次のように出力されていました。
(画像をクリックして拡大して見てください)


いろいろと攻撃が検知されていることがわかります。

次は"管理コンソール編"...
--------
http://www.suz-lab.com

AWS対応WAF InfoCage SiteShell インストール編

スズキです。

ちょっと昔になりますが、"InfoCage SiteShell"というNEC製のWAFがAWSに対応しました。
国内初!「アマゾン ウェブ サービス」に、
WAFソフトとクラスタリングソフト提供開始
実際に下記のページでもAWSに対応していることが確認できます。
国内主要クラウド基盤サービス(IaaS)での動作

そして、この製品はトライアル版も用意されており、試しに下記のAMIで
動作確認してみました。

SUZ-LAB謹製 CentOS AMI (6.3.3 ap-northeast-1)

トライアル版のダウンロードは下記より可能です。
ダウンロード : Webアプリケーションファイアウォール製品 InfoCage SiteShell





上記より"Apache Linux 版"をダウンロードしたら、下記のようにインストールです。
(JavaがインストールされておりApacheも起動している必要があります)
# cd /opt/SiteShell/src/
# ls
SiteShell_ApacheLinux_Trial.zip
# unzip SiteShell_ApacheLinux_Trial.zip
# ls
Apache(Linux)_Trial  SiteShell_ApacheLinux_Trial.zip
# cd Apache\(Linux\)_Trial/Apache/Linux/x64
# ls
SiteShell_Apache-1.6.0.0-1.x86_64.rpm
# rpm -Uvh SiteShell_Apache-1.6.0.0-1.x86_64.rpm
RPMで簡単にインストールできます。

インストールができたら、次のように設定スクリプトを実行します。
# cd /opt/SiteShell_Apache/
# ./setup.sh 
Please enter JDK/JRE install path for SiteShell or enter [q] to quit:/usr/lib/jvm/jre
Please enter license ID or enter [i] to ignore or enter [q] to quit:i
The following versions can be selected:
1. Apache1.3.x
2. Apache1.3.x(EAPI)
3. Apache2.0.x
4. Apache2.2.x
Please enter a number from '1' to '4' to select the apache version which siteshell will be installed into :4
The selected apache version : 4. Apache2.2.x
Please enter [r] to reset, [c] to continue, or [q] to quit:c
Please enter apache configuration file or enter [q] to quit:/etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf
Please enter [s] to setup or [q] to quit:s
Run SiteShell in test mode? [y/n]:y
Enable all protection automatically? [y/n]:y
SiteShell is being setuped...
Setup successfully !
SiteShellServiceForApache installed.
Starting SiteShellServiceForApache  
SiteShellServiceForApache was started
SiteShell has been installed successfully, you must restart apache server to enable the installation!
Do you want to restart apache server right now? [y/n] :y
httpd を停止中:                                            [  OK  ]
httpd を起動中: httpd: apr_sockaddr_info_get() failed for ip-10-0-0-166
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName

7-Zip (A) [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=C,Utf16=off,HugeFiles=on,1 CPU)

Processing archive: /opt/SiteShell_Apache/config/SiteShell_logic.jar

Extracting  recipe/OSC.xml
Extracting  recipe/PT.xml
Extracting  recipe/SF.xml
Extracting  recipe/SQL.xml
Extracting  recipe/XSS.xml

Everything is Ok

Files: 5
Size:       57218
Compressed: 89995

7-Zip (A) [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=C,Utf16=off,HugeFiles=on,1 CPU)

Processing archive: /opt/SiteShell_Apache/config/SiteShell_logic.jar

Extracting  CSC.properties
Extracting  LogicVersion.properties

Everything is Ok

Files: 2
Size:       823
Compressed: 89995
                                                           [  OK  ]

設定が完了したら下記のSQLを使って、SQLインジェクションを試してみます。
SELECT * FROM user WHERE uid='suz-lab' AND pwd='' OR 'A'='A'

下記のフォームに上記のSQLを入力して、

<html>
  <body>
    <form action="success.html">
      <textarea name="sql">SELECT * FROM user WHERE uid='suz-lab' AND pwd='' OR 'A'='A'</textarea>
      <input type="submit"/>
    </form>
  </body>
</html>

送信ボタンを押すと、次のような成功ページにいきます。

<html>
  <body>success</body>
</html>

本来なら、SiteShellのエラーページが表示されるのですが、トライアル版は防御までは
できず、検知のみとなっています。

ということで、下記のログを確認すると、
# cat /opt/SiteShell_Apache/logs/audit/audit.log
[2012/10/08 15:59:23][SQL][SQL-0015-03][replace(noaction)][xxx.xxx.xxx.xxx][/success.html][paramValues]sql=SELECT * FROM user WHERE uid='suz-lab' AND pwd='' OR 'A'='A'
SQLインジェクションとして検知されていることが確認できます。

Skipfishかけてみよう...
--------
http://www.suz-lab.com

2012年10月4日木曜日

"Amazon SES Mailbox Simulator"を試してみた

スズキです。

"Amazon SES Mailbox Simulator"とは、SESでのメール送信における、いくつかの挙動を
シミュレートできる仕組みです。
といっても仕組みは簡単で、いくつかのメールアドレスが用意されており、SESから、
そのメールアドレスに送信し、それぞれのメールアドレスに割り当てられた挙動を
確認する形となっています。

メールアドレスは下記の5個が用意されています。
  • Success : success@simulator.amazonses.com

    この宛先のメールボックスにメールが無事、送信された挙動を示します。
    エラーメールなどが戻ってくることはありません。

  • Bounce : bounce@simulator.amazonses.com

    この宛先へのメールが"SMTP 550 5.1.1 response code ("Unknown User")"で
    送信できなかった挙動を示します。エラーメール戻ってきたり、SNSで通知されます。

  • Out of the Office : ooto@simulator.amazonses.com

    この宛先のメールボックスにメールは届きますが、"out-of-the-office"(OOTO)
    と呼ばれるメッセージが返される挙動を示します。このメッセージはメールで
    戻ってきたり、SNSで通知されます。

  • Complaint : complaint@simulator.amazonses.com

    この宛先のメールボックスにメールは届きますが、スパムとして報告される挙動を
    示します。スパム報告はメールで戻ってきたり、SNSで通知されます。

  • Address Blacklisted : blacklist@simulator.amazonses.com

    この宛先はSESのブラックリストに登録されており、送信自体ができない共同を
    示します。

では実際にAWSコンソールからSESで上記の宛先にメールを送信して確認してみます。

その前に、"Bounce / Out of the Office / Complaint"が発生したときに、SNSでも
通知される設定を行っておきます。

SESの検証されたメールアドレスの"Feedback Details"で設定でき、


"Edit Configuration"ボタンでSNSの通知を行い、


"Click here to create a new Amazon SNS topic"から通知先トピックを作成し、


作成したトピックをBounceとComplaintの通知先として設定すると、


SESのBounceとComplaintに対して、SNSでも通知がくるようになります。


実際に通知されるには、SNSのトピックに対してサブスクリプション(通知先)を
設定する必要もあります。(トピックは"US East"にあります!)


SESの方で作成したトピックに対して、通知先を設定します。


一旦、メールアドレスの検証待ちとなるので、


検証用に届いたメールのURLをクリックすることで、


検証完了の状態にします。


それでは"Amazon SES Mailbox Simulator"にメールを送信してみます。

まずは、"Success : success@simulator.amazonses.com"です。


正常に送信されていることになっているので、メールが戻ってきたり、SNSの通知が
くることはありません。

次に、"Bounce : bounce@simulator.amazonses.com"です。


下記のメールと、



SNSの通知が届きました。


そして、"Out of the Office : ooto@simulator.amazonses.com"です。


下記のメールと、


SNSの通知が届きました。


さらに、"Complaint : complaint@simulator.amazonses.com"です。


下記のメールと、


SNSの通知が届きました。


最後に、"Address Blacklisted : blacklist@simulator.amazonses.com"です。


送信時のときにエラーになってしまいました。


SESを使う理由がもう一つ増えた!
--------
http://www.suz-lab.com

SUZ-LAB謹製 CentOS AMI (6.3.3 ap-northeast-1)

スズキです。

下記をアップデートしました。
SUZ-LAB謹製 CentOS AMI (6.2.1 64bit ap-northeast-1)
AMIを「suz」で検索してもらえれば、
811118151095/suz-lab_centos-core-6.3.3
として見つかるはずです。

今回は、CentOS自体のバージョンが6.2から6.3に上がり、カーネルも最新のパッケージ
(2.6.32-279.9.1.el6)で起動するようになっています。

また、すべてのインスタンスタイプで64bitのOSが起動できるようになったので、
作成するAMIも今後、64bitのもののみとするつもりです。

アップデートは下記のように行っています。

▼パッケージのアップデート
# yum -y update
▼CentOSのバージョン確認
# cat /etc/redhat-release 
CentOS release 6.3 (Final)
▼起動カーネルの更新
# cat /boot/grub/menu.lst
default=0
timeout=0
hiddenmenu
title SUZ-LAB CentOS 6
root (hd0)
kernel /boot/vmlinuz-2.6.32-279.9.1.el6.x86_64 ro root=/dev/xvde1
initrd /boot/initramfs-2.6.32-279.9.1.el6.x86_64.img
▼変更したカーネルで起動
# reboot
▼カーネルが変更されていることを確認
# uname -a
Linux ip-10-150-174-115 2.6.32-279.9.1.el6.x86_64 #1 SMP Tue Sep 25 21:43:11 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
▼古いカーネルを削除
# yum -y remove kernel-2.6.32-279.2.1.el6
▼いろいろとクリア
# echo "" > /root/.ssh/authorized_keys
# echo "" > /var/log/boot.log
# echo "" > /var/log/btmp
# echo "" > /var/log/cron
# echo "" > /var/log/dmesg
# echo "" > /var/log/dmesg.old
# echo "" > /var/log/lastlog
# echo "" > /var/log/maillog
# echo "" > /var/log/messages
# echo "" > /var/log/secure
# echo "" > /var/log/spooler
# echo "" > /var/log/tallylog
# echo "" > /var/log/wtmp
# echo "" > /var/log/yum.log
# echo "" > /var/log/audit/audit.log
# history -c

Enjoy!
--------
http://www.suz-lab.com

2012年10月3日水曜日

EBS暗号化ツールSecureCloudを使ってみる(登録編)

スズキです。

以前、EBSの暗号化ツールとして"cryptsetup"を紹介しましたが、
トレンドマイクロ社が下記の"SecureCloud"と呼ばれる、同様の(高機能の)を商用ツール
もあるので、今回は、こちら(Free Trial)を試してみました。



まずは"Free Trial"ボタンから、トライアルライセンス(Activation Code)を取得します。

下記のように登録を行うと、


以下のようにトライアルライセンスの"Activation Code"が発行されます。


そして、"Management Console"への"Continue"ボタンを押して、今度は次のように
"Management Console"への登録を行います。


上記のアカウントが利用できるようになったら、下記のように"Management Console"に
ログインします。(実はアカウントが登録済みだったので上記の登録は行っていません...)


ログインすると、以下のように左に、いろいろなメニューのあるページになります。


そして、下記のメニュー(Production License)から"Activation Code"の登録を行います。


すでに昔の期限切れトライアルライセンスのものが登録されていたので、


"Please enter a new activation code"ボタンより、最初に取得したトライアルライセンスの
"Activation Code"に入れ替えます。


入れ替えが成功すると次のようになり、60日間、合計5個のEBSまで利用することが
確認できます。(すでに1個使っちゃってます...)


最後に、下記のメニュー(User Management)から、エージェントをインストールするときに
利用する情報を確認しておきます。


エージェントをインストールするときに必要な情報は、"Account ID"と
"Provision passphrase"となります。


さらに、エージェントのインストールとEBSの暗号化と続きます。

今日中に全部書いて、引き継ぐ!
--------
http://www.suz-lab.com