タグ: ChatGPT

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バックアップ時にパスワードをかけるなど
  • 対話式で実行

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

ChatGPTによるスクリプト変換。(bash → Ruby)

ことのあらまし

手なりで作ったシェルスクリプトを発展させたり可読性を高めるために利用しているChatGPT。

考えを発展させて「スクリプトの変換はできるのではないか」と考えました。

元となったスクリプト

こちらにある

cat error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort | uniq > /var/lib/redmine/log/suspicious_ip/suspicious_ip.`date +%Y%m%d`
  • error.logを読み込み
  • IPアドレスにマッチする正規表現を取り出し
  • ソートした上で重複を排除
  • 指定のディレクトリに書き出す

という一文のシェルスクリプトをRubyで動かすにはとChatGPTに質問しました。

出来上がったRubyスクリプト

require 'date'

## 変数指定ここから
# error.log の格納ディレクトリ
log_dir = '/path/to/log_dir'
# error.log の名前
log_file = 'error.log'
# 別ファイルの出力ディレクトリ
output_dir = '/path/to/output_dir'
# 重複を排除する場合は 1、しない場合は 0 を指定
remove_duplicates = 1
# 別ファイルの名前
output_file = 'output.txt'
# IPアドレスを抜き出すための正規表現パターン
ip_regex = /client (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
# error.log ファイルのフルパス
log_path = File.join(log_dir, log_file)
## 変数指定ここまで

# error.log ファイルを開く
File.open(log_path) do |file|
  # IPアドレスのみを格納する配列
  ips = []

  # 各行をチェックする
  file.each_line do |line|
    # 正規表現パターンに一致するか確認する
    match = line.match(ip_regex)
    if match
      # 一致した場合、IPアドレスを配列に格納する
      ips << match[1]
    end
  end

  # 重複を排除する場合
  if remove_duplicates == 1
    ips.uniq!
  end

  # 昇順にソートする
  ips.sort!

  # 結果を出力するファイルのパス
  output_path = File.join(output_dir, "error_#{Date.today.strftime('%Y%m%d')}_#{output_file}")

  # 結果を出力する
  File.open(output_path, 'w') do |file|
    ips.each do |ip|
      file.puts ip
    end
  end
end

スクリプトは長くなりましたが、以下の利点があります。

  • 読み込むディレクトリや正規表現のパターンを変数化しているため、他のログにも転用可能
  • 重複を排除するかしないかを決められる

また、可読性も高くなっています。

何より、シェルスクリプトの動きをRubyで動かすための文法を学べるのも素晴らしく。

今後の作業の大きな力になります。

Mod_SecurityのIPアドレス調査。(IPアドレスごとのカウント)

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

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

を把握するため、シェルスクリプトを書きました。(前回はこちらです)

やりたいこと

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

本項でやること

  1. 同じIPアドレスごとに件数を数え、降順で並べ替える

前提と準備

以下の環境です。

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

前回の「エラーログからIPアドレスのみを抽出し、アクセス元の国を付与する」スクリプトが導入されていることが条件です。

スクリプト生成

参考

chatGPTの力を借りました。何度か質問を変え、動作確認しつつコマンドを足しています。

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

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

# 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

exit 

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

chmod +x ip_count.sh

動作確認

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

  • ip_check.sh スクリプトが生成したログip_list.YYYYMMDD.csv
  • ip_count.sh スクリプト

スクリプト実行

./ip_count.sh

スクリプト実行結果

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

  • sorted_ip.YYYYMMDD.csv (以下の様に、アクセスごとの件数とIPアドレスとアクセス元の国を記述し、アクセス数の降順で並べ替えたファイル)
100, AAA.BBB.CCC.DDD,シンガポール
30, AAA.BBB.CCC.DDD,ベトナム
20,AAA.BBB.CCC.DDD,中国
  • 同時に、以下のファイルが消去されます。
  • ip.YYYYMMDD.csv (エラーログからIPアドレスのみを抜き出したファイル)
  • ip_list.YYYYMMDD.csv (IPアドレスにアクセス元を追記したファイル)
  • counted_ip.YYYYMMDD.csv (IPアドレスごとのカウントを行ったファイル)

合間に余計なファイルが含まれるので、ここはもっとスマートに書きたいです。

次にやること

  1. cronによる定期実行化
  2. redmineのプラグインredmine_logsで閲覧できるように設定

chatGPTが作成したシェルスクリプト。

こちらにより、apacheのバーチャルファイルをAIで作成できると知り、そこから更に発展させました。

作成して欲しいと思った機能

こちらのスクリプトで抜き出したIPアドレスを、

  • 10.0.0.0/24
  • 10.3.3.0/24
  • 172.28.3.0/24
  • 192.168.1.0/24

のように、ネットワークアドレスにした上でNWごとにブロックできないかと思い立ち、その前段として「IPをソートしてネットワークアドレスを付与できないか」

と、以下のようにして書いてもらいました。

AIへの質問

192.168.1.3
192.168.1.2
10.0.0.2
10.3.3.2
10.3.3.254
172.28.3.4
172.28.3.5

などのIPアドレスが書かれたテキストファイルip.txtがあります。

これを読み込んだ後にソートして

192.168.1.0/24
192.168.1.0/24
10.0.0.0/24
10.3.3.0/24
10.3.3.0/24
172.28.3.0/24
172.28.3.0/24

とネットワークアドレスに変換後、

10.0.0.0/24
10.3.3.0/24
172.28.3.0/24
192.168.1.0/24

と重複を排除し、アドレスごとに改行した上でnetwork.txtに出力するシェルスクリプトを書いてください。

AIの回答

以下のようなシェルスクリプトを作成することで、指定した要件を満たすことができます。

#!/bin/bash

# ip.txtを読み込んで、1行ごとに処理する
while read line; do
  # IPアドレスを/24のサブネットマスクで分割する
  network=$(echo "$line" | cut -d "." -f 1-3).0/24

  # 分割したサブネットアドレスを出力する
  echo "$network"
done < ip.txt | sort | uniq > network.txt

上記のスクリプトでは、ip.txtを読み込んで1行ごとに処理しています。

その後、cutコマンドを使用して、IPアドレスを"."で分割し、最初の3つのフィールドを取り出します。

最後に、取り出したフィールドに".0/24"を追加して、サブネットアドレスを生成します。

生成したサブネットアドレスをsortコマンドでソートし、uniqコマンドで重複を除外した上で、network.txtに出力するようにしています。

作成結果

以下、作成しました。

vi script.sh
# 上記のスクリプトを貼り付けて保存
chmod +x script.sh
# 平行してIPアドレスを抜き出したip.txtを用意します
./script.sh

で、予想通りの出力が得られました。

後は少しずつ応用していけば、まるごとブロックしたり他のセキュリティソフトとの連携も可能になります。

ChatGPTが作成したapacheバーチャルファイル。

2022年12月頃にTwitterで大いに話題となったChatGTP。

https://chat.openai.com/chat

これは文書作成のみならずコードも書けると知ったので早速試してみました。

作成してほしいコード

  • apacheでwordpressを動かすためのコンフィグ。
  • httpアクセスをhttpsにリダイレクトする。
  • アクセスログとwordpressのプログラムの格納場所は指定。

質問した内容

以下の文章をChatGPTに入力しました。

apacheでwordpressを公開するためのバーチャルサイトのコンフィグを作成してください。
サーバはUbuntu22.04です。apacheとmod_sslは導入済みです。
ドメインはweblog.example.comです。
wordpressは/home/www-virtual/wordpressに格納されています。
アクセスログは/var/log/apache2/weblog.example.comを指定します。
httpアクセスを強制的にhttpsにリダイレクトし、TLS1.2のみを有効化します。
wp-adminディレクティブは192.168.1.0/24以外アクセスできないようにします。

返ってきた内容

結論から言って驚きの結果でした。


まず、/etc/apache2/sites-available/weblog.example.com.confという名前のファイルを作成します。 次に、以下の内容を記述します:

<VirtualHost *:80>
    ServerName weblog.example.com
    DocumentRoot /home/www-virtual/wordpress
    ErrorLog /var/log/apache2/weblog.example.com/error.log
    CustomLog /var/log/apache2/weblog.example.com/access.log combined
    <Directory /home/www-virtual/wordpress>
        Require all granted
    </Directory>
</VirtualHost>

次に、SSL用のバーチャルサイトの設定を追加します。

<VirtualHost *:443>
    ServerName weblog.example.com
    DocumentRoot /home/www-virtual/wordpress
    ErrorLog /var/log/apache2/weblog.example.com/ssl-error.log
    CustomLog /var/log/apache2/weblog.example.com/ssl-access.log combined
    SSLEngine on
    SSLCertificateFile /path/to/your/certificate.crt
    SSLCertificateKeyFile /path/to/your/privatekey.key
    SSLProtocol TLSv1.2
    <Directory /home/www-virtual/wordpress>
        Require all granted
    </Directory>
    <Location "/wp-admin/">
        Require ip 192.168.1.0/24
    </Location>
</VirtualHost>

最後に、httpアクセスをhttpsにリダイレクトするために、mod_rewriteモジュールを有効化し、以下の設定を追加します。

<VirtualHost *:80>
    ServerName weblog.example.com
    DocumentRoot /home/www-virtual/wordpress
    ErrorLog /var/log/apache2/weblog.example.com/error.log
    CustomLog /var/log/apache2/weblog.example.com/access.log combined
    <Directory /home/www-virtual/wordpress>
        Require all granted
        RewriteEngine on
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    </Directory>
</VirtualHost>

これで、バーチャルサイトの設定が完了しました。

注意: 上記の設定は一例であり、適切な設定はサイトの状況や環境によって異なります。また、必要に応じて、この設定をカスタマイズしてください。


注文通りです。想定通りの動きになるのはほぼ間違いないです。(後で検証したいぐらいです)これに付け加えるならば、

sudo a2ensite weblog.example.com.conf
sudo apache2ctl configtest
# Syntax OKを確認します
sudo systemctl restart apache2.service

ぐらいでしょう。

今後の各種サーバ設定に大いに貢献する予感です。

Page 3 of 3

Powered by WordPress & Theme by Anders Norén