From 799c111fb47e03b693074374210c8c9c938bc8e7 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 18 Apr 2025 23:53:53 +0300 Subject: can generate keys --- .gitignore | 1 + wireguardmeshgenerator.rb | 82 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 849ddff..fa29eef 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ dist/ +keys/ diff --git a/wireguardmeshgenerator.rb b/wireguardmeshgenerator.rb index ae7ddd4..2a76e73 100644 --- a/wireguardmeshgenerator.rb +++ b/wireguardmeshgenerator.rb @@ -1,7 +1,8 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby require 'fileutils' +WIREGUARD_TOOL = '/usr/bin/wg'.freeze HOSTS = { f0: { lan: { domain: 'lan.buetow.org', ip: '192.168.1.130' }, wg0: { domain: 'wg0.buetow.org', ip: '192.168.2.130' } }, @@ -17,45 +18,82 @@ HOSTS = { wg0: { domain: 'wg0.buetow.org', ip: '192.168.2.122' } } }.freeze -PeerSnippet = Struct.new(:description, :public_key, :preshared_key, :allowed_ips) do +# Generates Wireguard keys and config files for each host +class KeyTool + def initialize(myself) + keys_dir = "keys/#{myself}/" + FileUtils.mkdir_p(keys_dir) unless Dir.exist?(keys_dir) + + @pubkey_path = "#{keys_dir}/pubkey" + @privkey_path = "#{keys_dir}/privkey" + @preshared_path = "#{keys_dir}/preshared" + + generate! if !File.exist?(@pubkey_path) || + !File.exist?(@privkey_path) || + !File.exist?(@preshared_path) + end + + def pub = File.read(@pubkey_path).strip + def priv = File.read(@privkey_path).strip + def preshared = File.read(@preshared_path).strip + + private + + def generate! = gen_privpub! && genpsk! + def genpsk! = File.write(@preshared_path, `#{WIREGUARD_TOOL} genpsk`) + + def gen_privpub! + privkey = IO.popen("#{WIREGUARD_TOOL} genkey", 'r+', &:read) + IO.popen("#{WIREGUARD_TOOL} pubkey", 'r+') do |io| + io.puts(privkey) + io.close_write + File.write(@privkey_path, privkey) + File.write(@pubkey_path, io.read) + end + end +end + +PeerSnippet = Struct.new(:myself, :domain, :allowed_ips) do def to_s + keys = KeyTool.new(myself) <<~PEER_CONFIG [Peer] - # #{description} - PublicKey = #{public_key} - PresharedKey = #{preshared_key} - AllowedIPs = #{allowed_ips} + # #{myself}.#{domain} + PublicKey = #{keys.pub} + PresharedKey = #{keys.preshared} + AllowedIPs = #{allowed_ips}/32 PEER_CONFIG end end WireguardConfig = Struct.new(:myself, :hosts) do - @peers = hosts.map do |name, data| - PeerSnippet.new("#{name}.#{data[:wg0][:domain]}", - :PUB_KEY, :PRESHARED_KEY, "#{data[:wg0][:ip]}/32") - end - def to_s + peers = hosts.reject { _1 == myself }.map do |hostname, data| + PeerSnippet.new(hostname, data[:wg0][:domain], data[:wg0][:ip]) + end + + keys = KeyTool.new(myself) <<~CONFIG [Interface] + # #{myself}.#{hosts[myself][:wg0][:domain]} Address = #{hosts[myself][:wg0][:ip]} - PrivateKey = #{private_key} + PrivateKey = #{keys.priv} + PresharedKey = #{keys.preshared} - #{@peers.map(&:to_s).join("\n")} + #{peers.map(&:to_s).join("\n")} CONFIG end - - private - - def private_key = 'PRIVATE_KEY' end -HOSTS.each_key do |name| - config_dir = "dist/#{name}/etc/wireguard" +HOSTS.each_key do |hostname| + raise 'Wireguard tool not found' unless File.exist?(WIREGUARD_TOOL) + + config_dir = "dist/#{hostname}/etc/wireguard" + key_dir = "keys/#{hostname}/" config_path = "#{config_dir}/wg0.conf" - FileUtils.mkdir_p(config_dir) unless Dir.exist?(config_dir) + [config_dir, key_dir].each { FileUtils.mkdir_p(_1) unless Dir.exist?(_1) } - wg0 = WireguardConfig.new(name, HOSTS) - puts "Generating config for #{name} at #{config_path}" + wg0 = WireguardConfig.new(hostname, HOSTS) + puts "Generating config for #{hostname} at #{config_path}" File.write(config_path, wg0.to_s) end -- cgit v1.2.3