タグ: Ubuntu Page 18 of 22

Redmineのファイル一式の日次バックアップ。(復旧方法込みのシェルスクリプト作成)

概要

Redmineのメンテナンスの中で重要となるDBのバックアップは記載しました。

ここでは、それ以外のファイル一式をバックアップするスクリプトを作成することで不測の事態に備えます。

バックアップ対象となるファイル群

基本的に、以下のファイル群が残っていれば復旧は(理論上)可能です。

  • /Redmine格納ディレクトリ/plugins配下一式
  • /Redmine格納ディレクトリ/files配下一式
  • /Redmine格納ディレクトリ/public/themes配下一式
  • /Redmine格納ディレクトリ/config/database.yml
  • /Redmine格納ディレクトリ/config/configuration.yml (メール設定などで設定している場合)
  • /Redmine格納ディレクトリ/config/additional_environment.rb (プラグインなどで追記している場合)

本記事で扱うこと

  1. 先に述べたバックアップ対象となるファイル群の定期バックアップを行うシェルスクリプトを作成します。
  2. バックアップ時、パスワードが書かれているコンフィグに関してはその箇所をマスクします。(これもスクリプトに組み込みます)
  3. 動作を確認し、cronに設定して日次でバックアップを行います。

動作を確認した環境

  • Ubuntu 20.04 LTS
  • Redmine 4.2

実施前提

  • 利用しているRedmine環境の容量を確認し、バックアップ先に十分な空き容量があることを確認してください。
  • 本スクリプトは「全てのデータを一時的なバックアップディレクトリにコピーした上で圧縮し、そのディレクトリは削除する」処理を取っています。その容量も加味してください。
  • バックアップ元(Redmine格納ディレクトリ)の所有者が全てRedmine実行ユーザ(通例はwww-data)となっていることを確認してください。
  • また、本記事において、Redmineの格納ディレクトリは/home/www-data/redmineと一般的な構成と異なっております。

確認した手順

  • Redmineが稼働しているUbuntuサーバのターミナル上での操作です。

さっくりとした手順

  1. バックアップディレクトリを作成します。
  2. バックアップスクリプトを作成します。(環境に合わせて修正します)
  3. crontabに登録します。

バックアップディレクトリ作成

sudo mkdir -p /home/backup/redmine
# 運用に合わせて指定ください

sudo chown -R www-data:www-data /home/backup/redmine
# Redmineディレクトリの所有者に設定します

cd /home/backup/redmine && pwd
# 指定したディレクトリに移動します

リストア方法のテキストファイル作成

バックアップから切り戻すとき、作業者はかなり焦るものです。そこで、簡単な手順をバックアップファイル一式に配置しておけばスムーズな復旧を行うことができます。

以下の内容を教義・信仰に沿ったエディタで作成します。(ここでは筆者が用いているテキスト内容です。必要に応じて修正してください)

  • テキスト内容
    • テキスト名:how_to_restore.md
    • テキストの所有者はスクリプトの実行者と同じ(またはroot)である必要があります。
    • 上記、設定したディレクトリと同じ場所に作成します。
# Redmine復旧方法

## 前提環境

- Ubuntu 20.04系サーバ
- MySQL 8.3以上
- Apache 2.4系
- Redmineの実行ユーザはデフォルトのwww-data

## 【リストア/移行方法】

### 移行先にRedmineを作成

1. 新たにRedmineサイトを立ち上げます。(移行元と移行先のバージョンは合わせます)
2. リストア先/移行先のdb名/dbユーザはバックアップ元と同じにします。
3. バックアップされたdatabase.ymlを /redmine/config/配下に上書きます。dbパスワードを設定してください。
4. この状態で、Redmineのデータマイグレーションまで行います。

### バックアップされたファイル一式の再配置

- files/ディレクトリ一式は /redmine/配下に上書きしてください。
- plugins/ディレクトリ一式は /redmine/配下に上書きしてください。
- themesディレクトリ一式は /redmine/public/配下に格納してください。
- configuration.yml : (あるなら)/redmine/config/配下に上書き。メールパスワードを設定してください。
- additional_environment.rb : (あるなら)/redmine/config/配下に上書きします。

※ それぞれのディレクトリ/ファイルの所有者を「www-data」にします。

sudo chown -R www-data:www-data /redmine格納ディレクトリ/
> 例 sudo chown -R www-data:www-data /var/lib/redmine

### プラグインのDBマイグレーション

1. redmineを配置したディレクトリに移動します。(例; cd /var/lib/redmine/
2. 以下のコマンドを発行して、プラグインのマイグレーションを行います。

sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production

### プラグインマイグレーション後のApache再起動

1. 以下を実施してWebサービスを再起動します。
sudo systemctl restart apache2.service

### DBのリストア

1. 別途、バックアップしたRedmineのsqlファイルを移行先サーバの任意のディレクトリに転送します。
2. 以下のコマンドを発行して、DBをリストアします。

mysql -u redmineのdbユーザ -p redmineのdb名 < バックアップしたsql
> 例  mysql -u redmine -p redmine < redmine_backup

### DBリストア後のApache再起動

1. 以下を実施してWebサービスを再起動します。

sudo systemctl restart apache2.service

### 動作確認

移行先(または復旧した)Redmineのホストにブラウザでアクセスし、バックアップした時の状態になっているかを確認します。

スクリプト作成

以下の内容を教義・信仰に沿ったエディタで作成します。

  • スクリプト内容
    • スクリプト名:redmine_daily_backup.sh
    • 実行ユーザ:Redmineの所有者 (通例はwww-dataです)、またはroot
#!/bin/bash

### ▼ここからはスクリプトの変数を定義します。""の記述は自身の環境に合わせて修正ください。▼ ###
# バックアップ先のディレクトリを指定します。
backup_dir="/home/backup/redmine"
# バックアップ元のRedmineが格納されているディレクトリを指定します。
redmine_dir="/home/www-data/redmine"
# ファイルに付与する日付/作業ディレクトリ名/バックアップファイル名を指定します。
current_date=$(date +%Y%m%d)
backup_name="redmine_backup_${current_date}"
zip_file="redmine_backup.${current_date}.zip"
# 保存する日数を指定します。(ここでは3日にします。)
retention_period=3
### ▲変数はここまでです▲ ###

# 一時的なバックアップディレクトリを作成します。
mkdir "${backup_dir}/${backup_name}"

# # Redmineのユーザデータ/プラグイン/テーマをバックアップディレクトリにコピーします。

cp -R "${redmine_dir}/plugins" "${backup_dir}/${backup_name}"
cp -R "${redmine_dir}/files" "${backup_dir}/${backup_name}"
cp -R "${redmine_dir}/public/themes" "${backup_dir}/${backup_name}"

# マイグレーション時に必要となるdatabase.ymlをコピーします。この時、パスワードが書かれている行をマスクします。
cp $redmine_dir/config/database.yml $backup_name
sed -i 's/password:.*/password: "type your db password"/' $backup_name/database.yml

# メール設定などでconfiguration.ymlを設定している場合、これもコピーします。(存在しない場合はコピーしません)
# 同様にパスワードが書かれていたらその行はマスクします。
if [ -f $redmine_dir/config/configuration.yml ]; then
  cp $redmine_dir/config/configuration.yml $backup_name
  sed -i 's/password:.*/password: "type your password"/' $backup_name/configuration.yml
fi

# プラグイン設定などでadditional_environment.rbを設定している場合、これもコピーします。(存在しない場合はコピーしません)
if [ -f $redmine_dir/config/additional_environment.rb ]; then
  cp $redmine_dir/config/additional_environment.rb $backup_name
fi

# スクリプトと同じディレクトリにあるhow_to_restore.txtをバックアップディレクトリに流し込みます。(存在しない場合はコピーしません)
if [ -f $backup_dir/how_to_restore.txt ]; then
  cp $backup_dir/how_to_restore.txt $backup_name/how_to_restore.md
fi

# バックアップディレクトリをzip形式で圧縮します。
cd "${backup_dir}"
zip -r "${zip_file}" "${backup_name}"

# 一時的なバックアップディレクトリを削除します。
rm -rf "${backup_dir}/${backup_name}"

# 上記retention_periodで指定した日数前のバックアップしたzipファイルを削除します。
find "${backup_dir}" -type f -name "redmine_backup.*.zip" -mtime +"${retention_period}" -delete
  • 実行権限の付与
chmod +x redmine_daily_backup.sh

動作確認

sudo -u www-data bash redmine_daily_backup.sh
# 管理者権限で実行する場合は sudo bash redmine_daily_backup.sh

以下を確認します。

  • エラーなく実行できること
  • redmine_backup.実行日付.zip形式でファイルが作成されること
  • sudo -u www-data unzip redmine_backup.実行日付.zipでファイルが解凍されディレクトリに移動できること
  • ymlファイルのパスワードが「type your (db) password」と本来のパスワードが上書きされていること
  • 設定したhow_to_restore.mdが回答したディレクトリの中にあり、参照できること

Crontab設定

Cron登録

sudo crontab -e -u www-data
# 管理者が実行する場合は sudo crontab -e -u root

登録内容例

5 0 * * * /home/backup/redmine/redmine_daily_backup.sh
# 実行時刻、頻度などは自分の運用形態に合わせます。

Cron登録確認

sudo tail -20 /var/log/cron.log

操作時刻に

  • BEGIN EDIT
  • REPLACE
  • END EDIT

が表示されれば設定は完了です。

動作確認日

2023/02/08

MySQLの定期バックアップ、現状の運用に修正。

こちらの記事を2023年2月時点での運用に併せ、以下、修正しました。

概要

Redmineのメンテナンスの中で、「データベースのバックアップ」は非常に重要なものです。

そこで、改めて、シェルスクリプトとCronによるバックアップ手順を整理しました。

動作を確認した環境

  • Ubuntu 20.04 LTS
  • Redmine 4.2
  • MySQL 8.0.32

実施前提

  • MySQLに管理者権限でログインできること。
  • Redmine用のDBとDBユーザ、DBパスワードを把握していること。
  • また、DBサーバはローカルホストです。

確認した手順

  • Redmineが稼働しているUbuntuサーバのターミナル上での操作です。
  • MySQL以外は全て一般権限で実行します。

さっくりとした手順

  1. Redmineのデータベースユーザに権限を付与します。
  2. バックアップディレクトリを作成します。
  3. アカウントファイルを作成します。
  4. バックアップスクリプトを作成します。
  5. crontabに登録します。

データベース設定

管理者権限でMySQLにログインします。

mysql -u root -p

データベースのユーザ権限を変更します。

これを行わないとDump処理ができませんでした。

GRANT RELOAD ON *.* TO '【RedmineのDBユーザ】'@'localhost';
FLUSH PRIVILEGES;
EXIT

ディレクトリとスクリプト作成

バックアップディレクトリ作成

sudo mkdir -p /home/backup/mysql
# 運用に合わせて指定ください。ファイルサーバや別パーティションにマウントしている方がサーバ事態の障害発生でも冗長化を持たせられます。

sudo chown -R hoge:hoge /home/backup/mysql
# ディレクトリの所有者をログインユーザに修正します

cd /home/backup/mysql && pwd
# 指定したディレクトリに移動します

アカウントファイル作成

※このファイルを作成しないと、「安全ではない」とエラーが出ます。

以下の内容を教義・信仰に沿ったエディタで作成します。(【】内は取り除き、自分の設定に合わせます)

  • アカウントファイル内容
  • ファイル名:account.txt
[client]
user = 【RedmineのDBユーザ】
password = "【RedmineのDBユーザ用パスワード】"

アカウントファイルでアクセスできることを確認

mysql --defaults-extra-file=account.txt

MySQLのプロンプトが出れば成功です。exitで抜けます。

スクリプト作成

以下の内容を教義・信仰に沿ったエディタで作成します。

  • スクリプト内容
  • スクリプト名:mysql_daily_backup.sh
#!/bin/bash

# スクリプトの日付形式を定義します
date=$(date +"%Y%m%d")

# バックアップディレクトリを定義します
# 上記手順で示したディレクトリを指定してください
backup_dir="/home/backup/mysql"

# アカウントファイルを指定します
credentials_file="$backup_dir/account.txt"

# バックアップ時に指定するオプションを定義します
options="--defaults-extra-file=$credentials_file --no-tablespaces --single-transaction"

# バックアップファイル名を定義します
backup_file="$backup_dir/redmine.sql.$date.gz"

# バックアップを実行し、.gz形式でバックアップをします
mysqldump $options -h localhost redmine | gzip > $backup_file

# 10世代前の圧縮ファイルを削除します(運用に合わせて指定ください)
find $backup_dir -type f -name "redmine.sql.*.gz" -mtime +10 -delete
  • 実行権限の付与
chmod +x mysql_daily_backup.sh

動作確認

sh mysql_daily_backup.sh

以下を確認します。

  • エラーなく実行できること
  • redmine.sql.実行日付.gz形式でファイルが作成されること
  • gunzip redmine.sql.実行日付.gzでファイルが解凍できること

Crontab設定

Cron登録

crontab -e

登録内容例

0 0 * * * /home/backup/mysql/mysql_daily_backup.sh
# 実行時刻、頻度などは自分の運用形態に合わせます。

Cron登録確認

sudo tail -20 /var/log/cron.log

操作時刻に

  • BEGIN EDIT
  • REPLACE
  • END EDIT

が表示されれば設定は完了です。

動作確認日

2023/02/08

AWS LightsailにSwap領域を確保。(Ubuntuでの設定)

概要

筆者が用いているAWS Lightsail。自動起動サービスやWebサービスの追加のためメモリが心許なくなりました。

インスタンスの底上げを図る前にいったんSwap領域を確保して、メモリの枯渇に備えます。

環境

  • Ubuntu 20.04
  • 2GBメモリ/60GBディスクのインスタンスを利用

実施した手順

さっくりとした手順

  1. 現在のメモリとディスク容量を確認します。
  2. Swap領域を確保します。
  3. 確保したSwap領域を有効化します。
  4. Swap領域が増えたことを確認します。
  5. fstabを修正します。
  6. fstab修正後にシステムを再起動し、Swap領域有効化を確認します。

作業の前に

ディスク起動時のオプションなど、特に重要なシステム領域の設定ファイルを修正する作業です。
失敗時に復旧できるようシステム全体のバックアップを取ることを強く推奨します。

現在のメモリ情報を確認

free -h
# -hオプションは(human readableの略だそうです)
  • ○実行結果
              total        used        free      shared  buff/cache   available
Mem:          1.9Gi       1.6Gi       114Mi        58Mi       209Mi       109Mi
Swap:            0B          0B          0B

Swapが全く作成されていません。

現在のディスク容量の確認

df -h
  • ○実行結果
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        59G  7.6G   51G  13% /
(後略)

まだ容量的に問題なさそうなので、2GBのディスク領域をSwapとして割り当てます。

Swap領域の確保

sudo fallocate -l 2G /swap

ls -ldh /swap
# 指定ディレクトリに2GBのファイルがあることを確認します

Swapの有効化

  • ★/swapのパーミッション変更
sudo chmod 600 /swap

ls -ldh /swap
# rootのみが読み書き可能なことを確認します
  • ★/swapの設定
sudo mkswap /swap
  • ○実行結果
スワップ空間バージョン 1 を設定します。サイズ = 2 GiB (2147479552 バイト)
ラベルはありません, UUID=f6d01f7d-6a48-45e9-a483-5757ec47cd8e
  • ★/swapの有効化
sudo swapon /swap

Swap有効化確認

free -h
  • ○実行結果
              total        used        free      shared  buff/cache   available
Mem:          1.9Gi       1.2Gi       430Mi        58Mi       283Mi       499Mi
Swap:         2.0Gi          0B       2.0Gi

2GBのSwap領域が確保されました。まずは一安心です。

fstab設定

  • ★/etc/fstabのバックアップ
sudo cp -pi /etc/fstab /path/to/backup/directory/fstab.$(date +%Y%m%d)

diff -u /etc/fstab /path/to/backup/directory/fstab.$(date +%Y%m%d)
# 差分が無いことでバックアップが取れていることを確認します。
  • ★/etc/fstab追記
cat <<- __EOF__ | sudo tee -a /etc/fstab
/swap none swap sw 0 0
__EOF__
  • ○差分確認
diff -u /path/to/backup/directory/fstab.$(date +%Y%m%d) /etc/fstab
  • ●差分
+/swap none swap sw 0 0

再起動後の修正確認

  • ★システム再起動
sudo reboot
  • ★再起動後の確認

以下が確認できれば作業完了です。

  1. サーバにログインできること
  2. Webサービスなど既存システムが設定前と同様に稼働すること
  3. free -h を実行し、Swap領域が確保されていること

NextcloudサーバのPHPアップグレードとエラー解消、そして再設定。(PHP7.4→PHP8.1)

Nextcloudを動かしている自宅サーバでPHPをアップグレード。

ちょっとだけハマったのでメモを残します。

環境

以下の環境でNextcloudを動かしています。

  • Ubuntu 20.04
  • Apache
  • MySQL
  • PHP 7.4

さっくりとした手順

  1. PHP7.4をアンインストールします。
  2. PHP8.1をインストールします。
  3. 追加モジュールを有効化します。
  4. NextCloudの追加設定を行います。

手順

  • 今回は全て通常ユーザで作業をします。
  • また、viを使わずコマンドを用いて設定を置き換えています。
  • 設定をするのはPHPのみです。他は設定の変更をしていません。
  • パッケージ/モジュールのインストールにaptitudeを用いています。好みに合わせてaptをご利用ください。

PHPの削除を行います。

sudo apt-get --purge autoremove php*

PHP8.1をインストールします。

sudo aptitude install php8.1

sudo aptitude install php8.1-{opcache,pdo,bcmath,calendar,ctype,fileinfo,ftp,gd,intl,json,ldap,mbstring,mysql,posix,readline,sockets,bz2,tokenizer,zip,curl,iconv,phar,xml}

sudo aptitude install php8.1-apcu

sudo aptitude install php8.1-memcached

php -v
# PHP 8.1.14 (cli)を確認しました。(2023/01/19)

apache再起動を行います。

sudo systemctl restart apache2.service

アップグレード後にエラー。

PHPアップグレード後、Nextcloudにアクセスするとこうなりました。

前の設定が全て消えたので、エラーが発生しました。

こちらを解消していきます。

エラーチェック

cd /var/www/html/nextcloud/
# Nextcloudの格納ディレクトリに移動します。自分の環境に置き換えてください。

sudo -u www-data php ./occ
# NextcloudのCLIインタフェースです
エラー内容
An unhandled exception has been thrown:
OCP\HintException: [0]: Memcache \OC\Memcache\APCu not available for local cache (Is the matching PHP module installed and enabled?)

memcacheとAPCuが読み込まれていないと怒られましたので、有効化していきます。

memcacheとAPCuの有効化

cd /etc/php/8.1/cli/conf.d
cat <<- __EOF__ | sudo tee -a /etc/php/8.1/cli/conf.d/10-opcache.ini
opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1
__EOF__
cat <<- __EOF__ | sudo tee -a /etc/php/8.1/cli/conf.d/20-apcu.ini
[apcu]
apc.enabled=1
apc.shm_size=32M
apc.ttl=7200
apc.enable_cli=1
apc.serializer=php
__EOF__
sudo systemctl restart apache2.service

再設定後の確認

cd /var/www/html/nextcloud/
# nextcloudの格納ディレクトリに移動します

sudo -u www-data php ./occ
# エラーが出ず、occのオプションが表示されることを確認しました。

この後、Nextcloudにアクセスし、画面が表示されることを確認しました。

管理者画面確認

Nextcloudに管理者アカウントでログインし、管理者設定を確認すると

  • PHPのメモリ制限が推奨値の512MB以下です。
  • テーマ別アプリは有効ですが、PHPモジュール「imagick」が有効ではありません。ファビコン生成を正しく行うには、このモジュールをインストールし、有効化する必要があります。
  • PHP モジュール "gmp" および "bcmath" が有効になっていない。WebAuthnパスワードレス認証を利用する場合は、これらのモジュールが必要です。

が出てきました。これを修正していきます。

php.ini修正

sudo cp -pi /etc/php/8.1/apache2/php.ini /etc/old/php.ini.$(date +%Y%m%d)
# /etc/oldがなければディレクトリを作成するか、任意のバックアップパスを指定してください

diff -u /etc/php/8.1/apache2/php.ini /etc/old/php.ini.$(date +%Y%m%d)
# 差分が存在しないことにより、バックアップが取れていることを確認します。

sudo sed -i 's/memory_limit = 128M/memory_limit = 512M/g' /etc/php/8.1/apache2/php.ini
# memory_limitを推奨値の512Mに置き換えます。
差分確認
diff -u  /etc/old/php.ini.$(date +%Y%m%d) /etc/php/8.1/apache2/php.ini
# 取得したバックアップと置き換えたファイルの差分を確認します
  • 差分
-memory_limit = 128M
+memory_limit = 512M

不足モジュールのインストール

sudo aptitude install php8.1-{imagick,gmp}

設定反映と確認

sudo systemctl restart apache2.service

Nextcloudに管理者アカウントでログインし、管理者設定を確認。

「すべてのチェックに合格しました」

と出たので設定完了です。

redmineのテーブルをタブ区切りで書くプラグイン導入。(redmine_tsv_macro)

これで、Redmineでの記事やチケットの作成作業が更に捗ります。

プラグイン概要

こういうエクセルファイルのテーブルをredmineのMarkdownに書き写す場合、TyporaやGrowiのテーブル機能を経由して変換する必要がありました。

これをほぼコピペだけで完結させるプラグインです。

参照URL

  • https://taikii.net/posts/2019/12/redmine-plugins-2019/
  • https://github.com/taikii/redmine_tsv_macro

手順

全て管理者権限で実施しています。

redmineディレクトリに移動します。

cd /var/lib/redmine/plugins
# 自分の環境に読み替えます

プラグインをインストールします。

sudo -u www-data git clone https://github.com/taikii/redmine_tsv_macro.git
# Webサービスを実行するユーザに合わせます(apache,nginxなど)

システムに反映させます。

systemctl restart apache2.service
# 自身の環境に合わせます

使い方

テーブルを作りたいところに{{tsv_h }}と入力し、その間にエクセルのブックをコピーしてペーストするだけです。

入力例

{{tsv_h
日付    曜日  天気  朝   朝:場所    昼   昼:場所    夜   夜:場所    備考
2023/1/1    日   晴れ  おせち 自宅  おせち 自宅  カレー 自宅  
2023/1/2    月   晴れ  明太釜玉うどん 自宅  クリームパスタ 自宅  餃子雑煮    自宅  
2023/1/3    火   晴れ  鳥オムレツ   自宅  ソーセージ定食 自宅  カツ丼 自宅  
2023/1/4    水   晴れ  ハンバーグ定食 自宅  春巻き弁当   自宅  雑煮  自宅  
2023/1/5    木   晴れ  ソーセージ定食 自宅  チャーシュー麺セット  ぎょうざの満洲 プラウンマサラ 自宅  
}}

出力結果

Excelのみならず、Googleスプレッドシート経由でも他のアプリを利用することなく、ブラウザ間のみでシートの貼り付けが可能になります。

また、{{tsv_h }}{{tsv }}とすることで、ヘッダを用いないテーブルが作成可能です。

注意点

  • ヘッダは空白行を作らないようにしてください。そうしないと全体のテーブルがずれます。
  • また、セルに改行があったり記号などでも崩れるようです。
  • 崩れないテーブルを作りたい場合は素直に他のツールを使います。

mod_securityが検知した不審なアクセスをufwで一括遮断。

あらまし

apacheにmod_securityを導入後、以下を実施しました。

  1. Mod_Securityが検知した不審なアクセスのうち、IPアドレスのみを抜き出す
  2. その抜き出したIPアドレスをMod_securityによってブロックする
  3. これを日次で追加していく

この方法はそこそこうまくいっています。ですが、「これら不審なアクセス元はWebだけでの攻撃だけか? メールやSSHへの攻撃もしているだろう」と思い立ち、不審なアクセスを元から絶つ方法を採りました。

環境

AWS Lightsailで以下を動かしています。

  • Ubuntu 20.04
  • いわゆるLAMP環境

前提

以下が準備済みです。

  • Mod_Security導入済み
  • 前述したmod_securityから不審なアクセス元のみを抜き出したIPアドレスのリストがある
    • このリストをnegativelist.txtとして用意しています。
リスト形式
192.168.0.1
192.168.1.123

のように、一行ずつIPアドレスだけが記述されているファイルです。

さっくりとした手順

  1. ufwを有効化します。
  2. 不審なアクセス元のIPアドレスのみを抜き出したnegativelist.txtを一行ずつ読み込みアクセスを遮断するシェルスクリプトを作成します。
  3. 作成したスクリプトを実行します。

実行の前の注意事項

  • 自環境のアクセスが遮断される可能性があることに注意してください。
  • 事前にスナップショットやバックアップを取り、失敗した時に備え切り戻しができる準備を強く推奨します
  • この方法によりアクセスができなくなった等に対し、筆者は責任を負いかねます。

手順

全て管理者権限で実施しています。

ufwがインストールされていることを確認します。(導入済みの場合はスキップ)

apt list ufw
#  [インストール済み] となっていることを確認します。

ufwを有効化します。(導入済みの場合はスキップ)

ufw enable

許可するサービスを指定します。(導入済みの場合はスキップ)

ufw limit ssh
# 連続したSSHアクセスを遮断します
ufw allow http
ufw allow https
# その他の許可するサービスは必要に応じて指定してください

この段階で、以下を確認します。

  • ターミナルクライアントからSSH接続ができること
  • 既存のサービスが外部NWからアクセスできること

サービス確認

ufw status
実行例
状態: アクティブ

To                         Action      From
--                         ------      ----
22                         LIMIT       Anywhere                  
80                         ALLOW       Anywhere                  
443                        ALLOW       Anywhere                  
22 (v6)                    LIMIT       Anywhere (v6)             
80 (v6)                    ALLOW       Anywhere (v6)             
443 (v6)                   ALLOW       Anywhere (v6)             

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

vi /hoge/add_ufw.sh
スクリプト内容
#!/bin/bash

# UFWを念のため事前に有効化します
ufw enable

# ファイルに書かれたIPアドレスを一行ずつ読み込みアクセスを遮断します。
while read line; do
    ufw deny from $line
# 読み込むファイルを指定します
done < /path/to/negativelist.txt

シェルスクリプトに実行権限を与えます。

chmod +x /hoge/add_ufw.sh

シェルスクリプトを実行します。

./hoge/add_ufw.sh
# 行数によっては相当な時間がかかります

実行後の確認を行います。

ufw status
実行例(抜粋)
Anywhere                   DENY        192.168.0.1              
Anywhere                   DENY        192.168.1.111              

まとめ

これで、「Webサイトに対して不審なアクセスを行ったIPをまるごと遮断する」ことが可能になりました。相当乱暴な方法ではあることにご注意ください。

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で運用しているだけあって、かなりのログが引っかかっています。

Page 18 of 22

Powered by WordPress & Theme by Anders Norén