diff --git a/manifests/interface.pp b/manifests/interface.pp index 4f02f7f..70328d9 100644 --- a/manifests/interface.pp +++ b/manifests/interface.pp @@ -17,6 +17,7 @@ # @param routes different routes for the systemd-networkd configuration # @param private_key Define private key which should be used for this interface, if not provided a private key will be generated # @param preshared_key Define preshared key which should be used for this interface +# @param provider Set provider for interface config. Allowed values: systemd, wgquick (default: systemd) # # @author Tim Meusel # @author Sebastian Rakel @@ -94,6 +95,7 @@ Array[Hash[String[1], Variant[String[1], Boolean]]] $routes = [], Optional[String[1]] $private_key = undef, Optional[String[1]] $preshared_key = undef, + Enum['systemd', 'wgquick'] $provider = 'systemd', ) { require wireguard @@ -171,33 +173,30 @@ $peer = [] } - systemd::network { "${interface}.netdev": - content => epp("${module_name}/netdev.epp", { - 'interface' => $interface, - 'dport' => $dport, - 'description' => $description, - 'preshared_key' => $preshared_key, - 'mtu' => $mtu, - 'peers' => $peers + $peer, - }), - restart_service => true, - owner => 'root', - group => 'systemd-network', - mode => '0440', - require => File["/etc/wireguard/${interface}"], - } - - $network_epp_params = { - 'interface' => $interface, - 'addresses' => $addresses, - 'routes' => $routes, - } - - systemd::network { "${interface}.network": - content => epp("${module_name}/network.epp", $network_epp_params), - restart_service => true, - owner => 'root', - group => 'systemd-network', - mode => '0440', + case $provider { + 'systemd': { + class { 'wireguard::provider::systemd': + interface => $interface, + peers => $peers + $peer, + dport => $dport, + addresses => $addresses, + description => $description, + mtu => $mtu, + routes => $routes, + preshared_key => $preshared_key, + } + } + 'wgquick': { + class { 'wireguard::provider::wgquick': + interface => $interface, + peers => $peers + $peer, + dport => $dport, + addresses => $addresses, + preshared_key => $preshared_key, + } + } + default: { + fail("provider ${provider} not supported") + } } } diff --git a/manifests/provider/systemd.pp b/manifests/provider/systemd.pp new file mode 100644 index 0000000..975f965 --- /dev/null +++ b/manifests/provider/systemd.pp @@ -0,0 +1,53 @@ +# +# @summary manages a systemd wireguard interface +# +# @param interface the name for the wg interface +# @param peers is an array of struct (Wireguard::Peers) for multiple peers +# @param dport destination for firewall rules / where our wg instance will listen on. defaults to the last digits from the title +# @param addresses different addresses for the systemd-networkd configuration +# @param description an optional string that will be added to the wireguard network interface +# @param mtu configure the MTU (maximum transision unit) for the wireguard tunnel. By default linux will figure this out. You might need to lower it if you're connection through a DSL line. MTU needs to be equal on both tunnel endpoints +# @param routes different routes for the systemd-networkd configuration +# @param preshared_key Define preshared key which should be used for this interface +# +# @see https://www.freedesktop.org/software/systemd/man/systemd.netdev.html#%5BWireGuardPeer%5D%20Section%20Options +class wireguard::provider::systemd ( + String[1] $interface, + Wireguard::Peers $peers = [], + Integer[1024, 65000] $dport = Integer(regsubst($title, '^\D+(\d+)$', '\1')), + Array[Hash[String,Variant[Stdlib::IP::Address::V4::CIDR,Stdlib::IP::Address::V6::CIDR]]] $addresses = [], + Optional[String[1]] $description = undef, + Optional[Integer[1280, 9000]] $mtu = undef, + Array[Hash[String[1], Variant[String[1], Boolean]]] $routes = [], + Optional[String[1]] $preshared_key = undef, +) { + systemd::network { "${interface}.netdev": + content => epp("${module_name}/netdev.epp", { + 'interface' => $interface, + 'dport' => $dport, + 'description' => $description, + 'mtu' => $mtu, + 'peers' => $peers, + 'preshared_key' => $preshared_key, + }), + restart_service => true, + owner => 'root', + group => 'systemd-network', + mode => '0440', + require => File["/etc/wireguard/${interface}"], + } + + $network_epp_params = { + 'interface' => $interface, + 'addresses' => $addresses, + 'routes' => $routes, + } + + systemd::network { "${interface}.network": + content => epp("${module_name}/network.epp", $network_epp_params), + restart_service => true, + owner => 'root', + group => 'systemd-network', + mode => '0440', + } +} diff --git a/manifests/provider/wgquick.pp b/manifests/provider/wgquick.pp new file mode 100644 index 0000000..d53a34e --- /dev/null +++ b/manifests/provider/wgquick.pp @@ -0,0 +1,30 @@ +# +# @summary manages a wireguard config file for wg-quick +# +# @param interface the name for the wg interface +# @param peers is an array of struct (Wireguard::Peers) for multiple peers +# @param dport destination for firewall rules / where our wg instance will listen on. defaults to the last digits from the title +# @param addresses different addresses for the systemd-networkd configuration +# @param preshared_key Define preshared key which should be used for this interface +# +class wireguard::provider::wgquick ( + String[1] $interface, + Wireguard::Peers $peers = [], + Integer[1024, 65000] $dport = Integer(regsubst($title, '^\D+(\d+)$', '\1')), + Array[Hash[String,Variant[Stdlib::IP::Address::V4::CIDR,Stdlib::IP::Address::V6::CIDR]]] $addresses = [], + Optional[String[1]] $preshared_key = undef, +) { + $params = { + 'interface' => $interface, + 'dport' => $dport, + 'peers' => $peers, + 'addresses' => $addresses, + 'preshared_key' => $preshared_key, + } + + file { "/etc/wireguard/${interface}.conf": + content => epp("${module_name}/wireguard_conf.epp", $params), + owner => 'root', + mode => '0600', + } +} diff --git a/spec/acceptance/init_spec.rb b/spec/acceptance/init_spec.rb index 87a64cb..14df4c9 100644 --- a/spec/acceptance/init_spec.rb +++ b/spec/acceptance/init_spec.rb @@ -10,4 +10,31 @@ end end end + + context 'with wg-quick' do + let :facts do + facts + end + + it 'work with no errors' do + pp = <<-EOS + wireguard::interface { 'tun0': + manage_firewall => false, + dport => 51820, + destination_addresses => [$facts['networking']['ip']], + addresses => [{'Address' => '192.0.2.1/24'}], + provider => 'wgquick', + peers => [ + { + public_key => 'hZC2VwCilfF9k9nQC6a86xOBFKaqdAgy123dkA6Z008=', + allowed_ips => ['192.0.2.3'], + } + ], + } + EOS + + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end end diff --git a/spec/defines/interface_spec.rb b/spec/defines/interface_spec.rb index 97d9c02..0ad9b6b 100644 --- a/spec/defines/interface_spec.rb +++ b/spec/defines/interface_spec.rb @@ -313,6 +313,29 @@ class {"systemd": it { is_expected.to contain_file("/etc/systemd/network/#{title}.network").with_content(%r{Address=fe80::ade1/64}) } it { is_expected.not_to contain_ferm__rule("allow_wg_#{title}") } end + + context 'wgquick with required params (public_key) and without firewall rules' do + let :params do + { + public_key: 'blabla==', + endpoint: 'wireguard.example.com:1234', + manage_firewall: false, + # we need to set destination_addresses to overwrite the default + # that would configure IPv4+IPv6, but GHA doesn't provide IPv6 for us + destination_addresses: [facts[:networking]['ip'],], + provider: 'wgquick', + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('wireguard') } + it { is_expected.to contain_exec("generate private key #{title}") } + it { is_expected.to contain_exec("generate public key #{title}") } + it { is_expected.to contain_file("/etc/wireguard/#{title}.pub") } + it { is_expected.to contain_file("/etc/wireguard/#{title}") } + it { is_expected.to contain_file("/etc/wireguard/#{title}.conf") } + it { is_expected.not_to contain_ferm__rule("allow_wg_#{title}") } + end end end end diff --git a/templates/wireguard_conf.epp b/templates/wireguard_conf.epp new file mode 100644 index 0000000..81163a2 --- /dev/null +++ b/templates/wireguard_conf.epp @@ -0,0 +1,28 @@ +<%- | + String[1] $interface, + Stdlib::Port $dport, + Wireguard::Peers $peers, + Array[Hash] $addresses, + Optional[String[1]] $preshared_key, +| -%> +[Interface] +<% $addresses.each |$address| { -%> +Address = <%= $address['Address'] %> +<% } -%> +ListenPort = <%= $dport %> +PostUp = wg set %i private-key /etc/wireguard/<%= $interface %> +<% $peers.each |$peer| { -%> + +[Peer] +PublicKey=<%= $peer['public_key'] %> +<% if $peer['endpoint'] { -%> +Endpoint=<%= $peer['endpoint'] %> +<% } -%> +<% if $preshared_key { -%> +PresharedKey=<%= $preshared_key %> +<% } -%> +PersistentKeepalive=<%= pick($peer['persistent_keepalive'], 0) %> +<% pick($peer['allowed_ips'], ['fe80::/64', 'fd00::/8', '0.0.0.0/0']).each |$allowed_ip| { -%> +AllowedIPs=<%= $allowed_ip %> +<% } -%> +<% } -%> \ No newline at end of file