■ 設定ファイルのコメント行を外す
通常、コンフィグファイルやシェルスクリプトには多くのコメントがついているが、httpd,conf
や squid.conf のようにコメント行があまりにも多く、設定本体を見渡しづらいファイルがある。次のスクリプトは引数1にこのようなファイルを指定し、コメント行を取り除いて出力する。見てわかるとおりこのスクリプトの本体は
grep と tr による処理がある一行のみで、他行は引数の評価とファイルの存在確認によるエラー処理である。当然、同じ作業はコマンドラインから
grep -v '^#' ファイル名 |
tr -s '\n' としても実行できる。
スクリプトに
commentoff など適切な名前をつけ、コマンドパスの通ったディレクトリに設置する。一般論だが、管理者の使用するツールは一般ユーザのアクセスできないディレクトリ(
/root/bin など)に設置し、パーミッションを700等に指定しておくべきである。
使用法は次のとおり。機能としては単純なフィルタコマンドなので、ファイル名を指定してリダイレクトすることもできる。
commentoff
ファイル名 ( > リダイレクトファイル名 )
#
---- commentoff -----
#!/bin/bash
if
[ $# -eq 0 ] || [ $# -ge 2 ] then echo echo
"ARGUMENTS INCORRECT --- Usage
: commentout FILENAME" echo else if
[ -e "$1" ] then echo echo
$1 echo grep
-v '^#' "$1" | tr -s '\n' echo else echo echo
"$1 : No Such File" echo fi fi
(注意:本稿ではバックスラッシュを¥記号で代用しているので、UNIX系で使用する場合は確認・訂正すること。)
|
■ man
ページをテキストファイルに掃き出す
man
ページをプレーンテキストに変換したい場合、次のようなスクリプトを用意しておくと便利である。このスクリプトの中核になるコマンドは他でもない
man のマニュアルページの最後に載っているが、そのままでは強調文字の制御コードが出力されてしまう。本スクリプトではこの制御コードをフィルタしてプレーンテキストを出力する。引数に2つ以上指定すると
warning が出るが、出力には特に問題はない。なお、引数に何も指定しないと使用法を表示して終了する。
注意:このスクリプトでは
man ページの項目が実際に存在するかどうかのチェックを行っていない。manpath
から find で検索を実施し、項目の存在を確認してから動作させることもできるが、検索に時間がかかることがあるので採用しなかった。多くの場合、man
ページを一通り眺めてからテキストが必要になるものなので、この仕様でもそれほど問題はない(
No manual entry for MANPAGE のエラーが返るだけ)だろうと思う。なお強調文字に対するフィルタロジックについては、何度も
sed を起動したりテンポラリファイルを4つも作ったりでいささか要領が悪いが、プログラムの見通しを良くするためにこのままにしておく。
#----
man2text -----
#!/bin/bash
if
[ $# -eq 0 ] then echo echo
"NO ARGUMENT --- Usage
: man2text MANPAGE MANPAGE ..." echo
else
for manpage in $* do
txtpage=$manpage.txt
man
$manpage | col -bfx > $txtpage
sed
's/1m//g' $txtpage >tmp1 sed
's/22m//g' tmp1 >tmp2 sed
's/4m//g' tmp2 >tmp3 sed
's/24m//g' tmp3 >tmp4 sed
's/0m//g' tmp4 >$txtpage
rm
-f tmp[1-4]
done fi
|
筆者注:man
ページの強調文字の仕様がすでに変わっているため、現在の
RedHat EL5.1 では以下のスクリプト中の col -bfx は必要ない。逆に
col による処理を残しておくと見出し部分が欠けてしまうので、現行
EL5 系への対応として以下の修正版を上げておく。
#----
man2text -----
#!/bin/bash
if
[ $# -eq 0 ] then echo echo
"NO ARGUMENT --- Usage
: man2text MANPAGE MANPAGE ..." echo
else
for manpage in $* do
txtpage=$manpage.txt
man
$manpage > $txtpage
sed
's/1m//g' $txtpage >tmp1 sed
's/22m//g' tmp1 >tmp2 sed
's/4m//g' tmp2 >tmp3 sed
's/24m//g' tmp3 >tmp4 sed
's/0m//g' tmp4 >$txtpage
rm
-f tmp[1-4]
done fi
|
ヒントと応用
:文書化の作業があるときなど man ページを windows 上で引用したり通読したいことがある。このような場合は
nkf を使って DOS ファイルに変換し、windows からアクセスできる
samba 共有にリダイレクトする。以下に one liner の形で示す。
$
nkf
-cs < man.txt > /home/public_samba/man.txt
|
■ 起動用フロッピディスクを作成する
現在の
Linux では LILO や GRUB などのブートローダをインストールするのが常識だが、この方法ではブートローダにパスワードをかけておかないかぎり、誰にでも再起動ができてしまう。したがって、管理者の知らないうちにシステムが再起動させられたり、コンソールから直接シングルユーザモードでログインされることもありえる。サーバのファシリティ管理上の理由(専用のサーバルームがなく、サーバがむき出しのままオフィスに置かれているなど)でこのような問題が想定される場合、システムにブートローダをインストールせず、フロッピィディスクから起動する方法を取るとよい。この手法はセキュリティだけではなく、何らかの理由でブートローダにトラブルが発生する可能性を考え、バックアップとして作成する意味がある。(もちろん、フロッピィディスクの管理がきちんとできることが前提であるが…。)
起動用フロッピィを作成する手順は以下のとおり。
1.デバイス
fd0 のマウント 2.フロッピィディスクのフォーマット 3.mkbootdisk
の起動とブートディスクの作成 4.デバイス
fd0 のアンマウント
mkbootdisk は起動用フロッピィディスク作成用のユーティリティスクリプトである。これを使ってコマンドラインから直接コマンドを叩けばいいだけのことだが、FDのマウント/アンマウントやカーネルバージョンの調査などわずらわしい部分があるので一連の手続きをスクリプト化しておく。
#----
make_bootdisk ----
#!/bin/bash
mount
/dev/fd0 /mnt/floppy fdformat /dev/fd0H1440 mkbootdisk
--device /dev/fd0 `uneme -r` umount /mnt/floppy
|
起動用ディスクは運用専用とバックアップ用の2組作っておき、それぞれ別の場所に保管することが望ましい。これはセキュリティ上の観点だけではなく、火災や天災等によってすべてのリソースが一度に失われることを防ぐ意味合いである。
■ /etc/hosts
ファイルに登録されているホストのPINGリプライを確認する
現在ではDNSによる名前解決が当たり前になっているが、/etc/hosts
ファイルは最低限ローカルネットでの通信を確保するために記述するべきである。クライアントに関してはDHCPを利用することが多いので対象外とするが、サーバやルータなどの主要なネットワークノードは
hosts ファイルに記述しておくと、以下のようなスクリプト上で
ping を使って生存確認ができる。
このスクリプトでは作業ディレクトリを
/root/bin としているので、実際に使用する場合は同じディレクトリを作るかパスを変更すること。ここに
/etc/hosts を一時的に hosts.tmp としてコピーする。次に
hosts ファイルの第二フィールド(ドメインつきホスト名)を切り出し、改行コードをタブに置き換えてリスト化する。あとはリストをシェル変数にロードして
ping を実行するLoopを回せばよい。
なお、ping
オプションは「4回発呼・4秒で終了」の意。このスクリプトは単に
hosts ファイルを参照するだけなので、ファイアウォールの仕様によっては
ping が通らないことも当然ありうる。(システム仕様について検討すること。)
#----
arrivehosts ----
#!/bin/bash
cp
/etc/hosts /root/bin/hosts.tmp cut -f
2 /root/bin/hosts.tmp |tr -s '\n' '\t' >/root/bin/hosts.tmp
HOSTS=`cat
/root/bin/hosts.tmp`
for hostname
in $HOSTS do ping
-c 4 -w 4 $hostname done
rm /root/bin/hosts.tmp
|
■ 現在のすべてのソケットユーザを調べる
調整期のサーバではどのようなサービスが上がっているのかわからなくなることがよくある。このような場合、稼動中のサービスを調査するには
netstat で tcp/udp ソケットを調べることが多い。lsof
-i で見るのが確実だが、パッケージをインストールしていないシステムが多いことや、lsof
の表示が未整理で情報が読み取りづらいという欠点がある。そこで
netstat の結果を拾い出して fuser に入力するわけだが、これを手順化したのが以下kのスクリプトである。
なお使用しているポート番号を抜き出す処理にややトリッキーな部分があるが、":"
を空白に置き換えて再び awk に渡しているにすぎない。(このような部分を正規表現などで処理しようとするとかえってわかりづらくなりやすい。)
拡張版
fuser :: tcp/udp ソケットを使用しているすべてのプロセスを表示する
1.UDPバージョン
for p in
`netstat -anu | awk '{ print $4}' | tr ":" " "| awk '{ print
$2 }'`
do echo fuser -vn udp $p done | less
2.TCPバージョン
for p in
`netstat -ant | awk '{ print $4}' | tr ":" " "| awk '{ print
$2 }'`
do echo fuser -vn tcp $p done | less
|
以下に出力例を示す。
[root@server
root]# for p in
`netstat -ant | awk '{ print $4}' | tr ":"
" "| awk '{ print $2 }'` ; do \ echo
; fuser -vn tcp $p; done
| less
USER
PID
ACCESS COMMAND 32776/tcp root
3915
f.... kinput2
USER
PID
ACCESS COMMAND 4043/tcp root
4251
f.... httpd root
4254
f.... httpd root
4255
f.... httpd root
4256
f.... httpd root
4257
f.... httpd root
4258
f.... httpd root
4259
f.... httpd root
4260
f.... httpd root
4261
f.... httpd
USER
PID
ACCESS COMMAND 111/tcp root
2643
f.... portmap
USER
PID
ACCESS COMMAND 80/tcp root
4251
f.... httpd root
4254
f.... httpd root
4255
f.... httpd root
4256
f.... httpd root
4257
f.... httpd root
4258
f.... httpd root
4259
f.... httpd root
4260
f.... httpd root
4261
f.... httpd
USER
PID
ACCESS COMMAND 6000/tcp root
3895
f.... X
USER
PID
ACCESS COMMAND 22/tcp root
2696
f.... sshd root
4456
f.... sshd
USER
PID
ACCESS COMMAND 8088/tcp root
4251
f.... httpd root
4254
f.... httpd root
4255
f.... httpd root
4256
f.... httpd root
4257
f.... httpd root
4258
f.... httpd root
4259
f.... httpd root
4260
f.... httpd root
4261
f.... httpd
USER
PID
ACCESS COMMAND 443/tcp root
4251
f.... httpd root
4254
f.... httpd root
4255
f.... httpd root
4256
f.... httpd root
4257
f.... httpd root
4258
f.... httpd root
4259
f.... httpd root
4260
f.... httpd root
4261
f.... httpd
USER
PID
ACCESS COMMAND 22/tcp root
2696
f.... sshd root
4456
f.... sshd
|
■ 引数リストから複数のサーバデーモンを起動する
このスクリプトは
RedHat での起動コントロールを行うディレクトリ /etc/rc.d/init.d/
以下にある起動スクリプトへサーバ名を渡す。ファイルの存在を実行ファイルかどうかのオプションつきで確認し、存在していれば
start し、存在しなければ Not Exist …以下のコメントを表示して終了する。(サーバプロセスがすでに動いている場合は
restart 動作になる。)
サーバプロセス名の引数はいくつでも指定できるが、引数がない場合は
Usage を表示して終了する。以下に使用例を示す。
daemon_start
httpd squid
なお、このスクリプトの /etc/rc.d/init.d/$daemon
start 行の start を stop に書き換えればそのままサーバプロセス停止スクリプトができる。
#----
daemon_start ----
#!/bin/bash
if
[ $# -eq 0 ] then echo echo
"NO ARGUMENT --- Usage
: daemon_start DAEMONNAME DAEMONNAME …" echo
else
for daemon in $* do if
[ -x /etc/rc.d/init.d/$daemon ] then /etc/rc.d/init.d/$daemon
start else echo
"Not Exist Script $daemon" fi
done fi
|
■ 簡易リモートバックアップ
このスクリプトはローカルマシンのディレクトリを tar で固め、ssh へ渡す処理を行う。通常リモートバックアップを行うには対応するバックアップアプリケーションが必要だが、この方法では ssh が使える状態になっていれば実行可能である。このスクリプトのミソは、前もってこれをリモートマシン側に scp しておけば、リモートマシンのバックアップを手元に取得できるということである。つまり、ssh でリモートホストへログインしたのち、本スクリプトを「向こう側からこちら側へ」使えばよい。
ほとんどワンライナーだけにかえって理解しづらいかもしれないので、以下に処理の概要を述べておく。
まずローカルマシンのルートディレクトリへ移り、etc, root, opt, var/log の各ディレクトリを tar で固めたのち、ssh にパイプする。転送先は仮に 192.168.0.1 としておくが、リモートマシン上で /var/tmp に移動し、容量節約と集約のために bkup.tar.gz ファイルへと gzip する。
なお、本スクリプトは元来シェルコマンドのグループ化の例題として作成したのでエラー処理はしていない。応用する場合はファイルの存在確認およびディスクの容量チェック、通信できなかった場合のエラー処理などを行うこと。また、本スクリプトを実行すると当然リモートホストのパスワード入力が求められるが、無認証sshの設定を行っておけば cron 等を使用してバックアップを自動化することができる。 (ただし、セキュリティの観点からはお勧めできません。)
#----
bkup.sh ----
#!/bin/bash
cd /
tar cf - etc root opt var/log
| (ssh 192.168.0.1 -l root "cd /var/tmp; gzip > bkup .tar.gz")
|
■ 複数のインタフェースの IP アドレスの切り出し
このスクリプトはマルチホームドホストの接続セグメントに対応したインタフェースの IP アドレスを取得するための sed ワンライナーである。マルチホームドホストとは2つ以上のネットワークインタフェースを持つホストのことであるが、このような場合は IP アドレスを取得するために以下のようなスクリプトを書いておくとよい。ここでは ifconfig の結果から "inet addr:"を検索語として sed で切り出した値を単に echo しているだけだが、アプリケーションで自ホストの IP アドレスが必要になったときなど、広く応用が可能である。なお、IP アドレスの切り出しは ifconfig | grep "inet addr:" のような形でもよいのだが、複数のインタフェースを持つホストでは eth0, eth1, eth2 …のように行儀よく認識されていないことがあるので、単純な grep を行う場合は注意すること。
なお、ifconfig の結果からは同様にしてネットワークアドレスやブロードキャストアドレス、ネットマスク等が取得できる。いずれも検索語をどう設定するかの問題にすぎないので、読者自ら変更点を考慮されたい。
#------ getipaddr.sh -------
#!/bin/bash
SEG0_IF='eth0'
SEG1_IF='eth1'
SEG0_ADDR=`ifconfig $SEG0_IF | sed -e 's/^.*inet addr:\([^ ]*\).*$/\1/p' -e d`
SEG1_ADDR=`ifconfig $SEG1_IF | sed -e 's/^.*inet addr:\([^ ]*\).*$/\1/p' -e d`
echo "SEGMENT0 INTERFACE = " $SEG0_IF " "$SEG0_ADDR
echo "SEGMENT1 INTERFACE = " $SEG1_IF " "$SEG1_ADDR
|
■ SET
UID ビットの立ったファイルを洗い出す
1.SUIDに関する予備知識
UNIX系OSではファイルの属性として
owner / group / other の各実行者について read /
write / execute のパーミッションを割り当てることができる。これは3桁の8進数で表記されるのが普通だが、こ
の他に set userID(suid)、set groupID(sgid)、スティッキー(sticky)という属性をつけることができる。suid
/ sgid / sticky の機能は次のとおり。
種類
|
機能
|
suid |
通常、プログラムやコマンド、スクリプト等を実行するときは実行者の権限で動作するが、suid
ビットがセットされていると実行ファイル作成者の権限で動作する。このため root
が作った実行ファイルにSUIDビットをセットすると、そのファイルは
root 権限で実行できてしまい、セキュリティ上問題になることがある。 |
sgid |
あるユーザがディレクトリを作成すると、その中に作成されるファイルやディレクトリの所有グループは自動的にユーザの所属するグループになる。SGIDビットをセットすると、他のグループも所有者グループの権限でファイルを実行することができるようになる。root
グループのSGIDが問題になるのはSUIDと同じ理由による。 |
sticky |
ディレクトリに sticky
ビットをセットすると、そのディレクトリ以下にあるファイルの削除やファイル名の変更は所有者にしかできなくなる。(ファイルにセットした場合は、実行が終了しても仮想メモリに残ったままになる。) |
SUID・SGID・STICKY は ls -l コマンドでファイルを表示したとき、次のように実行権限部分が
x から s または S に変更されて表示される。s と S の違いは、もともと実行権限があった場合となかった場合についての区別である。
対象
|
本来の実行権限
|
種類
|
表示
|
owner |
あり |
suid |
s |
なし |
S |
group |
あり |
sgid |
s |
なし |
S |
other |
あり |
sticky |
t |
なし |
T |
たとえばSUIDをつける前のファイルパーミッションが
-rwxr--r--r だったなら、 -rwsr--r--r になり、 -rw-r--r--r
ならば -rwSr--r--r となる。また、これがSGIDビットを立てるなら、本来のパーミッションが
drw-r--r--r のとき drw-r-Sr--r となる。
2.検索用コマンドをスクリプト化する
先に述べたとおり、SUIDビットの立った実行ファイルを放置していると、セキュリティ上問題となることがある。管理者はSUIDビットがセットされたファイルをシステムから洗い出し、その数を必要最低限に抑制する必要がある。以下の1行スクリプトは
find を使った単純な検索プログラムであるが、システムからこの種のファイルをすべて洗い出すのに役立つ。なお、この手のコマンドスクリプトの実行結果はファイルにリダイレクトしてチェックを行うとよい。また、出力形式を変更したい場合は、ls
のオプションを変更する。
# ----
ls_suid_files -----
#!/bin/bash
find
/ \( -perm -04000 -o -perm -02000 \) -exec
ls -ald '{}' '\';
|
■ iptables
を初期化する(RedHat 8)
iptables
によるファイアウォールを検証中に設定のミスを発見したときなど、一度設定を完全に初期化したいことがある。このような場合、設定をフラッシュしたのち再起動するのが普通だが、設定を
iptables-save コマンドでセーブしてしまったときなど、同じ状態のまま再起動してしまうので初期化が面倒になる。このような設定を初期状態に戻すには次のスクリプトを実行する。lsmod の出力を見て、iptables 関係のモジュールが揃っており、iptables
-L によってチェインが初期状態に戻っていることが確認できればOKである。
なお、このファイルは一般ユーザのアクセスを禁止したディレクトリに置き、読み・書き・実行もすべて禁止にしておく。もちろん、ファイアウォールの構築が終了したら、運用を開始する前に削除しておくこと。
#----
iptables_reset ----
#!/bin/bash
modprobe="/sbin/modprobe" iptables="/sbin/iptables"
if
[ -f /etc/sysconfig/iptables ] then
rm -f /etc/sysconfig/iptables
$iptables -F
$iptables
-X
/etc/rc.d/init.d/iptables stop
$modprobe
ip_tables $modprobe ip_conntrack
$modprobe iptable_nat
$modprobe
iptable_filter $modprobe iptable_mangle
lsmod echo
$iptables
-L else $iptables -F
$iptables
-X
/etc/rc.d/init.d/iptables stop
$modprobe
ip_tables $modprobe ip_conntrack
$modprobe iptable_nat
$modprobe
iptable_filter $modprobe iptable_mangle
lsmod echo
$iptables
-L fi
|
リセットスクリプトを実行後は
iptables 設定用スクリプトを書き直し、あらためて検証を行う。iptables
はカーネルのステータスを変更するので、/etc/rc.d/init.d/iptables stop
によって一度停止・再起動しなければ初期状態に戻らないことに注意すること。最終的にファイアウォールが仕様通りに構築できたことが確認できたら
iptables-save コマンドによって設定を /etc/sysconfig/iptables
にリダイレクトするか、設定用スクリプトを /etc/rc.local に登録しておけばよい。これによって再起動時にも同じ設定が有効になる。
|