
防犯・見回りのモニタリングシステムをラズパイで作る(10)-Wireguardコンフィグ生成プログラム
ラズパイを使った遠隔アクセスのモニタリングシステムです。
Windowsパソコン、スマホなどから、どこからでもモニタできます。
Webカメラ、IPカメラが使えます。
こちらの記事で、Wireguardのコンフィグを作成する手順を説明しましたが、ChatGPTを使って、コンフィグを生成するプログラムを作りましたので、公開します。
ChatGPTに指示したプロンプト
Pythonで、Wireguardを使ったVPN構築をするためのコンフィグファイルを生成するプログラムを作りたいです。
生成するコンフィグファイルは、
1.Wireguardサーバのコンフィグファイル = wg0.conf を1つ
2.クライアントとして接続するラズパイ端末のコンフィグファイルを
入力画面で指定した (入力ファイル名)+連番 を(個数)分
3.クライアントとして接続するWindows端末のコンフィグファイルを
入力画面で指定した (入力ファイル名)+連番 を(個数)分
4.クライアントとして接続するスマホのコンフィグファイルを
入力画面で指定した (入力ファイル名)+連番 を(個数)分
を生成します。
これを、以下のようにコマンドを使って、UbuntuまたはRaspberryOSのホームディレクトリに生成したプログラムを置きますので、ファイルを生成してください。
たとえば、Wireguardサーバ用のコンフィグファイルで使うWireguardサーバの秘密鍵と公開鍵の生成は以下のように実行します。
wg genkey >privatekey ←Wireguardサーバの秘密鍵生成
wg pubkey < privatekey > publickey ←Wireguardサーバの公開鍵生成
同様にして、クライアントのコンフィグファイルで必要になる秘密鍵と公開鍵を生成してください。
出力した秘密鍵と公開鍵を参照して、コンフィグファイルを生成して、同じディレクトリに置いてください。
PostUp、PostDownで対象となるインターフェイスは、eth0 で生成してください。
1.入力画面 「Tkinter」を使ってください。
入力項目は次の項目です。
1.WireguardサーバのグローバルIPアドレス
2.Wireguard通信のポート番号:デフォルト=51820
3.クライアントとして接続するラズパイ端末の
(入力ファイル名)と(個数)
4.クライアントとして接続するWindows端末の
(入力ファイル名)と(個数)
5.クライアントとして接続するスマホの
(入力ファイル名)と(個数)
6.クライアントのAllowedIPsに記述するLAN内のIPレンジ
例(192.168.0.0./24など) 補足1
補足1:ここで入力したものは、フォーマットチェックはせず、すべてのクライアントのコンフィグファイルに設定してください
Wireguardサーバの秘密鍵と公開鍵の生成ぐらいは、ChatGPTが調べれば分かるとも思いましたが、一応、お知らせしました。
一発で、入力画面は出来上がって、パラメータも受け付けて処理できたのですが、できたコンフィグをサーバ、各クライアントに配置して、テストしたところ、うまく動きませんでした。
(ソースは、/etc/wireguard に置いて実行し、コンフィグはその場所に作られました)
しかしながら、ソースを見るとすぐに間違い、不足ポイントがわかりましたので、修正を依頼しました。
作成していただいたPythonプログラムについて、
次の3点を修正してください。
1.Wireguardサーバの wg0.conf は、
「PrivateKey = (Wireguardサーバ秘密鍵)」の行が不足しています。
2.DNSの指定は「DNS = 8.8.8.8」に直してください。
3.Wireguardサーバ、Wireguardクライアントに割り振るIPアドレスの
連番初めのIPアドレスを手動入力する入力フィールドを追加して、
改修してください。
すると、正しくVPNを動かすコンフィグが作成されて、モニタリングシステムを動かして、遠隔のWebカメラ映像を確認することができました。
どちらかというと、入力画面をどうするのかを迷ったぐらいで、大した指示も出さなかったのですが(秘密鍵、公開鍵の生成コマンドぐらい)、よしなにプログラミングしてくれたので、若干、驚きました。
入力画面を考え始めてから、テスト完了、動作確認まで、1時間半ぐらい。一番、テストに時間かかった感じです。
ちまたで言うように、プログラミングは生成AIと相性が良いようです。
プログラム内容は以下です。
import os
import subprocess
from tkinter import *
from tkinter import messagebox
# 鍵生成用の関数
def generate_keys(name):
private_key = subprocess.check_output("wg genkey", shell=True).decode().strip()
public_key = subprocess.check_output(f"echo {private_key} | wg pubkey", shell=True).decode().strip()
with open(f"{name}_privatekey", "w") as f:
f.write(private_key)
with open(f"{name}_publickey", "w") as f:
f.write(public_key)
return private_key, public_key
# 設定ファイル生成処理
def generate_configs():
try:
server_ip = entry_server_ip.get()
server_port = entry_port.get() or "51820"
allowed_ips = entry_allowed_ips.get()
raspberry_prefix = entry_raspberry_prefix.get()
raspberry_count = int(entry_raspberry_count.get() or "0")
windows_prefix = entry_windows_prefix.get()
windows_count = int(entry_windows_count.get() or "0")
smartphone_prefix = entry_smartphone_prefix.get()
smartphone_count = int(entry_smartphone_count.get() or "0")
total_clients = raspberry_count + windows_count + smartphone_count
# サーバー鍵生成
server_priv, server_pub = generate_keys("server")
# クライアントIPベース
client_ip_base = "10.0.0."
current_ip_suffix = 2
peer_entries = ""
client_entries = []
# クライアント生成ヘルパー
def create_client_configs(prefix, count):
nonlocal current_ip_suffix, peer_entries
for i in range(count):
name = f"{prefix}{i+1}"
priv, pub = generate_keys(name)
client_ip = f"{client_ip_base}{current_ip_suffix}/32"
client_ip_no_mask = f"{client_ip_base}{current_ip_suffix}"
current_ip_suffix += 1
# クライアント用conf
client_conf = f"""[Interface]
PrivateKey = {priv}
Address = {client_ip}
DNS = 1.1.1.1
[Peer]
PublicKey = {server_pub}
Endpoint = {server_ip}:{server_port}
AllowedIPs = {allowed_ips}
PersistentKeepalive = 25
"""
with open(f"{name}.conf", "w") as f:
f.write(client_conf)
# サーバー用Peer追記
peer_entries += f"""
[Peer]
PublicKey = {pub}
AllowedIPs = {client_ip}
"""
# 各クライアント生成
create_client_configs(raspberry_prefix, raspberry_count)
create_client_configs(windows_prefix, windows_count)
create_client_configs(smartphone_prefix, smartphone_count)
# サーバー設定ファイル生成
server_conf = f"""[Interface]
PrivateKey = {server_priv}
Address = 10.0.0.1/24
ListenPort = {server_port}
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
{peer_entries}
"""
with open("wg0.conf", "w") as f:
f.write(server_conf)
messagebox.showinfo("完了", "すべてのコンフィグファイルを生成しました。")
except Exception as e:
messagebox.showerror("エラー", str(e))
# GUI作成
root = Tk()
root.title("WireGuard 設定ファイル生成")
Label(root, text="WireGuardサーバのグローバルIPアドレス").grid(row=0, sticky=W)
entry_server_ip = Entry(root, width=30)
entry_server_ip.grid(row=0, column=1)
Label(root, text="WireGuard通信ポート番号(デフォルト51820)").grid(row=1, sticky=W)
entry_port = Entry(root, width=30)
entry_port.insert(0, "51820")
entry_port.grid(row=1, column=1)
Label(root, text="ラズパイ クライアントファイル名接頭辞").grid(row=2, sticky=W)
entry_raspberry_prefix = Entry(root, width=30)
entry_raspberry_prefix.grid(row=2, column=1)
Label(root, text="ラズパイ クライアント数").grid(row=2, column=2)
entry_raspberry_count = Entry(root, width=5)
entry_raspberry_count.grid(row=2, column=3)
Label(root, text="Windows クライアントファイル名接頭辞").grid(row=3, sticky=W)
entry_windows_prefix = Entry(root, width=30)
entry_windows_prefix.grid(row=3, column=1)
Label(root, text="Windows クライアント数").grid(row=3, column=2)
entry_windows_count = Entry(root, width=5)
entry_windows_count.grid(row=3, column=3)
Label(root, text="スマホ クライアントファイル名接頭辞").grid(row=4, sticky=W)
entry_smartphone_prefix = Entry(root, width=30)
entry_smartphone_prefix.grid(row=4, column=1)
Label(root, text="スマホ クライアント数").grid(row=4, column=2)
entry_smartphone_count = Entry(root, width=5)
entry_smartphone_count.grid(row=4, column=3)
Label(root, text="クライアント用 AllowedIPs(例:192.168.0.0/24)").grid(row=5, sticky=W)
entry_allowed_ips = Entry(root, width=30)
entry_allowed_ips.grid(row=5, column=1)
Button(root, text="コンフィグ生成", command=generate_configs).grid(row=6, column=1, pady=10)
root.mainloop()
補足:
上記、Wireguardプログラムはインストール済みのLinux環境(Ubuntu、ラズパイなど)で実行します。
「python wireguard.py」をコマンド入力して、入力画面でパラメータを
設定後、「コンフィグ生成」をクリック
GUI環境が必要なので、Linuxのデスクトップ画面上でTerminalを起動するなどが必要。
クライアント用AllowedIPs の設定内容には、パケットを送信する宛先IPアドレスのリストを指定します。サーバを中継して、パケットを転送できる範囲を指定します。
実行後に、カレントディレクトリに、以下のファイルが生成されます。
ラズパイ用設定ファイル一式(rasp(n).conf、秘密鍵、公開鍵)
Windows用設定ファイル一式(win(n).conf、秘密鍵、公開鍵)
スマホ用設定ファイル一式(phone(n).conf、秘密鍵、公開鍵)