Skip to content

Commit

Permalink
Add fwknop profile to bastion role
Browse files Browse the repository at this point in the history
  • Loading branch information
daaang committed Aug 16, 2024
1 parent ac969e6 commit 6b1071f
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 1 deletion.
81 changes: 81 additions & 0 deletions manifests/profile/fwknop.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright (c) 2024 The Regents of the University of Michigan.
# All Rights Reserved. Licensed according to the terms of the Revised
# BSD License. See LICENSE.txt for details.

# nebula::profile::fwknop
#
# @param pcap_filter Protocol and port to sniff packets to
# @param default_open_ports Default ports clients are allowed to request
# @param default_source Default allowed client CIDRs
# @param server_gpg_fingerprint GPG key fingerprint for decrypting packets
# @param server_gpg_passphrase GPG key passphrase for decrypting packets
# @param access Array of client configs
#
# @example
# nebula::profile::fwknop::access:
# - username: "bob"
# symmetric: "kgohbCga6D5a4YZ0dtbL8SEVbjI1A5KYrRvj0oqcKEk="
# hmac_key: "Zig9ZYcqj5gYl2S/UpFNp76RlD7SniyN5Ser5WoIKM7z"
# - username: "alice"
# source: "ANY"
# open_ports: "tcp/22, tcp/123"
# gpg: "7234ABCD"
# hmac_key: "STQ9m03hxj+WXwOpxMuNHQkTAx/EtfAKaXQ3tK8+Azcy"
# - username: "john"
# source: "3.3.3.0/24, 4.4.0.0/16"
# open_ports: "tcp/80"
# symmetric: "bOx25a5kjXf8/TmNQO1IRD3s/E9iLoPaqUbOv8X4VBA="
# hmac_key: "i0mIhR//1146/T+IMxDVZm1gosNVatvpqpCfkv4X6Xzv"
class nebula::profile::fwknop (
String $pcap_filter = 'udp port 62201',
String $default_open_ports = 'tcp/22, tcp/993',
String $default_source = '10.0.0.0/8, 192.168.0.0/16',
String $server_gpg_fingerprint = 'abcd1234',
String $server_gpg_passphrase = 'efgh5678',
Array[Hash[String, String]] $access = [],
) {
$primary_interface = $facts['networking']['primary']
$access.each |$index, $account| {
if $account["username"] == undef {
$account_id = "nebula::profile::fwknop::access[${index}]"
} else {
$account_id = "nebula::profile::fwknop::access[${index}] (for ${account['username']})"
}

if $account["hmac_key"] == undef {
fail("${account_id} missing required hmac_key")
}

if $account["symmetric"] == undef {
if $account["gpg"] == undef {
fail("${account_id} missing required symmetric or gpg key")
}
} else {
if $account["gpg"] != undef {
fail("${account_id} cannot have both symmetric and gpg key")
}
}
}

package { 'fwknop-server': }
service { 'fwknop-server':
require => Package['fwknop-server'],
}

file {
default:
owner => 'root',
group => 'root',
mode => '0600',
notify => Service['fwknop-server'],
;

'/etc/fwknop/access.conf':
content => template('nebula/profile/fwknop/access.conf.erb'),
;

'/etc/fwknop/fwknopd.conf':
content => template('nebula/profile/fwknop/fwknopd.conf.erb'),
;
}
}
6 changes: 6 additions & 0 deletions manifests/profile/networking/firewall.pp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
]
}

'fwknop': {
$input_ignore = ['-j FWKNOP_INPUT']
$output_ignore = []
$forward_ignore = []
}

default: {
$input_ignore = []
$output_ignore = []
Expand Down
6 changes: 5 additions & 1 deletion manifests/role/bastion.pp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
# BSD License. See LICENSE.txt for details.

class nebula::role::bastion {
include nebula::role::minimum
class { 'nebula::role::minimum':
internal_routing = 'fwknop',
}

include nebula::profile::bolt
include nebula::profile::fwknop
include nebula::profile::root_ssh_private_keys

# These three are effectively the requirements for getting user login
Expand Down
177 changes: 177 additions & 0 deletions spec/classes/profile/fwknop_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# frozen_string_literal: true

# Copyright (c) 2024 The Regents of the University of Michigan.
# All Rights Reserved. Licensed according to the terms of the Revised
# BSD License. See LICENSE.txt for details.
require 'spec_helper'

describe 'nebula::profile::fwknop' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }

context "with defaults" do
it { is_expected.to compile }

it { is_expected.to contain_package("fwknop-server") }
it { is_expected.to contain_service("fwknop-server").that_requires("Package[fwknop-server]") }

it { is_expected.to contain_file("/etc/fwknop/fwknopd.conf").with_owner("root") }
it { is_expected.to contain_file("/etc/fwknop/fwknopd.conf").with_group("root") }
it { is_expected.to contain_file("/etc/fwknop/fwknopd.conf").with_mode("0600") }
it { is_expected.to contain_file("/etc/fwknop/fwknopd.conf").that_notifies("Service[fwknop-server]") }

it do
is_expected.to contain_file("/etc/fwknop/fwknopd.conf").with_content(
<<~CONFIG
# Managed by puppet (nebula/profile/fwknop/fwknopd.conf.erb)
PCAP_INTF #{facts[:networking]["primary"]};
PCAP_FILTER udp port 62201;
CONFIG
)
end

it { is_expected.to contain_file("/etc/fwknop/access.conf").with_owner("root") }
it { is_expected.to contain_file("/etc/fwknop/access.conf").with_group("root") }
it { is_expected.to contain_file("/etc/fwknop/access.conf").with_mode("0600") }
it { is_expected.to contain_file("/etc/fwknop/access.conf").that_notifies("Service[fwknop-server]") }

it do
is_expected.to contain_file("/etc/fwknop/access.conf").with_content(
<<~CONFIG
# Managed by puppet (nebula/profile/fwknop/access.conf.erb)
CONFIG
)
end
end

context "with bare minimum access config" do
let(:params) { { access: [{ "hmac_key" => "eghmac", "symmetric" => "egkey" }] } }

it { is_expected.to compile }

it do
is_expected.to contain_file("/etc/fwknop/access.conf").with_content(
<<~CONFIG
# Managed by puppet (nebula/profile/fwknop/access.conf.erb)
SOURCE 10.0.0.0/8, 192.168.0.0/16
OPEN_PORTS tcp/22, tcp/993
REQUIRE_SOURCE_ADDRESS Y
KEY_BASE64 egkey
HMAC_KEY_BASE64 eghmac
CONFIG
)
end

context "with default_open_ports set to tcp and udp 53" do
let(:params) { super().merge("default_open_ports" => "tcp/53, udp/53") }

it { is_expected.to compile }

it do
is_expected.to contain_file("/etc/fwknop/access.conf").with_content(
<<~CONFIG
# Managed by puppet (nebula/profile/fwknop/access.conf.erb)
SOURCE 10.0.0.0/8, 192.168.0.0/16
OPEN_PORTS tcp/53, udp/53
REQUIRE_SOURCE_ADDRESS Y
KEY_BASE64 egkey
HMAC_KEY_BASE64 eghmac
CONFIG
)
end
end

context "with default_source set to ANY" do
let(:params) { super().merge("default_source" => "ANY") }

it { is_expected.to compile }

it do
is_expected.to contain_file("/etc/fwknop/access.conf").with_content(
<<~CONFIG
# Managed by puppet (nebula/profile/fwknop/access.conf.erb)
SOURCE ANY
OPEN_PORTS tcp/22, tcp/993
REQUIRE_SOURCE_ADDRESS Y
KEY_BASE64 egkey
HMAC_KEY_BASE64 eghmac
CONFIG
)
end
end
end

context "with bare minimum access config but without hmac" do
let(:params) { { access: [{ "symmetric" => "egkey" }] } }
it { is_expected.not_to compile }
end

context "with bare minimum access config but without key" do
let(:params) { { access: [{ "hmac_key" => "eghmac" }] } }
it { is_expected.not_to compile }
end

context "with bare minimum access config but with both gpg and symmetric" do
let(:params) { { access: [{ "hmac_key" => "eghmac", "symmetric" => "egkey", "gpg" => "eggpg" }] } }
it { is_expected.not_to compile }
end

context "with defaults" do
let(:params) do
{
access: [{
"username" => "bob",
"symmetric" => "kgohbCga6D5a4YZ0dtbL8SEVbjI1A5KYrRvj0oqcKEk=",
"hmac_key" => "Zig9ZYcqj5gYl2S/UpFNp76RlD7SniyN5Ser5WoIKM7z",
}, {
"username" => "alice",
"source" => "ANY",
"open_ports" => "tcp/22, tcp/123",
"gpg" => "7234ABCD",
"hmac_key" => "STQ9m03hxj+WXwOpxMuNHQkTAx/EtfAKaXQ3tK8+Azcy",
}, {
"username" => "john",
"source" => "3.3.3.0/24, 4.4.0.0/16",
"open_ports" => "tcp/80",
"symmetric" => "bOx25a5kjXf8/TmNQO1IRD3s/E9iLoPaqUbOv8X4VBA=",
"hmac_key" => "i0mIhR//1146/T+IMxDVZm1gosNVatvpqpCfkv4X6Xzv",
}]
}
end

it { is_expected.to compile }

it do
is_expected.to contain_file("/etc/fwknop/access.conf").with_content(
<<~CONFIG
# Managed by puppet (nebula/profile/fwknop/access.conf.erb)
SOURCE 10.0.0.0/8, 192.168.0.0/16
REQUIRE_USERNAME bob
OPEN_PORTS tcp/22, tcp/993
REQUIRE_SOURCE_ADDRESS Y
KEY_BASE64 kgohbCga6D5a4YZ0dtbL8SEVbjI1A5KYrRvj0oqcKEk=
HMAC_KEY_BASE64 Zig9ZYcqj5gYl2S/UpFNp76RlD7SniyN5Ser5WoIKM7z
SOURCE ANY
REQUIRE_USERNAME alice
OPEN_PORTS tcp/22, tcp/123
REQUIRE_SOURCE_ADDRESS Y
GPG_REMOTE_ID 7234ABCD
GPG_DECRYPT_ID abcd1234
GPG_DECRYPT_PW efgh5678
HMAC_KEY_BASE64 STQ9m03hxj+WXwOpxMuNHQkTAx/EtfAKaXQ3tK8+Azcy
SOURCE 3.3.3.0/24, 4.4.0.0/16
REQUIRE_USERNAME john
OPEN_PORTS tcp/80
REQUIRE_SOURCE_ADDRESS Y
KEY_BASE64 bOx25a5kjXf8/TmNQO1IRD3s/E9iLoPaqUbOv8X4VBA=
HMAC_KEY_BASE64 i0mIhR//1146/T+IMxDVZm1gosNVatvpqpCfkv4X6Xzv
CONFIG
)
end
end
end
end
end
21 changes: 21 additions & 0 deletions templates/profile/fwknop/access.conf.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Managed by puppet (nebula/profile/fwknop/access.conf.erb)
<% @access.each_index do |index| -%>
<% if index > 0 -%>
<% end -%>
SOURCE <%= @access[index].fetch("source", @default_source) %>
<% if @access[index].has_key?("username") -%>
REQUIRE_USERNAME <%= @access[index]["username"] %>
<% end -%>
OPEN_PORTS <%= @access[index].fetch("open_ports", @default_open_ports) %>
REQUIRE_SOURCE_ADDRESS Y
<% if @access[index].has_key?("symmetric") -%>
KEY_BASE64 <%= @access[index]["symmetric"] %>
<% end -%>
<% if @access[index].has_key?("gpg") -%>
GPG_REMOTE_ID <%= @access[index]["gpg"] %>
GPG_DECRYPT_ID <%= @server_gpg_fingerprint %>
GPG_DECRYPT_PW <%= @server_gpg_passphrase %>
<% end -%>
HMAC_KEY_BASE64 <%= @access[index]["hmac_key"] %>
<% end -%>
3 changes: 3 additions & 0 deletions templates/profile/fwknop/fwknopd.conf.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Managed by puppet (nebula/profile/fwknop/fwknopd.conf.erb)
PCAP_INTF <%= @primary_interface %>;
PCAP_FILTER <%= @pcap_filter %>;

0 comments on commit 6b1071f

Please sign in to comment.