2012年1月31日火曜日

VPCのサブネット内で利用できるIPアドレスを取得(PHP)

スズキです。

VPCでELBを利用していると、ELBは負荷に応じてスケールして
サブネット内のIPアドレスを消費してしまいます。

ですので、ELBが存在するサブネット内で十分は利用可能なIPアドレスがあるか、
逐次チェックしたいと思うはずです。

ということでPHP(AWS SDK)でVPCのサブネットの利用可能なIPアドレスを取得してみました。

#!/usr/bin/php
<?php
require_once("/opt/aws/php/latest/sdk.class.php");
$ec2 = new AmazonEC2("ACCESS_KEY", "SECRET_KEY");
$ec2->set_region("ap-northeast-1");
$response = $ec2->describe_subnets(array("SubnetId" => "subnet-xxxxxxxx"));
print((int)$response->body->subnetSet->item->availableIpAddressCount);
?>

実行すると下記のようになります。

# ./get-subnet-ip 
249

これも、また、Nagiosのプラグインにしよう。
--------
http://www.suz-lab.com

2012年1月30日月曜日

NagiosのCloudWatchプラグイン(PHP版)でRDSの監視

スズキです。

こちらでEC2のCPU使用率が監視できるようになったので、
NagiosのCloudWatchプラグイン(PHP版)を実際に利用
今回はRDSの監視をしてみます。

RDSで監視する項目は、実装の都合上(後述)
CPUUtilization, DatabaseConnections, SwapUsage
としています。

Nagiosのコマンドは、下記のように設定します。

# RDS CPUUtilization
define command {
    command_name    check-cloudwatch-cpu_rds-cloudpack
    command_line    /opt/cloudpack/nagios/check_cloudwatch -f /opt/cloudpack/conf/$HOSTGROUPNAME$/credential.yml -n AWS/RDS -m CPUUtilization -s Average -u Percent -d DBInstanceIdentifier -r ap-northeast-1 -w $ARG1$ -c $ARG2$ -v $ARG3$
}

# RDS DatabaseConnections
define command {
    command_name    check-cloudwatch-connection_rds-cloudpack
    command_line    /opt/cloudpack/nagios/check_cloudwatch -f /opt/cloudpack/conf/$HOSTGROUPNAME$/credential.yml -n AWS/RDS -m DatabaseConnections -s Average -u Count -d DBInstanceIdentifier -r ap-northeast-1 -w $ARG1$ -c $ARG2$ -v $ARG3$
}

# RDS SwapUsage
define command {
    command_name    check-cloudwatch-swap_rds-cloudpack
    command_line    /opt/cloudpack/nagios/check_cloudwatch -f /opt/cloudpack/conf/$HOSTGROUPNAME$/credential.yml -n AWS/RDS -m SwapUsage -s Average -u Bytes -d DBInstanceIdentifier -r ap-northeast-1 -w $ARG1$ -c $ARG2$ -v $ARG3$
}

そのコマンドを利用して、下記のように監視設定します。

# RDS CPUUtilization
define service {
    use                    suzlab_cloudpack.jp-service
    host_name              suzlab_cloudpack.jp_suzlab-rds
    service_description    cpu_rds
    service_groups         cpu_rds
    check_command          check-cloudwatch-cpu_rds-cloudpack!60!80!suzlab
}

# RDS DatabaseConnections
define service {
    use                    suzlab_cloudpack.jp-service
    host_name              suzlab_cloudpack.jp_suzlab-rds
    service_description    connection_rds
    service_groups         connection_rds
    check_command          check-cloudwatch-connection_rds-cloudpack!50!100!suzlab
}

# RDS SwapUsage
define service {
    use                    suzlab_cloudpack.jp-service
    host_name              suzlab_cloudpack.jp_suzlab-rds
    service_description    swap_rds
    service_groups         swap_rds
    check_command          check-cloudwatch-swap_rds-cloudpack!0!0!suzlab
}

問題なければ下記のようにWebの方でも表示されているはずです。

RDS CPUUtilization


RDS DatabaseConnections


RDS SwapUsage


ちなみに現状のNagiosのCloudWatchプラグインのコードは次のようになっています。

#!/usr/bin/php
<?php
require_once("/opt/aws/php/latest/sdk.class.php");

// define status
$ok       = array("code" => 0, "name" => "OK");
$warning  = array("code" => 1, "name" => "WARNING");
$critical = array("code" => 2, "name" => "CRITICAL");
$unknown  = array("code" => 3, "name" => "UNKNOWN");

// set option
$option = getopt("c:w:f:r:n:m:s:u:d:v:");
$critical_size = $option["c"];
$warning_size  = $option["w"];
$credential    = yaml_parse_file($option["f"]);
$region        = $option["r"];
$namespace     = $option["n"];
$metrics       = $option["m"];
$statistics    = $option["s"];
$unit          = $option["u"];
$name          = $option["d"];
$value         = $option["v"];

// init cw
$cw = new AmazonCloudWatch($credential["accessKey"], $credential["secretKey"]);
$cw->set_region($region);
date_default_timezone_set("Asia/Tokyo");

// get metric statistics
$response = $cw->get_metric_statistics(
    $namespace,
    $metrics,
    "-10 minutes",
    "now",
    300,
    $statistics,
    $unit,
    array(
        "Dimensions" => array(
            array("Name" => $name, "Value" => $value)
        )
    )
);
$data = (float)$response->body->GetMetricStatisticsResult->Datapoints->member->$statistics->to_string();

// check status
if($data > $critical_size) {
    $status = $critical["code"];
} elseif($data > $warning_size) {
    $status = $warning["code"];
} elseif($data >= 0) {
    $status = $ok["code"];
} else {
    $status = $unknown["code"];
}

// output status
$output = " - ${namespace} ${metrics} ${statistics} ${name} ${value}: ${data} ${unit};| data=${data};${warning_size};${critical_size};0;";
switch($status) {
    case $ok["code"]:
        print("CloudWatch " . $ok["name"]       . $output);
        exit($ok["code"]);
    case $warning["code"]:
        print("CloudWatch " . $warning["name"]  . $output);
        exit($warning["code"]);
    case $critical["code"]:
        print("CloudWatch " . $critical["name"] . $output);
        exit($critical["code"]);
    case $unknown["code"]:
        print("CloudWatch " . $unknown["name"]  . $output);
        exit($unknown["code"]);
}
print("CloudWatch " . $unknown["name"] . $output);
exit($unknown["code"]);
?>

見てのとおり、WarningやCriticalは閾値「より大きい」の場合となっています...
RDSにはFreeableMemoryやFreeStorageSpaceと、閾値「より小さい」場合を
WarningやCriticalにする項目もあり、現状それには対応できていません...

次回は「より小さい」にも対応してRDSの監視をもっと細かく出来るようにしよう!
--------
http://www.suz-lab.com

2012年1月27日金曜日

NagiosのCloudWatchプラグイン(PHP版)を実際に利用

スズキです。

少し時間がたってしまいましたが、下記で作成したNagiosのCloudWatchプラグインを
実際に利用して、EC2のCPU使用率を監視してみました。
NagiosのCloudWatchプラグイン(PHP版)
まずは、下記のようにコマンドを定義します。

define command {
    command_name    check-cloudwatch-cpu-cloudpack
    command_line    /opt/cloudpack/nagios/check_cloudwatch -f /opt/cloudpack/conf/$HOSTGROUPNAME$/credential.yml -n AWS/EC2 -m CPUUtilization -s Average -u Percent -d InstanceId -r ap-northeast-1 -w $ARG1$ -c $ARG2$ -v $ARG3$
}

次に、下記のように作成したコマンドを利用して、EC2を監視するようにします。

define service {
    use                    admin_cloudpack.jp-service
    host_name              admin_cloudpack.jp_admin-a-ec2
    service_description    cloudwatch_cpu
    service_groups         cloudwatch_cpu
    check_command          check-cloudwatch-cpu-cloudpack!60!80!i-xxxxxxxx
}

今回はCPU使用率が60%でwarning、80%でcriticalになるようにしています。

Nagiosを再起動すると、下記のように監視できていることが確認できます。


次はRDSの監視も作ろう。
--------
http://www.suz-lab.com

2012年1月24日火曜日

VPCのSubnetとELBの関係(Availability Zone編)

スズキです。

前回はVPC上で構築するELBと、ELBにアタッチするSubnetと、
そのSubnetで必要なIPアドレスについてまとめました。
VPCのSubnetとELBの関係(Available IP編)
そして、ELBにアタッチできるSubnetは複数アタッチすることができるので、
今回は、アタッチする複数のSubnetとAvailability Zoneの関係をまとめてみます。

まずは下記のようにaゾーンに属する2つのSubnentとbゾーンに属する
1つのSubnetを容易します。



あらかじめaゾーンのSubnet(10.0.0.0/24)をアタッチしておき、
さらに同じaゾーンのSubnet(10.0.4.0/25)をアタッチすると、


下記のように後からアタッチしたSubnetに入れ替わってしまいます。
どうも、同じゾーンのSubnetは複数アタッチできないようです。


このaゾーンのSubnet(10.0.4.0/25)がアタッチされた状態で、
bゾーンのSubnet(10.0.1.0/24)をアタッチすると、今度は追加される形で
アタッチされることがわかります。


今度は複数ゾーンのSubnetをアタッチに関して、Subnetで必要なIPアドレス数を
確認してみます。

まずは、aゾーン、bゾーン、それぞれの利用可能なIPアドレスの合計が
123未満の場合で試してみます。
(ELBを作成するにはSubnetに利用可能なIPアドレスが123必要です)



やはり、IPアドレスが足りない旨のエラーが出力されます。


次に、aゾーン、bゾーン、それぞれの利用可能なIPアドレスの合計が
123以上の場合で試してみます。




利用可能なIPアドレスの合計が123以上でも、まだ、
IPアドレスが足りない旨のエラーが出力されてしまいます。


そして、aゾーン、bゾーンのどちらか一方の利用可能なIPアドレスが
123以上の場合で試してみます。



一方のゾーンの利用可能なIPアドレスの合計が123以上でも、やはり、
IPアドレスが足りない旨のエラーが出力されてしまいます。


そして、aゾーン、bゾーンの両方の利用可能なIPアドレスが
123以上の場合で試してみます。



今度は無事、ELBを作成することができました。


つまり、ELBに対して複数のゾーン(Subnet)をアタッチする場合は、
どちらのSubnetの利用可能なIPアドレスも123以上、必要となることになります。

VPNとSubnetとELBの関係は、これである程度まとまったかな…
--------
http://www.suz-lab.com

2012年1月20日金曜日

VPCのSubnetとELBの関係(Available IP編)

スズキです。

以前、VPCでELBを作成するときに、所属するSubnetのCIDRブロックに関して紹介しました。
(少なくとも"/25"ということでしたが)
VPC上のELBに対するサブネットのCIDRブロックについて

今回は、このELBとSubnetの関係を、もう少し掘り下げてみます。

まずはSubnetを、どこまで細かく切れるか確認してみます。


Netmaskは最小28、最大16ということになります。

では、最小の28でSubnet(10.0.2.0/28)を作ってみます。
ちなみに、この時に利用できるIP(Available IP)は11です。


そして、このSubnetに対してELBを作成してみます。


当然、Netmaskが25より小さいので作成できません。
エラーメッセージをみると、
ELBを作成するには少なくても123個の利用可能なIPアドレスが必要
ということになります。

ということで、Netmaskを25にして作成してみます。
この時に利用できるIP(Available IP)は123です。


当然、利用可能なIPアドレスが123個になるのでELBは作成できるのですが、
もう一つ同じSubnetにELBを作成しようとすると、今度は利用可能なIPアドレスが、
一つ減って122個なので、下記のように作成することができません。


つまり、Netmaskが25のSubnetでは、ELBは一つしか作成できないことになります。

今度は、Netmaskを24にして作成してみます。
この時に利用できるIP(Available IP)は251です。


すると、当然といえば当然ですが、下記のように複数のELBを同一のSubnetに
作成することができます。
(おそらく残りの利用可能なIPが122個になるまで作成できると思います)


そもそもELBが作成できるSubnetのNetmaskの最小が25になってるのは、
ELBが適切にスケールするためのはずです。
そうだと、ELB一つに対して、122個の利用可能なIPアドレスを用意しておく必要があると、
思ってしまうのですが、Netmaskが24の時は、おそらく残りのIPアドレスが122個になる、
129個のELBが作成できてしまうと思います。
この場合は、一つのELBに対して、平均1個弱のIPアドレスしかスケールのために
用意されてないことになります。

このあたりは、少し不思議な感覚になってしまいますが、そういうものなのでしょう…

とりあえず、整理できたぞ!
--------
http://www.suz-lab.com

skipfishでログイン後のページのセキュリティ診断

スズキです。

下記でskipfishを現実的なスピードで実施できるようになったので、
skipfishを早く終了させるために
今回は、ログイン後のページに対してもセキュリティ診断してみます。

といっても、ログイン後の埋めこまれているCookieをskipfish実行時に指定するだけです。

Cookieの確認は下記のようにChromeなどのブラウザで行うことができます。



上記で確認した、ログイン維持に利用しているCookieを、
下記のようにskipfish実行時に指定(-C CAKEPHP=xxxxxxxxxxxxxxxxxxxxxxxxxx)します。

# ./skipfish -LVY -W /dev/null -C CAKEPHP=xxxxxxxxxxxxxxxxxxxxxxxxxx \
> -X /login -X /logout -o portal-auth http://www.suz-lab.com/

ここで、”-X”オプションは除外するパスを指定するもので、
今回はセッションがクリアされてしまう、ログイン(/login)とログアウト(/logout)を
除外するようにしています。

セキュリティ診断対象のWebサーバのサクセスログで、
ちゃんとログインしていないとアクセスできないページが出力されていれば、成功です。

セキュリティ診断職人、ブラッシュアップしよう。
--------
http://www.suz-lab.com

2012年1月18日水曜日

暗号化ファイルシステム(cryptsetup)を更にDRBDで冗長化(2)

スズキです。

こちらでDRBD上にcryptsetupで暗号化ファイルシステムを作成したので、
暗号化ファイルシステム(cryptsetup)を更にDRBDで冗長化(1)
今回は、スタンバイ状態のマシンにフェイルオーバーしても、
問題なくファイルシステムが利用できるか確認してみます。

まずは、アクティブマシンでの作業です。

ファイルシステムの中身を確認し、

# ls /mnt/encrypted/
lost+found  test.txt

アンマウントし、

# umount /mnt/encrypted/

DRBDもセカンダリにし、

# drbdsetup /dev/drbd0 secondary

DRBDの状態がセカンダリになっていることを確認しておきます。

# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.3.12 (api:88/proto:86-96)
GIT-hash: e2a8ef4656be026bbae540305fcb998a5991090f build by dag@Build32R6, 2011-11-20 10:55:07
m:res    cs         ro                   ds                 p  mounted  fstype
0:mysql  Connected  Secondary/Secondary  UpToDate/UpToDate  C

次に、スタンバイマシンでの作業です。

まずは、DRBDをプライマリにします。

# drbdsetup /dev/drbd0 primary

次に、ちゃんとプライマリになっていることを確認します。

# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.3.12 (api:88/proto:86-96)
GIT-hash: e2a8ef4656be026bbae540305fcb998a5991090f build by dag@Build32R6, 2011-11-20 10:55:07
m:res    cs         ro                 ds                 p  mounted  fstype
0:mysql  Connected  Primary/Secondary  UpToDate/UpToDate  C

そして、DRBDのデバイスをオープンします。オープン時に聞かれるパスフレーズは、
アクティブサーバで入力したものと同じ物を利用します。

# cryptsetup luksOpen /dev/drbd0 encrypted
Enter passphrase for /dev/drbd0: 

最後に、マウントして、ファイルシステムとして利用できるようにします。

# mount -t ext4 /dev/mapper/encrypted /mnt/encrypted

ファイルシステムの中身を確認すると、
アクティブサーバと同様の状態であることがわかります。

# ls /mnt/encrypted/
lost+found  test.txt

Next Stepとしては、
(1)パスフレーズなしで利用できるよにする。
(2)Heartbeatと連動してフェイルオーバーするようにする。
(3)フェイルオーバー時に接続先も自動的に変更するよにする(EIP/VPCルーティング)
といった感じでしょうか?(上記もブログ化できるように頑張ります)

とりあえず、skipfishに戻るか...
--------
http://www.suz-lab.com

暗号化ファイルシステム(cryptsetup)を更にDRBDで冗長化(1)

スズキです。

クラウド上だと、セキュリティを気にし、ディスクの暗号化が要件になることが
よくあります。このような場合は、下記で紹介されているようにcryptsetupと呼ばれる
オープンソースのツールを利用して実現することができます。
cryptsetupで暗号化ファイルシステムの作成 - lost and found ( for me ? )
今回は、この暗号化されたファイルシステム(ディスク)をさらに"DRBD"で
冗長化する方法を試してみます。

その前に、DRBDの状態を確認して、作業するマシンがプライマリになるように
しておきます。

# drbdsetup /dev/drbd0 primary
# /etc/init.d/drbd status
drbd driver loaded OK; device status:
version: 8.3.12 (api:88/proto:86-96)
GIT-hash: e2a8ef4656be026bbae540305fcb998a5991090f build by dag@Build32R6, 2011-11-20 10:55:07
m:res    cs         ro                 ds                 p  mounted  fstype
0:mysql  Connected  Primary/Secondary  UpToDate/UpToDate  C

まずは、cryptsetup(CentOS 6)をインストールします。

# yum -y install cryptsetup

次に、DRBDのデバイス(/dev/drbd0)をフォーマットします。
フォーマット時にパスフレーズを入力する必要もおります。

# cryptsetup -y luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 /dev/drbd0 

WARNING!
========
This will overwrite data on /dev/drbd0 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase: 
Verify passphrase: 

そして、フォーマットしたデバイスをオープンします。オープン時にも同様の
パスフレーズを入力します。オープンされると、/dev/mapper/encryptedという
デバイス(デバイスマッパー)が作成され、以後、このデバイスを利用していきます。

# cryptsetup luksOpen /dev/drbd0 encrypted
Enter passphrase for /dev/drbd0: 

その後、ファイルシステムをフォーマットします。

# mkfs.ext4 /dev/mapper/encrypted 
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
65408 inodes, 261615 blocks
13080 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8176 inodes per group
Superblock backups stored on blocks: 
 32768, 98304, 163840, 229376

Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 36 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

最後にマウントすることでdrbdで冗長化された暗号化ファイルシステムが
利用できるようになります。

# mkdir /mnt/encrypted
# mount -t ext4 /dev/mapper/encrypted /mnt/encrypted

次は、フェイルオーバーしても(スタンバイマシンで)暗号化ファイルシステムが
利用できることを確認してみます。

多分、大丈夫...
--------
http://www.suz-lab.com

2012年1月17日火曜日

skipfishを早く終了させるために

スズキです。

以前、下記よりskipfishを利用したセキュリティ診断を紹介しました。
"skipfish"でWebアプリのセキュリティ診断

しかしこのskipfish、実際に利用してみると診断が全然終わりません。
アクセスログなどでアクセス内容を確認してみると、延々と、膨大な辞書ファイル上の
キーワードに対して、それらをファイル名としたURLのチェックをしています。

このURLチェックは実行時間を考えると現実的ではないので、下記のようなオプションで、
このチェックを行わないようにすることができます。

./skipfish -LVY -W /dev/null -o admin http://www.suz-lab.com/

オプションは下記のとおりです。
-L: do not auto-learn new keywords for the site
-V: do not update wordlist based on scan results
-Y: do not fuzz extensions in directory brute-force
-W wordlist: load an alternative wordlist (skipfish.wl)
(今回は辞書ファイルを使わないように"/dev/null"を指定しています)

これで、キーワードによるURLチェックがスキップでき、
セキュリティ診断を短時間で実施することができます。

ディレクトリ数が少ないサイトならいいんだけど...
--------
http://www.suz-lab.com

スナップショットからWindowsインスタンスを復元

スズキです。

よく、スナップショットからAMIを作成して昔の状態のEC2インスタンスを復元する
ってことをやっているのですが、スナップショットからWindowsのAMIを作成することは、
現時点でできないようです。

なので、定期的にスナップショットはとっているものの、いざ復元するときは、
AMIにはできないので、Windows自体の復元はできず、Root Device(Cドライブ)を
適当にアタッチして、ファイルを取り出すことしかできないと思っていました。

そしたら cloudpack Night #1@oko_chang が、それに近い内容を発表してくれました。
(ありがとうございます!)

発表内容は、Windows AMIのリージョン間移行だったのですが、
移行元リージョンのWindowsをスナップショットとって移行先リージョンのWindowsで
復元するって部分は、まさに上記の問題の解決方法となります。

基本的な考え方は、インスタンスはストップするとRoot DeviceのEBSも交換できるので、
AMIを作るのではなく、スナップショットから作成したRoot DeviceのEBSを、
適当なWindowsのものと差し替えてしまうものです。

具体的な手順は下記となります。

まずはバックアップです。

(1)スナップショットを取るインスタンス(バックアップ元)を停止します。


(2)停止したインスタンスのEBS(Root Device)のスナップショットをとります。


(3)スナップショットがとれたら、取得元のインスタンスをターミネートします。

 

そして、復元です。

(4)スナップショットからEBSを作成します。


※サイズはスナップショットと同じ(30G)にします。
※ゾーン(AZ)は復元に使うインスタンスと同じ(a)にします。


(5)予め起動していた復元用インスタンス(Windows)を停止します。


(6)復元用インスタンスのEBS(Root Device)をデタッチします。


(7)復元用インスタンスにスナップショット(バックアップ元)から作成した
EBS(Root Device)をアタッチします。


※デバイスはRoot Deviceとしてアタッチするので"/dev/sda1"とします。

 

(8)復元用インスタンスをスタートします。


リモートデスクトップでログインすると、ちゃんとスナップショットをとったWindowsが
復元されていることを確認することができます。

今まで、できないと思って、再インストールしてた...
--------
http://www.suz-lab.com