From ce123035760a08a107f511de164542c997860eb8 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Sun, 3 Nov 2024 02:24:06 +1100 Subject: [PATCH] feat: add firewall module - add nftables/ipset modules - add custom firewall module --- Puppetfile | 3 +- hieradata/common.yaml | 35 +++++++++++++++++++ hieradata/os/AlmaLinux/all_releases.yaml | 2 ++ hieradata/roles/infra/storage/vault.yaml | 6 ++++ modules/firewall/manifests/init.pp | 26 ++++++++++++++ .../firewall/manifests/rules/in/cobbler.pp | 13 +++++++ modules/firewall/manifests/rules/in/consul.pp | 10 ++++++ modules/firewall/manifests/rules/in/dns.pp | 19 ++++++++++ .../firewall/manifests/rules/in/exporters.pp | 13 +++++++ modules/firewall/manifests/rules/in/http.pp | 10 ++++++ modules/firewall/manifests/rules/in/https.pp | 10 ++++++ modules/firewall/manifests/rules/in/ntp.pp | 10 ++++++ modules/firewall/manifests/rules/in/ssh.pp | 16 +++++++++ modules/firewall/manifests/rules/in/tftp.pp | 13 +++++++ modules/firewall/manifests/rules/in/vault.pp | 10 ++++++ .../firewall/manifests/rules/out/consul.pp | 29 +++++++++++++++ modules/firewall/manifests/rules/out/dns.pp | 14 ++++++++ modules/firewall/manifests/rules/out/http.pp | 10 ++++++ modules/firewall/manifests/rules/out/https.pp | 10 ++++++ modules/firewall/manifests/rules/out/ntp.pp | 11 ++++++ .../firewall/manifests/rules/out/puppet.pp | 11 ++++++ modules/firewall/manifests/rules/out/vault.pp | 11 ++++++ site/profiles/manifests/base.pp | 1 + site/profiles/manifests/base/repos.pp | 1 - 24 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 modules/firewall/manifests/init.pp create mode 100644 modules/firewall/manifests/rules/in/cobbler.pp create mode 100644 modules/firewall/manifests/rules/in/consul.pp create mode 100644 modules/firewall/manifests/rules/in/dns.pp create mode 100644 modules/firewall/manifests/rules/in/exporters.pp create mode 100644 modules/firewall/manifests/rules/in/http.pp create mode 100644 modules/firewall/manifests/rules/in/https.pp create mode 100644 modules/firewall/manifests/rules/in/ntp.pp create mode 100644 modules/firewall/manifests/rules/in/ssh.pp create mode 100644 modules/firewall/manifests/rules/in/tftp.pp create mode 100644 modules/firewall/manifests/rules/in/vault.pp create mode 100644 modules/firewall/manifests/rules/out/consul.pp create mode 100644 modules/firewall/manifests/rules/out/dns.pp create mode 100644 modules/firewall/manifests/rules/out/http.pp create mode 100644 modules/firewall/manifests/rules/out/https.pp create mode 100644 modules/firewall/manifests/rules/out/ntp.pp create mode 100644 modules/firewall/manifests/rules/out/puppet.pp create mode 100644 modules/firewall/manifests/rules/out/vault.pp diff --git a/Puppetfile b/Puppetfile index ddb6e0a..6a17bff 100644 --- a/Puppetfile +++ b/Puppetfile @@ -11,7 +11,6 @@ mod 'puppetlabs-apt', '9.4.0' mod 'puppetlabs-lvm', '2.1.0' mod 'puppetlabs-puppetdb', '7.13.0' mod 'puppetlabs-postgresql', '9.1.0' -mod 'puppetlabs-firewall', '6.0.0' mod 'puppetlabs-accounts', '8.1.0' mod 'puppetlabs-mysql', '15.0.0' mod 'puppetlabs-xinetd', '3.4.1' @@ -42,6 +41,8 @@ mod 'puppet-filemapper', '4.0.0' mod 'puppet-letsencrypt', '11.0.0' mod 'puppet-rundeck', '9.1.0' mod 'puppet-redis', '11.0.0' +mod 'puppet-ipset', '4.3.0' +mod 'puppet-nftables', '4.0.0' # other mod 'ghoneycutt-puppet', '3.3.0' diff --git a/hieradata/common.yaml b/hieradata/common.yaml index 518df23..0c9a6cb 100644 --- a/hieradata/common.yaml +++ b/hieradata/common.yaml @@ -143,6 +143,14 @@ hiera_include: - networking - ssh::server - profiles::accounts::rundeck + - firewall::rules::in::exporters + - firewall::rules::out::consul + - firewall::rules::out::dns + - firewall::rules::out::http + - firewall::rules::out::https + - firewall::rules::out::ntp + - firewall::rules::out::puppet + - firewall::rules::out::vault profiles::ntp::client::ntp_role: 'roles::infra::ntp::server' profiles::ntp::client::use_ntp: 'region' @@ -341,3 +349,30 @@ profiles::ceph::client::mons: # aliases: # - prodinf01n22 # - repos.main.unkin.net + +firewall::ipset_queries: + certbot: "enc_role=roles::infra::pki::certbot" + cobbler: "enc_role=roles::infra::cobbler::server" + consul: "enc_role=roles::infra::storage::consul" + dhcp: "enc_role=roles::infra::dhcp::server" + dns_master: "enc_role=roles::infra::dns::master" + dns_resolver: "enc_role=roles::infra::dns::resolver" + edgecache: "enc_role=roles::infra::storage::edgecache" + gitea_runner: "enc_role=roles::infra::git::runner" + gitea_server: "enc_role=roles::infra::git::gitea" + glauth: "enc_role=roles::infra::auth::glauth" + gonic: "enc_role=roles::apps::music::gonic" + grafana: "enc_role=roles::infra::metrics::grafana" + haproxy: "enc_role=roles::infra::halb::haproxy" + jumphost: "enc_role=roles::infra::proxy::jumphost" + ntp: "enc_role=roles::infra::ntp::server" + prometheus: "enc_role=roles::infra::metrics::prometheus" + puppetboard: "enc_role=roles::infra::puppetboard::server" + puppetmaster: "enc_role=roles::infra::puppet::master" + puppetdb_sql: "enc_role=roles::infra::puppetdb::sql" + puppetdb_api: "enc_role=roles::infra::puppetdb::api" + redis: "enc_role=roles::infra::db::redis" + rundeck: "enc_role=roles::infra::automation::rundeck" + sql_galera: "enc_role=roles::infra::sql::galera" + sql_patroni: "enc_role=roles::infra::sql::patroni" + vault: "enc_role=roles::infra::storage::vault" diff --git a/hieradata/os/AlmaLinux/all_releases.yaml b/hieradata/os/AlmaLinux/all_releases.yaml index 8ac3c3c..39e2d72 100644 --- a/hieradata/os/AlmaLinux/all_releases.yaml +++ b/hieradata/os/AlmaLinux/all_releases.yaml @@ -10,6 +10,8 @@ hiera_include: profiles::packages::include: lzo: {} + firewalld: + ensure: absent network-scripts: {} policycoreutils: {} unar: {} diff --git a/hieradata/roles/infra/storage/vault.yaml b/hieradata/roles/infra/storage/vault.yaml index 7d5cc42..b4849f7 100644 --- a/hieradata/roles/infra/storage/vault.yaml +++ b/hieradata/roles/infra/storage/vault.yaml @@ -1,4 +1,10 @@ --- +hiera_include: + - firewall::rules::in::ssh + - firewall::rules::in::vault + +firewall::rules::in::ssh::ipset: jumphost + profiles::vault::server::members_role: roles::infra::storage::vault profiles::vault::server::members_lookup: true profiles::vault::server::data_dir: /data/vault diff --git a/modules/firewall/manifests/init.pp b/modules/firewall/manifests/init.pp new file mode 100644 index 0000000..dd540d9 --- /dev/null +++ b/modules/firewall/manifests/init.pp @@ -0,0 +1,26 @@ +# manage the firewall +class firewall ( + Hash $ipset_queries = {}, +){ + + $ipset_queries.each |$ipset, $query| { + $ips = sort(query_nodes($query, 'networking.ip')) + + nftables::set{$ipset: + type => 'ipv4_addr', + flags => ['dynamic'], + elements => $ips, + } + } + + class {'nftables': + in_ssh => false, + in_icmp => true, + out_ntp => false, + out_dns => false, + out_http => false, + out_https => false, + out_icmp => true, + out_all => false, + } +} diff --git a/modules/firewall/manifests/rules/in/cobbler.pp b/modules/firewall/manifests/rules/in/cobbler.pp new file mode 100644 index 0000000..8edd91d --- /dev/null +++ b/modules/firewall/manifests/rules/in/cobbler.pp @@ -0,0 +1,13 @@ +class firewall::rules::in::cobbler ( + Array[Stdlib::Port] $ports = [25150,25151], + Array[Enum['tcp','udp']] $protocols = ['udp','tcp'], +) { + + $ports.each |$port| { + $protocols.each |$proto| { + nftables::rule { "default_in-cobbler_${proto}_${port}": + content => "${proto} dport ${port} accept", + } + } + } +} diff --git a/modules/firewall/manifests/rules/in/consul.pp b/modules/firewall/manifests/rules/in/consul.pp new file mode 100644 index 0000000..a3cd3a7 --- /dev/null +++ b/modules/firewall/manifests/rules/in/consul.pp @@ -0,0 +1,10 @@ +class firewall::rules::in::consul ( + Array[Stdlib::Port] $ports = [8300,8301,8302,8500,8503,8600], +) { + + $ports.each |$port| { + nftables::rule { "default_in-consul_${port}": + content => "tcp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/in/dns.pp b/modules/firewall/manifests/rules/in/dns.pp new file mode 100644 index 0000000..4056ccf --- /dev/null +++ b/modules/firewall/manifests/rules/in/dns.pp @@ -0,0 +1,19 @@ +class firewall::rules::in::dns ( + Array[Stdlib::Port] $ports = [53], + Array[Enum['tcp','udp']] $protocols = ['udp','tcp'], + Optional[String] $ipset = undef, +) { + + $ports.each |$port| { + $protocols.each |$proto| { + if $ipset != '' { + $rule = "${proto} dport ${port} ip saddr @${ipset} accept" + }else{ + $rule = "${proto} dport ${port} accept" + } + nftables::rule { "default_in-dns_${proto}_${port}": + content => $rule, + } + } + } +} diff --git a/modules/firewall/manifests/rules/in/exporters.pp b/modules/firewall/manifests/rules/in/exporters.pp new file mode 100644 index 0000000..207f128 --- /dev/null +++ b/modules/firewall/manifests/rules/in/exporters.pp @@ -0,0 +1,13 @@ +# 9100: node_exporter +# 9558: sysstemd_exporter +class firewall::rules::in::exporters ( + Array[Stdlib::Port] $ports = [9100,9558], + String $ipset = 'prometheus', +) { + + $ports.each |$port| { + nftables::rule { "default_in-metrics_exporter_tcp_${port}": + content => "tcp dport ${port} ip saddr @${ipset} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/in/http.pp b/modules/firewall/manifests/rules/in/http.pp new file mode 100644 index 0000000..1ad7dc2 --- /dev/null +++ b/modules/firewall/manifests/rules/in/http.pp @@ -0,0 +1,10 @@ +class firewall::rules::in::http ( + Array[Stdlib::Port] $ports = [80], +) { + + $ports.each |$port| { + nftables::rule { "default_in-http_${port}": + content => "tcp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/in/https.pp b/modules/firewall/manifests/rules/in/https.pp new file mode 100644 index 0000000..3e6ed4f --- /dev/null +++ b/modules/firewall/manifests/rules/in/https.pp @@ -0,0 +1,10 @@ +class firewall::rules::in::https ( + Array[Stdlib::Port] $ports = [443], +) { + + $ports.each |$port| { + nftables::rule { "default_in-https_${port}": + content => "tcp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/in/ntp.pp b/modules/firewall/manifests/rules/in/ntp.pp new file mode 100644 index 0000000..6bbfc45 --- /dev/null +++ b/modules/firewall/manifests/rules/in/ntp.pp @@ -0,0 +1,10 @@ +class firewall::rules::in::ntp ( + Array[Stdlib::Port] $ports = [123], +) { + + $ports.each |$port| { + nftables::rule { "default_in-ntp_${port}": + content => "udp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/in/ssh.pp b/modules/firewall/manifests/rules/in/ssh.pp new file mode 100644 index 0000000..66e6848 --- /dev/null +++ b/modules/firewall/manifests/rules/in/ssh.pp @@ -0,0 +1,16 @@ +class firewall::rules::in::ssh ( + Array[Stdlib::Port] $ports = [22], + Optional[String] $ipset = undef, +) { + + $ports.each |$port| { + if $ipset != '' { + $rule = "tcp dport ${port} ip saddr @${ipset} accept" + }else{ + $rule = "tcp dport ${port} accept" + } + nftables::rule { "default_in-ssh_tcp_${port}": + content => $rule, + } + } +} diff --git a/modules/firewall/manifests/rules/in/tftp.pp b/modules/firewall/manifests/rules/in/tftp.pp new file mode 100644 index 0000000..884cdd5 --- /dev/null +++ b/modules/firewall/manifests/rules/in/tftp.pp @@ -0,0 +1,13 @@ +class firewall::rules::in::tftp ( + Array[Stdlib::Port] $ports = [69], + Array[Enum['tcp','udp']] $protocols = ['udp','tcp'], +) { + + $ports.each |$port| { + $protocols.each |$proto| { + nftables::rule { "default_in-tftp_${proto}_${port}": + content => "${proto} dport ${port} accept", + } + } + } +} diff --git a/modules/firewall/manifests/rules/in/vault.pp b/modules/firewall/manifests/rules/in/vault.pp new file mode 100644 index 0000000..c2d3891 --- /dev/null +++ b/modules/firewall/manifests/rules/in/vault.pp @@ -0,0 +1,10 @@ +class firewall::rules::in::vault ( + Array[Stdlib::Port] $ports = [8200, 8201], +) { + + $ports.each |$port| { + nftables::rule { "default_in-vaultserver_${port}": + content => "tcp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/out/consul.pp b/modules/firewall/manifests/rules/out/consul.pp new file mode 100644 index 0000000..c41b219 --- /dev/null +++ b/modules/firewall/manifests/rules/out/consul.pp @@ -0,0 +1,29 @@ +class firewall::rules::out::consul ( + String $ipset = 'consul', +) { + + # serf traffic (lan and wan) + nftables::rule { 'default_out-consul_udp_8301': + content => 'udp dport 8301 accept', + } + nftables::rule { 'default_out-consul_tcp_8301': + content => 'tcp dport 8301 accept', + } + nftables::rule { 'default_out-consul_udp_8302': + content => 'udp dport 8302 accept', + } + nftables::rule { 'default_out-consul_tcp_8302': + content => 'tcp dport 8302 accept', + } + + # communication with servers + nftables::rule { 'default_out-consul_tcp_8300': + content => "tcp dport 8300 ip daddr @${ipset} accept", + } + nftables::rule { 'default_out-consul_tcp_8500': + content => "tcp dport 8500 ip daddr @${ipset} accept", + } + nftables::rule { 'default_out-consul_tcp_8503': + content => "tcp dport 8503 ip daddr @${ipset} accept", + } +} diff --git a/modules/firewall/manifests/rules/out/dns.pp b/modules/firewall/manifests/rules/out/dns.pp new file mode 100644 index 0000000..1cf1666 --- /dev/null +++ b/modules/firewall/manifests/rules/out/dns.pp @@ -0,0 +1,14 @@ +class firewall::rules::out::dns ( + String $ipset = 'dns_resolver', + Array[Stdlib::Port] $ports = [53], +) { + + $ports.each |$port| { + nftables::rule { "default_out-dns_udp_${port}": + content => "udp dport ${port} ip daddr @${ipset} accept", + } + nftables::rule { "default_out-dns_tcp_${port}": + content => "tcp dport ${port} ip daddr @${ipset} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/out/http.pp b/modules/firewall/manifests/rules/out/http.pp new file mode 100644 index 0000000..b709b7d --- /dev/null +++ b/modules/firewall/manifests/rules/out/http.pp @@ -0,0 +1,10 @@ +class firewall::rules::out::http ( + Array[Stdlib::Port] $ports = [80], +) { + + $ports.each |$port| { + nftables::rule { "default_out-http_tcp_${port}": + content => "tcp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/out/https.pp b/modules/firewall/manifests/rules/out/https.pp new file mode 100644 index 0000000..43b90d4 --- /dev/null +++ b/modules/firewall/manifests/rules/out/https.pp @@ -0,0 +1,10 @@ +class firewall::rules::out::https ( + Array[Stdlib::Port] $ports = [443], +) { + + $ports.each |$port| { + nftables::rule { "default_out-https_tcp_${port}": + content => "tcp dport ${port} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/out/ntp.pp b/modules/firewall/manifests/rules/out/ntp.pp new file mode 100644 index 0000000..6ac0425 --- /dev/null +++ b/modules/firewall/manifests/rules/out/ntp.pp @@ -0,0 +1,11 @@ +class firewall::rules::out::ntp ( + String $ipset = 'ntp', + Array[Stdlib::Port] $ports = [123], +) { + + $ports.each |$port| { + nftables::rule { "default_out-ntp_udp_${port}": + content => "udp dport ${port} ip daddr @${ipset} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/out/puppet.pp b/modules/firewall/manifests/rules/out/puppet.pp new file mode 100644 index 0000000..af038c0 --- /dev/null +++ b/modules/firewall/manifests/rules/out/puppet.pp @@ -0,0 +1,11 @@ +class firewall::rules::out::puppet ( + String $ipset = 'puppetmaster', + Array[Stdlib::Port] $ports = [8140], +) { + + $ports.each |$port| { + nftables::rule { "default_out-puppet_${port}": + content => "tcp dport ${port} ip daddr @${ipset} accept", + } + } +} diff --git a/modules/firewall/manifests/rules/out/vault.pp b/modules/firewall/manifests/rules/out/vault.pp new file mode 100644 index 0000000..0e98a3f --- /dev/null +++ b/modules/firewall/manifests/rules/out/vault.pp @@ -0,0 +1,11 @@ +class firewall::rules::out::vault ( + String $ipset = 'vault', + Array[Stdlib::Port] $ports = [8200], +) { + + $ports.each |$port| { + nftables::rule { "default_out-vault_${port}": + content => "tcp dport ${port} ip daddr @${ipset} accept", + } + } +} diff --git a/site/profiles/manifests/base.pp b/site/profiles/manifests/base.pp index 7eec9ab..3c60927 100644 --- a/site/profiles/manifests/base.pp +++ b/site/profiles/manifests/base.pp @@ -38,6 +38,7 @@ class profiles::base ( include profiles::metrics::default include profiles::helpers::node_lookup include profiles::consul::client + include firewall # include the python class class { 'python': diff --git a/site/profiles/manifests/base/repos.pp b/site/profiles/manifests/base/repos.pp index 8d3223f..b5925b6 100644 --- a/site/profiles/manifests/base/repos.pp +++ b/site/profiles/manifests/base/repos.pp @@ -4,7 +4,6 @@ class profiles::base::repos { case $facts['os']['family'] { 'RedHat': { include profiles::yum::global - include profiles::firewall::firewalld } 'Debian': { include profiles::apt::global