月: 2023年2月 Page 1 of 3

連携:RedmineのディレクトリとWasabiバケット。

概要

クラウドストレージで作成したバケットは無事にマウントできるようになったので、Redmineの添付ファイルの保存先を切り替えます。

確認環境

  • Ubuntu 20.04
  • s3fsによりWasabiクラウドストレージのバケットがマウントされていること

サックリとした手順

  1. 保存先のディレクトリを作ります。
  2. Remineの添付ファイル一式をバケットにコピーします。
  3. 添付ファイルの保存先をシンボリックリンクに切り替えます。

詳細手順

マウントしたバケットにディレクトリを作成します。

sudo mkdir -p /mnt/wasabi/redmine
# 自分がマウントした環境に合わせます。

sudo chown www-data:www-data /mnt/wasabi/redmine

ls -ld /mnt/wasabi/redmine
# ファイルがあることと所有者がwww-dataであることを確認します。

Remineの添付ファイル一式をコピーします。

sudo -u www-data cp -pir /var/lib/redmine/files /mnt/wasabi/redmine
# Redmineのパスは自分の環境に合わせます。

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

cd /var/lib/redmine
# 自分の環境に合わせます。

sudo mv files files.org
# 一時的に退避します。

sudo ln -s /mnt/wasabi/redmine/files files
# 自分がマウントした環境に合わせます。

sudo chown -h www-data:www-data files

ls -ld /var/lib/redmine/files
# filesの向き先がリンクを張った場所にあることとリンクの所有者がwww-dataであることを確認します

動作を確認します。

  1. Redmineの任意のチケットでファイルを添付します。
  2. 添付後、上記、マウントしたバケットの内容を確認してファイルがあることを確認します。

これで、AWSのRedmineでもファイルを大量に添付できるようになります。

fail2banの再設定。

概要

不正アクセスからサーバを保護するfail2ban。様々なルールが存在するため、チューニングの失敗によっては機能不全に陥ります。

そんなこんなで、ちょっとハマった出来事を記します。

確認実施環境

Ubuntu 20.04

fail2banはアンインストールできない場合があります。

apt-get --purge autoremove fail2ban

をやってもアンインストールできませんでした。

対処: dpkgのinfoファイル削除

sudo su -
# この作業は全て管理者権限で行った方がいいです

cd /var/lib/dpkg/info/

ls -l fail*
rm fail*
# fail2banのみのパッケージがあることを確認して消去します

apt-get --purge autoremove fail2ban
# この段階でようやくアンインストールできました

cd /etc/

rm -rf fail2ban
# fail2banの設定を変更します

と、dpkgのinfoファイルを削除して

ufwとうまく連携できません。

「なぜチューニングに失敗したのか」の理由です。ネットにあるfail2banの記事は大概がiptablesとの連携を前提としているため、Ubuntu系での標準ファイアウォールであるufwとうまく連携できませんでした。

なので、

  • 記事を鵜呑みにして設定するとエラーが発生してfail2banの起動に失敗する。
  • 再設定のためにアンインストールしようとすると上記問題が発生する

という経緯があります。

対処:ufwに即した設定変更

参考記事:
https://blog.fernvenue.com/archives/ufw-with-fail2ban/

前提:

まっさらな状態で(上記手段でアンインストールした上で)

sudo aptitude install fail2ban

を実行した状態とします。

jail.localを編集します。

協議・信仰に沿ったエディタで以下のファイルを編集(作成)します。

  • ファイル名 /etc/fail2ban/jail.local

○内容

[ufw]
enabled=true
filter=ufw.aggressive
action=iptables-allports
logpath=/var/log/ufw.log
maxretry=1
bantime=-1
ignoreip = 127.0.0.0/8 ::1
# ignoreipは任意の(自分のアクセス元)を指定ください

[sshd]
enabled=true
filter=sshd
mode=normal
port=22
protocol=tcp
logpath=/var/log/auth.log
maxretry=3
bantime=-1
ignoreip = 127.0.0.0/8 ::1
# ignoreipは任意の(自分のアクセス元)を指定ください
  • ファイル名 /etc/fail2ban/filter.d/ufw.aggressive.conf

○内容

[Definition]
failregex = [UFW BLOCK].+SRC=<HOST> DST
ignoreregex =

設定反映

systemctl enable fail2ban
systemctl start fail2ban
systemctl statsu fail2ban

これで、不審なアクセスは次回以降は有無を言わせずブロックする設定となります。

検証:AWS LightsailのUbuntuにWasabiクラウドストレージをマウント。

概要

(ほぼ)固定費でそれなりのスペックのサーバを運用できるAWS Lightsail。ストレージを増やすには

  • スペックの増強を図る
  • AWS S3などのクラウドストレージを増強する

といった策が必要です。ですが、もっと低価格で利用できるサービスはないものかと探していたところにみつけました。

クラウドストレージ:Wasabi

https://wasabi.com/ja

なかなか挑戦的な言葉が書かれています。

  1. 1TBでも6$程度
  2. データ転送料無料

は魅力的。(逆に言えば、たとえ1バイトのファイルしか保存しなくても最低1TB分は請求されます)

そして、S3と同じプロトコルが使えるとのこと。

無料トライアルもあるので、Linuxサーバにマウントできるかを検証してみます。

試した手順

環境

AWS上で動かしているUbuntu 20.04で利用しています。

さっくりとした流れ

  1. Wasabiのアカウントを作成します
  2. バケットを作成します
  3. アクセスキーを作成します
  4. Linuxサーバで必要なパッケージをインストールします
  5. アクセスキーを保存します
  6. マウントを確認します
  7. fstabを修正します

詳細の手順

Wasabiアカウント作成

上記URLから自身のアカウントを作成。確認メールからパスワードを設定します。

バケット作成

ログイン後、「バケット」をクリック。

任意のバケット名を入力し、地域を選択します。(ここでは大阪を選択)

バージョン管理などは全て無効の状態で「次」をクリック。

確認画面後に「バケットを作成」で作成できました。

アクセスキーの生成

アクセスキーをクリックし「新しいアクセスキーを作成する」からアカウントキーと秘密鍵を控えます。(この情報は全てのストレージへのアクセスに必要となるため、取り扱いは厳重にしてください)

Linuxサーバ上での動作

スナップショット取得

念のため、作業直前にAWSコンソールからスナップショットを作成します。

必要パッケージインストールします

sudo aptitude update
sudo aptitude install s3fs

パスワードファイルの作成

信仰・協議に従ってエディタを起動します。次のファイルを作成します。

.passwd-s3fs
# アクセスキー:秘密鍵 の順番で貼り付け

chmod 600 .passwd-s3fs

ls - ${HOME}/.passwd-s3fs
# ファイルがあることを確認します

マウントポイントの指定

sudo mkdir /mnt/wasabi
# /mntファイルに任意の名前を作成ください

udo s3fs 【wasabiで作成したバケット名】 /mnt/wasabi -o passwd_file/【上記作成したパスワードファイルのパス】/.passwd-s3fs -o url=https://【バケットのリージョン名】.wasabisys.com -o use_path_request_style -o endpoint=【バケットのリージョン名】 -o allow_other

これでマウントしたことを確認しました。

WasabiのWebインタフェースから任意のファイルをアップロード。

cd /mnt/wasabi 
# 作成したマウントポイントに移動します

ここから、アップロードしたファイルが確認できれば設定完了です。

fstabの設定

システムを再起動してもマウントできるようにfstabの設定を追記します。

sudo cp -pi /etc/fstab /path/to/directory/fstab.date +%Y%m%d
diff -u /etc/fstab /path/to/directory/fstab.date +%Y%m%d
# 差分がないことでバックアップを確認します

バックアップ後、協議・信仰に従ったエディタで末尾に追記します。

s3fs#【wasabiバケット名】 /mnt/wasabi fuse _netdev,allow_other,passwd_file=/【パスワードファイルのパス】/.passwd-s3fs,url=https://s3.バケットのリージョン名wasabisys.com,use_path_request_style,endpoint=バケットのリージョン名 0 0

マウント確認

sudo mount -a
# エラーが出ないことを確認します

df -h
# マウントしたバケットが見えているかを確認します

今後の検証

トライアルの間、

  • マウントしたディレクトリに保存されたファイルをWebに公開できるか
  • 遜色なく利用できるか
  • 転送速度などに問題ないか

を確認後、本格的に使っていこうと思います。

スクリプト:連携。(パスワード生成を呼び出したSQLバックアップ)

概要

ChatGPTに助けられて作成した

  • SQLのバックアップを行うシェルスクリプト
  • より安全なパスワード生成を行えるRubyスクリプト

この2つを連携させてみました。

スクリプトのフロー図

以下のようにして動きます。

sequenceDiagram participant b as バックアップ participant p as パスワード生成 note over b: 処理実行 note over b: 作業ディレクトリ<br>作成 note over b: MySQL dump b->>p: スクリプト呼び出し note over p: 処理実行 note over p: PW発行 note over p: PWファイル作成 p-->>b: スクリプト実行完了 note over b,p: PWファイルを元に暗号化 note over b: 作業ディレクトリ<br>削除 note over b: 古いバックアップ削除 note over b,p: 古いPWファイルを削除 note over b: 処理完了

スクリプト内容

スクリプト1: DBバックアップ

  • スクリプトタイプ:シェルスクリプト
#!/bin/bash

## 変数ここから ##
# SQLをバックアップするディレクトリ(保管先)を指定します。
backup_dir="/home/backup/mysql"
# 保持するバックアップの世代を日数で指定します。
keep_days=7
# ファイルに付与する日付/作業ディレクトリ名/バックアップファイル名を指定します。
current_date=$(date +%Y%m%d)
backup_name="redmine_mysql_${current_date}"
zip_file="redmine_mysql.${current_date}.zip"
# アカウントファイルを指定します。
credentials_file="$HOME/mysql/account.txt"
# パスワードを生成するスクリプトの格納場所を指定します。
password_generate="$HOME/scripts/ruby/password_generate_for_redmine.rb"
# 上記スクリプトによって生成されたパスワードファイルの格納場所を指定します。
password_file="$HOME/restore_password/mysql-restore.${current_date}.txt"
# バックアップ時に指定するオプションを指定します。
options="--defaults-extra-file=$credentials_file --no-tablespaces --single-transaction"
## 変数ここまで ##

## 処理ここから ##

# 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 redmine > "${backup_dir}/${backup_name}/${backup_name}.sql"

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

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

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

# 7. 保持期間より古いバックアップファイルを削除します。
find "$backup_dir" -name "redmine_mysql.*.zip" ! -type f -newermt "${keep_days} days ago" -delete
find "$password_file" -name "*.txt" -type f -mtime +$keep_days -delete

スクリプト2:パスワード生成

  • スクリプトタイプ: Ruby
#このRubyスクリプトは、SecureRandomモジュールを使用してランダムなパスワードを生成するためのスクリプトです。
#パスワードの生成に関する様々な設定を変数で行うことができます。
#例えば、パスワードの長さ、数字やアルファベット、大文字や記号を使用するかどうかなどを指定することができます。
#スクリプトは、出力先がファイルか標準出力かを選択できます。
#ファイルに出力する場合は出力先のディレクトリやファイル名を指定することができます。

# モジュールを呼び出します 
require 'securerandom'
require 'fileutils'
require 'date'

### 変数はここからです
## 出力するパスワードの数(行数)を数字で指定します
num_passwords = 1
## 出力先を選択します
# ファイルに出力する場合は 1、標準出力に出力する場合は 0 に設定します
output_to_file = 1
# 出力先のディレクトリを指定します
output_directory = '/home/hoge/restore_password' 
# 出力ファイル名を名前+yyyymmdd形式.txtで指定します
# 最初の''部分の名前を任意の名前に入力ください
output_filename =  'mysql-restore.' + Time.now.strftime("%Y%m%d") + '.txt'
## パスワードの強度を指定します
# パスワード桁数を数字で指定します
password_length = 12
# 数字を用いる場合は1を、用いない場合は0を指定します
use_numbers = 1
# アルファベット小文字を用いる場合は1を、用いない場合は0を指定します
use_alphabet = 1
# アルファベット大文字を用いる場合は1を、用いない場合は0を指定します
use_uppercase = 1
# 記号を用いる場合は1を、用いない場合は0を指定します
use_symbols = 1
## パスワード生成用の文字種を定義します
# 必要に応じて使わない文字を削除することが可能です(lと|, 0とOなど)
characters = ''
characters += '0123456789' if use_numbers == 1
characters += 'abcdefghijklmnopqrstuvwxyz' if use_alphabet == 1
characters += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if use_uppercase == 1
characters += '!#$%&()*+,-./:;<=>?@[]^_`{|}~' if use_symbols == 1
### 変数はここまでです

# パスワード生成関数を定義します
def generate_password(length, characters)
  SecureRandom.random_bytes(length).unpack('C*').map do |byte|
    characters[byte % characters.length]
  end.join
end

## パスワードファイルを出力する場合(変数 output_to_fileを1にしたとき)の処理です
#出力先のパスを作成します
if output_to_file == 1
  output_path = File.join(output_directory, output_filename)
# 出力先のディレクトリが存在しない場合は作成します
  FileUtils.mkdir_p(output_directory)
# パスワードを出力します
  File.open(output_path, 'w') do |file|
    num_passwords.times do
      password = generate_password(password_length, characters)
      file.puts password
    end
  end
else

## 標準出力に出すだけの場合(変数 output_to_fileを0にしたとき)の処理です
# パスワードを標準出力に出力します
  num_passwords.times do
    password = generate_password(password_length, characters)
    puts password
  end
end

上記、Rubyスクリプトを「変数の定義でファイル出力と標準出力」の2つが選べるようにしたのは幸いでした。(パスワード1つのみを使うので行数も1にしています)

Redmineプラグイン導入時に起因するエラーの発生原因と対処方法について

こちらの記事を更に詳細にまとめたものとなります。

概要

様々なプラグインにより機能を追加できるのがRedmineの魅力。
しかしながら、そのプラグイン導入の過程によって予期せぬエラーが起きます。

本記事では、エラーの内容と対処、並びにこれが起きないための運用について筆者の経験を元に書き起こしています。

想定としている読者

  • LinuxでRedmineを動かしている
  • その管理をしている / 管理を任されている
  • プラグインインストール時にエラーが発生している

エラーが起きた環境

種別環境1環境2環境3
OSUbuntu 20.04CentOS 7Ubuntu 22.04
Redmine4.23.35.0
DBMySQL 8.3.xMariaDB 5.5.xMySQL 8.3.x
Ruby2.72.33.1

具体的に何が起こったか?

Case 1. エラー画面が表示され、どこにもアクセスできない。

We're sorry, buty something went wrong.
We've been notified about this issue and we'll take a look at it shortly.

この画面は「やってしまったか」感がとても強いです。

Case 1.の原因

経験上、以下の理由で発生しました。

原因1-1:DBマイグレーションをしていない

プラグインインストール時、DBのマイグレーションを行っていない手順ミスはありがちです。

原因1-1の対処:DBマイグレーションを行う。

こちらはrailsとapacheの手順です。自身の環境に合わせて実施してください。

cd /home/www-data/redmine && pwd
# Redmineのルートディレクトリに移動します。自分の環境に合わせます。

sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production
# RedmineのルートディレクトリでDBマイグレーションを実施します

sudo systemctrl restart apache2.service
# Webサービスを再起動します。

原因1-2: プラグイン名とレポジトリが異なる。(バージョン名が付与されている)

view_customizeのように、プラグイン名とレポジトリ名が異なるパターンはあります。

例:
https://github.com/onozaty/redmine-view-customize
と、レポジトリ名はredmine-view-customizeですが、実際のプラグイン名は
view_customizeです。

また、zipを直接入手した場合は、解凍したディレクトリにバージョン名が付与されます。

原因1-2の対処: ディレクトリをリネーム

以下は一例です。

cd /home/www-data/redmine/plugins && pwd
# Redmineのルートディレクトリに移動します。
sudo mv redmine-view-customize view_customize

sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production
# RedmineのルートディレクトリでDBマイグレーションを実施します

sudo systemctrl restart apache2.service
# Webサービスを再起動します。

原因1-3: プラグインとRedmineのバージョンが合ってない。

例として:
https://www.redmine.org/plugins/redmine_custom_workflows

  • Compatible with Redmine 5.0.x, 4.2.x, 4.1.x.

と書かれているように、古いRedmineのバージョンに合ってないプラグインをインストールしたときに起こりがちです。

また、逆に、プラグインが新しいRedmineに対応していない時にも発生します。

原因1-4: 導入済みのプラグインとコンフリクトを起こしている。

ある種、オープンソースの宿命と言えます。
有志/企業が機能を追加しているので、他のプラグインと同じライブラリを用いていたりDBのテーブルが重複するなどで発生します。

以下のように、メンテナが相性が悪いプラグインを認識している場合はそれに注意すればいいのですが、多数あるプラグイン同士の相性をチェックするのは極めて難しい問題です。

https://github.com/ncoders/redmine_local_avatars

As reported in issue #12, the plugin "mega_calendar" ist not compatible with this plugin due to an issue with the provided users_controller_path.rb file.

原因1-3 / 原因1-4の対処: プラグインのアンインストール

こちらも、rails / apacheでの実施です。自分の環境に合わせて実施してください。

cd /home/www-data/redmine && pwd
# 自分の環境に合わせます。

sudo -u www-data bundle exec rake redmine:plugins:migrate NAME=プラグイン名 VERSION=0 RAILS_ENV=production
# プラグイン名は /plugin/配下にあるディレクトリ名です

cd plugins && pwd
# プラグインが配置されているディレクトリに移動します。

sudo rm -rf プラグイン名

ls -ld /home/www-data/redmine/plugins/プラグイン名
# 削除したディレクトリが存在しないことを確認します

sudo systemctl restart apache2.service

上記、プラグインに起因したエラーの大半はDBの再マイグレーションやアンインストールによって解消しますが、これだけで収まらないのがRedmineプラグイン追加/アップデートの恐怖です。

Case 2. 一部の機能が使えない (Internal Error)

Case1.で発生したエラー画面の対処としてDB再マイグレーションやアンインストールを行った後、この事象が起きました。

  1. ログインはできる
  2. あるプラグインにアクセスできる

けれども、

  1. 管理画面に遷移する
  2. チケット一覧を見ようとする
  3. 他のプラグインの画面を見ようとする

等で、

Internal Error
An error occured on the page you were trying to access.
If you continue to experience problems please contact your Redmine administrator for assistance.
If you are the Redmine administrator, check your log files for details about the error.

の無慈悲なメッセージが出てきます。特にRedmineをファイルサーバ化するdmsfプラグイン周りで発生しました。

こうなると、

  • DBの再マイグレーション
  • プラグインアインインストール

でも、今の筆者の知見では修復できませんでした。その場合の対処方法は以下の通りです。

Case 2の対処方法: バックアップしたDBからの切り戻し

この作業は、「エラーを起こす前のDBバックアップデータを持っていないと元に戻すことはできません」

この前提条件がない場合は他の有識者に頼ってください。(少なくとも筆者は持ち合わせていません)

また、以下の環境で復旧を確認しています。

  • MySQL 8.0.3系
  • Redmine 5.0
  • Redmine 4.2

手順

  • プラグインアンインストール(実施済みの方は不要です)
cd /home/www-data/redmine && pwd
# 自分の環境に合わせます。

sudo -u www-data bundle exec rake redmine:plugins:migrate NAME=プラグイン名 VERSION=0 RAILS_ENV=production
# プラグイン名は /plugin/配下にあるディレクトリ名です

cd plugins && pwd
# プラグインが配置されているディレクトリに移動します。

sudo rm -rf プラグイン名

ls -ld /home/www-data/redmine/plugins/プラグイン名
# 削除したディレクトリが存在しないことを確認します

sudo systemctl restart apache2.service
  • バックアップしたDBのレストア
cd /hoge && pwd
# DBデータをバックアップしたディレクトリに移動します。

mysql -h DBホスト -u RedmineのDBユーザ -p RedmineのDB名 < RedmineのDBバックアップ
# 例 mysql -h localhost -u redmine -p redmine < redmine_backup.$(date +%Y%m%d).sql
# この処理で聞かれるパスワードはredmineインストール時に設定したDBユーザのものです

sudo systemctl restart apache2.service

この後、元に戻っていれば作業は完了です。

こうならないために

日々のバックアップを取る

これは必須です。最低限、データベースの定期的なバックアップを取り、障害に備えましょう。

参照(『こうなってしまったため』書き起こしました:)

また、作業前に

cd /hoge && pwd
# 任意のバックアップディレクトリに移動します

mysqldump -h localhost -u redmine -p --no-tablespaces --single-transaction redmine > redmine_backup.$(date +%Y%m%d).sql
# それぞれ -h ホスト名 -u redmine -p ユーザ オプション db名です。
# パスワードはredmineインストール時に設定したDBユーザのものです

等の、DBバックアップも必要です。

システムごとバックアップを取る

仮想サーバで動かしている、AWSのようなクラウドサービスを利用している場合はスナップショットを取得し、OSごとバックアップするのが後腐れありません。

ChatGPTによるRubyスクリプト。(パスワード生成スクリプト)

ChatGPTを利用するようになってから、「こういう処理ができたら仕事の処理が楽になるのに」が現実的になりました。

概要

割と設定する機会があるパスワード。

  • キチッとランダムに
  • 桁数や出力数が指定可能で
  • ファイルに出力する必要があるか
  • または標準出力に表示させればいいのか

を設定するRubyスクリプトはできないものかとChatGPTにお伺い。幾度かの対話を繰り返し、ようやく想定通りの動きをするスクリプトができました。

openssl rand と異なり、

  • 大文字/小文字の利用
  • 数字や記号の混在

を細かく設定できるのがポイントです。

生成・編集したスクリプト

  • スクリプト名:password_generate.rb

前提

以下の環境で動作を確認しました。

  • Ubuntu 20.04 LTS
  • CentOS 7
  • Ruby 2.4 / 2.7.0

スクリプト内容

  • password_generate.rb
#このRubyスクリプトは、SecureRandomモジュールを使用してランダムなパスワードを生成するためのスクリプトです。
#パスワードの生成に関する様々な設定を変数で行うことができます。
#例えば、パスワードの長さ、数字やアルファベット、大文字や記号を使用するかどうかなどを指定することができます。
#スクリプトは、出力先がファイルか標準出力かを選択できます。
#ファイルに出力する場合は出力先のディレクトリやファイル名を指定することができます。

# モジュールを呼び出します 
require 'securerandom'
require 'fileutils'
require 'date'

### 変数はここからです
## 出力するパスワードの数(行数)を数字で指定します
num_passwords = 12
## 出力先を選択します
# ファイルに出力する場合は 1、標準出力に出力する場合は 0 に設定します
output_to_file = 1
# 出力先のディレクトリを指定します
output_directory = '/home/hoge/restore_password' 
# 出力ファイル名を名前+yyyymmdd形式.txtで指定します
# 最初の''部分の名前を任意の名前に入力ください
output_filename =  'mysql-restore.' + Time.now.strftime("%Y%m%d") + '.txt'
## パスワードの強度を指定します
# パスワード桁数を数字で指定します
password_length = 10
# 数字を用いる場合は1を、用いない場合は0を指定します
use_numbers = 1
# アルファベット小文字を用いる場合は1を、用いない場合は0を指定します
use_alphabet = 1
# アルファベット大文字を用いる場合は1を、用いない場合は0を指定します
use_uppercase = 1
# 記号を用いる場合は1を、用いない場合は0を指定します
use_symbols = 1
## パスワード生成用の文字種を定義します
# 必要に応じて使わない文字を削除することが可能です(lと|, 0とOなど)
characters = ''
characters += '0123456789' if use_numbers == 1
characters += 'abcdefghijklmnopqrstuvwxyz' if use_alphabet == 1
characters += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if use_uppercase == 1
characters += '!#$%&()*+,-./:;<=>?@[]^_`{|}~' if use_symbols == 1
### 変数はここまでです

# パスワード生成関数を定義します
def generate_password(length, characters)
  SecureRandom.random_bytes(length).unpack('C*').map do |byte|
    characters[byte % characters.length]
  end.join
end

## パスワードファイルを出力する場合(変数 output_to_fileを1にしたとき)の処理です
#出力先のパスを作成します
if output_to_file == 1
  output_path = File.join(output_directory, output_filename)
# 出力先のディレクトリが存在しない場合は作成します
  FileUtils.mkdir_p(output_directory)
# パスワードを出力します
  File.open(output_path, 'w') do |file|
    num_passwords.times do
      password = generate_password(password_length, characters)
      file.puts password
    end
  end
else

## 標準出力に出すだけの場合(変数 output_to_fileを0にしたとき)の処理です
# パスワードを標準出力に出力します
  num_passwords.times do
    password = generate_password(password_length, characters)
    puts password
  end
end

使い方

  1. 変数を環境に合わせて定義します。
  2. ruby password_genarate.rbを実行します。
  3. 定義したとおりパスワードファイルが出力されていたり、画面に表示されれば成功です。

今後の展望

  • 他のスクリプトで呼び出す(以前に紹介したMySQLバックアップ時にパスワードをかけるなど
  • 対話式で実行

など、使い勝手に合わせて修正していきたいです。

お茶道具、刷新。(割れないティーポット感想)

従来の環境を変えうる力がありました。

やってみたかったこと

業務中に「ティーポットを使った本格的なお茶」を飲みたいという希望は漠然と抱えていたものの、次の問題点がありました。

やってみたかったことの問題点

「何かがあって壊したくない」に尽きます。

陶器やガラス製ではお茶を入れるときに人や物にぶつかって割れたときの被害が甚大。金属の場合は錆や変形などの恐れがあります。この解決策が最近見つかったという感じです。

問題点に対する解決策

こちらの「割れない」ティーポット。強化プラスチックでできているため、給湯室などで衝撃があっても割れる心配は無用です。また、細かいステンレスメッシュはお茶袋を使うことなくお茶を入れることができるだろうという判断です。

使ってみての感想

家での使い勝手が上々だったので職場でも使いました。

耐衝撃性の安心感

これは予想通りです。紹介動画でもあるように、この「割れない」と謳われているとおりの頑丈さによる安心感。
破片が飛散することによる被害を減らす(というかなくす)ことができました。

保温性とレンジによる再加熱

これは予想外のことでした。思った以上に入れたお茶の温度を保ってくれます。また、作業や打ち合わせで長時間席を離れたとしても、「茶こしを外してティーポットごとレンジにかける」という力業が可能。これによって冷めたお茶の温め直しが気軽にできるのは思わぬ収穫でした。

注意した方がいいこと

細かすぎる茶葉

ステンレスの茶こしは小さめの茶葉でも受け止めてくれましたが、例外がありました。

  • CTCの茶葉
  • ルイボスティー

です。特に後者はたわしで数回こする必要があったので、こればかりはお茶パックに詰める運用が出てきます。

注ぎ口の変色

茶渋が溜まるところの宿命と言えそうです。洗いにくいので漂白剤や重曹による定期クリーニングが必要だと感じました。

総じて

  • 比較的安価であり
  • 大量のお茶を作ることができて
  • 軽く
  • 壊れず
  • 保温性が高い

と、オフィスワークでの喫茶の条件を満たす品でした。

ボードゲーム『タッジーマッジー』感想。

18枚のカード、2回のドラフトでひりつく勝負が楽しめる「花束」をモチーフにしたカードゲームです。

概要

プレイヤーはロンドンでお茶を楽しむ人たち。合間合間に花束を贈り、その(行間ならぬ)花間にメッセージを込めようとしています。限られた時間の中で、誰が一番メッセージをうまく伝えることができるでしょうか?

ゲームシステム

いわゆるドラフトとセットコレクション。流れは以下の通りです。

  1. 各プレイヤーには2枚のカード(花)が配られます。
  2. 1枚を表(花束)、もう1枚を裏(思い出)として隣接するプレイヤーに公開します。
  3. 隣のプレイヤーはそれらの中から向きを変えずに受け取ります。選ばれなかったカードは保持します。(裏のカードは受け取るまで見られません)
  4. これを2回繰り返し4枚の花からなるアレンジを作ります。このとき、「披露の準備」と書かれてればそれに従います。
  5. カード(花)に従った得点計算を行います。

これを3ラウンドに渡って繰り返し、一番高い得点を獲得したプレイヤーが勝利となります。

良かったと思った点

コンボの多彩さ

18枚のオールユニークなカードはいずれも組み合わせれば得点の相乗効果が見込まれます。運と戦略が合致して大量得点を出したときの喜びはかなり得がたいものがあります。

虚々実々のブラフ

上述したように「一枚は表/一枚は裏」で隣のプレイヤーに選択を任せるため、

「表に弱めのカードがあるけど裏はいいカードなのか?」
「相手、既にこちらが取ったカードとコンボするカード見せてるけど……」

と、裏をかいたりしてやられたりの駆け引きが最大の魅力です。

シンプルで美麗なイラストに込められたメッセージ

「カード」というより「タイル」と言った方がいい大きく厚いカード(日本版)に描かれた美麗なイラストは並べるだけで花束という形。
いずれもカード効果と合った花言葉が書かれているのもまた魅力の一つです。

やや残念だと思ったところ

経験者有利となるテキスト量

TCG慣れしていない人にはちょっと手間取るテキストがカード上にいくつかあります。(特に思い出と花束の位相を参照するカードなど)そして、そのテキスト慣れがそのままゲーム上の得点行動につながります。

  1. 最初に全てのカードを全プレイヤーに見せる
  2. インスト時に実際の流れを説明すると共に得点を披露する

の処理は必要です。

“徒花”マリーゴールドの使いどころ

これは一項目を使うべき問題。

このカードは披露の準備(得点計算の前)として他の花を捨て札にする強烈なデメリットがあります。
これによってコンボの邪魔となるカードを払うことができるのもまた事実ではありますが、引いた(引かれた)時に顔に出るほどです。

まとめ

最初に言ったように、たった18枚、2回のドラフト。4枚のカードで駆け引きやコンボを楽しめるのは、さすが『ウイングスパン』のデザイナーによる作品。
15分~30分と手短に終わるので言語依存に抵抗がないプレイヤーがいる中でのスターターやアイスブレイクにぴったりでした。

ボードゲーム『キャンバス』感想。

ようやく崩す機会がありました。話題になっていただけあって、

  • とにかく映える盤面
  • 比較的シンプルでわかりやすいルール
  • 高いリプレイ性
  • 楽しい感想戦

などが秀逸なゲームとなっていました。

概要

プレイヤーは芸術祭に参加する画家。コントラストや強調、余白などを意識しながら主催者の意向に沿うように定められた条件に沿った絵を出品していきます。

良かったと思った点

視覚に訴えるコンポーネント群

3枚のクリアなカードを背景のカードと組み合わせて一対の絵にするアイディアはとかく壮観。ゲームが進むごとに盤面が華やかになり、「絵を出品する」気分を高めてくれます。

インストしやすいルール

プレイヤーのアクションは2つのみ。

  1. カードを取る
  2. カード3枚を組み合わせてリボン(得点)を得る

右に行けば行くほど資源(パレット)を消費する制限がカードを取るアクションで発生するものの直感的で分かりやすいです。絵を組み合わせることによって発生する細かい得点計算も裏に書かれている親切設計なのもポイントです。

上記のリボン(得点_を成す条件も毎回のように組み合わせが変わりますし、一定数存在する特別ボーナス(銀リボン)もあるので「ああでもないこうでもない」とのジレンマに悩まされるでしょう。

今風の脱落しないゲーム進行

サドンデスもなければ失点要素もありません。また、各プレイヤーには「3枚の絵」が確実に残るので最後までゲームに参加できます。

やや残念だと思ったところ

ダウンタイムの長さ

「組み合わせによって効率的な得点を重ねられる」が弱みになる形。高得点を目指すプレイヤーがいると手番が遅くなりがちです。(特に条件が複雑な場合)

写真撮影の悪条件

これは「映え」のお話。

アクリル板+スリーブと光が乱反射する悪条件が揃います。進行中や感想戦で写真をアップしたい方がいる場合は、その旨を伝える方がベターです。

まとめ

  • インパクトも見栄えも十二分なコンポーネント
  • 分かりやすいルール
  • 程よく終わるプレイ時間

はライト層を引きつける要素に満ちあふれています。特に、「どのカードをどの順番で重ねていくか」はアナログゲームの強みと言えるでしょう。

個人的には壁掛け用の穴まで箱にあり、パッケージそのものが一枚の絵になるのが特にお気に入り。
(インテリアとして機能するためにずっと部屋に飾られて崩す機会が失われていたほどです)

そのため、飾りにすることなく普通に遊んでいきたいと思った一本でした。

続・MySQLの自動バックアップ。(パスワードによる暗号化付与)

こちらの記事で挙げたRedmineなどのMySQLを実行するスクリプト。

この問題点を修正します。

問題点

  • むきだしのSQLファイルが平文で格納されてしまうのはセキュリティ的によろしくありません。
  • MySQLのバックアップ時に使うアカウントファイルが誰でも読み取れるのも問題です。

そこで、バックアップされたファイルにパスワードをかけることで簡単な防波堤を作ることにします。

前提

上記URLに併せます。

  1. MySQL dumpを行うDBにRELOAD権限があること。
  2. 次の環境で動作を確認しています。
  • Ubuntu 20.04
  • MySQL 8.0.32

実施した手順

さっくりとした手順

  1. バックアップディレクトリを作成します。
  2. DBにアクセスするためのアカウント情報を記したファイルを作成します。
  3. 開封パスワードを格納するディレクトリを作成します。
  4. バックアップスクリプトを作成します。
  5. crontabに登録します。

バックアップディレクトリを作成します。

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

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

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

DBにアクセスするためのアカウントファイルを作成します。

Cronによる自動実行を前提としているため、スクリプト実行時にDBユーザとパスワードを記したファイルを読み込むことでセキュリティのリスクを抑えます。

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

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

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

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

その後、このファイルの読み取り権限を変更します。

chmod 400 account.txt

ls -l account.txt
# パーミッションが400であることを確認します

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

mysql --defaults-extra-file=【アカウントファイルを格納したディレクトリ】/account.txt

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

スクリプト作成

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

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

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

## 処理ここから ##

# 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 "redmine_mysql.*.zip"  ! -type f -newermt "${keep_days} days ago" -delete
find "$password_dir" -name "*restore*.txt" ! -type f -newermt "${keep_days} days ago" -delete

## 処理ここまで

前回との修正点

  1. 変数と処理のセクションを明確化しています。
  2. アカウントファイルのパーミッションチェックを行い、400以外は処理を中止します。
  3. opensslで生成したパスワードで暗号化します。(このパスワードはランダムで生成されるので運用者は覚える必要がありません)
  4. 圧縮と同時に暗号化を行うので、gz形式からzip形式に変更しています。
  5. このパスワードを任意のディレクトリに転送します。
  • 実行権限の付与
chmod +x pw_mysql_daily_backup.sh

動作確認

cd 【スクリプトを格納したディレクトリ】 && pwd
bash pw_mysql_daily_backup.sh

以下を確認します。

  1. エラーなく実行できること
  2. バックアップ格納ディレクトリにredmine.sql.実行日付.zip形式でファイルが作成されること
  3. パスワードファイル格納ディレクトリにファイル名.実行日付.txt形式でファイルが作成されること
  4. unzip redmine.sql.実行日付.zipでファイル解凍時にパスワードを確認されること
  5. パスワードファイルで暗号化されたファイルを解凍することができること

Crontab設定

Cron登録

crontab -e

登録内容例

0 0 * * * /home/backup/mysql/pw_mysql_daily_backup.sh
# 実行時刻、頻度などは自分の運用形態に合わせます。
# また、既に平文でのバックアップスクリプトを設定している場合はコメントアウトして処理を外します。

Cron登録確認

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

操作時刻に

  • BEGIN EDIT
  • REPLACE
  • END EDIT

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

動作確認日

2023/02/18

Page 1 of 3

Powered by WordPress & Theme by Anders Norén