この記事は
スマホゲームを作っている中でサーバが要るので、
WebAPIサーバとDBサーバの土台を作ろうと思い立ち、
いろいろなサイトと自分の過去の経験・知識からのサーバを構築した日記です。
主に自分がやった事を中心に書いています。
設定内容についての説明はかなり省略して書いております。
ご不明な点がございましたら、コメントお願いします。
本記事でやっている事
MacOSX 10.11.3 をホストOSとし、VirtualBox 5.0.16 上に CentOS7.1 (1503) minimal をインストール1
その状態でセキュアにやれる設定に手を入れています。
- ネットワークサービスはsshのみです。(SNMP、Webサーバ、DB等はインストールしていません)
- SELinuxは有効にしていますが、ゆるめの設定で使っています。
- その他監視系のソフトはインストールしていません。
設定項目概要
ip
タイトル | 概要 |
---|---|
IP設定 | 軽く設定 |
SELinux
タイトル | 概要 |
---|---|
ポート設定 | ssh用のポート番号を変対応 |
sshd
タイトル | 概要 |
---|---|
sshポート変更 | 接続先のポート番号を変更 |
sshのプロトコルの制限 | sshdのプロトコルを2に限定 |
公開鍵の設定 | RSAの鍵ではなくてED25519で鍵を作成 |
パスワード認証を切る | 公開鍵でログインするように設定 |
rootでlogin出来なくする | 左記の通り |
認証周りの設定 | 認証の猶予時間や認証回数など |
ログインユーザの制限 | 指定ユーザのみが接続できるように |
接続プロトコルの制限 | X11、仮想端末の使用制限 |
firewall ( iptables )
タイトル | 概要 |
---|---|
破棄設定 | ip spoofing、port scan、Flood攻撃 等をDROP |
条件付きの接続 | 1回目はよくても立て続けに来た攻撃等の対応 |
接続設定 | 自分が使うものは無条件に接続 |
TCPWrapper
タイトル | 概要 |
---|---|
host.allow | サービスとユーザを紐付けて接続の許可 |
host.deny | allowで許可されなかった通信の拒否 |
sudo
タイトル | 概要 |
---|---|
利用できるコマンドの制限 | 実行できるコマンドを制限する |
接続制限 | コンソールを持たない接続は拒否 |
シェル実行禁止 | sudo でのシェルの実行を禁止 |
セッションタイムアウトの時間設定 | 認証有効期間の設定 |
カーネルの設定
タイトル | 概要 |
---|---|
ネットワーク対応 | TCP SYN Flood、Sumrf攻撃対応等々 |
その他
タイトル | 概要 |
---|---|
最新バージョンの適用 | yum update |
不要なサービスの停止 | 不要なサービスの停止 |
logwatchの導入 | 今回は見送っています |
使わないユーザーのログイン不可 | 使わないユーザーのログイン不可 |
umaskの設定 | 関係ないユーザのファイルアクセス制限 |
ipアドレスの設定
コマンドだけでやれたらカッコよかったけど、、、TUIで設定(゜゜
# nmtui
Edit a Connection ←選択
(NICカードを選択)
IPv4 Configuration <Show> ←選択
Require IPv4 addressing for this connection ← チェック
Automatically Connect ← チェック
OK ← 選択
Quit ← 選択
確認
# ip addr
SELinuxの設定
ここではポートの穴あけ をやっています。
sshで通信する予定のポート(=49152)になります。
まずこれをやっておかないとssh通信ができず、慌てることに。
(というか実際、数時間iptablesとsshd_configの設定の見直しばっかりやって時間を浪費してしまいました。)
編集用パッケージインストール
$ yum install policycoreutils-python
ポートの追加
$ semanage port -a -t ssh_port_t -p tcp 49152
設定確認
$ semanage port -l | grep ssh
SELinuxのログ
$ cat /var/log/audit/audit.log
sshの設定
sshの設定を仕上げてないと何かと不便なので、
最初にsshの設定をしていきます。
ssh接続用ユーザ(=ssher)の作成
# groupadd -g 1900 mainte
# useradd -G mainte,wheel -u 1901 ssher #<sshで接続するユーザ and ルート権限に昇格できるユーザ>
# mkdir /home/ssher/.ssh
# chmod 700 /home/ssher/.ssh # <- 忘れがちなので注意
秘密鍵/公開鍵の作成
RSAはもう古いのでED25519で作ります。(ミーハー)
MacOSXで鍵(秘密鍵/公開鍵)を作ってサーバ側へ公開鍵をコピーします。
(サーバ側で作ってMacOSXに秘密鍵をコピーって方法もやりましたが、
MacOSXのssh接続と相性が悪くてうまく接続できませんでした。)
$ sshe-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/hogehoge/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/hogehoge/.ssh/id_ed25519.
Your public key has been saved in /Users/hogehoge/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:FiublKpEQNgXnoVhogehogefugafugayWT74RSIRJEY hogehoge@MacOSX.local
The key's randomart image is:
+--[ED25519 256]--+
| . +oo |
| . . = * . |
| . sos = = |
| . o = B + . |
|. ... o S * o |
| o .o. = o |
|..++. + |
|.oBoss o |
|Eo.=*+o |
+----[SHA256]-----+
$
$ # サーバ側へ公開鍵をコピー
$ scp /Users/hogehoge/.ssh/id_ed25519.pub root@localhost:/home/ssher/.ssh/
root@localhost's password:
$
(ちなみに上記で作成した鍵は作り直しています。一部表示を伏せています。)
サーバ側で受け取った公開鍵をauthorized_keysへ登録
# su - ssher
$ cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys
$ chown ssher:ssher ~/.ssh/authorized_keys
$ exit # ssherユーザを抜ける
sshd_configの設定
基本設定は終わったのでここから本格的にセキュリティ設定に入る
# vi /etc/ssh/sshd_config
Protocol 2 # Protocol 1 は使わない(Protocol 1で繋ぐソフトを使用する予定が一切無い)
Port 49152 # ssh標準の番号を使わない(自由に使えるポート番号 = 49152 〜 65535 )
# ed25519の鍵だけ有効にする
# HostKeys for protocol version 2
# HostKey /etc/ssh/ssh_host_rsa_key
# HostKey /etc/ssh/ssh_host_dsa_key
# HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Logging
SyslogFacility AUTHPRIV
# 認証時の挙動設定
LoginGraceTime 10 # コネクションを貼って認証するまでの猶予時間(s)
PermitRootLogin no # root ユーザがsshでログインできないようにする
MaxAuthTries 3 # 最大認証試行回数
MaxStartups 2:90:4 # 2つを超える認証受付は90%の確率で遮断。4つを超えると全て遮断
# 認証方式の設定
PasswordAuthentication no # パスワードによるログイン禁止
ChallengeResponseAuthentication no # チャレンジレスポンスによるログイン禁止
PermitEmptyPasswords no # 空のパスワード設定は接続拒否
RSAAuthentication no # おそらくProtocol 1の時代専用パラメータ
PubkeyAuthentication yes # 鍵認証によるログインを許可
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
AuthorizedKeysFile .ssh/authorized_keys
# シングルサインオンの設定(GSSAPI options) 使用予定無し
GSSAPIAuthentication no
GSSAPICleanupCredentials no
# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux
# and may cause several problems.
UsePAM yes # 無効にすると挙動不審になるくさいのでyesのまま
# 接続制限
AllowUsers ssher # 接続できるユーザの制限
#AllowAgentForwarding no
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding no # GUIでサーバを操作しない
PermitTTY yes # 仮想端末の許可。tmux?なにそれ?な方はno
# DNS接続設定
UsePrivilegeSeparation sandbox # Default for new installations.
UseDNS no # IPアドレスを使用して接続するため、FQDNの検索にかかる待機時間を無くす。
# 以下、デフォルトのまま。(正直よくわかってない)
# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
# override default of no subsystems
Subsystem sftp /usr/libexec/openssh/sftp-server
パスワード認証の件ですが、有効にしたままだと鍵認証に失敗した時、
パスワード認証に流れていくようです。鍵認証にする場合、必ず無効にしましょう。
設定の確認
$ sshd -t
設定にミスがある場合、以下の様に出力されます。
(問題ない場合、何も出力されません)
/etc/ssh/sshd_config: line 36: Bad configuration option: hogehoge
/etc/ssh/sshd_config: terminating, 1 bad configuration options
設定の反映
$ systemctl restart sshd
繋ぐときのコマンド
$ ssh -i ~/.ssh/id_ed25519 ssher@接続先IPアドレス -p 49152
ちなみに、クライアント側に設定をぶち込んでおくとコマンドが短くなって幸せです。
(クライアント側を乗っ取られた時は、簡単に接続されてしまうのでセキュリテイを高く保つならオススメしません)
Host 接続先の任意の名前
HostName 接続先のIPアドレス
User ssher
IdentityFile ~/.ssh/id_ed25519
Port 49152
接続コマンド
$ ssh 接続先の任意の名前
失敗メモ
環境構築中、サーバに疎通できるにも関わらず、証明書を受け付けてもらえないことがありました。
/var/log/secure に認証がうまくいかなかったログ(以下内容)を見つけた。
Authentication refused: bad ownership or modes for directory /home/ssher/.ssh
原因はディレクトリの権限設定でした。
755で動いた方もおられるみたいですが、私の場合すでに755になっていたので、
700に変更しました。
$ chmod 700 .ssh
ssh参考サイト
iptablesの設定
CentOS7からは従来のiptables
に変わり、firewall-cmd
になってますので、
こちらで設定します。
firewall-cmd
パッケージが入ってなかったり、情報が少なかったり、これが本当に色々苦労しました。1
破棄設定
DROPの設定はdirectコマンドでガツガツ入れていきます。
(directコマンドは優先度が高いのでこちらに設定します。)
# firewall-cmd --remove-service=ssh --permanent # 通常のsshポートは塞ぐ
# # データを持たないパケットの接続を破棄する
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --tcp-flags ALL NONE -j DROP
# # SYNflood攻撃と思われる接続を破棄する
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp ! --syn -m state --state NEW -j DROP
# # ステルススキャンと思われる接続を破棄する
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --tcp-flags ALL ALL -j DROP
# # ブロードキャストアドレスを破棄する
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m pkttype --pkt-type broadcast -j DROP
# # マルチキャストアドレスを破棄する
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m pkttype --pkt-type multicast -j DROP
# # IP Spoofing(なりすまし) の対応(外部からやってくるローカルIPは破棄)
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i enp0s3 -s 127.0.0.1/8 -j DROP
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i enp0s3 -s 10.0.0.0/8 -j DROP #開発環境では許可
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i enp0s3 -s 172.16.0.0/12 -j DROP
# # firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i enp0s3 -s 192.168.0.0/16 -j DROP #開発環境では許可
# # firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i enp0s3 -s 192.168.0.0/24 -j DROP #開発環境では許可
# # Ping of Death 攻撃対策(firewall-cmdに修正するのがめんどくなったので割愛。参考サイトを参照してください。)
# # Pingに不要なicmpタイプのブロック(echo-request、echo-reply 以外)
# firewall-cmd --permanent --add-icmp-block=destination-unreachable
# firewall-cmd --permanent --add-icmp-block=parameter-problem
# firewall-cmd --permanent --add-icmp-block=redirect
# firewall-cmd --permanent --add-icmp-block=router-advertisement
# firewall-cmd --permanent --add-icmp-block=router-solicitation
# firewall-cmd --permanent --add-icmp-block=source-quench
# firewall-cmd --permanent --add-icmp-block=time-exceeded
# # invalid パケットを破棄
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m state --state INVALID -j DROP
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -m state --state INVALID -j DROP
# firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -m state --state INVALID -j DROP
条件付きで許可
# # Ping Flood攻撃対策(4回以上pingを受信した場合、以降は1秒間に1度だけ許可します。)
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p icmp --icmp-type 8 -m length --length :85 -m limit --limit 1/s --limit-burst 4 -j ACCEPT
# # flooding of RST packets, smurf attack Rejection
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT
# # Protecting portscans
# # Attacking IP will be locked for 24 hours (3600 x 24 = 86400 Seconds)
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m recent --name portscan --rcheck --seconds 86400 -j DROP
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -m recent --name portscan --rcheck --seconds 86400 -j DROP
# Remove attacking IP after 24 hours
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m recent --name portscan --remove
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -m recent --name portscan --remove
許可
# firewall-cmd --add-port=49152/tcp --permanent # 49152番の通信許可(このサーバのsshのポート番号)
基本動作
下記設定はsshの接続が確認されてから行う事。(でないと、ターミナルからログインできなくなる。)
# # ルールに当てはまらない受信を破棄(これで、INPUT、FORWARD両方にDROP)
# firewall-cmd --permanent --zone=public --set-target=DROP
設定反映
# firewall-cmd --reload
ログの設定
気力が尽きたのでその内、下記サイトを参考に設定します
参考サイト:
- iptablesでログ出力設定
- iptablesの設定ファイルをシェルスクリプトを利用して動的に作成
- そこそこセキュアなlinuxサーバーを作る
- さくらのサポート情報 iptablesの設定方法
- 自分仕様のboxファイルを作成する
- 立ち上げ直後のiptablesを設定する。
- iptablesの設定ファイルをシェルスクリプトを利用して動的に作成
TCPWrapper(hosts.allow、hosts.deny)の設定
sshdの接続は許可し、その他の接続は拒否します
hosts.allow → hosts.deny の順に処理します
sshd : ALL
ALL : ALL
sudoの設定
sudo を使ってシェルログインされるとログにも残らないまま、
全権限を持ってコマンドを実行されると 具合が悪いので実行禁止にします
ついでに他の設定もちょこっとだけ設定しています。
shell コマンド
# visudo
記述内容
Defaults requiretty # コンソールを持たないsshの接続はさせない
#Defaults:vagrant !requiretty # vagrantユーザだけ許可する場合はこの行のコメントを外す。
Defaults timestamp_timeout = 0 # sudoすると毎回必ずパスワードを求めるようにする
Defaults rootpw # sudoを実行する際はrootパスワードを求める
# 最初に実行できるコマンドをある程度制限する
Cmnd_Alias ALLOWCMND = /usr/sbin/
# sudoでシェルを実行させないようにする。(起動したシェル内で実行したコマンドがログに残らないため。)
Cmnd_Alias SHELLS = /bin/sh, /bin/csh, /bin/tcsh, /bin/bash, /usr/local/bin/bash
Cmnd_Alias SHELLS_NONINTERACTIVE = /bin/sh -c *, /bin/csh -c *, /bin/tcsh -c *, /bin/bash -c *
Cmnd_Alias SU = /bin/su, /usr/sbin/visudo
# %wheel ALL=(ALL) NOPASSWD: ALL, !SU, !SHELLS, SHELLS_NONINTERACTIVE
%wheel ALL=(ALL) ALLOWCMND, !SU, !SHELLS, SHELLS_NONINTERACTIVE
参考サイト:
カーネル設定
設定始めた当初はここまで手を出す予定はありませんでしたが、
調べてくうちに出てきちゃったので設定します。
# SYN Cookiesを有効にする
# ※TCP SYN Flood攻撃対策
sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
# ブロードキャストアドレス宛pingには応答しない
# ※Smurf攻撃対策
sed -i ‘/net.ipv4.icmp_echo_ignore_broadcasts/d’ /etc/sysctl.conf
echo “net.ipv4.icmp_echo_ignore_broadcasts=1” >> /etc/sysctl.conf
# ICMP Redirectパケットは拒否
sed -i '/net.ipv4.conf.*.accept_redirects/d' /etc/sysctl.conf
sed -i '/net.ipv6.conf.*.accept_redirects/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
sysctl -w net.ipv4.conf.$dev.accept_redirects=0 > /dev/null
echo "net.ipv4.conf.$dev.accept_redirects=0" >> /etc/sysctl.conf
done
for dev in `ls /proc/sys/net/ipv6/conf/`
do
sysctl -w net.ipv6.conf.$dev.accept_redirects=0 > /dev/null
echo "net.ipv6.conf.$dev.accept_redirects=0" >> /etc/sysctl.conf
done
# Source Routedパケットは拒否
sed -i ‘/net.ipv4.conf.*.accept_source_route/d’ /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
sysctl -w net.ipv4.conf.$dev.accept_source_route=0 > /dev/null
echo “net.ipv4.conf.$dev.accept_source_route=0” >> /etc/sysctl.conf
done
設定反映
# sysctl -p
確認方法
SYN Cookiesを有効にする
# sysctl -a | grep net.ipv4.tcp_syncookies
net.ipv4.tcp_syncookies = 1
上記はサイトから拾ってきた内容そのままですが、
設定変更前に必要なのは ICMPリダイレクトパケットの拒否のみでした。
その他は設定済みでした。
参考サイト:
その他
ここから一気に ~~手抜き、、、~~ゲフンゲフン
ソフトウェア更新
$ yum update
不要なサービスの停止
systemctl
でactiveなサービスを確認しつつ
不要なサービスを停止していきます。
が、ちょっと力尽きたので省略
気力が出てきたら更新します。
logwatchを入れる
とりあえず防げてたらいいのと、
まだローカル環境の開発ようにしか使わないので、見送りします。
公開前ぐらいにまた見直します
使わないユーザーをログイン不可にする
割とどのユーザも/nologinになってたのでとりあえずは良さげ。
umaskを027
othersからは好きに見れないように007、027に設定します。
# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
# Before
# if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then
# umask 007
# else
# umask 027
# fi
# After
if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then
umask 007
else
umask 027
fi
参考サイト:
終わりに
ここまで読んで頂きありがとうございます。
最後の方は明らかに手抜き感が漂っていますが、
また機会を見つけて見直していこうかと思います。
セキュリティの世界は楽しいですよね。
本記事ではやってる事ばかり書いていますが、 設定の必要性から深く勉強していくと、
人と人のガチの知恵比べの歴史が凝縮されている様が見えてきたりします。
まさに叡智の結晶。
(不謹慎ですみません)
ここで書いた設定も時間が経てば、それを破る攻撃方法とか見つけられている可能性も大いにあります。
そしてその攻撃を防ぐための新しい設定ができている事になると思います。
やることが変われば、設定も変わります。
この設定を鵜呑みに設定しないで、ご自身の環境に合わせて
検討してくださいますようお願いします。2
皆様の何かのお役に立てれば幸いです。
また、サーバの構築及び本記事を書くにあたり、多くのサイトから参考にさせていただき、サイト管理者様に感謝いたします。