« 2010年1月 | トップページ | 2010年4月 »

2010年2月

2010年2月23日 (火)

LinuxでchrootによるJail環境を構築

FreeBSDにはJailという簡易仮想マシンを作るコマンドがあるけど、残念ながら
Linuxにはない。ただ、chrootという古くからあるunixコマンドで仮想マシンに
近いことができる。
この辺のことについては、Apacheセキュリティ という本に記述されている。
Apacheセキュリティの場合は、root権限を使わないようにしたり、必要最低限の
ファイルのみをJail環境に移行することによって、セキュリティを強固にするため
に使われている。
私の場合は、自分のプロジェクトのチームが作成しているWebアプリが、/etc配下
の設定ファイルのパスをソースに直で書いてあるため、設定ファイルを書き換え
て、Webアプリを同時に2個立ち上げることができなかったためにJail環境を構築し
た。そのため、厳密にセキュリティを考慮していないが、悪しからず。
Apacheセキュリティでは、必要な実行ファイルとその実行ファイルを引数にlddを
実行して、依存関係のあるファイルのみ移行していた。

sudo su -l

rootになる。

mkdir /chroot

適当なchroot用のディレクトリの作成(どこでもいい。以降は/chrootと仮定)

mkdir /chroot/proc

procディレクトリの作成

mkdir /chroot/bin

chroot用の/binディレクトリの作成

cp -r /bin/* /chroot/bin/

/bin配下のコマンドをchroot環境にコピー

mkdir /chroot/lib

chroot用の/libディレクトリの作成

cp -r /lib/* /chroot/lib/

/lib配下のライブラリをchroot環境にコピー

mkdir /chroot/usr

chroot用の/usrディレクトリの作成

cp -r /usr/lib /chroot/usr/

/usr/lib配下のライブラリをchroot環境にコピー

mkdir /chroot/tmp

chroot用の/tmpディレクトリの作成

mkdir /chroot/dev

chroot用の/devディレクトリの作成

mknod  -m 666 /chroot/dev/null c 1 3

chroot環境に/dev/nullデバイスの作成

mknod  -m 666 /chroot/dev/zero c 1 5

chroot環境に/dev/zeroデバイスの作成

mknod  -m 644 /chroot/dev/random c 1 8

chroot環境に/dev/randomデバイスの作成

mkdir /chroot/etc

chroot環境に/etcディレクトリの作成

cp /etc/group /chroot/etc/group

chroot環境にgroup設定ファイルをコピー

cp /etc/hosts /chroot/etc/hosts

chroot環境にhosts設定ファイルをコピー

cp /etc/mime.types /chroot/etc/mime.types

chroot環境にmime一覧ファイルをコピー

cp /etc/mtab /chroot/etc/mtab

chroot環境にmount設定ファイルをコピー

cp /etc/nsswitch.conf /chroot/etc/nsswitch.conf

chroot環境にネームサービス設定ファイルをコピー

cp /etc/passwd /chroot/etc/passwd

chroot環境にユーザ設定ファイルをコピー

cp /etc/resolv.conf /chroot/etc/resolv.conf

chroot環境にDNSサーバー設定ファイルをコピー

cp -r /etc/apache2 /chroot/etc

chroot環境にapacheの設定ファイルをコピー

vim /chroot/etc/apache2/ports.conf

chroot環境のapacheのポートを今起動しているサーバとかぶらないよう変更

mkdir /chroot/etc/init.d

chroot環境に起動用スクリプトディレクトリの作成

cp /etc/init.d/apache2 /chroot/etc/init.d/apache2

chroot環境にApacheの起動スクリプトをコピー

mkdir /chroot/usr/bin

chroot環境に/usr/binディレクトリの作成

mkdir /chroot/usr/sbin

chroot環境に/usr/sbinディレクトリの作成

cp /usr/bin/env /chroot/usr/bin/env

chroot環境にenvコマンドをコピー

cp /usr/bin/install /chroot/usr/bin/install

chroot環境にinstallコマンドをコピー

cp /usr/bin/perl /chroot/usr/bin/perl
cp /usr/bin/perl5.10.0 /chroot/usr/bin/perl5.10.0
cp /usr/bin/perlbug /chroot/usr/bin/perlbug
cp /usr/bin/perldoc /chroot/usr/bin/perldoc
cp /usr/bin/perlivp /chroot/usr/bin/perlivp

chroot環境にperlコマンドをコピー

cp /usr/bin/vim /chroot/usr/bin/vim

chroot環境にvimコマンドをコピー

cp /usr/sbin/apache2 /chroot/usr/sbin/apache2
cp /usr/sbin/apache2ctl /chroot/usr/sbin/apache2ctl

chroot環境にapacheコマンドをコピー

mkdir /chroot/var
cp -r /var/www /chroot/var
mkdir  /chroot/var/lock
mkdir /chroot/var/log
mkdir /chroot/var/run

chroot環境に各種/varディレクトリの作成

mkdir /chroot/usr/share
cp -r /usr/share/perl /chroot/usr/share/
cp -r /usr/share/perl5 /chroot/usr/share/

chroot環境にperlライブラリのコピー

sudo cp /usr/share/zoneinfo/Japan /chroot/etc/localtime
mkdir -p /chroot/usr/lib/locale
set|grep LANG
sudo cp -dpR /usr/lib/locale/ja_JP.utf8 /chroot/usr/lib/locale

chroot環境の時刻のlocaleを設定

chroot /chroot

chrootの実行!!

mount -t proc proc /proc

/procのmount

/etc/init.d/apache2 start

congraturation!!

mysql -u root -h 127.0.0.1 --password=root

ちなみに、mysqlはunix socketでは通信できなくなったのでTCPで通信する
必要があります。その際に-pだけでは駄目で、--password=パスワードのよう
にパスワードをコマンドライン上で指定しないと繋がりませんでした。

| | コメント (0) | トラックバック (0)

auとdocomoのIPアドレス帯域のチェックツール

キャリアのIPを登録し忘れたせいで、最近立て続けにサイトにアクセスできない問
い合わせをいただいた。キャリアごとにWebで使用しているIPを公開しているのだ
が、ついチェックをサボるとこういうことになってしまう。
正直atomで公開してくれていると更新がわかって便利なのだが、auもdocomoも
Webページでしか公開していない。そこでezweb(au)PCサイトビューア(au)
brew(au)iモード(docomo) のWebページを解析して、変更があればメールで
通知するスクリプトを書いた。
チェックごとに前回チェックした時とのIPの差分をとって差分があった場合に通知
します。初回は必ずメールが来ます。cronに登録して毎日実行するといいと思いま
す。

#!/usr/bin/perl -w
use strict;
use warnings;
use LWP::Simple;
use HTML::TreeBuilder;
use Data::Dumper;
use Mail::Mailer;
use YAML ();
my $file_name  = "/var/tmp/mobile_app_ip.yml";

my %provider = (
    "ezweb"=>"http://www.au.kddi.com/ezfactory/tec/spec/ezsava_ip.html",
    "brew"=>"http://www.kddi.com/business/customer/tec/index.html",
    "ezpcsv"=>"http://www.au.kddi.com/ezfactory/tec/spec/pcsv.html",
    "imode" => "http://www.nttdocomo.co.jp/service/imode/make/content/ip/index.html",
    );
my %ydoc;
if( -f $file_name){
    %ydoc = YAML::LoadFile($file_name);
}
my %notices;
my %new_doc;
for my $prov_name (keys(%provider)){
    my $html = get($provider{$prov_name});
    my $tree = new HTML::TreeBuilder;
    $tree->parse($html);
    $tree->eof();
    my $num = 1;
    my %ip_set;
    my @ip_order;
    my $state;
    if($prov_name =~ /^ez/){
        for my $tag ( $tree->look_down("class", "TableText")){
            if($tag->as_text eq $num){
                $state = "ip";
                $num++;
                next;
            }
            unless($state){
                next;
            }
            if($state eq "ip"){
                $state = "mask";
                push @ip_order,$tag->as_text;
                $ip_set{$tag->as_text} = {provider=>$prov_name};
                next;
            }
            if($state eq "mask"){
                $ip_set{$ip_order[-1]}->{"mask"} = $tag->as_text;
                $state = undef;
                next;
            }
        }
    }
    elsif($prov_name =~ /brew/){
        for my $tag ( $tree->look_down("class", "center")){
            if($tag->as_text eq $num){
                $state = "ip";
                $num++;
                next;
            }
            unless($state){
                next;
            }
            if($state eq "ip"){
                $state = undef;
                my @nodes = split "/",$tag->as_text;
                $nodes[0] =~ s/\s+//g;
                $nodes[1] =~ s/\s+.*$//;
                push @ip_order,$nodes[0];
                $ip_set{$nodes[0]} = {provider=>$prov_name,"mask"=>"/".$nodes[1]};
            }
        }

    }
    else {
        my $cnt=0;
        for my $tag ( $tree->look_down("class", "normal txt")){
            my $li_html = $tag->as_HTML;
            my $li_tree = new HTML::TreeBuilder;
            $li_tree->parse($li_html);
            $li_tree->eof();
            for my $li ( $li_tree->find("li")){
                my @nodes = split "/",$li->as_text;
                $nodes[1] =~ s/\s+.*$//;
                push @ip_order,$nodes[0];
                $ip_set{$nodes[0]} = {provider=>$prov_name,"mask"=>"/".$nodes[1]};
            }
            $li_tree = $li_tree->delete;

            $cnt++;
            if($cnt > 1){
                last;
            }
        }
    }
    $tree = $tree->delete;
    for my $ip (@ip_order){
        if(!$ydoc{$prov_name} or !$ydoc{$prov_name}->{$ip}){
            $notices{$prov_name} = [] unless $notices{$prov_name};
            push @{$notices{$prov_name}},"ip:$ip" .$ip_set{$ip}->{"mask"} . " added.\n";
        }elsif($ydoc{$prov_name}->{$ip}->{"mask"} ne $ip_set{$ip}->{"mask"}){
            $notices{$prov_name} = [] unless $notices{$prov_name};
            push @{$notices{$prov_name}}," ip:$ip".$ip_set{$ip}->{"mask"} . " mask modified.\n";
        }
    }
    for my $ip (keys(%{$ydoc{$prov_name}})){
        unless($ip_set{$ip}){
            $notices{$prov_name} = [] unless $notices{$prov_name};
            push @{$notices{$prov_name}},"ip:$ip".$ydoc{$prov_name}->{$ip}->{"mask"} . " deleted.\n";
        }
    }
    $new_doc{$prov_name} = \%ip_set;
}
if(%notices){
    my $mailer = Mail::Mailer->new("smtp",Server=>"SMTPサーバ");
    $mailer->open({
        From => '送信元メールアドレス',
        To => '送信先メールアドレス',
        Subject => 'Provider IP Modified',
        }) or die "Can't open $! \n";

    for my $prov_name (keys(%notices)){
        print $mailer "\nPROVIDER:". $prov_name ." URL:" . $provider{$prov_name} ."\n";
        for my $message (@{$notices{$prov_name}}){
            print $mailer $message;
        }
    }
    $mailer->close();
}
open my $new_file ,">",$file_name;
print $new_file YAML::Dump(%new_doc);
close $new_file

EZアプリはPCサイトビューア用のIPでアクセスしてくるみたいだったので、PCサ
イトビューアのIPもチェックするようにした

Rubyで書こうと思っていたけど、nokogiriがlibxml2のdevel環境に依存している
が、私のサーバ環境ではインストールに失敗(libxml2とlibxml2-devのバージョン
が一致しない)したため、PerlのHTML::TreeBuilderを使用することにした。
こちらはサクッとCPANからインストールできた。

追記 2010 02.25
brew用のアドレス一覧のサイトがありました。
プログラムに追記しました。

| | コメント (0) | トラックバック (0)

2010年2月13日 (土)

Amazon S3にバックアップをする2

以前からrubyのgemcutterに登録しているs3backupというツールをこのところいろいろとBug修正や仕様を変更しました。仕様は変更しましたが、バージョンアップしても、今までのバックアップは失われず、設定ファイルもそのまま使用できます。
Amazon S3にバックアップする

Amazon S3の登録はクレジットカードがあれば、あっという間にできます。
値段は現在のところ下記の通りです。
Storage
$0.150 per GB - first 50 TB / month of storage used
Data Transfer
$0.000 per GB Internet Data Transfer - all data transfer into Amazon S3 (Until June 30, 2010)**
Requests
$0.01 per 1,000 PUT, COPY, POST, or LIST requests

300Gをバックアップするとして、今の為替だとだいたい月4500円ぐらい。
個人ユースには、ちょっと高い?
ただ、必要なファイルだけに絞れば、3Gだと45円。これならいつでもどこでも取り出せて、万一災害等で一切のバックアップメディアが失われたとしても、大丈夫なことを考えるとお得な気もします。

仕様の変更
1.sqlite3を使用するようになった。
バックアップ対象の各ファイル情報を今までHashのメモリでもっていたのに対して、sqlite3を使用するようにしました。理由は200Gぐらいあるディレクトリツリーをバックアップしたところ、4Gもメモリがあるにもかかわらず、メモリ不足で強制的にkillされるということがあったためです。そのため、sqlite3-rubyというgemに依存するようになりました。sqlite3-rubyはnative extentionを含むため、gccが必要になったり、sqlite3のdevel環境が必要になったりと少しインストールのハードルが上がりました。

2.レジューム機能を必ずするようになった。
以前はメモリを使用しすぎるため、resume機能をデフォルトでoffにしたのですが、sqlite3使用により、resume機能を付加してもメモリ消費が変わらなくなったため、常にonにしました。

3.一時ディレクトリを指定できるようになった。
以前は/tmpの下で圧縮や展開をしていたのですが、バックアップ対象のディレクトリのサイズが大きかった場合、/tmpでは賄えない場合に一時ディレクトリを/tmp以外にできるようにしました。

Bugの修正
1. パスワード設定をしていなかった場合、backupがエラーになるのを修正。
2. 特殊文字を含むディレクトリの場合、backupがエラーになるのを修正。
3.コネクションリセットのエラーによりbackupが中断されるのを修正。
4. ディレクトリ名と直下のサブディレクトリ名が同じ場合、そのディレクトリのバックアップが正常に行われないため、リストアに失敗するのを修正。
5.ディレクトリ名が長すぎる場合に、backupに失敗するのを修正。

| | コメント (0) | トラックバック (0)

« 2010年1月 | トップページ | 2010年4月 »