2012年3月22日木曜日

サイト公開、と今後の予定

公開してます↓↓
http://penguincourt.dip.jp/

コンテンツが皆無、まさに内容がないよう状態なのであしからず。とかいいつつちゃっかりファビコンとか作っちゃって、わりとノリノリである。
いちおうPHPで処理するありがたみを感じるため、ちょくちょく動的要素を組み込んでる(接続ユーザ情報とか)。あとJavaScriptもちょっと書いた(時計が動くところ)。
それからエラーページを自作してみた。あの指定URLが存在しないときに出る「404 Not Found」のページ。企業のホームページでも結構その会社の遊び心とユーザビリティ意識が反映されるので意外な注目ポイントでもあったり。サクラクレパスのとか、しゃれが効いてて好きです。

(参考:)
http://www.craypas.com/INVALID_URL/

そもそもなぜエラーページから作ろうと思ったかというと、例のいらんこだわりが発揮されたわけではなく、セキュリティ上の話。例えばあるディレクトリについては開発の便利上LAN内からはアクセスできるようにしているけど、外からはアクセス拒否の設定にしている。すると外部からこのディレクトリを指すURLにアクセスすると普通「403 Forbidden」が返るんだけど、これでは少なくともディレクトリの存在がばれてしまう。ばれたところでアクセスできないんだけど、「ここは秘密だから見せないよ!!」ってわざわざ宣言して、不必要に悪意ある人の興味を煽るのもいい感じがしないでしょ。
というわけでapacheの設定をいじって、エラーの時に返すドキュメントを指定することにした。

ErrorDocument 403 /Errors/HTTP_NOT_FOUND.php
ErrorDocument 404 /Errors/HTTP_NOT_FOUND.php

PHPだとHTTPヘッダを書き換えることができるからね。ページの見た目だけでなく実際に返ってくるパケット自体404レスポンスになる。どや!っつってね。いまはデフォルトのページを真似て作ったから普通の味気ないページだけど、今後いろいろお遊び要素が追加できる。楽しみ。

/* ============================================================ */

と、ここまででサーバ構築は一段落にする。今後はWEBコンテンツの充実にシフトしていくんだけど、これもゆっくりペースで行きたい。他にもいろいろやりたいことがあるし。メモ程度にまとめておく。

・HTML5+JavaScript で公開用のWEBコンテンツ作り
  → Ajaxとか使いたい。CSS はしばらく放置になる予感

・アクセス監視
  → 外部からのSSH、VPN接続をトラップ(通知)する仕組み。SNMPかな
  → WEBのアクセス解析、ランキング

・サーバのリソース管理
  → 定期的にディスク残量、メモリ使用量、CPU使用率なんかを記録する仕組み。
      できればrrdでグラフ化して管理用のWEBページを作りたいな

・ソースコード、ドキュメント管理
  → 一人での開発だから必要性は低いけど変更履歴とか残せるし便利なこともあるかと。
      言ってみればこれも道楽だけど、SVNの運用にも興味があるので。

・Earlang、Haskell 
  → 前から興味があって本で読んでただけだったけど、今や開発環境を作ることができる。
      作成したツールをWEBで公開したり、CGIとしてサーバサイドで動作させたりできるかな

うはー、夢がひろがりんぐ。

最終兵器、LAMP

いよいよWEBサイト公開の最終段階である。

LAMPとは、
「Linux」をOS
「Apache」をwebサーバ
「MySQL」をデータベース
「PHP」をサーバサイド処理言語
という、WEBサイトを構築するのに一般的なフリーソフトの組み合わせを指す用語。ソフトのインストール自体はOS導入時のパッケージ選択で済んでいるので、ちょっと設定ファイルをいじるだけですぐに使えるようになる。以下順に詳細(ってほどでもないけど)。

PHPの設定は「/etc/php.ini」。変更が必須のところはないんだけど、メモリ上限をいじりたい。写真をアップロードすることを想定するとこんくらいかな。

memory_limit = 16M
post_max_size = 12M
upload_max_filesize = 8M
あんまり上限あげてもあれなので、しばらく様子見。

MySQLの設定は「/etc/my.cnf」。変更はたいしたことない(ユーザ設定とOS起動時のサービス設定くらい)ので割愛。

Apacheの設定は「/etc/httpd/conf/httpd.conf」。こっちは逆に色々ありすぎて、いまひとつ理解が追い付いてない。とりあえず下記参考サイトを見ながら最低限のセキュリティとサービスが提供できる程度の設定で動かしてみる。

(参考:)

変更点をまとめると
・KeepAlive の時間とリクエスト回数上限
・ServerName 関係
・ユーザディレクトリの公開設定(← 不要かも。見直しを検討中)
・ServerSignature 非表示
・文字セット非固定
ってところかね。ServerName 関係については勉強が必要だと感じている。HTTP自体の勉強になるからすごくいい機会だと思うし。sudo設定時の反省を生かすと、やっぱり公式の説明をあてにするのが一番かもしんない、と思うので今後はここを見ながら徐々にカスタマイズしていこうと思う次第。

(参考:)

2012年3月21日水曜日

sudoに復讐

sudoの設定について。前回もやっとしたまま終わったのでわりときちっと勉強した。するとsudoersファイルについて本家のmanページ(man sudoers)に「かなーり詳しく」いろんな設定例と説明が載っていた。なんと。最初からこっち見ろよというお話か。
で、こんなお話も。
セキュリティ上の注意
  ’!’ オペレータを使って ALL からコマンドを "差し引く" ことは、一般に有効でない。ユーザは、欲しいコマンドを別な名前でコピーして実行すれば、これを簡単に回避できてしまう。例を挙げる。
           bill        ALL = ALL, !SU, !SHELLS
  上の例では、実際には SU と SHELLS にリストされているコマンドを bill に実行させないようにすることができない。なぜなら、bill は、これらのコマンドを別な名前にコピーしたり、エディタや他のコマンドのシェルエスケープから使えるからである。よって、このような制限は、せいぜい補助的なものと考えるべきである (さらにポリシーで強化すべきである)。
つまりまさに前回例として挙げた
Cmnd_Alias SHUTDOWN = /sbin/halt,/sbin/poweroff,/sbin/reboot,/sbin/shutdown
ADMIN            ALL=(ALL)       ALL, !SHUTDOWN
は無意味な設定ということらしい。実際ADMINユーザは(特になんの設定もすることなく)rebootを実行できた。なぜなら/usr/bin/rebootコマンドがconsolehelperへのシンボリックリンクになっていて、consolehelperを経由して/sbin/rebootを実行できるようになっていて、かつ/usr/binに(ふつうに)パスが通っているから。あれ、ほんとだ。
シャットダウン系コマンドの実行権限を委譲しない、という意図のこの設定はほとんど意味をなさないことが分かった。しかしこれはsudoの設定について説明するかなり多くのサイトで「オススメの設定」として紹介されている。どうなんだろうね。情報を鵜呑みにしちゃならんというのを改めて実感したというか。
さらにいえば「ALL, !SHUTDOWN」だと/bin/bashの実行も許可しちゃうんだよね。つまり「sudo -s」ができちゃう。するとrootでシェルを実行するんだから、ほぼrootログインと同等。rootのパスワードを知る必要なく。これ危ないだろどう考えても。
というわけで設定を見直し。ファイル閲覧はパスワードなし、ファイル編集とサービス起動・停止系のコマンドはパスワード付きで実行できるようにした。「sudo -l」で確認するとこんな感じ。
User **** may run the following commands on this host:
    (root) NOPASSWD: /bin/ls, /bin/cat, /usr/bin/less, /usr/bin/tail
    (root) /usr/bin/vim
    (root) /sbin/service, /sbin/chkconfig
これで試用中。ただ「cp」「mv」「mkdir」とかのコマンドも許可しないと使い勝手が悪いかなぁ、と思っているところ。

2012年3月18日日曜日

セキュリティっぽい設定

春。花粉症になったかもしんない。

WEBサーバ公開とは関係ないイベントだけど、SSHとsudoの設定をしてみる。いちおうセキュリティ対策。といっても外部からの攻撃に対する防御というより、自分がセキュリティ意識を高く保つために設定ファイルをいじってみたい、というかんじ。

まずSSHの設定だけど、rootログインを禁止する。rootユーザはすべてのファイルを書き換えることができるし、削除することもできる。そんな強い権限を持ってふらっとログインしてはぱたぱたコマンド叩くというのはお行儀がよくない。基本的には一般ユーザアカウントでログインして、必要な時だけ「su -」でユーザ切り換え、というのが正しい。うちの場合「管理者=自分」なので実際には何をするにもひと手間ふえるだけなんだけど、まぁroot権限が必要な操作っていうのは本来それなりに面倒でしかるべきなのだと思ってあきらめる。
ではsshdの設定ファイル、/etc/ssh/sshd_config を編集する。書き換えるのはPermitRootLogin のディレクティブ。デフォルトでは「yes」になっているのを「no」にする。こんだけ。

次にsudoの設定。sudoってのは特定のコマンドを特定のユーザの権限で実行できるプログラム。たいていは一般ユーザに対してroot権限(の一部)を委譲する目的で使う。例えばシステムログ/var/log/messagesはroot権限でしか閲覧することができないので、一般ユーザが
less /var/log/messages
ってしても「Permission denied」って怒られる。もちろん「su -」でrootユーザになっちゃえば読めるんだけど、ちょっとログ見たいだけなのにほいほいrootユーザになれって言われてもねぇ、rootパスワードだって結構ふくざつなのにしてるし・・・・。って場合でも、sudoに「○○さん(一般ユーザ)にはroot権限による less コマンドの実行を許可する」という設定をしておけば、○○さんに限って
sudo less /var/log/messages
とすることでrootユーザにならずともログを見ることができる、というわけ。
このときデフォルト設定ではパスワードを聞かれるんだけど、聞かれてるのはrootパスワードじゃなくて「○○さんのパスワード」。つまり「あなたはほんとに(root権限を委譲された)○○さんなの?」ってことを確認される。ほんともなにも○○ユーザでログインしている限りパスワードは知ってて当然なんだけど、なぜわざわざパスワードを確認されるのか。「これからsudoするんだからちょっと慎重になれよ」ってメッセージなのか。
まぁ無理やり実用的な解釈をすれば、例えばログインした人とコマンド実行している人が別人だっていう可能性を排除しているのかも。LAN、つまり自分の部屋の中で操作する時はそんなこと起きないんだけど、例えば会社とか、他人が自分のパソコンを触るかもしれない状況でリモートアクセスしてて、ログインしたまま放置して席を離れたりすると、実際にログインしていない人、つまりパスワードを知らない人がsudoできちゃう、って状況はあるかもしれない。それならsudo実行時にパスワードを確認する意味はあるかも。
ただねぇ。これもデフォルト設定では「最後にsudoしてから5分間はパスワード確認なしでsudoできる」ってことになってて。なんか矛盾してない?ってか中途半端じゃない?

まぁいいや。

sudoの設定ファイルは/etc/sudoersなんだけど、ファイルの編集にはvisudoって特別なコマンドが用意されている。文法チェックとかロック取ったりとかしてくれるそうだ。visudoやりよる。
で書式はこんな感じ。
ADMIN            ALL=(ALL)       ALL
なんかこの書式も好きじゃないんだけどね。まぁいいや。4つ設定箇所があるんだけど、左から
・sudoを許可するユーザ
・sudoを許可するホスト(接続元)
・権限を委譲するユーザ
・権限を委譲するコマンド

を表していて、これだと「ADMINユーザはどこから接続しても、どのユーザ権限でも、どのコマンドでも実行できる」ことになる。ADMIN無敵。
「ADMIN」は上でエイリアス(別名)を定義してるだけで、直接ユーザ名を書いてもだいじょぶ。定義はこんな感じ。
User_Alias ADMIN = (ユーザ名1),(ユーザ名2),(ユーザ名3),...
「(ALL)」はroot以外の一般ユーザの権限も含めて全部って意味だけど、(SELinuxとか設定してなければ)rootで何でもできるので「(root)」って書いてもたぶん同じことだと思う。

実行許可を与えるコマンドを制限しなきゃsudoのありがたみがない。たとえば
ADMIN            ALL=(ALL)       /usr/bin/less
にすれば、「lessだけはsudoできる」設定になる。ほかのコマンドをroot権限で実行したかったらrootユーザになるしかない。またコマンドにもエイリアスを定義できるので
Cmnd_Alias SHUTDOWN = /sbin/halt,/sbin/poweroff,/sbin/reboot,/sbin/shutdown
ADMIN            ALL=(ALL)       ALL, !SHUTDOWN
にすれば、「シャットダウン系のコマンドはsudoできない」っていう設定にもできる。まぁコマンドの制限はそこまで厳格にしなくていいや。どうせ自分以外にユーザはいないし。
あとは例のパスワードのキャッシュの設定。
Defaults timestamp_timeout = 0
これを設定しておけば、5分とおかず毎回パスワードを聞かれるようになる。
「パスワード確認は必要ない」と思ったら
ADMIN            ALL=(ALL)       NOPASSWD:ALL, !SHUTDOWN 
ってしておけば、パスワードの確認がされなくなる。便利とセキュリティとどっちをとるかって話だけど。

さっきの「他人が自分のパソコンを触ってるかもしれない」状況を考えると、リモートアクセスではパスワード確認がほしいところだけど、LAN内からのアクセスならパスワード確認は冗長だと思うわけで、理想としては
Host_Alias LOCAL = 192.168.230.0/24
ADMIN          LOCAL=(ALL)     NOPASSWD: ALL, !SHUTDOWN
ADMIN           !LOCAL=(ALL)    ALL, !SHUTDOWN
みたいな設定が望ましい。

ところがこれが何故かうまく行かなくって。なんかねぇ、接続元ホストってイメージしてたのと違うみたい。例えば普段LANからアクセスする時って「192.168.230.2」(Windows)から「192.168.230.230」(CentOS)にSSHでアクセスしてるんだけど、この場合の「接続元ホスト」って「192.168.230.2」じゃなくて「192.168.230.230」なんだって!よくわかんないけど!ほんとわけわかんない!じゃあ接続元ホストってなんなのよ!LANからのアクセスか、外部からのアクセスか、見分ける方法はどこにあるのか!

2012年3月7日水曜日

ルータの設定

ルータとは、ネットワークの間にあって両ネットワーク間を行き来するパケットの通過許可/拒否を判断したり宛先の変換を行う「機能」のことである。あえて「装置」と言わないところがミソ。

さて、うちのBuffaloAirStationのように「InternetとLANの間にあるルータ」の仕事は主に
1. 「LAN → Internet」 のパケットはすべて通す
   (ただしパケットフィルタリングの設定をしている場合を除く)
2. 「Internet → LAN」 のパケットは 1. への応答のみ通し、他は通さない
   (ただしポートフォワーディングの設定をしている場合を除く)
となっている。
いつもインターネットに接続してwebサイトを見ているときは、「このページをください」とLAN内からリクエストを出しているので、その応答として目的のページがLAN内に届けられる。Internet側から能動的に何かを送ることは基本できない。
逆に、WEBサーバを動かしてサイトのURLを公開しても、Internet側からのリクエストパケットはLAN内のサーバまで届かない。結果、アクセスした側から見ると「サイトに接続できません」みたいな状態になる。
というわけでポートフォワーディングの設定をする。似たような用語はいろいろあって、アドレス変換とか静的NATとかIPマスカレードとか、でも全部同じ意味(だと思う)。そして概念は難しくない。

Internet側で受けたパケットの宛先ポートによって、宛先IPアドレスとポートを書き換えてLAN側に通す


例えば。
Internet       LAN
*.*.*.*:80 → 192.168.230.230:80
っていう設定をすると
80番ポートで受けたパケットは
IPアドレス 192.168.230.230 ポート 80番 宛パケットとしてLAN側に通す 
っていう動作になる。するとLAN内の 192.168.230.230 のホスト上で80番ポートをリッスンしながら常時起動しているプログラム、つまりWEBサーバが、HTTPリクエストパケットを受け取れるようになる。

他にも
Internet           LAN
*.*.*.*:80         → 192.168.230.230:80
*.*.*.*:37184 → 192.168.230.230:23
を設定すると、37184番ポートにアクセスすることによって、LAN内のサーバにSSHでログインできるようになる。サーバは23番ポートをリッスンしてるんだけど、23番はSSHのポート番号として世界的に有名だからInternet側に同じ番号をさらすのは大変危険。Internet側には分かりにくい番号を設定するのがおすすめらしい。

あとは
Internet             LAN
*.*.*.*:80          → 192.168.230.230:80
*.*.*.*:37184     → 192.168.230.230:23
*.*.*.*:10080  → 192.168.230.1:80
みたいに別のホストに転送させることもできる。ちなみに 192.168.230.1 はルータのLAN側アドレスで、Buffaloのルータは管理画面用に小規模なWEBサーバが動いている。これで10080番ポートにアクセスすると、Internet側からルータの設定を行えるようになる。

ちなみに下2つは設定しない予定。こんなこともできるよって話。


別件。サーバ公開とは全然関係ない話だけどパケットフィルタリングについて。
LANから外に通したくないパケットは、設定すれば通さないようにできる。代表的なのはWindowsのファイル共有用に常時LAN内に飛ばしまくってる「なんとか」っていうパケット。ホスト名とIPアドレスの紐付け情報を交換してるんだっけか。こういう設定も大事よね。

2012年3月5日月曜日

公開する準備

サーバ公開にあたって、わが家のLANがどうやってインターネットにつながってるか改めて確認。最初の記事に書いていたInternet@Startの方はやっぱりデフォルト設定だったっぽい。のでちゃんとISP(Yahoo!BB)からもらったアカウントとパスワードをルータに登録して、PPPoE接続でインターネットにつなぐようにした。よってわが家のLANのInternet側IPアドレスは確実にISPのPPPoEサーバから割り振られたものになった。

さて、ここでISPとの契約が「固定IP契約」だと「あなたには 123.45.67.xx のアドレスを割り振ります」というお知らせをもらってるはずで、だとすれば「WEBサーバ公開してます!URLはhttp://123.45.67.xx/ です!」と言えるわけだ。でもそんなお知らせはもらっていない。なぜかというと「固定IP契約」ではないから。つまりインターネットに接続する時にISPがプールしている未使用のIPアドレスの中から動的に割り振られ、切断する時に返しているということだ。なんと。自分んちのIPアドレスがそんなころころ変わっていたなんて知らなかった。
しかしこれでも今までは不都合がなかったわけだ。電話に例えると分かりやすい。常に自分が「電話をかける側」だとすれば、極論自分の電話番号は知る必要がないし、知らないうちに電話番号が変わっていても通話はできる。なるほど。ただしWEBサーバを公開するということは「電話を受ける側」になるということだ。IPアドレス(電話番号)がころころ変わっては困る。
そこんとこを上手いこと解決してくれるのがDDNSという技術だ。割り振られたIPアドレスをドメイン名とともにDNSサーバに登録し、WEBにアクセスする人にはドメイン名でアクセスしてもらう。そしてIPアドレスが変わるたびにDNSサーバに登録しなおす。そうすれば実際のIPアドレスがころころ変わってもDNSが動的に名前解決をしてくれるというわけ。よくできてる。
DDNSのサービスを無料で提供してくれてるところはいくつかあったんだけど、今回はieServer(家サーバ)というところを利用してみた。理由はユーザ登録が簡単なのと利用規約がゆるいこと。そこで以下のドメインを取得した。

penguincourt.dip.jp

次に「IPアドレスが変わるたびにDNSサーバに登録しなおす」ための設定がいる。これはなんと同サイトでスクリプトを配布していたのでありがたく使わせて頂くことにした。スクリプト自体はPerlで書かれていて、これをcronで10分おきに実行する。DNSにIPアドレスを登録するところにはwgetを用いる。perl、crond、wget はどれもインストール済だ。まずはスクリプトの必要な部分を書き換えて、単独で実行してみる。
wget -q -O - 'http://ieserver.net/cgi-bin/dip.cgi?username=$ACCOUNT&domain=$DOMAIN&password=$PASSWORD&updatehost=1'
$ACCOUNT、$DOMAIN、$PASSWORD はユーザ登録に使った個人設定で置き換えられる。パスワードも入ってるので http は https に置き換える。wget がSSL接続可能でビルドされていることは次のように確認できる。
ldd /usr/bin/wget |grep -i ssl
さて、wgetを実行する。「-O -」オプションがついているので結果は標準出力に出る。成功すると現在のIPアドレス(をどこかに含むテキスト)が表示されるはずである。・・・・、がなにも出ない。
そこで「-q」オプションをとってみる。これでエラーログが見れるはず。やってみる。

エラー: ieserver.net の証明書の検証エラーです: unable to get local issuer certificate
ieserver.net に安全の確認をしないで接続するには、`--no-check-certificate' を使ってください。
SSL による接続が確立できません。

やっぱりね。というわけでwgetを「--no-check-certificate」オプション付きで実行。・・・・うわ、なんかすごいhtmlが出た!けど確かにうちに割り振られているIPアドレスが入ってる!成功っぽい。
wgetの確認ができたところで、スクリプトをコピーして、実行権限をつけてperlで実行してみる。これが成功するとログファイルができるはず。実行。・・・・ログファイルの生成を確認。成功。やったね。
最後にcronの設定をする。10分おきに実行する設定にする。
crontab -e
で設定ファイルを開いて
5,15,25,35,45,55 * * * * /usr/local/ddns/ddns-update.pl
の内容を書き込む。いちおう再起動。
service crond restart
実行予定時間のちょっと前にさっきのログファイルを削除する。予定通り実行されればログファイルができるはずだ。待つ。・・・・できたかな?・・・・できてる。成功だ。

これでDDNS関係の設定は終了。最大10分のタイムラグはあるかもだけど、ほぼリアルタイムでドメイン名によるアクセスができるようになった。
明日はルータのポートフォワーディングの設定をする。

2012年3月4日日曜日

ほんとにさくっと

CentOSのインストーラが起動してからは、ほんとにさくっと終わった。拍子抜けするぐらい。しかしそこにはFedoraCore3のセットアップで経験した苦労が確実に生きているのであった。

・・・・、まぁほんと特筆することがないんだよね。しいて言えばパーティション分けぐらいか。ハードディスクの領域を用途ごとに細かく割り振るやつ。こんなかんじ。

デバイス         マウントポイント  容量(MB)
 /dev/hda
 |
 +- /dev/hda1         /boot                  100
 +- /dev/hda2         (swap)                4000
 +- /dev/hda3         /                       1000
 +- /dev/hda4
      |
      +- /dev/hda5    /var                   8000
      +- /dev/hda6    /usr                   4000
      +- /dev/hda7    /usr/local            1000
      +- /dev/hda8    /tmp                    100
      +- /dev/hda9    /home               20000

/dev/hda が実ディスクね。物理的な意味のディスクが2枚、3枚あると /dev/hdb、/dev/hdc って増えてくらしい。26枚超えたらどうなるのかな。/dev/hdaa かな。んで番号付いてるのがパーティション。
1~3 が基本パーティション、4 は拡張パーティション。基本 + 拡張で 合わせて4つまでしか分割できないんだって。5~9 は論理パーティションつって 4(拡張) を分割したやつ。ただしOSの起動に必要なデータは基本パーティションにないとダメ。

UNIX系のファイルシステム(CentOS4系はext3)ではディスクドライブに保存されたデータにユーザがアクセスできるようにするために「マウント」という処理が必要になる。例えば「AAA.dat」とかいうファイルが入ったUSBメモリをPCに挿しても、それだけではデータにアクセスできない。USBメモリを例えば「/mnt/usbmem」に「マウント」することによって「/mnt/usbmem/AAA.dat」っていうふうにアクセスできるようになる。これはハードディスクでも同じこと。/dev/hda1を/bootにマウントすることで初めて/dev/hda1(基本パーティション1)に保存されたデータにアクセスできる。このマウントする場所のことを「マウントポイント」という。ちなみに/bootには起動プラグラム、/varにはログ、/usr、/usr/localにはアプリケーションが保存される。/tmpは一時的な使用が目的の作業領域、/home下には各ログインユーザごとのディレクトリを切って、それぞれが自由に使っていい領域とする。/dev/hda2 はSWAP領域として割り当てた。SWAP領域はメモリが足りなくなったときにデータを退避させる場所で、ユーザはアクセスできない。

パーティション分けはこんな感じ。あとはパッケージインストールして、必要ないサービスを停止して。キーボードも日本語だし。そうそう、yumの設定をしてupdateもしました。今回はつるっとできたよ。勝手に「CentOS4.9」にバージョンアップしたけどな。