タグ: Ubuntu Page 10 of 14

exitの恐怖。(systemctlの罠)

かなりのヒヤリハットが起きました。

現象:突然のアクセス不可

AWS Lightsailで動かしているUbuntu。その設定変更を終えたときです。

突然、SSH接続が切れました。Webブラウザ上からも接続できず。これは一体と思いながらAWSコンソールを確認するとインスタンスは停止状態。

取り急ぎ、再度起動してログインできることを確認し、「なぜ、こうなってしまったのか」を確認します。

原因と思われるコマンド

さっそく、historyを追ってみます。その中に

systemctl exit

と入力していたことがわかりました。

  • 一度、systemctlでサービスの状態を確かめようとする
  • でも、普通に起動していたことは確認できていた。
  • Ctrl + Cでコマンドをキャンセルするのを忘れ
  • そのままログアウト感覚で「exit」を入力

が、このコマンドを発行した経緯だと推測。そこで、もう一つの仮説です。

systemctl exitのコマンド結果

「このコマンドを発行することでシャットダウンとなるのではないか」と推測し、物理環境のUbuntu 20系Linuxで試してみました。

systemctl exit

結果、ものの見事にシャットオフ。Webの記事などで乗っていない挙動だっただけに焦りましたけど、文脈としては腑に落ちます。

今後、systemctl系を触るときはもっと注意が必要だと改めて悟りました。

Ubuntu 22.04系にRuby2.7をインストール

結論から言えば、Ubuntu 22.04系は普通にやったのではRuby 2.7はインストールできません。

なぜならRuby 2.7が必要とするOpenssl1.1.1系をUbuntu 22.04系がサポートしていないからです。

そんな中で、どうしてもこのバージョンを入れたいというケースがあったので対応を行いました。

手順

参考
https://github.com/rbenv/ruby-build/discussions/1940#discussioncomment-2663209

依存関係をインストールします。

sudo apt install git build-essential checkinstall zlib1g-dev

rbenvをインストールします。

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
rbenvのパスを通します。
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

source ~/.bashrc

ruby-buildをインストールします。

git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

OpenSSL 1.1.1をインストールします。

cd ~/Downloads
wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz
tar xf openssl-1.1.1q.tar.gz

cd ~/Downloads/openssl-1.1.1q
./config --prefix=/opt/openssl-1.1.1q --openssldir=/opt/openssl-1.1.1q shared zlib
make
make test
sudo make install

シンボリックリンクを張り替えます。

sudo rm -rf /opt/openssl-1.1.1q/certs
sudo ln -s /etc/ssl/certs /opt/openssl-1.1.1q

ruby 2.7系をインストールします。

RUBY_CONFIGURE_OPTS=--with-openssl-dir=/opt/openssl-1.1.1q
RUBY_CONFIGURE_OPTS=--with-openssl-dir=/opt/openssl-1.1.1q rbenv install 2.7.6

rbenv global 2.7.6

インストールされていることを確認します。

ruby -v
ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-linux]

rootが参照できるようにパスを通します。

which ruby
# /home/user1/.rbenv/shims
# 結果を控えておきます
sudo su -

# ↓以下、rootでの作業↓
echo "export PATH=$PATH:/home/user1/.rbenv/shims" >> ~/.bashrc
source ~/.bashrc
which ruby
# /home/user1/.rbenv/shims
# 控えておいたパスであることを確認します
ruby -v
# ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-linux]
# 2.7系であることを確認します

と、ここまで書きましたがきっとDockerなどのコンテナを使ったほうが楽かと思います。

Ubuntuのログイン画面編集。(Update-Motd修正)

UbuntuにSSHでログインしたときに出てくるこの画面を修正します。

Ubuntu 20.04 / 22.04共に同じ手順で実施できました。

手順

motd配下の全てのアクセス権を一時剥奪します。

sudo chmod -x /etc/update-motd.d/*

Welcomeメッセージに入れるパッケージをインストールします。

sudo apt install ansiweather
# 都市の天気予報をコマンドラインで答えるコマンドです

独自のWelcomeメッセージを作成します

sudo vi /etc/update-motd.d/01-custom
メッセージ内容
#!/bin/bash
echo "NOBODY EXPECTS THE SPANISH INQUISITION!"
echo "まさかの時のスペイン宗教裁判!"
echo " "

ansiweather -l tokyo
ansiweather -l penzance

# -l の後に都市名を入力することで、その都市の天気予報が表示されます

fail2ban-client status sshd
# fail2banでのブロック状況を確認

作成したWelcomeメッセージに実行権をつけます

sudo chmod +x /etc/update-motd.d/01-custom

変更後、このように表示されることを確認。

ログイン時のWelcomeメッセージ(motd)が修正されました。

Fail2Banによるセキュリティ対策。(SSH保護)

概要

AWSはメジャーなサービスのため、ここで使われているIPアドレスは攻撃のリスクがとても高くなります。
ここでSSH権限を乗っ取ろうとする攻撃に備え、Fail2Banを導入しました。

Fail2Banとは

様々なログファイルを読み込み、何度もアクセスを繰り返すようなアクセス元を遮断するプログラムです。

前提

  • AWS Ligthsailで動かしているUbuntu 20.04サーバ/Ubuntu22.04サーバで動作を確認しています。
  • (当然のように)SSHが導入されていることが大前提です。

手順

  • 全て管理者権限で実施しています。
  • パッケージ管理にaptitudeを利用しています。必要に応じてaptに読み替えてください。

参考:
https://www.kkaneko.jp/tools/server/fail2ban.html

https://github.com/mitchellkrogza/Fail2Ban-Blacklist-JAIL-for-Repeat-Offenders-with-Perma-Extended-Banning

Fail2Banのインストール

aptitude update
aptitude install fail2ban

wget https://raw.githubusercontent.com/mitchellkrogza/Fail2Ban-Blacklist-JAIL-for-Repeat-Offenders-with-Perma-Extended-Banning/master/filter.d/blacklist.conf -O /etc/fail2ban/filter.d/blacklist.conf

wget https://raw.githubusercontent.com/mitchellkrogza/Fail2Ban-Blacklist-JAIL-for-Repeat-Offenders-with-Perma-Extended-Banning/master/action.d/blacklist.conf -O /etc/fail2ban/action.d/blacklist.conf

systemctl restart fail2ban
systemctl status fail2ban
# active (running) を確認します

Fail2Banのログローテーション変更

mv /etc/logrotate.d/fail2ban /backup/directory/path/fail2ban.bak
vi /etc/logrotate.d/fail2ban
設定内容
/var/log/fail2ban.log {
                monthly
                rotate 13
                compress
                delaycompress
                missingok
                notifempty
                postrotate
                fail2ban-client flushlogs 1>/dev/null
                endscript
                create 640 root adm
                }

設定反映

fail2ban-client reload
# OKを確認します

fail2ban-client status sshd

#以下のように表示されました

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list: 

systemctl enable fail2ban
# 自動起動を行います

設定ファイルを作成します

vi /etc/fail2ban/jail.local 
設定内容
[DEFAULT]
port = 0:65535

filter = %(__name__)s
[blacklist]
enabled = true
logpath  = /var/log/fail2ban.*
filter = blacklist
banaction = blacklist
action = %(action_)s
bantime  = 31536000   ; 1 year
findtime = 31536000   ; 1 year
maxretry = 10

追加した設定を反映させます

touch /etc/fail2ban/ip.blacklist
chmod 775 /etc/fail2ban/ip.blacklist
systemctl restart fail2ban
fail2ban-client reload
systemctl restart sshd

systemctl enable fail2ban

導入後に注意する内容

cat /var/log/fail2ban.log
cat /etc/fail2ban/ip.blacklist

AWSで運用しているだけあって、かなりのログが引っかかっています。

AWS LightsailでのUbuntu20.04立ち上げとUbuntu22.04へのアップグレード。

概要

定額でAWSのインスタンスを利用できるLightsail。

Ubuntu系OSを利用できるものの、2022年12月時点ではUbuntu22.04に対応していません。

20.04は選べますので、

  1. Ubuntu20.04で新たなインスタンスを立ち上げる
  2. Ubuntu22.04にアップグレードする

方法を紹介します。

どハマりしたこと

結論を言うと、Ubuntu 22.04にアップグレードするとLigtsailの管理画面から直接SSHすることはできません。
(SSH-1アルゴリズムによるRSA認証が無効化されます)

つまり、 何も設定せずWeb画面のSSH接続で最初にアップグレードをすると、再起動した瞬間にログインできず詰みます。

これに気づかず、アップグレード後に全くログインできずインスタンスを作り直す羽目になりました。以下はメモとして残しておきます。

成功した手順(さっくりした手順)

以下、ある程度の知識がある方ならこの手順を行えば問題ないと思います。

  1. Lightsail上でUbuntu 20.04のインスタンスを立ち上げる。
  2. 静的IPを付与してIPを固定化する。
  3. 必要に応じてDNSレコードに登録する。
  1. Lightsail管理画面から初期ユーザーでログインする。
  2. 初期ユーザー以外のrootに昇格可能なユーザーを作成する。
  3. そのユーザーで強力な暗号による秘密鍵/公開鍵を設定する。
  4. Ubuntu 20.04 → 22.04にアップグレードする。

成功した手順(より詳細な記述)

インスタンスの作成

AWS Lightsailの管理画面にログインします。

https://lightsail.aws.amazon.com/ls/webapp/home/instances

「インスタンスの作成」をクリックします。

インスタンス作成

自分は以下のように選択しました。

  • リージョン:東京
  • インスタンスイメージの選択:Linux (OSのみ)
  • Ubuntu 20.04 LTSを選択。
  • 月次料金:10USD/月
  • インスタンス名:任意のもの
  • そのほかは空白

→設定後、「インスタンスの作成」をクリックします。
 → 作成後、「ネットワーキング」から静的IPを付与します。
  → 必要に応じてDNSを設定し、名前解決できるようにします。

管理画面のWebコンソール(SSH)操作

Web画面からログインし、rootに昇格します。

sudo su -
# この時、パスワードは設定されていないのでそのまま昇格できます。

ここから、ローカルのターミナルクライアントから接続できるようにユーザーを作成し、設定します。

ここではhogeとしていますので、任意のユーザーを指定して下さい。

adduser hoge
# パスワードなどを設定します

usermod -G sudo hoge
# ユーザーhogeを管理者グループに入れます

su - hoge
# ユーザーhogeに変われることを確認します

sudo su -
# パスワード入力後にrootに昇格できることを確認します

exit
# ユーザーhogeに戻ります

whoami
# ユーザーhogeであることを確認します

ssh-keygen -t ed25519
# 鍵の格納場所は初期値でいいので空Enter。(/home/hoge/.ssh/
# パスワードを設定します。

cd .ssh
ls -l
# 以下のファイルを確認します
# └id_ed25519
# └id_ed25519.pub
# ※これらのファイルはscp等で自分のクライアントにコピーします

rm id_ed25519
# sshサーバ上でそのまま鍵を作成したので秘密鍵は*クライアントにコピー後*削除します

mv id_ed25519.pub authorized_keys
chmod 600 authorized_keys
# 公開鍵をauthorized_keysに変更し、パーミッションを厳密にします

この後、ローカルにコピーしたid_ed25519をSSHターミナルクライアントに保存して設定し、接続確認を行います。

接続ができたらいよいよUbuntu 20.04→Ubuntu22.04へのアップグレードです。

ローカルPC(ターミナルクライアント)からの操作

whoami
#上記、作成したユーザーであることを確認します

sudo su -
# rootに昇格できることを確認します

apt update && apt upgrade && apt autoremove
# パッケージを最新版にして不要パッケージを削除します。途中で不要パッケージを消すかを求められるので[y]で消去します

reboot
# 一度再起動をします
# 再起動後、ログインします

Ubuntu20.04→22.04へのアップグレード

whoami
#上記、作成したユーザーであることを確認します

sudo su -
# rootに昇格できることを確認します

do-release-upgrade
# *ここからの作業は中断せず、一気通貫で行います*
アップグレード中にプロンプトから質問されたこと

以下、主要な質問事項です。コメント(#の後)に概要を書いています。

Reading cache

Checking package manager

Continue running under SSH?

This session appears to be running under ssh. It is not recommended
to perform a upgrade over ssh currently because in case of failure it
is harder to recover.

If you continue, an additional ssh daemon will be started at port
'1022'.
Do you want to continue?

# SSHのポートを追加するか
# → y

Starting additional sshd 

To make recovery in case of failure easier, an additional sshd will 
be started on port '1022'. If anything goes wrong with the running 
ssh you can still connect to the additional one. 
If you run a firewall, you may need to temporarily open this port. As 
this is potentially dangerous it's not done automatically. You can 
open the port with e.g.: 
'iptables -I INPUT -p tcp --dport 1022 -j ACCEPT' 

To continue please press [ENTER]

# 設定を変更するか
# → Enter

Do you want to start the upgrade?


4 packages are going to be removed. 85 new packages are going to be
installed. 555 packages are going to be upgraded.

You have to download a total of 247 M. This download will take about
49 seconds with a 40Mbit connection and about 6 minutes with a 5Mbit
connection.

Fetching and installing the upgrade can take several hours. Once the
download has finished, the process cannot be canceled.

 Continue [yN]  Details [d]

# アップグレード前の最終確認
# → y

There are services installed on your system which need to be restarted when certain libraries, such as libpam, libc, and libssl, are upgraded. Since these restarts may cause interruptions of service for the system, you will     x
   x normally be prompted on each upgrade for the list of services you wish to restart.  You can choose this option to avoid being prompted; instead, all necessary restarts will be done for you automatically so you can avoid being   x
   x asked questions on each library upgrade.                                                                                                                                                                                            x
   x                                                                                                                                                                                                                                     x
   x Restart services during package upgrades without asking?

# アップグレード時、各種サービスを再起動前にプロンプトでy/nを確認するか
# → 質問されるのがめんどいので yes

# この間、SSH等の設定変更を行うか訊いてきます。プロンプトの選択を変えずに先に進みました
# keep the local version currently installed

Remove obsolete packages? 

# 不要パッケージの削除
# → Yes

System upgrade is complete.

Restart required

To finish the upgrade, a restart is required.
If you select 'y' the system will be restarted.

Continue [yN]

# アップグレード完了後にリブートするか
# → y

こうして、再起動後、無事にアップグレードが完了です。

cat /etc/lsb-release

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.1 LTS"

アップグレード後の操作

以下、速やかに行います。

管理者に昇格できることを確認します。

sudo su -

rootのパスワードを設定します。

passwd root

初期ユーザー(ubuntu)が物理的にログインできないようにします。

cd /home/ubuntu/.ssh

rm authorized_keys

Let’s Encryptワイルドカード証明書によるredmineのSSL化対応。

先だって、AWS Lightsail上で2つめのredmineを構築する手順について触れました。

こちらをLet's Encryptで常時SSL化します。

前提

  • Ubuntu 20.04、Apache2での記録です。
  • 以下、sample.comで証明書を発行するための記録です。ドメインはお持ちのものを使ってください。(自環境で実施する際は必ず書き換えてください)
  • certbotで定期的に更新を行うのではなく、多目的に用いるために手動でワイルドカード証明書を発行する手順です。
  • 既にcertbotはインストールされていることと、DNSの更新権限を持っていることが前提です。

また、管理者権限で実施します。

ワイルドカード証明書発行

sudo certbot certonly --manual \
    --preferred-challenges dns-01 \
    --server https://acme-v02.api.letsencrypt.org/directory \
    -m メールアドレス \
    -d *.sample.com
TXTレコード登録
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
# IPは記録される旨を訊かれるので了承のためY

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.sample.com with the following value:

「文字列」

# 上記文字列をDNSのテキストレコードに登録します
# 登録後、
# nslookup -type=TXT _acme-challenge.sample.comを入力し、「文字列」が返ってくるまで少し待ちます

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

# TXTレコードが返ってくるのを確認したらEnter
発行完了
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/sample.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/sample.com/privkey.pem
   Your cert will expire on 2023-03-24. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

発行確認

cd /SSL一時格納ディレクトリ

cp -pi /etc/letsencrypt/live/sample.com/fullchain.pem ./sample.com.crt.$(date +%Y%m)
cp -pi /etc/letsencrypt/live/sample.com/privkey.pem ./sample.com.key.$(date +%Y%m)
# 一時格納ディレクトリにコピーします


openssl x509 -noout -dates -subject -in ./sample.com.crt.$(date +%Y%m)
# 証明書の発行期限を確認します

openssl x509 -in sample.com.crt.$(date +%Y%m) -noout -modulus | md5sum
openssl rsa -in sample.com.key.$(date +%Y%m) -noout -modulus | md5sum
# 証明書と秘密鍵のハッシュがそれぞれ一致していることを確認します

openssl x509 -issuer_hash -noout -in sample.com.crt.$(date +%Y%m)
sed -n -e'1d' -e'/BEGIN/,$p' sample.com.crt.$(date +%Y%m) | openssl x509 -subject_hash -noout
# 証明書と中間証明書のハッシュがそれぞれ一致していることを確認します

SSL格納、リンク貼り替え

mkdir /etc/certs
cp -pi sample.com.crt.$(date +%Y%m) /etc/certs
# 証明書ディレクトリ

cd /etc/certs
ln -sf sample.com.crt.$(date +%Y%m) sample.com.crt
# Let's Encryptは有効期限が3ヶ月と短いため、メンテナンスしやすいようにリンクを貼り替えるだけで更新できるようにします
ll
# シンボリックリンクが張られていることを確認します

mkdir /etc/private
cp -pi sample.com.key.$(date +%Y%m) /etc/private
# 秘密鍵ディレクトリ

cd /etc/private
ln -sf sample.com.key.$(date +%Y%m) sample.com.key
# Let's Encryptは有効期限が3ヶ月と短いため、メンテナンスしやすいようにリンクを貼り替えるだけで更新できるようにします
ll
# シンボリックリンクが張られていることを確認します
リリースファイル

cd /etc/sites-available/redmine2.conf

<VirtualHost *:80>
servername redmine2.sample.com
# 常時SSL化の設定
 RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
  ServerName redmine2.sample.com
  ErrorLog /var/log/apache2/atlier/redmine2.sample.com_error.log
  CustomLog /var/log/apache2/atlier/redmine2.sample.com_access.log combined

Alias /redmine2 /var/lib/redmine2/public
<Location /redmine2>
PassengerBaseURI /redmine2
PassengerAppRoot /var/lib/redmine2
Require all granted
</Location>


#SSL対応
  SSLEngine on
    Protocols h2 http/1.1
    Header always set Strict-Transport-Security "max-age=63072000"

# 先に指定したLet's Encryptの格納先
SSLCertificateFile /etc/certs/sample.com.crt
SSLCertificateKeyFile /etc/private/sample.com.key

        # redmine2.sample.comでアクセスしてきた場合、強制的に/redmine2サブディレクトリに遷移します
        RewriteEngine On
        RewriteCond %{HTTP_HOST} ^redmine2\.sample\.com
        RewriteRule ^/$ https://redmine2.sample.com/redmine2/ [R]

</VirtualHost>

SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE6-GCM-SHA384
SSLHonorCipherOrder     off
SSLSessionTickets       off

SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

動作確認

http://redmine2.sample.com (自分が設定したドメイン名)にアクセスして

  • redmineの画面が表示されること
  • SSl通信に置き換わること

を確認します。また、こちらの設定は可能な限りSSLの強度を高めています。

https://www.ssllabs.com/ssltest/analyze.html

こちらの暗号化強度チェックで

A+となっています。(2022年12月現在

Mod_SecurityのIPアドレス調査。(Cronによる自動実行)

2022年12月現在、「Mod_Securityが検知したIPアドレスネガティブリストに放り込む」は達成しました。

  • これら検知したIPはどこの国からか?
  • 日々、どのぐらいの数、不審なアクセスが来ているのか?

を把握するため、シェルスクリプトを書きました。(今回で一端終了です)

やりたいこと

  1. Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
  2. 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する
  3. 同じIPアドレスごとに件数を数え、降順で並べ替える
  4. cronで定期実行する

本項でやること

  1. cronで定期実行

前提

  • エラーログからIPアドレスを抜き出しアクセス元の国を抜き出すスクリプト
  • そのIPアドレスをカウントして降順に表示するスクリプト

が用意されていること。(前回前々回で提示)

また、

  • apacheのログが日ごとにローテーションされていること
  • redmineの稼働サーバに導入しているので、ログ表示プラグインで閲覧できる

も想定しています。

スクリプト作成

cron用に一部手を加えます。

エラーログからIPアドレスを抜き出してアクセス元の国を付与

ip_check.sh

スクリプト内容

#!/bin/bash

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# ログの格納場所に移動
cd /var/lib/redmine/log

# error.logからIPアドレスだけを抜き出します
cat ./error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort > ip.`date +%Y%m%d`.csv

listfile="./ip.`date +%Y%m%d`.csv"
# ip.YYYYMMDD.csvファイルがない場合にエラーを返します
if [ ! -f $listfile ]; then
        echo "ファイル $listfile が存在しないので終了します。"
        exit 1
fi

country_list="./country_list.csv"
# 国コード,国の名前が書かれたcountry_list.csvがない場合にエラーを返します
# このCSVファイルはログの格納場所に配置します
if [ ! -f $country_list ]; then
        echo "ファイル $country_list が存在しないので終了します。"
        exit 1
fi

# IPアドレスに国名を付与したファイルを定義します。(ip_list.YYYYMMDD.csv)
result_file="./ip_list.`date +%Y%m%d`.csv"
cat /dev/null > $result_file

cat ${listfile} | while read line
do
                # IPアドレスを逆順に並び替えます。(例: 1.2.3.4 → 4.3.2.1
                ip_revers=`echo ${line}|awk -F'.' '{print $4,".",$3,".",$2,".",$1}'|sed -e 's/ //g'`
                # 並び替えたIPアドレスをcc.wariate.jpに並び替えて、国コードを抜き出します。(JP,CH,ESなど
                country_code=`nslookup -type=TXT ${ip_revers}.cc.wariate.jp | grep '"'|awk -F'"' '{print $2}' `
                # 国コードをcountry_list.csvから参照して国名を抜き出します。
                country_name=`cat ${country_list} | grep ${country_code} | cut -d"," -f 2`

                # 次の行は標準出力に返す処理を行います。cron処理する場合は#をつけて作動しないようにします。
                # echo "${line},${country_name}"
                # IPアドレス,国名の形式にして同ディレクトリのip_list.YYYYMMDD.csvに保存します
                echo "${line},${country_name}" >> $result_file
        sleep 1
done

chown www-data:www-data ip.`date +%Y%m%d`.csv
chown www-data:www-data ip_list.`date +%Y%m%d`.csv

exit

アクセス元の国を付与したリストを集計するスクリプト

ip_count.sh

スクリプト内容

#!/bin/bash

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

cd /var/lib/redmine/log

# ip_list.csv.YYYYMMDDを読み込んで、IPアドレスをキー、国を値とする連想配列を作成します
declare -A countries
while read -r line; do
  # CSVの1列目をIPアドレス、2列目を国とします
  ip=$(echo $line | cut -d',' -f1)
  country=$(echo $line | cut -d',' -f2)
  # 連想配列に格納します
  countries[$ip]=$country
done < ip_list.`date +%Y%m%d`.csv

# 結果を格納するための変数を定義します
result=""

# 連想配列を反復処理します
for ip in "${!countries[@]}"; do
  # 各IPアドレスの件数を数えます
  count=$(grep -c $ip ip_list.`date +%Y%m%d`.csv)
  # 件数、IPアドレス、国をカンマ区切りで結合します
  line="$count,$ip,${countries[$ip]}"
  # 結果に追加します
  result="$result\n$line"
done

# カウントした結果をcounted_ip.YYYYMMDD.csvに出力します
echo -e $result > counted_ip.`date +%Y%m%d`.csv

### ↑ここまでchatGPTが作成したスクリプト↑ ###

# 最終結果をsorted_ip.`date +%Y%m%d`.csvに出力します
# LC_ALL=Cを設定しないと日本語で書かれた国名の並べ替えがうまくいきませんでした
cat counted_ip.`date +%Y%m%d`.csv |LC_ALL=C sort -n -r > sorted_ip.`date +%Y%m%d`.csv

# 最終結果以外のログファイルを削除します
# 必要に応じて無効化してください
rm ip.`date +%Y%m%d`.csv
rm ip_list.`date +%Y%m%d`.csv
rm counted_ip.`date +%Y%m%d`.csv

chown www-data:www-data sorted_ip.`date +%Y%m%d`.csv

exit

Cron配置

sudo crontab -e -u root

定期実行

0 7 * * * /スクリプト配置パス/ip_check.sh && /スクリプト配置パス/ip_count.sh

これで、指定した時刻に

  1. IPアドレスの抜き出し
  2. IPアドレスの集計

を行うようにしてくれます。

Mod_SecurityのIPアドレス調査。(アクセス元の国を抜き出す)

2022年12月現在、「Mod_Securityが検知したIPアドレスネガティブリストに放り込む」は達成しました。

  • これら検知したIPはどこの国からか?
  • 日々、どのぐらいの数、不審なアクセスが来ているのか?

を把握するため、シェルスクリプトを書きました。

やりたいこと

  1. Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
  2. 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する
  3. 同じIPアドレスごとに件数を数え、降順で並べ替える
  4. cronで定期実行する

本項でやること

  1. Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
  2. 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する

前提と準備

以下の環境です。

  • Ubuntu 20.04とCentOS 7以降で動作を確認しました。

nslookupコマンドが実装されていること

which nslookup
# パスがあれば実装されています。
nslookupがない場合のインストール
sudo apt-get install dnsutils

スクリプト生成

参考

以下のスクリプトをベースにしています。

https://raintrees.net/news/11

本スクリプトの作成者様と、IPアドレスと国の対応を結びつけるサービスの作成者様にこの場を借りて御礼申し上げます。

1. 国コードとアドレスを対応させたCSVを作成します。

以下のようなCSVを作成します。

vi country_list.csv
ファイル内容
AC,アセンション島
AD,アンドラ
AE,アラブ首長国連邦
AF,アフガニスタン
AG,アンティグア・バーブーダ
AI,アンギラ
AL,アルバニア
etc...

作成に当たっての参照先:

https://memorva.jp/memo/website/domain_cctld_country_code.php

スクリプトを作成します。

vi ip_check.sh
スクリプト内容
#!/bin/sh

# error.logのディレクトリを指定する場合は指定して下さい
# error.logからIPアドレスだけを抜き出して同ディレクトリのip.YYYYMMDD.csvに保存します
cat ./error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort > ip.`date +%Y%m%d`.csv

listfile="./ip.`date +%Y%m%d`.csv"
# ip.YYYYMMDD.csvファイルがない場合にエラーを返します
if [ ! -f $listfile ]; then
        echo "ファイル $listfile が存在しないので終了します。"
        exit 1
fi

country_list="./country_list.csv"
# 国コード,国の名前が書かれたcountry_list.csvがない場合にエラーを返します
if [ ! -f $country_list ]; then
        echo "ファイル $country_list が存在しないので終了します。"
        exit 1
fi

# IPアドレスに国名を付与したファイルを定義します。(ip_list.YYYYMMDD.csv)
result_file="./ip_list.`date +%Y%m%d`.csv"
cat /dev/null > $result_file

cat ${listfile} | while read line
do
                # IPアドレスを逆順に並び替えます。(例: 1.2.3.4 → 4.3.2.1
                ip_revers=`echo ${line}|awk -F'.' '{print $4,".",$3,".",$2,".",$1}'|sed -e 's/ //g'`
                # 並び替えたIPアドレスをcc.wariate.jpに並び替えて、国コードを抜き出します。(JP,CH,ESなど
                country_code=`nslookup -type=TXT ${ip_revers}.cc.wariate.jp | grep '"'|awk -F'"' '{print $2}' `
                # 国コードをcountry_list.csvから参照して国名を抜き出します。
                country_name=`cat ${country_list} | grep ${country_code} | cut -d"," -f 2`

                # 次の行は標準出力に返す処理を行います。cron処理する場合は#をつけて作動しないようにします。
                 echo "${line},${country_name}"
                # IPアドレス,国名の形式にして同ディレクトリのip_list.YYYYMMDD.csvに保存します
                echo "${line},${country_name}" >> $result_file
        sleep 1
done

exit

スクリプトに実行権限を付与します。

chmod +x ip_check.sh

動作確認

任意のディレクトリに以下のファイルがあることを確認します。

  • error.log (またはスクリプトにログのパスを記載)
  • ip_check.sh スクリプト
  • country_list.csv

スクリプト実行

./ip_check.sh

スクリプト実行結果

出力先(上記例ではスクリプトを配置したディレクトリ)に以下のファイルが出力されます。

  • ip.YYYYMMDD.csv (エラーログからIPアドレスのみを抜き出したファイル)
  • ip_list.YYYYMMDD.csv (以下の様に、IPアドレスとアクセス元の国を記述したファイル)
AAA.BBB.CCC.DDD,シンガポール
AAA.BBB.CCC.DDD,ベトナム
AAA.BBB.CCC.DDD,中国

次にやること

  1. このスクリプトの実行結果を元に件数ごとにまとめて並べ替えるスクリプトの作成
  2. cronによる定期実行化

Ubuntu 22.04でZabbix 6.2(MySQL/nginx構成)を設定するときにハマったこと。

以下の環境でZabbixを導入してみましたが、いくつかハマったことがあったのでメモを残しておきます。

導入した環境

  • Ubuntu 22.04
  • 導入しようとしたZabbix : 6.2
  • MySQL / nginx構成
  • 他サービス未導入(OSインストールと初期設定を終えたのみです)
  • ドメイン登録済みです。
  • ワイルドカードSSL証明書を発行済みです。

導入手順(ハマりポイント込み)

前提

  • 全て管理者権限で実施しています。
  • パッケージ管理は基本的にaptitudeを利用しています。
  • ローカルNWで設定しているのでufwなどは考慮していません。

参考URL

Zabbixレポジトリを追加してインストールします。

aptitude update
aptitude upgrade
wget https://repo.zabbix.com/zabbix/6.2/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.2-1+ubuntu22.04_all.deb
dpkg -i zabbix-release_6.2-1+ubuntu22.04_all.deb
aptitude update
aptitude install zabbix-server-mysql zabbix-frontend-php zabbix-nginx-conf zabbix-sql-scripts zabbix-agent

MySQLの初期設定

aptitude install mysql-server
systemctl start mysql
systemctl enable mysql

必要に応じて: mysql_secure_installation

参考 https://level69.net/archives/28557
vi /etc/mysql/mysql.conf.d/mysqld.cnf
追記内容
#末尾に以下を追加
default_authentication_plugin=mysql_native_password

設定後にmysqlサービス再起動

systemctl restart mysql

MySQL rootパスワード設定

mysql -u root -p
# 未設定のためパスワードは不要です
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'パスワード';
#パスワードは任意のものを入力ください
flush privileges;
exit

mysql初期設定

mysql_secure_installation
初期設定内容
Enter password for user root: 
# 上記で設定したパスワードを入力します

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: 
# Yを入力してEnter

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG:
# ポリシーに合わせて0/1/2を入力(ローカル環境のため0としました)

Estimated strength of the password: 50 
Change the password for root ? ((Press y|Y for Yes, any other key for No) : 
# 既に設定しているのでn

By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : 
# anonymousユーザーを削除するためY

Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : 
# rootユーザのリモートログインを禁止するためY

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : 
# テストDBを削除するためY

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : 
# 設定を反映するためy

MySQLでZabbix用のユーザーを作成

mysql -uroot -p
# 上記で設定したパスワードを入力します
CREATE DATABASE zabbix character set utf8mb4;
CREATE USER 'zabbix'@'localhost' IDENTIFIED BY 'パスワード';
# 任意のパスワードを設定
GRANT ALL ON redmine.* TO 'zabbix'@'localhost';
flush privileges;
exit

ハマりポイント1:SQL実行時にエラーが出る

ERROR 1419 (HY000) at line 2123: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

と出たので、設定をしておきます。

対処方法
mysql -uroot -p

rootでmysqlにログイン後、以下を実行します。

SHOW VARIABLES LIKE 'log_bin_trust_function_creators';
# OFF を確認
set global log_bin_trust_function_creators=1;
# 設定を有効化
 SHOW VARIABLES LIKE 'log_bin_trust_function_creators';
 # ONを確認

ハマりポイント2: インポート用SQLが存在しない(正しい手順を後述)

Webサイトの手順によると、

zcat /usr/share/doc/zabbix-sql-scripts/mysql/server.sql.gz | mysql -uzabbix -p zabbix

とありますが、該当ディレクトリにmysql用のSQLが存在しません。

対処方法
apt reinstall zabbix-sql-scripts

として、sqlを再インストールします。

updatedb
 locate server.sql.gz
 →  /usr/share/zabbix-sql-scripts/mysql/server.sql.gz

SQLをインポートします。

zcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | mysql -uzabbix -p zabbix
# zabbixのDBパスワードを入力します。

Zabbixの設定を行います。

vi /etc/zabbix/zabbix_server.conf
追記/編集内容
DBName=zabbix
DBUser=zabbix
DBPassword=zabbix

nginx用のconfファイルを設定します。

vi /etc/zabbix/nginx.conf
編集内容
        listen          443 ssl http2 default_server;
        # ポートを443のみで受け付けるようにします。
        server_name     ドメイン名;

        ssl_certificate "/SSL証明書と中間証明書を結合したファイル";
        ssl_certificate_key "秘密鍵ファイル";
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
        ssl_prefer_server_ciphers off;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 10m;

設定内容を確認します。

nginx -t
# Syntax OKを確認します

設定内容を反映します。

systemctl restart zabbix-server zabbix-agent nginx php8.1-fpm
systemctl enable zabbix-server zabbix-agent nginx php8.1-fpm

セットアップ確認

ブラウザから

https://ドメイン名/setup.php

が表示されれば問題ないです。その後、Next Stepに進んでください。

サーバ3台構成によるlsyncのバックアップ。

サーバ3台構成になっていることで、データの更なる冗長化を図ります。

バックアップ概要

redmineのデータをnextcloudにリアルタイム同期、nextcloudからgrowiに更に同期させます。

設定

基本的にこの設定通り。以前のサーバ設定をコピペする形なので、バックアップ先と元が逆にならないように細心の注意を払いました。

設定中のエラー

動作確認中のlsyncログを見たら以下を発見。

Sun Dec  4 04:20:39 2022 Error: Terminating since out of inotify watches.
Consider increasing /proc/sys/fs/inotify/max_user_watches

幸い、解決策がネットにありました。

http://blog.livedoor.jp/kmiwa_project/archives/1072412621.html

解決

vi /etc/sysctl.conf
設定内容
fs.inotify.max_user_watches = 819200
# 上記の内容を追記します
設定反映
sysctl -p
systemctl restart lsync

これによって、同期が無事に始まりました。

Page 10 of 14

Powered by WordPress & Theme by Anders Norén