From 3a418e342086f3948bc6f9a07a3cb243db5ae700 Mon Sep 17 00:00:00 2001 From: Matthew Mosesohn Date: Mon, 23 Jun 2014 21:41:37 +0400 Subject: [PATCH] Improve firewall rules for Fuel Master Replaces hardcoded functions to create iptables rules for Nailgun and Cobbler with firewall module managed rules. Restricts network access to Fuel Master for all services (except Fuel Web/API) to Admin Network, plus restricts postgres to localhost access only. blueprint master-node-iptables-ruleset Change-Id: Ib5d0c554bf97957c45b206b8bf4f6e64c9be109f --- .../puppet/cobbler/manifests/iptables.pp | 90 ++++---- .../puppet/docker/manifests/dockerctl.pp | 9 +- deployment/puppet/docker/manifests/init.pp | 1 + .../docker/templates/dockerctl_config.erb | 24 ++- .../puppet/docker/templates/functions.sh.erb | 16 +- .../puppet/nailgun/examples/host-only.pp | 5 +- .../puppet/nailgun/manifests/iptables.pp | 200 +++++++++++++++--- .../puppet/nailgun/manifests/rabbitmq.pp | 23 -- 8 files changed, 247 insertions(+), 121 deletions(-) diff --git a/deployment/puppet/cobbler/manifests/iptables.pp b/deployment/puppet/cobbler/manifests/iptables.pp index 8c40243072..63c755fa57 100644 --- a/deployment/puppet/cobbler/manifests/iptables.pp +++ b/deployment/puppet/cobbler/manifests/iptables.pp @@ -13,29 +13,9 @@ # under the License. -class cobbler::iptables { - - define access_to_cobbler_port($port, $protocol='tcp') { - $rule = "-p $protocol -m state --state NEW -m $protocol --dport $port -j ACCEPT" - case $operatingsystem { - /(?i)(centos|redhat)/: { - exec { "access_to_cobbler_${protocol}_port: $port": - command => "iptables -t filter -I INPUT 1 $rule; \ - /etc/init.d/iptables save", - unless => "iptables -t filter -S INPUT | grep -q \"^-A INPUT $rule\"", - path => '/usr/bin:/bin:/usr/sbin:/sbin', - } - } - /(?i)(debian|ubuntu)/: { - exec { "access_to_cobbler_${protocol}_port: $port": - command => "iptables -t filter -I INPUT 1 $rule; \ - iptables-save -c > /etc/iptables.rules", - unless => "iptables -t filter -S INPUT | grep -q \"^-A INPUT $rule\"", - path => '/usr/bin:/bin:/usr/sbin:/sbin', - } - } - } - } +class cobbler::iptables ( +$chain = "INPUT", +) { case $operatingsystem { /(?i)(debian|ubuntu)/:{ @@ -54,32 +34,40 @@ class cobbler::iptables { } } - # HERE IS IPTABLES RULES TO MAKE COBBLER AVAILABLE FROM OUTSIDE - # https://github.com/cobbler/cobbler/wiki/Using%20Cobbler%20Import - # SSH - access_to_cobbler_port { "ssh": port => '22' } - # DNS - access_to_cobbler_port { "dns_tcp": port => '53' } - access_to_cobbler_port { "dns_udp": port => '53', protocol => 'udp' } - # DHCP - access_to_cobbler_port { "dhcp_67": port => '67', protocol => 'udp' } - access_to_cobbler_port { "dhcp_68": port => '68', protocol => 'udp' } - # SQUID PROXY - access_to_cobbler_port { "http_3128": port => '3128',protocol => 'tcp' } - # PXE - access_to_cobbler_port { "pxe_4011": port => '4011',protocol => 'udp' } - # TFTP - access_to_cobbler_port { "tftp_tcp": port => '69' } - access_to_cobbler_port { "tftp_udp": port => '69', protocol => 'udp' } - # NTP - access_to_cobbler_port { "ntp_udp": port => '123', protocol => 'udp' } - # HTTP/HTTPS - access_to_cobbler_port { "http": port => '80' } - access_to_cobbler_port { "https": port => '443'} - # SYSLOG FOR COBBLER - access_to_cobbler_port { "syslog_tcp": port => '25150'} - # xmlrpc API - access_to_cobbler_port { "xmlrpc_api": port => '25151' } - - + firewall { '101 dns_tcp': + chain => $chain, + port => '53', + proto => 'tcp', + action => 'accept', + } + firewall { '102 dns_udp': + chain => $chain, + port => '53', + proto => 'udp', + action => 'accept', + } + firewall { '103 dhcp': + chain => $chain, + port => ['67','68'], + proto => 'udp', + action => 'accept', + } + firewall { '104 tftp': + chain => $chain, + port => '69', + proto => 'udp', + action => 'accept', + } + firewall { '110 squidproxy': + chain => $chain, + port => '3128', + proto => 'tcp', + action => 'accept', + } + firewall { '111 cobbler_web': + chain => $chain, + port => ['80','443'], + proto => 'tcp', + action => 'accept', + } } diff --git a/deployment/puppet/docker/manifests/dockerctl.pp b/deployment/puppet/docker/manifests/dockerctl.pp index 2994bfbd23..44a98535dd 100644 --- a/deployment/puppet/docker/manifests/dockerctl.pp +++ b/deployment/puppet/docker/manifests/dockerctl.pp @@ -1,8 +1,9 @@ class docker::dockerctl ( - $bin_dir = '/usr/bin', - $share_dir = '/usr/share/dockerctl', - $config_dir = '/etc/dockerctl', - $profile_dir = '/etc/profile.d', + $bin_dir = '/usr/bin', + $share_dir = '/usr/share/dockerctl', + $config_dir = '/etc/dockerctl', + $profile_dir = '/etc/profile.d', + $admin_ipaddress = $::fuel_settings['ADMIN_NETWORK']['ipaddress'], $release, $production, ) { diff --git a/deployment/puppet/docker/manifests/init.pp b/deployment/puppet/docker/manifests/init.pp index 43e575d0b3..3cebd7ace7 100644 --- a/deployment/puppet/docker/manifests/init.pp +++ b/deployment/puppet/docker/manifests/init.pp @@ -1,4 +1,5 @@ class docker ( +$admin_ipaddress = $::fuel_settings['ADMIN_NETWORK']['ipaddress'], $limit = "102400", $docker_package = "docker-io", $docker_service = "docker", diff --git a/deployment/puppet/docker/templates/dockerctl_config.erb b/deployment/puppet/docker/templates/dockerctl_config.erb index 88762c681d..cc888d6c61 100644 --- a/deployment/puppet/docker/templates/dockerctl_config.erb +++ b/deployment/puppet/docker/templates/dockerctl_config.erb @@ -9,6 +9,9 @@ SOURCE_DIR="${DOCKER_ROOT}/sources" #SUPERVISOR_CONF_DIR="${docker_root}/supervisor" #SUPERVISOR_CONF_DIR="<%= @config_dir %>/supervisor/" ASTUTE_YAML="<%= @astute_settings_file %>" +ADMIN_IP="<%= @admin_ipaddress %>" +LOCAL_IP="127.0.0.1" + #Version of Fuel to deploy VERSION=$(awk '/release/{gsub(/"/, "");print $2}' /etc/fuel/version.yaml || echo <%= @release %>) IMAGE_PREFIX="fuel" @@ -60,17 +63,20 @@ declare -A CONTAINER_OPTIONS base_opts="-t" FOREGROUND="-i" BACKGROUND="-d" -CONTAINER_OPTIONS["cobbler"]="-p 53:53/udp -p 69:69/udp -p 80:80 -p 443:443 --privileged $base_opts" -CONTAINER_OPTIONS["postgres"]="-p 5432:5432 $base_opts" -CONTAINER_OPTIONS["rabbitmq"]="-p 5672:5672 -p 4369:4369 -p 15672:15672 -p 61613:61613 $base_opts" -CONTAINER_OPTIONS["rsync"]="-p 873:873 $base_opts" +BIND_ALL="" +BIND_ADMIN="${ADMIN_IP}:" +BIND_LOCAL="${LOCAL_IP}:" +CONTAINER_OPTIONS["cobbler"]="-p ${BIND_ADMIN}53:53/udp -p ${BIND_LOCAL}53:53/udp -p ${BIND_ADMIN}69:69/udp -p ${BIND_LOCAL}69:69/udp -p ${BIND_ALL}80:80 -p ${BIND_ALL}443:443 --privileged $base_opts" +CONTAINER_OPTIONS["postgres"]="-p ${BIND_ADMIN}5432:5432 -p ${BIND_LOCAL}5432:5432 $base_opts" +CONTAINER_OPTIONS["rabbitmq"]="-p ${BIND_ADMIN}5672:5672 -p ${BIND_LOCAL}5672:5672 -p ${BIND_ADMIN}4369:4369 -p ${BIND_LOCAL}4369:4369 -p ${BIND_ADMIN}15672:15672 -p ${BIND_LOCAL}15672:15672 -p ${BIND_ADMIN}61613:61613 -p ${BIND_LOCAL}61613:61613 $base_opts" +CONTAINER_OPTIONS["rsync"]="-p ${BIND_ADMIN}873:873 -p ${BIND_LOCAL}873:873 $base_opts" CONTAINER_OPTIONS["astute"]="$base_opts" -CONTAINER_OPTIONS["nailgun"]="-v /etc/nailgun -p 8001:8001 $base_opts" -CONTAINER_OPTIONS["ostf"]="-p 8777:8777 $base_opts" -CONTAINER_OPTIONS["nginx"]="-p 8000:8000 -p 8080:8080 $base_opts" -CONTAINER_OPTIONS["rsyslog"]="--privileged -p 514:514 -p 514:514/udp -p 25150 $base_opts" +CONTAINER_OPTIONS["nailgun"]="-v /etc/nailgun -p ${BIND_ADMIN}8001:8001 -p ${BIND_LOCAL}8001:8001 $base_opts" +CONTAINER_OPTIONS["ostf"]="-p ${BIND_ADMIN}8777:8777 -p ${BIND_LOCAL}8777:8777 $base_opts" +CONTAINER_OPTIONS["nginx"]="-p ${BIND_ALL}8000:8000 -p ${BIND_ALL}8080:8080 $base_opts" +CONTAINER_OPTIONS["rsyslog"]="--privileged -p ${BIND_ADMIN}514:514 -p ${BIND_LOCAL}514:514 -p ${BIND_ADMIN}514:514/udp -p ${BIND_LOCAL}514:514/udp -p ${BIND_ADMIN}25150:25150 -p ${BIND_LOCAL}25150:25150 $base_opts" CONTAINER_OPTIONS["mcollective"]="--privileged $base_opts" -CONTAINER_OPTIONS["keystone"]="-p 5000:5000 -p 35357:35357 $base_opts" +CONTAINER_OPTIONS["keystone"]="-p ${BIND_ALL}5000:5000 -p ${BIND_ALL}35357:35357 $base_opts" ###### #DRAFT: Dependency of volumes for deployment diff --git a/deployment/puppet/docker/templates/functions.sh.erb b/deployment/puppet/docker/templates/functions.sh.erb index b5333e8c50..b7bc5aacc2 100644 --- a/deployment/puppet/docker/templates/functions.sh.erb +++ b/deployment/puppet/docker/templates/functions.sh.erb @@ -106,20 +106,20 @@ function check_ready { failure=0 echo "checking container $1" case $1 in - nailgun) retry_checker '[ $(curl --connect-timeout 1 -s -w %{http_code} http://127.0.0.1:8000/api/version -o /dev/null) = "200" ]' ;; - ostf) retry_checker '[ $(curl --connect-timeout 1 -s -w '%{http_code}' http://127.0.0.1:8000/ostf/not_found -o /dev/null) = "404" ]' ;; + nailgun) retry_checker "grep -q 200 < <(curl --connect-timeout 1 -s -w %{http_code} http://$ADMIN_IP:8000/api/version -o /dev/null)" ;; + ostf) retry_checker "grep -q 404 < <(curl --connect-timeout 1 -s -w '%{http_code}' http://$ADMIN_IP:8000/ostf/not_found -o /dev/null)" ;; #NOTICE: Cobbler console tool does not comply unix conversation: 'cobbler profile find' always return 0 as exit code cobbler) retry_checker "shell_container cobbler ps aux | grep -q 'cobblerd -F'" retry_checker "shell_container cobbler cobbler profile find --name=centos* | grep -q centos" retry_checker "shell_container cobbler cobbler profile find --name=ubuntu* | grep -q ubuntu" retry_checker "shell_container cobbler cobbler profile find --name=bootstrap* | grep -q bootstrap" ;; - rabbitmq) retry_checker "curl -f -L -i -u \"$astute_user:$astute_password\" http://127.0.0.1:15672/api/nodes 1>/dev/null 2>&1" - retry_checker "curl -f -L -u \"$mcollective_user:$mcollective_password\" -s http://127.0.0.1:15672/api/exchanges | grep -qw 'mcollective_broadcast'" - retry_checker "curl -f -L -u \"$mcollective_user:$mcollective_password\" -s http://127.0.0.1:15672/api/exchanges | grep -qw 'mcollective_directed'" ;; - postgres) retry_checker "PGPASSWORD=$postgres_nailgun_password shell_container postgres psql -h 127.0.0.1 -U \"$postgres_nailgun_user\" \"$postgres_nailgun_dbname\" -c '\copyright' 2>&1 1>/dev/null" ;; + rabbitmq) retry_checker "curl -f -L -i -u \"$astute_user:$astute_password\" http://$ADMIN_IP:15672/api/nodes 1>/dev/null 2>&1" + retry_checker "curl -f -L -u \"$mcollective_user:$mcollective_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'mcollective_broadcast'" + retry_checker "curl -f -L -u \"$mcollective_user:$mcollective_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'mcollective_directed'" ;; + postgres) retry_checker "PGPASSWORD=$postgres_nailgun_password shell_container postgres psql -h $ADMIN_IP -U \"$postgres_nailgun_user\" \"$postgres_nailgun_dbname\" -c '\copyright' 2>&1 1>/dev/null" ;; astute) retry_checker "shell_container astute ps aux | grep -q 'astuted'" - retry_checker "curl -f -L -u \"$astute_user:$astute_password\" -s http://127.0.0.1:15672/api/exchanges | grep -qw 'nailgun'" - retry_checker "curl -f -L -u \"$astute_user:$astute_password\" -s http://127.0.0.1:15672/api/exchanges | grep -qw 'naily_service'" ;; + retry_checker "curl -f -L -u \"$astute_user:$astute_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'nailgun'" + retry_checker "curl -f -L -u \"$astute_user:$astute_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'naily_service'" ;; rsync) retry_checker "shell_container rsync netstat -ntl | grep -q 873" ;; rsyslog) retry_checker "shell_container rsyslog netstat -nl | grep -q 514" ;; mcollective) retry_checker "shell_container mcollective ps aux | grep -q mcollectived" ;; diff --git a/deployment/puppet/nailgun/examples/host-only.pp b/deployment/puppet/nailgun/examples/host-only.pp index d584d3511f..c05814e5e6 100644 --- a/deployment/puppet/nailgun/examples/host-only.pp +++ b/deployment/puppet/nailgun/examples/host-only.pp @@ -34,8 +34,9 @@ class { "openstack::clocksync": } class { "docker::dockerctl": - release => $::fuel_version['VERSION']['release'], - production => $production, + release => $::fuel_version['VERSION']['release'], + production => $production, + admin_ipaddress => $::fuel_settings['ADMIN_NETWORK']['ipaddress'], } class { "docker": } diff --git a/deployment/puppet/nailgun/manifests/iptables.pp b/deployment/puppet/nailgun/manifests/iptables.pp index cea1109360..a5e88f991b 100644 --- a/deployment/puppet/nailgun/manifests/iptables.pp +++ b/deployment/puppet/nailgun/manifests/iptables.pp @@ -1,27 +1,179 @@ -class nailgun::iptables { - - define access_to_nailgun_port($port, $protocol='tcp') { - $rule = "-p $protocol -m state --state NEW -m $protocol --dport $port -j ACCEPT" - exec { "access_to_nailgun_${protocol}_port: $port": - command => "iptables -t filter -I INPUT 1 $rule; \ - /etc/init.d/iptables save", - unless => "iptables -t filter -S INPUT | grep -q \"^-A INPUT $rule\"" - } - } - - define ip_forward($network) { - $rule = "-s $network ! -o docker0 -j MASQUERADE" - exec { "ip_forward: $network": - command => "iptables -t nat -I POSTROUTING 1 $rule; \ - /etc/init.d/iptables save", - unless => "iptables -t nat -S POSTROUTING | grep -q \"^-A POSTROUTING $rule\"" - } - sysctl::value{'net.ipv4.ip_forward': value=>'1'} - } - - access_to_nailgun_port { "nailgun_web": port => '8000' } - access_to_nailgun_port { "nailgun_repo": port => '8080' } +class nailgun::iptables ( +$production = 'docker', +$admin_iface = 'eth0', +$ssh_port = '22', +$nailgun_web_port = '8000', +$nailgun_internal_port = '8001', +$nailgun_repo_port = '8080', +$postgres_port = '5432', +$ostf_port = '8777', +$rsync_port = '873', +$rsyslog_port = '514', +$ntp_port = '123', +$rabbitmq_ports = ['4369','5672','15672','61613'], +$chain = 'INPUT', +) +{ + #Host services $network_address = ipcalc_network_by_address_netmask($::fuel_settings['ADMIN_NETWORK']['ipaddress'],$::fuel_settings['ADMIN_NETWORK']['netmask']) $network_cidr = ipcalc_network_cidr_by_netmask($::fuel_settings['ADMIN_NETWORK']['netmask']) - ip_forward {'forward_slaves': network => "${network_address}/${network_cidr}"} + firewall { '004 forward_admin_net': + chain => 'POSTROUTING', + table => 'nat', + source => "${network_address}/${network_cidr}", + outiface => 'eth+', + jump => 'MASQUERADE', + } + sysctl::value{'net.ipv4.ip_forward': value=>'1'} + + firewall { '005 ssh': + port => $ssh_port, + proto => 'tcp', + action => 'accept', + } + + firewall { '006 ntp': + port => $ntp_port, + proto => 'tcp', + iniface => $admin_iface, + action => 'accept', + } + + firewall { '007 ntp_udp': + port => $ntp_port, + proto => 'udp', + iniface => $admin_iface, + action => 'accept', + } + + firewall { '008 snmp': + port => '162', + proto => 'udp', + action => 'accept', + } + + #Containerized services + firewall { '009 nailgun_web': + chain => $chain, + port => $nailgun_web_port, + proto => 'tcp', + action => 'accept', + } + + firewall { '010 nailgun_internal': + chain => $chain, + port => $nailgun_internal_port, + proto => 'tcp', + iniface => 'docker0', + action => 'accept', + } + firewall { '011 nailgun_internal_local': + chain => $chain, + port => $nailgun_internal_port, + proto => 'tcp', + src_type => "LOCAL", + action => 'accept', + } + + firewall { '012 nailgun_internal_block_ext': + chain => $chain, + port => $nailgun_internal_port, + proto => 'tcp', + action => 'reject', + } + + firewall { '013 postgres_local': + chain => $chain, + port => $postgres_port, + proto => 'tcp', + src_type => "LOCAL", + action => 'accept', + } + + firewall { '014 postgres': + chain => $chain, + port => $postgres_port, + proto => 'tcp', + iniface => 'docker0', + action => 'accept', + } + + firewall { '015 postgres_block_ext': + chain => $chain, + port => $postgres_port, + proto => 'tcp', + action => 'reject', + } + + firewall { '020 ostf_admin': + chain => $chain, + port => $ostf_port, + proto => 'tcp', + iniface => $admin_iface, + action => 'accept', + } + + firewall { '021 ostf_local': + chain => $chain, + port => $ostf_port, + proto => 'tcp', + src_type => "LOCAL", + action => 'accept', + } + + firewall { '022 ostf_block_ext': + chain => $chain, + port => $ostf_port, + proto => 'tcp', + action => 'reject', + } + + firewall { '023 rsync': + chain => $chain, + port => $rsync_port, + proto => 'tcp', + action => 'accept', + } + + firewall { '024 rsyslog': + chain => $chain, + port => $rsync_port, + proto => 'tcp', + iniface => $admin_iface, + action => 'accept', + } + + firewall { '040 rabbitmq_admin': + chain => $chain, + port => $rabbitmq_ports, + proto => 'tcp', + iniface => $admin_iface, + action => 'accept', + } + + firewall { '041 rabbitmq_local': + chain => $chain, + port => $rabbitmq_ports, + proto => 'tcp', + src_type => "LOCAL", + action => 'accept', + } + + firewall { '042 rabbitmq_block_ext': + chain => $chain, + port => $rabbitmq_ports, + proto => 'tcp', + action => 'reject', + } + + firewall {'999 iptables denied': + chain => 'INPUT', + limit => '5/min', + jump => 'LOG', + log_prefix => 'iptables denied: ', + log_level => '7', + } + + } + diff --git a/deployment/puppet/nailgun/manifests/rabbitmq.pp b/deployment/puppet/nailgun/manifests/rabbitmq.pp index 15df51da00..669338c65c 100644 --- a/deployment/puppet/nailgun/manifests/rabbitmq.pp +++ b/deployment/puppet/nailgun/manifests/rabbitmq.pp @@ -16,17 +16,6 @@ class nailgun::rabbitmq ( anchor { 'nailgun::rabbitmq start' :} anchor { 'nailgun::rabbitmq end' :} - define access_to_rabbitmq_port ($port, $protocol = 'tcp') { - $rule = "-p $protocol -m state --state NEW -m $protocol --dport $port -j ACCEPT" - - exec { "access_to_cobbler_${protocol}_port: $port": - command => "iptables -t filter -I INPUT 1 $rule; \ - /etc/init.d/iptables save", - unless => "iptables -t filter -S INPUT | grep -q \"^-A INPUT $rule\"", - path => '/bin:/usr/bin:/sbin:/usr/sbin', - } - } - if $production =~ /docker/ { #Known issue: ulimit is disabled inside docker containers file { '/etc/default/rabbitmq-server': @@ -35,18 +24,6 @@ class nailgun::rabbitmq ( before => Service['rabbitmq-server'], } } - else { - case $::osfamily { - 'Debian' : { - } - 'RedHat' : { - access_to_rabbitmq_port { "${stompport}_tcp": port => $stompport } - } - default : { - fail("Unsupported osfamily: ${osfamily} for os ${operatingsystem}") - } - } - } rabbitmq_user { $astute_user: admin => true,