Bash
CentOS
CentOSDay 3

CentOS 7 の初期設定でやっておくべきこと

VirtualBox に CentOS 7.3.1611 を minimal でインストールした初期状態で検証した。

locale

-bash: 警告: setlocale: LC_CTYPE: ロケールを変更できません (UTF-8): そのようなファイルやディレクトリはありません

CentOS 7.5 からか、ログイン時に上記のような警告が出るようになった。

echo 'LC_ALL="ja_JP.utf-8"' >> /etc/environment
echo 'LC_CTYPE="ja_JP.utf-8"' >> /etc/environment

/etc/environmentLC_CTYPE を指定すると出なくなる。

時刻の同期

date && chronyc -a makestep && date

クローンした仮想マシンの時刻が大幅にずれている場合などにログの時刻がおかしくなるので、インストール状況に応じて強制的に時刻を同期しておく。詳細は「NTP クライアント Chrony」を参照。

etckeeper による /etc 配下のバージョン管理

yum -y install epel-release git && yum -y install etckeeper && $_ init && etckeeper commit ":hatching_chick: Initial commit"

バックアップファイルを作成するのはナンセンスなので /etc 配下のファイルを git でバージョン管理する。詳細は「/etc をバージョン管理する etckeeper」を参照。

コマンド履歴

history

日時記録設定

cat << "_EOF_" > /etc/profile.d/history.sh && source /etc/profile.d/history.sh
# history initialization

HISTTIMEFORMAT='%F %T '
HISTSIZE=100000
HISTFILESIZE=100000
HISTIGNORE='history:w:top:pwd:ls:ll:df'
HISTCONTROL=ignoreboth
PROMPT_COMMAND='history -a; history -c; history -r'
_EOF_
etckeeper commit ":new: Add a history setting shell script"

デフォルトではコマンド履歴に実行日時が残らないので残るように設定。詳しくは「history コマンドに日時を付与する」を参照。

i-search の有効化

echo '[ -t 0 ] && stty -ixon' > /etc/profile.d/stty.sh && source /etc/profile.d/stty.sh
etckeeper commit ":new: Add a disabling XON/XOFF flow control (enabling i-search) shell script"

Ctrl+r でコマンド履歴検索モード (reverse-i-search) になるが、デフォルトでは戻りすぎた場合に逆方向に再検索することが出来ない。
Ctrl+s に割り当てられた端末ロックの stop を無効にすることで順検索 (i-search) が機能するようになる。
stty -ixon の代わりに stty stop undef を実行しても同様。

scp などで標準入力を受け付けていないのに stty しようとすると stty: 標準入力: 無効な引数です または stty: standard input: Invalid argument というエラーが発生するので [ -t 0 ] で標準入力かどうかを確認する。 1

script

mkdir /var/log/script && chmod 777 $_
cat << "_EOF_" > /etc/profile.d/script.sh && source /etc/profile.d/script.sh
# output operation log 
P_PROC=`ps aux | grep $PPID | grep sshd | awk '{ print $11 }'`
if [ "$P_PROC" = sshd: ]; then
  script -q /var/log/script/`whoami`_`date '+%F_%H%M%S'`.log
  exit
fi
_EOF_

history や psacct では実行結果が記録されないので script で履歴を残す。
上記のシェルスクリプトでは SFTP 接続がうまくいかないので要検討。

Audit システム

`auditctl -a always,exit -F arch=b64 -S execve`
echo "-a exit,always -F arch=b64 -S execve" >> /etc/audit/rules.d/audit.rules

デフォルトで起動している auditd サービスによるコマンド履歴の保存。
デフォルトでは /var/log/audit/audit.log に保存される。ログはテキストなので直接参照可能だが aureport コマンドや ausearch コマンドで参照すると見やすくなる。
実行ユーザーや実行ディレクトリ、オプションなども記録される。
pwd コマンドや cd コマンドなどは実行自体が記録されなかった。
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Defining_Audit_Rules_and_Controls.html

プロセスアカウンティング (psacct)

yum -y install psacct && systemctl start $_ && systemctl enable $_
etckeeper commit ":new: Install and enable process accounting (psacct)"

lastcomm コマンドでどのユーザーがどのコマンドをいつ実行したのかを確認できる。
非常に見づらいが、他のコマンド履歴と比べ改竄が難しいため監査証跡として有用。

HIDS による改ざん検知

ホスト型侵入検知システムの導入により改竄を検知する。OSSEC または AIDE などを利用する。

OSSEC HIDS

yum install -y epel-release wget && curl -s http://www.atomicorp.com/installers/atomic | sh && yum install -y ossec-hids-server
/var/ossec/bin/ossec-configure
sed -i.org '/directories check_all/s/"yes"/"yes" realtime="yes"/' /var/ossec/etc/ossec.conf
systemctl start ossec-hids && systemctl enable $_
etckeeper commit ":new: Install and enable OSSEC HIDS"

inotify によるリアルタイム検知が可能だが atomic リポジトリの導入が必要。詳細は「ファイル改ざん検知ツール OSSEC」を参照。

AIDE

yum -y install aide && $_ --init && mv /var/lib/aide/aide.db{.new,}.gz
curl -sL https://github.com/duritong/puppet-aide/raw/master/files/CentOS/{aide.cron} -o /etc/cron.daily/#1 && chmod +x /etc/cron.daily/aide.cron
etckeeper commit ":new: Install and enable AIDE"

inotify 未対応で古いが base リポジトリのみで導入可能。詳細は「ファイル改ざん検知ツール AIDE」参照。
Lynis や OpenSCAP などでインストールを要求される。

アップデート

yum clean all && yum -y update

Yum のキャッシュをクリアしてから、各パッケージを最新バージョンにアップデートする。
Kernel のバージョンアップがあった場合は reboot コマンドで再起動する。

パスワードなしでのログインの禁止

sed -i 's/\<nullok\>//g' /etc/pam.d/system-auth
etckeeper commit ":lock: Prohibit login without password"

su / sudo の設定

sed -i.org '/NOPASSWD/ s/^# //' /etc/sudoers
sed -i.org '/use_uid/ s/^#//' /etc/pam.d/su
etckeeper commit ":unlock: Enable su/sudo settings"

パスワードなし sudo 実行

/etc/sudoers
# %wheel ALL=(ALL)       NOPASSWD: ALL

上記コメントアウトを解除することで、sudo の実行をパスワードなしで行えるようになる。

パスワードなし root 切り替え

/etc/pam.d/su
#auth           sufficient      pam_wheel.so trust use_uid

上記コメントアウトを解除することで、root への切り替えをパスワードなしで行えるようになる。

su 許可ユーザーの制限

/etc/pam.d/su
#auth           required        pam_wheel.so use_uid

上記コメントアウトを解除することで、wheel グループに所属するアカウントのみ su できるようになる。

管理ユーザーの追加

useradd joe && passwd $_ && usermod -G wheel $_ && getent group wheel
sudo -u joe echo 'joe@example.com' > ~/.forward
sed -i /etc/aliases -e '/root:/ s/^#//' -e '/root:/ s/marc/joe/' && newaliases
echo "Test mail" | sendmail root
etckeeper commit ":email: Set a mail alias for root user"

ユーザーの作成後にパスワードを設定、 wheel グループに追加し、 wheel グループに所属するアカウントを確認する。

外部のメールアドレスに転送したい場合に .forward ファイルに設定する。

root 宛てメールをユーザー marc に転送する設定が /etc/aliases にコメントで記載されているので、アンコメントしてユーザー名を差し替える。

テストメールを送信する場合 CentOS 7 の minimal では mail コマンドや mailx コマンドはインストールされていないので、デフォルトでインストールされている Postfix の sendmail 互換コマンドを利用する。

ホスト名の変更

hostnamectl set-hostname server1.example.com

IPアドレスの変更

nmcli device && nmcli connection show enp0s8 | grep IP
nmcli connection modify enp0s8 ipv4.method manual ipv4.addresses 192.168.56.201/24
nmcli connection down enp0s8 && nmcli connection up $_

SSH 接続している場合は上記実行後に切断される。

NTP サーバーの変更

sed -i 's/centos/jp/' /etc/chrony.conf
systemctl restart chronyd
etckeeper commit ":: Change the addresses of NTP servers to better ones"

server 0.centos.pool.ntp.org iburstserver 3.centos.pool.ntp.org iburstserver 0.jp.pool.ntp.org iburstserver 3.jp.pool.ntp.org iburst に変更。意味があるかは不明。ping の時間は3倍くらい速い。
他の NTP サーバーは「公開 NTP サーバー」を参照。

ローカル PC での操作

ネットワーク設定が完了後、ローカル PC から公開鍵を登録する。

認証鍵の生成

ssh-keygen -t ed25519 -C "joe@example.com $(date +'%Y-%M-%dT%T%z')" -f ~/.ssh/id_ed25519_server1.example.com

ssh-id-copyls -t ${HOME}/.ssh/id*.pub でファイルを探すので、それに合わせてファイル名を指定する。
鍵種別は ed25519 が望ましい。
コメントはサーバーの鍵の管理者が連絡を取れるように使用者のメールアドレスを記載することが望ましい。鍵の生成日も記載すると参考になるかもしれない。

生成した認証鍵の確認

ls -t ${HOME}/.ssh/id*.pub
ssh-keygen -l -f `!!`

ssh-add

ssh-add ~/.ssh/id_ed25519_server1.example.com
ssh-add -l

サーバーへの公開鍵の登録 (ssh-copy-id)

ssh-copy-id -i ~/.ssh/id_ed25519_server1.example.com.pub example@192.168.56.201
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/Example/.ssh/id_ed25519_server1.example.com.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
example@192.168.56.201's password:

Number of key(s) added:        1

Now try logging into the machine, with:   "ssh 'example@192.168.56.201'"
and check to make sure that only the key(s) you wanted were added.

ローカル PC の公開鍵をサーバーに自動で登録する。

ssh

ssh example@192.168.56.201

パスワードなしで接続可能になる。

ssh-keygen -R

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Please contact your system administrator.
Add correct host key in /Users/Example/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/Example/.ssh/known_hosts:21
ECDSA host key for 192.168.56.201 has changed and you have requested strict checking.
Host key verification failed.
ssh-keygen -R 192.168.56.201

ローカル PC の known_hosts に重複するサーバー情報が残っているとエラーが出て接続できないので、その際は上記のコマンドで削除する。

.ssh/config

cat << "_EOF_" > ~/.ssh/config
Host heros
  User         example
  HostName     192.168.56.201
  IdentityFile ~/.ssh/id_ed25519_server1.example.com
  Port         10022
_EOF_

shopt

bashの”秘められた真のチカラ”を開放する。2

cat << "_EOF_" >> ~/.bashrc
shopt -s autocd
shopt -s cdspell
shopt -s dotglob
shopt -s extglob
shopt -s globstar
shopt -s nocaseglob
_EOF_

bash-completion

yum -y install epel-release && yum -y install bash-completion{,-extras}

Tab キーでファイルパス以外も色々補完してくれるようになる。

[root@localhost ~]# systemctl s
set-default       set-environment   set-property      show              
show-environment  snapshot          start             status            
stop              suspend           switch-root
[root@localhost ~]# ssh
::1                      localhost                localhost.localdomain    
localhost4               localhost4.localdomain4  localhost6               
localhost6.localdomain6
[root@localhost ~]# man z
zcat        zcmp        zdiff       zforce      zgrep       zipcmp      
zipdetails  zipmerge    ziptorrent  zless       zmore       znew        
zsoelim     zts-php     zts-phpize

Less

cat << '_EOF_' >> ~/.bashrc
export VISUAL=vim
export LESS="-M"
_EOF_

less コマンドの設定。
-M オプションはファイル名、行数、進行率を常時表示する。

Vim

cat << '_EOF_' >> ~/.vimrc && mkdir -p ~/.vim/tmp
set encoding=utf-8
set directory=~/.vim/tmp
set backupdir=~/.vim/tmp
set undodir=~/.vim/tmp
_EOF_

.swp などの一時ファイルの保存場所を変更する。

MySQL

cat << '_EOF_' > ~/.my.cnf
[mysql]
auto-rehash
pager = less -S -n -i -F -X
_EOF_

不足パッケージのインストール

Yum プラグイン

yum -y install epel-release && yum -y install yum-{axelget,changelog,cron,plugin-{ps,remove-with-leaves,rpm-warm-cache,show-leaves},utils}
パッケージ 説明
yum-axelget axel を利用してダウンロードを高速化する Yum プラグイン
yum-changelog 更新の前後でパッケージ変更ログの表示を可能にする --changelog オプションを追加する Yum プラグイン
yum-cron yum update を Cron で実行する Yum プラグイン
yum-plugin-ps yum ps で旧バージョンで稼働しているプロセスを一覧化する Yum プラグイン
yum-plugin-remove-with-leaves 依存関係のない孤立パッケージを削除する --remove-leaves オプションを追加する Yum プラグイン
yum-plugin-rpm-warm-cache rpmdb に直接アクセスする前に rpmdb ファイルをシステムキャッシュに読み込む Yum プラグイン
yum-plugin-show-leaves トランザクション後に依存関係のない孤立パッケージを表示する Yum プラグイン
yum-utils Yum を便利で強力にするためのユーティリティとサンプルのコレクション

ユーティリティ

minimal ではインストールされていないコマンドなどが多いので、よく使うものは事前にインストールしておく。

yum -y install bind-utils net-tools policycoreutils-python psmisc rlwrap traceroute tree vim-enhanced wget
パッケージ 説明
bind-utils dig host nslookup nsupdate
net-tools 代替コマンドがあるが互換性維持のため。
netstat arp ether-wake ifconfig ipmaddr iptunnel mii-diag mii-tool nameif plipconfig route slattach
policycoreutils-python SELinux の管理コマンドが含まれる。
audit2allow audit2why chcat sandbox semodule_package semanage
psmisc killall pstree fuser peekfd prtstat
rlwrap
traceroute
tree
vim-enhanced
wget 基本的に curl を使えば問題がないが、時折 wget が必須のスクリプトがある。

圧縮・解凍

yum -y install epel-release && yum -y install pigz {,p,l}bzip2 pxz {,un}zip
パッケージ 説明
unzip zip 形式のみで圧縮されていることが意外に多い。
bzip2 .tar.bz2 形式のファイルを展開するときに必要。
lbzip2 tar コマンドに -I lbzip2 を指定すると bzip2 を並列処理で時間短縮できる。
pbzip2 tar コマンドに -I pbzip2 を指定すると bzip2 を並列処理で時間短縮できる。
pigz tar コマンドに -I pigz を指定すると gzip を並列処理で時間短縮できる。
pxz tar コマンドに -I pxz を指定すると xz を並列処理で時間短縮できる。

モニターツールのインストール

yum -y install epel-release
yum -y install {a,apache,dns,h,if,io,inno,my,pg_}top iptraf-ng goaccess ncdu
yum -y --enablerepo=epel-testing install glances jnettop

GSSAPIAuthentication の無効化

sed -i '/GSSAPIAuthentication / s/yes/no/' /etc/ssh/sshd_config
etckeeper commit ":new: Disable the GSS API Authentication"

デフォルトで GSSAPIAuthentication が有効になっているが SSH ログイン時にもたつく模様。

カーネルの古いパッケージ保持数の上限を減らす 3

sed -e '/installonly_limit/ s/5/2/' -i /etc/yum.conf

セキュリティ設定

Lynis

sed -i.org '/mail_version/a smtpd_banner = $myhostname ESMTP' /etc/postfix/main.cf
sed -i.org /etc/login.defs -e '/PASS_MIN_DAYS/ s/0/1/' -e '/PASS_MAX_DAYS/ s/99999/3650/'
sed -i /etc/profile -e  's/umask 002/umask 027/' -e 's/umask 022/umask 027/'
cat << "_EOF_" > /etc/modprobe.d/blacklist.conf
blacklist usb-storage
blacklist firewire_core
blacklist firewire_ohci
_EOF_
for i in $(find /lib/modules/`uname -r`/kernel/drivers/net/wireless -name "*.ko" -type f) ; do echo blacklist $i >> /etc/modprobe.d/blacklist-wireless ; done
iptables --flush
firewall-cmd --reload
sed -i.org 's/#AllowTcpForwarding yes/AllowTcpForwarding no/' /etc/ssh/sshd_config
sed -i 's/#ClientAliveCountMax 3/ClientAliveCountMax 2/' /etc/ssh/sshd_config
sed -i 's/#Compression delayed/Compression no/' /etc/ssh/sshd_config
sed -i 's/#LogLevel INFO/LogLevel VERBOSE/' /etc/ssh/sshd_config
sed -i 's/#MaxAuthTries 6/MaxAuthTries 2/' /etc/ssh/sshd_config
sed -i 's/#MaxSessions 10/MaxSessions 2/' /etc/ssh/sshd_config
#sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
#sed -i 's/#Port 22/Port 10022/' /etc/ssh/sshd_config
sed -i 's/#TCPKeepAlive yes/TCPKeepAlive no/' /etc/ssh/sshd_config
sed -i 's/#UseDNS yes/UseDNS no/' /etc/ssh/sshd_config
sed -i 's/X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config
sed -i 's/#AllowAgentForwarding yes/AllowAgentForwarding no/' /etc/ssh/sshd_config
(echo; echo "Unauthorized access to this machine is prohibited."; echo "Disconnect now if you are not an authorized user."; echo) > /etc/issue
(echo; echo "Unauthorized access to this machine is prohibited."; echo "Disconnect now if you are not an authorized user."; echo) > /etc/issue.net
cat << "_EOF_" >> /etc/sysctl.conf
kernel.kptr_restrict=2
kernel.sysrq=0
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.log_martians=1
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.default.log_martians=1
net.ipv4.tcp_timestamps=0
net.ipv6.conf.all.accept_redirects=0
net.ipv6.conf.default.accept_redirects=0
_EOF_
sysctl -p
chmod 700 /usr/bin/as
yum install aide arpwatch psacct sysstat yum-utils
systemctl start arpwatch psacct && systemctl enable $_

詳細は「HowTos/OS Protection - CentOS Wiki」「Linuxセキュリティ監査ツール Lynis」「OpenSCAP」「脆弱性スキャナー Nikto」「脆弱性スキャナー OpenVAS」などを参照。

Fail2ban

yum -y install epel-release && yum -y install fail2ban{,-systemd}
cat << "_EOF_" > /etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 192.168.0.0/24
[sshd]
enabled  = true
_EOF_
etckeeper commit ":new: Add a Fail2ban setting file"
fail2ban-client -d
systemctl start fail2ban && systemctl enable $_
fail2ban-client status
fail2ban-client status sshd

詳細は「ブルートフォース攻撃対策 Fail2ban」を参照。

フールプルーフ(誤操作対策)

あくまでフールプルーフのための設定であり、これらに頼った運用や操作はしない。
やれ過保護だの慣れると他環境で失敗するだの言う人は宗教が異なりますのでお引き取りください。

リダイレクションによるファイル上書き禁止

.bashrc
set -o noclobber

interactive オプション

cat << "_EOF_" > /etc/profile.d/alias.sh
alias crontab='crontab -i'
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
_EOF_
etckeeper commit ":new: Add a shell script of adding interactive option"

crontab

crontab -e を実行しようとして r キーが e キーの隣にあるので、間違って crontab -r を実行してしまう可能性が考えられる。万が一そのような事態が生じても大丈夫なように -i オプションを指定しておくと -r オプション指定時に Y/N で確認を求めてくれるようになる。

cp/mv/rm

root ユーザーは /root/.bashrc で指定されているが、その他のユーザーでは指定がないので一律に指定する。
なお、この指定を無視したい場合は \mv source dist のように先頭にバックスラッシュを付加することで対応できる。

yum

echo "exclude=kernel* centos*" >> /etc/yum.conf
echo "alias yum='yum -disableexcludes=all'" >> /etc/profile.d/yum.sh
etckeeper commit ":new: Add excluding kernel setting from yum updating"

無防備に kenerl をアップデートして kernel パニックが発生すると慣れない作業で復旧に手間取るので、通常のアップデート時は除外して、kernel のアップデートは独立して作業を行うようにする。 4

なお、exclude を指定すると yum info などでも除外されるので注意。

yum update --disableexcludes=all

yum.conf で指定した exclude を無効にするには --disableexcludes オプションに all または main を指定する。

通常の yum update では kernel のバージョンアップの有無を含めて確認できなくなるため、 alias で --disableexcludes オプションを指定してこれを回避する。