Linux運用のスクリプト

ufwを用いてIPアドレスを対話的にブロックするシェルスクリプト。

概要

  1. 外部に公開しているサーバは、常に不審な攻撃に晒されます。これは、怪しいIPアドレスからのアクセスをブロックするためのスクリプトです。
  2. ufwを用いていることが前提です。
  3. このスクリプトは、/24や/16と、レンジを広げて遮断することができます。
  4. 広範囲なブロックはポリシーと併せて確認ください。
  5. また、ufwを扱うため、管理者権限で実行します。

スクリプト内容

#!/bin/bash

while true; do
    # IPアドレスを尋ねる
    read -p "ブロックしたいIPアドレスを入力してください: " ip_address

    # ブロック範囲を尋ねる
    read -p "IPアドレスをそのままブロックする場合は0、/24ごとにブロックする場合は1、/16ごとにブロックする場合は2を入力してください(空白エンターは0): " block_option

    # 入力が空白の場合はデフォルトで0(IPアドレスそのまま)とする
    block_option=${block_option:-0}

    # ブロック範囲を計算
    case $block_option in
        1) block_cidr="/24" ;;
        2) block_cidr="/16" ;;
        *) block_cidr="" ;;
    esac

    # ネットワークアドレスに変換
    if [[ -n "$block_cidr" ]]; then
        if [[ $block_option == "1" ]]; then
            # /24で区切る場合
            network_address=$(echo $ip_address | cut -d'.' -f1-3)
            # CIDR表記の生成 (/24)
            cidr_notation="$network_address.0$block_cidr"
        elif [[ $block_option == "2" ]]; then
            # /16で区切る場合
            network_address=$(echo $ip_address | cut -d'.' -f1-2)
            # CIDR表記の生成 (/16)
            cidr_notation="$network_address.0.0$block_cidr"
        fi
    else
        cidr_notation="$ip_address"
    fi

    # 設定内容を確認する
    echo "以下の内容でブロックを行います:"
    echo "IPアドレス: $cidr_notation"

    read -p "よろしいですか?(y/n): " confirm

    # ユーザーが処理を続行しない場合、スクリプトを終了する
    if [[ $confirm != "y" && $confirm != "Y" ]]; then
        echo "処理を中止しました。"
        exit 0
    fi

    # ブロックルールをufwに追加
    sudo ufw deny from "$cidr_notation"

    # エラーがあった場合はエラーメッセージを表示して終了
    if [[ $? -ne 0 ]]; then
        echo "ERROR: 不正なソースアドレス"
        exit 1
    fi

    echo "ルールを付け加えました。"

    # 他のIPをブロックするか尋ねる
    read -p "他のIPをブロックしますか?(y/n): " continue_blocking
    if [[ $continue_blocking != "y" && $continue_blocking != "Y" ]]; then
        break
    fi
done

# ufwを再読み込みする
sudo ufw reload

# ブロック状況を確認するか尋ねる
read -p "現在のブロック状況を確認しますか?(y/n): " check_status
if [[ $check_status == "y" || $check_status == "Y" ]]; then
    sudo ufw status numbered
fi

# 終了メッセージを出す
echo "IPブロックを終了しました。"

実行例

sudo bash ufw_deny.sh
  1. ブロックしたいIPアドレスがプロンプトに出てきます。
  2. IPv4アドレスを指定します。
  3. そのままか(0)/24(1)ごとブロックするか、/16(2)でブロックするかを質問しますので、0/1/2で答えます。
  4. 確認をy/nで聞いてきますので、入力をします。
  5. yならufwに、指定したIPアドレス(NWアドレス)を追加します。
  6. 別のIPをブロックするかy/nで聞いてきますので、こちらも入力します。
  7. 現在のブロック状況をy/nで尋ねられます。yならufwのブロック状況を表示してスクリプトが終了します。
  8. nならufwのブロック状況を表示せずスクリプトが終了します。

MySQLのデータベースを暗号化してバックアップするスクリプト。

概要

以前も作成していた、MySQLのデータベースのバックアップを自動的に取得するスクリプトを少々リファインさせました。

変数指定により、複数のDBを任意にバックアップできます。

スクリプトの動き

動作を確認したサーバ

前準備

アカウントファイル

任意のディレクトリに、db_account.txtといった、DBにユーザー名とパスワードを記したファイルを作成しておきます。

[client]
user = db_user
password = "password"

バックアップDBの格納先

  1. 冗長性があり
  2. 機密性が保たれる

場所を指定してください。筆者はクラウドストレージ(wasabi)をマウントしています。

パスワードの格納先

/home/hoge/dbrestore_password のように、複合化のパスワードを格納するディレクトリを作っておきます。 こちらも運用に合わせ、適切に保管ができる場所を指定します。

それぞれ、スクリプト実行アカウントがアクセス/実行できるものにします。

スクリプト

スクリプト内容

変数などは間違いの無いように指定ください。

#!/bin/bash

## 変数ここから ##
# $HOMEの変数を指定します。
HOME_DIR="/home/hoge"
# SQLをバックアップするディレクトリ(保管先)を指定します。運用に合わせて指定ください。
backup_dir="/path/to/backup/directory"
# 保持するバックアップの世代を日数で指定します。
keep_days=7
# ファイルに付与する日付/作業ディレクトリ名/バックアップファイル名を指定します。
current_date=$(date +%Y%m%d)
backup_name="backup_mysql_${current_date}"
zip_file="backup_mysql.${current_date}.zip"
# アカウントファイルを指定します。運用に合わせて指定ください。
credentials_file="${HOME_DIR}/script/config/db_account/db_account.txt"
# パスワードを記録するファイル名を指定します。運用に併せてして指定ください。
password_dir="${HOME_DIR}/dbrestore_password"
password_file="${password_dir}/db-restore.${current_date}.txt"
# redmineのデータベース名を指定します。
database_name=database
# バックアップ時に指定するオプションを指定します。
options="--defaults-extra-file=$credentials_file --no-tablespaces --single-transaction"
# バックアップファイルのパターンを指定します。
backup_file_pattern="backup_mysql.*.zip"
# パスワードファイルのパターンを指定します。
password_file_pattern="*restore*.txt"
## 変数ここまで ##

## 処理ここから ##

# 1.アカウントファイルのパーミッションが400かどうかチェックします。
# 400以外は処理そのものを終了します。
permissions=$(stat -c "%a" "$credentials_file")
if [ "$permissions" != "400" ]; then
echo "アカウントファイルのパーミッションは400である必要があります。"
exit 1
fi

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

# 3. mysqldumpを実行してデータベースのバックアップを取ります。
mysqldump $options -h localhost $database_name > "${backup_dir}/${backup_name}/${backup_name}.sql"

# 4. パスワードによる暗号化を実施します。
password=$(openssl rand -base64 12)
cd "${backup_dir}/${backup_name}"
zip -r "${backup_dir}/${zip_file}" -P "$password" .
cd -

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

# 6. 解凍パスワードを指定ディレクトリに保存します。
echo $password > $password_file

# 7.パスワードの読み取り権限を600に変更します。
chmod 600 $password_file

# 8. 保持期間より古いバックアップファイルを削除します。
find "$backup_dir" -name "$backup_file_pattern" ! -type f -newermt "${keep_days} days ago" -delete
find "$password_dir" -name "$password_file_pattern" ! -type f -newermt "${keep_days} days ago" -delete

## 処理ここまで ##

作成後、

chmod +x mysql_db_backup.sh

で実行権を付与します。

スクリプトの動かし方

スクリプトの動き

./mysql_db_backup.sh

として実行すると、

  1. 変数で指定したアカウントファイルを読み込み、mysqldumpでバックアップを取ります。
  2. バックアップ作成後、パスワード付きzipファイルに圧縮します。
  3. 圧縮されたバックアップと複合化のためのテキストファイルを変数で指定したディレクトリに格納します。
  4. 変数で指定した期日が過ぎたバックアップファイルと複合化のためのテキストファイルは自動的に削除されます。

バックアップDBの解凍

unzip backup_mysql.yyyymmdd.zip

とすると、パスワードを尋ねられます。

db-restore.yyyymmdd.txtに表示された文字列を入力します。

または、

unzip -P $(cat /path/to/password_file.txt) /path/to/zip_file.zip -d /path/to/output_directory

でファイルを直接引数にして解凍することもできます。

cronの指定

動作を確認したら、

crontab -e -u hoge

でcron編集画面を出し、

0 2 * * * /home/hoge/script/directory/mysql_db_backup.sh

などとして指定すれば、日次のDBバックアップを取得可能です。