📜 ⬆️ ⬇️

Simple firewall using puppet

Overview and basics of installing and configuring puppet Part 1 and Part 2 have already been published, so I will not stop here and go straight to setting up a firewall.

Formulation of the problem

The project uses a number of servers, most of which are in the cloud. A part is used to provide the company's infrastructure, and a part provides public service to customers. It is necessary to provide centralized access control.

The list of servers for our example:

Basic setting

To begin with, we will create the configuration of the basic firewall, in which all incoming ports except ssh will be closed.

 class firewall { exec { 'minimal-firewall': path => ["/bin", "/sbin", "/usr/bin", "/usr/sbin"], command => "iptables -P INPUT DROP \ && iptables -P FORWARD DROP \ && iptables --flush \ && iptables -t nat --flush \ && iptables --delete-chain \ && iptables -P FORWARD DROP \ && iptables -P INPUT DROP \ && iptables -A INPUT -i lo --source 127.0.0.1 --destination 127.0.0.1 -j ACCEPT \ && iptables -A INPUT -m state --state \"ESTABLISHED,RELATED\" -j ACCEPT \ && iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT \ && iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT \ && iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT \ && iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT \ && iptables -A INPUT -p tcp --dport ssh -j ACCEPT \ && iptables -A INPUT -j LOG -m limit --limit 40/minute \ && iptables -A INPUT -j DROP", } } 

')
There is no magic here. The iptables rules are found by Google on the “iptables minimal firewall”, the very first link is suitable. The only difference is: in order not to produce entities - not to create a separate script, all commands are combined into one with the && operator.

To apply this configuration to the server, you need to specify the class in the server configuration, in the terminology of the puppet node:

 node 'www' { include firewall } 

As the host name, you can specify either the FQDN or the short host name. By default, the puppet client rereads the configuration every thirty minutes, so you can wait a bit, or send a SIGHUP signal to the process, or just restart the service. After that you can make sure that the firewall rules are applied: iptables -L .

Opening input ports

There is a small subtlety. The order of adding rules to iptables matters, if we just add a new rule allowing access to the port, it will never work. Therefore, we will insert a new rule in the right place. It is very simple to define it: we will give the iptables -L --line-numbers command and look for the string mentioning ssh 7 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh . So we will insert the rule in position 7.

 define allowport ($protocol, $port) { exec { "/sbin/iptables -I INPUT 7 -p $protocol --dport $port -j ACCEPT": require => Exec['minimal-firewall'], } } 


Then the configuration of the www site becomes:

 node 'www' { allowport { http: protocol => tcp, port => 80, } allowport { https: protocol => tcp, port => 443, } include firewall } 


Please note: the description language for puppet is declarative, the order of the rules is not defined. Therefore, in fact, all the same, the import firewall will be recorded first and then the allowport or vice versa. For us, it is important that we first work out the rule for setting the minimum firewall and only then the opening of the port. This requirement is written in the definition of allowport - require => Exec['minimal-firewall']

Admin server configuration:

 node 'admin' { allowport { dns1: protocol => tcp, port => 53, } allowport { dns2: protocol => udp, port => 53, } allowport { http: protocol => tcp, port => 80, } allowport { webmin: protocol => tcp, port => 10000, } include firewall } 


Complicate the rules

The tomcat application server is required to run from an unprivileged user, and must respond to on the standard 443 port. Therefore, we will make the address translation (DNAT) of the connection to port 443 redirect to 8443, where tomcat will listen.

 define dnat ($protocol, $from, $to) { exec { 'dnat-$protocol-$from-$to': command => "/sbin/iptables -t nat -A PREROUTING -d $hostname -p $protocol --dport $from -j DNAT --to-destination $to \ && /sbin/iptables -t nat -A OUTPUT -d $hostname -p $protocol --dport $from -j DNAT --to-destination $to ", require => Exec['minimal-firewall'], } } 


We describe the configuration of the application server:

 node 'app' { allowport { https: protocol => tcp, port => 443, } allowport { tomcat: protocol => tcp, port => 8443, } dnat { java: protocol => tcp, from => 443, to => ':8443', } include firewall } 


Mysql server should not be accessible from outside the company. Developers, if necessary, access it from the admin server. Restrict access using the appropriate definition:

 define dmzport ($protocol, $port) { exec { 'dmz-$protocol-$port': command => "/sbin/iptables -I INPUT 7 -s admin.example.com -p $protocol --dport $port -j ACCEPT \ && /sbin/iptables -I INPUT 7 -s www.example.com -p $protocol --dport $port -j ACCEPT \ && /sbin/iptables -I INPUT 7 -s mysql.example.com -p $protocol --dport $port -j ACCEPT \ && /sbin/iptables -I INPUT 7 -s app.example.com -p $protocol --dport $port -j ACCEPT", require => Exec['minimal-firewall'], } } 

Now the mysql node configuration:

 node 'mysql' { dmzport { mysql: protocol => tcp, port => 3306, } include firewall } 


So we got a simple centralized firewall for all servers of the company.

Source: https://habr.com/ru/post/111313/


All Articles