cron-apt で自動アップデート

cron-aptを使うと毎日だいたい決まった時間にパッケージの自動更新を行える。

インストール

apt-get install cron-apt

/etc/cron-apt/config を編集

デフォルトでは全項目がコメントアウトされているので、変更したい部分だけ変更する。

APTCOMMAND=/usr/bin/apt-get
MAILTO="tateisu@juggler.jp"
MAILON="changes"
DEBUG="changes"
OPTIONS="-o quiet=1"

/etc/cron-apt/action.d/3-download を編集

dist-upgrade の -d (ダウンロードのみでインストールしない) オプションを削る。

変更前

autoclean -y
dist-upgrade -d -y -o APT::Get::Show-Upgraded=true

変更後

autoclean -y
dist-upgrade -y -o APT::Get::Show-Upgraded=true

/etc/cron.d/cron-apt を編集

0 4     * * *   root    test -x /usr/sbin/cron-apt && /usr/sbin/cron-apt

のようにcrontabの設定が書かれている。
実際にはcron-aptは1時間以内のランダムな時間だけsleepしてから処理を開始するのだが、それでもサーバが複数ある場合にはもっと大きく時間帯をずらした方が良いかもしれない。

動作確認

  • /usr/sbin/cron-apt を実行して、送られてくるメールを見る
  • 変更がないとメールが送られてこないので、 /var/log/cron-apt/log を見る
  • 自動アップデートが発生した際に送られてきたメールを見る

質問の省略

パッケージのアップデートの際に設定ファイルの更新などで質問されることがある。自動更新ありの場合はデフォルトでは既存の設定が保持されることが多いので、その場合には質問が省略されるように設定すると自動更新が捗る。…が、この設定はやや危険かもしれない。

dpkg-reconfigure debconf を実行すると設定を変更できる。

# 質問に使われるインタフェース
Interface to use:
→ (今回の設定には影響しないので、変更しないこと)

# これより重要性が低い質問を省略する
Ignore questions with a priority less than: 
→ critical

メールを受け取らないサーバでのexim4の設定

unixユーザアカウントが1つか2つ、メールを外部に送ることはあっても内部のローカルメールなんか見ないよという場合のexim4の設定。目新しくはないけど、よくやる設定なのでメモしておく。

今回の例では myhostname が設定するサーバのホスト名で、 myhostname.local がメールサーバのドメイン名、 tateisu がサーバ上のメインユーザのアカウント名とする。

/etc/exim4/update-exim4.conf.conf を編集

dc_eximconfig_configtype='satellite'
dc_other_hostnames='myhostname.local'
dc_local_interfaces='127.0.0.1'
dc_readhost='myhostname.local'
dc_relay_domains=''
dc_minimaldns='true'
dc_relay_nets=''
dc_smarthost='external.smtp.server::26'
CFILEMODE='644'
dc_use_split_config='false'
dc_hide_mailname='true'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'

dc_smarthost の部分に外部のSMTPサーバのホスト名とポート番号を書く。ポート番号の区切りがコロン2つで間違えやすい。

dpkg-reconfigure exim4-config

編集が終わったら dpkg-reconfigure exim4-config する。
質問が出るので以下のように答える。

# メール設定の種別
General type of mail configuration: 
→ mail sent by smarthost; no local mail

# このメールサーバのドメイン名
System mail name: 
→ myhostname.local

# SMTP 待ち受けアドレス
IP-addresses to listen on for incoming SMTP connections: 
→ 127.0.0.1

# ほか、このメールサーバがSMTPで受け取るメールのドメイン名
Other destinations for which mail is accepted:
→ myhostname.local

# ローカルメールを外部に送信する際にメールアドレスに付与するドメイン名
Visible domain name for local users:
→ myhostname.local

# メールを外部に転送する先のSMTPサーバのホストとポート
IP address or host name of the outgoing smarthost:  
→ rings.juggler.jp::26

# なるべくDNSクエリを減らして、不要な自動ダイアルアップを抑制する?
Keep number of DNS-queries minimal (Dial-on-Demand)?
→ Yes

# 設定ファイルを分割する?
Split configuration into small files? 
→ No

最後の2つの質問は今回の設定には影響しない。好きな方を選んで構わない。

設定が終わると自動的にexim4が再起動される

/etc/email-addresses を編集

ローカルユーザ宛のメールをどこに転送するかを記述する…のだが、これを使う送信先のサーバでリレー失敗が出てしまう問題があった。

/etc/aliases を編集

1ユーザしか作っていない、ほとんど素のdebianだとこんな感じ

mailer-daemon: postmaster
postmaster: root
nobody: root
hostmaster: root
usenet: root
news: root
webmaster: root
www: root
ftp: root
abuse: root
noc: root
security: root
root: tateisu
tateisu: tateisu@juggler.jp

最後の行だけを追加した。
編集が終わっても再起動は特に必要ない。

動作確認

# mail tateisu
Subject: test 5
hoge
(Ctrl-Dを押す)
Cc: 
(何も入れずにEnter)

これでメールが配送されればOK。
ダメなら /var/log/exim4/mainlog や 送信先SMTPサーバのログを確認する。

サーバ上のメインユーザ以外にもrootとpostmasterくらいは確認しておく。

node でIRCボットを書いてみた

書いてみた。フラッドプロテクションもちゃんと実装した。
http://dl.dropbox.com/u/10049046/node-ircclient.tgz

node v0.7.4で動作確認。追加で node-iconv モジュールが必要。

チャネル内のユーザがURLを書いたらそこにアクセスしてタイトルを読みに行くサンプルを書いてみたけど、HTTPで取ってきたデータの文字コードの推測に使えそうなモジュールがない。その部分だけ子プロセスでperlスクリプトを起動して誤魔化してしまった…。

crontabを使えるユーザを制限する

目新しい話でもないけど、忘れがちなのでメモ

/etc/cron.allow に許可するユーザ名を列挙するか、もしくは /etc/dron.deny に 禁止したいユーザ名を書いておく。なお、 /etc/cron.allow が存在する場合はたとえその内容が空でも /etc/dron.deny は参照されない。
どちらのファイルも、1行に1つずつユーザ名を書く。

デフォルト厳しめの設定で、そうでなくても少なくともwww-dataユーザは制限しておくべき

privoxyとiptablesで透過型HTTPプロクシ

privoxy正規表現ベースのアクセス制限や強力なフィルタ機能のあるHTTPプロクシだ。iptablesと組み合わせると透過型プロクシとして設定することもできる。

今回は透過型プロクシを使って、特定ホストに対してのみHTTPリクエストが可能なように設定してみる。この例では内部ネットワークが 192.168.0.0/16 で、その中のPCでゲートウェイとして設定されているのが透過型プロクシを処理するマシンとなる。

/etc/privoxy/config

privoxyの待ち受けアドレスとポート番号を適当に設定する。

listen-address 0.0.0.0:1499

一般的なHTTPプロクシは「GET http://host/path...」というリクエストを受け取るのだが、透過型プロクシでは「GET /path..(改行)Host: host」のような、通常のリクエストを受け取る。

privoxyはaccept-intercepted-requestsを有効にすると、通常のHTTPリクエストに対しても Host ヘッダの情報を利用して中継処理を行うようになる。

accept-intercepted-requests 1

iptablesの設定

iptables の nat テーブルの PREROUTING チェインに、内部ネットワークから外部のポート80へのリクエストをマシン内部にリダイレクトするよう設定する。

iptables -t nat -A PREROUTING -s 192.168.0.0/16 -p tcp --dport 80 -j REDIRECT --to-ports 1499 

アクセス制限

次のようなアクションファイルを書いて、whitelist.actionという名前で保存する。

# 全てのURLをブロックする
{ +block }
/

# 除外するURL
{ -block }
.debian.org
.recaptcha.net

/etc/privoxy/config でアクションファイルを参照するよう設定する。

actionsfile whitelist.action

AIDEで改竄検知

改竄検知は頻繁に偽陽性(false positive)に煩わされることになるイヤな管理タスクだが、セキュリティ上避けて通れない。

ファイルアクセスをフックしてリアルタイム保護してくれるようなサービスがあるともっといいのだが、Linuxではあまり発達していないようだ。SELinuxを使うとrootに対してでもファイルアクセスを制限できるのだが、現状では仮想PCと相性が悪い。

今回はGPLライセンスの改竄検知ソフトウェアAIDE (Advanced intrusion detection environment)を使って改竄検知を仕込んでみる。

Debian, Ubuntu のaideはかなりdebianizeされてて気持ち悪い。…というか読み切れないので既存のパターン設定は全て捨ててしまった。

/etc/aide.conf

設定例を公開するのもアレなのでポイントだけ。

  • パスのパターンは全部/で始まっていないと怒られるようだ
  • 行頭の=で「枝刈りはしないけど特定のフォルダだけチェック種別を変える」ことができる。ただしパターン末尾に$をつけないと枝も同じ正規表現にマッチしてしまう

aideinit

/etc/aide.conf を書いたら aideinit でデータベースを初期化する。

/etc/default/aide

レポートの送信先メールアドレスなどを設定する。

MAILTO=tateisu@gmail.com

/etc/cron.daily/aide

このスクリプトが定期的に呼ばれる。手動で起動してもよい。

動作確認

実際に動かしてみると、ディレクトリのctime,mtimeが変化しただけなどの偽陽性(false positive)で数回は設定を見直すことになる。

あと困ったのが、手動でaideinitを起動した場合と /etc/cron.daily/aide とで結果が違う。仕方なくaideinitでスキャンした結果は使わないことにした。

DBリセットは次の手順で行う

  • 設定ファイルを変更していたら事前にaideinitを呼ぶ
  • /etc/cron.daily/aide ; mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db ; /etc/cron.daily/aide

Xenを使って Ubuntu 11.10 (oneiric) の上で Debian 6.0 (squeeze) を動かす

(ホスト側) 必要なパッケージ

  • lvm2 2.02.66-4ubuntu3
  • libc6-xen 2.13-20ubuntu5
  • libxenstore3.0 4.1.1-2ubuntu4.1
  • xen-docs-4.1 4.1.1-2ubuntu4.1
  • xen-hypervisor-4.1-i386 4.1.1-2ubuntu4.1
  • xen-tools 4.2.1-1
  • xen-utils-4.1 4.1.1-2ubuntu4.1
  • xen-utils-common 4.1.0~rc6-1ubuntu1
  • xenstore-utils 4.1.1-2ubuntu4.1
  • ほか、その依存関係

ubuntuのカーネルイメージはデフォルトでxenのdom0に使えるので、カーネルそのものは特に追加する必要はない。
今回はホスト側のカーネルは linux-image-3.0.0-16-generic-pae をそのまま使っている。

(ホスト側) LVMのボリュームグループを作成しておく

最初はループバックで動かして後からLVMのブロックデバイスを追加しよう…としたら、domUinitrdにブロックデバイス用のモジュールがうまく入らなかった。最初からLVMを前提にしてxen-create-imageを行う方が確実なようだ。

  • partedかfdiskで適当にパーティションを確保して
  • 再起動はしたくないので partprobe でパーティション情報を再ロードして
  • 「pvcreate パーティションのデバイス名」でLVMの物理ボリュームに仕立てて
  • 「vgcreate -s 128m vg1 パーティションのデバイス名」でLVMのボリュームグループを作成する。

ここで作ったボリュームグループに対して、後からxen-create-imageが自動的に論理ボリュームの切り出しを行うことになる。

(ホスト側) grubの設定

  • パッケージを入れた後に update-grub する
  • その後に grep menuentry /boot/grub/grub.cfg すると 「~ and XEN」のついた起動選択肢があるのを確認できる
  • その選択肢が自動的に選ばれるように、mv /etc/grub.d/ にある 10_linux か 20_linux_xen のどちらかをリネームして順序を入れ替える
  • 再度 update-grub してからリブート
  • xm list でdom0が表示されていればOK

dom0の最低メモリ量を調整するために、何回かここで再起動するかもしれない。
また、OSのループバックデバイスの数を変更するのに /etc/modprobe.d/loopback.conf を作って options loop max_loop=16 …等と書く必要があるかもしれない。

(ホスト側) xen-create-image

domU用の、OS入りのディスクイメージを生成する。
今回は --mirror=http://ftp.jp.debian.org/debian --dist=squeeze を指定することで、debianを入れたディスクイメージを作成する。
なんでoneiric じゃないのかと言われそうだが、その理由は /usr/share/debootstrap/scripts/ の下に oneiric が存在していなかったからだ。debianのsqueeze は提供されているので、ちゃんとdebian用のディスクイメージを作れる。おそらくOSのリリース時期と、それを利用したdebootstrap設定の提供時期が原因だと思われる。
…というのはどうでもよくて、本当は単にdebianの方が好みだからだ。選択できるのであればホストOSにもdebianを選んでいただろう。

/etc/xen-tools/xen-tools.conf に書くか、もしくはxen-create-imageのコマンドラインオプションにこんな感じで指定する。どの項目をどちらに書くかはお好みで。

# /etc/xen-tools/xen-tools.conf
arch = i386   # i386 or amd64
lvm = vg1     # イメージが出力されるLVMボリュームグループ
install-method = debootstrap
gateway    = 192.168.2.21
netmask    = 255.255.255.0
broadcast  = 192.168.2.255
nameserver = 210.224.163.4
mirror = http://ftp.us.debian.org/debian # パッケージを取ってくるリポジトリ
ext3_options     = noatime,nodiratime,errors=remount-ro
ext2_options     = noatime,nodiratime,errors=remount-ro
xfs_options      = defaults
reiserfs_options = defaults
btrfs_options    = defaults

# command to create image
xen-create-image --force --hostname=guest1 --ip=192.168.2.2 --pygrub --dist=squeeze --mirror=http://ftp.jp.debian.org/debian 

うまくいけばrootのパスワードが出力されて作成が完了する。

(ホスト側) ネットワークの設定

今回の環境ではホストOSにはプライベートIPアドレスが全く割り当てられていないので、ブリッジモードを使うわけにはいかない。NATも後で外す予定なので、ルータモードでネットワークを設定してみた。

ルータもードを選択する場合、/etc/xen/xend-config.sxp で

(network-script network-route)
(vif-script     vif-route)

が呼ばれるようにするだけではなく、/etc/xen/scripts/vif-route にも手を入れた方が便利だ。vif-routeスクリプトは仮想NICのホストPC側のアドレスに、ホストPCのeth0と同じアドレスを設定してしまうのだが、そうするよりは、仮想NICのゲストOS側のアドレスと同じネットワーク内のアドレスを割り当てた方が色々と捗る。

私が取った方法は、ゲストOS側のアドレスの末尾に文字列の1を連結するというものだった。

# main_ip=$(dom0_ip) 
main_ip="${ip}1"

この変更によって、もしゲストOSに設定したIPアドレスが192.168.2.2なら、その仮想NICのホストPC側の端点は 192.168.2.21で初期化されることになる。なんとも原始的だが、今回はここを洗練させる必要は特にない。

(ホスト側) マスカレードの設定

ゲストOSから外向きの通信が行えるようにするには、ホストOSに次のような設定を行う。

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

送信先をフィルタするためにNATではなくプロクシを使うケースもあるが、ここでは説明しない。

マスカレードの設定(B)

今回はjailの代わりに仮想PCを使うのが目的なので、ゲストから外向きの通信を制限したい。
ホスト側に適当なプロクシを入れて、送信先をフィルタすることで賄う。
ただしDNSに限っては引けるようにする。

iptables -t nat -A POSTROUTING -p tcp --dport 53 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -p udp --dport 53 -o eth0 -j MASQUERADE

ゲストPCを起動

先ほど作成したディスクイメージにつけたhostname がguest1だったので、/etc/xen/guest1.cfgが作成されているはずだ。
xm create guest1.cfg -c でゲストPCを起動して、そのコンソールを表示する。
なお、ゲストPCを起動したままコンソールをデタッチするにはCTRL+]を押す。

(ゲスト側) ネットワーク設定

ゲストOSの/etc/network/interfaceを編集する。この時点ではエディタはnanoかviの二択だ。

auto eth0
iface eth0 inet static
 address 192.168.2.2
 gateway 192.168.2.21
 netmask 255.255.255.0
 broadcast 192.168.2.255
 dns-nameservers 192.168.2.21

編集が終わったらゲストOS側で /etc/init.d/networking restart を実行してネットワーク設定を更新する。
仮想NICのゲストOS側のアドレスと同じネットワーク内のアドレスが仮想NICのホストOS側に割り当てていた場合は、これでゲートウェイが自動的にルーティングに設定されるはずだ。
適当な外部のサーバにpingを打ってみて、もしネームサーバが正しく設定されていない場合は手動で/etc/resolv.conf を編集する。
pingと名前解決さえできれば後は全く普通のdebianだ。