How to configure Capsman

Today, I meet with a challenge. I need to set up good and working Wifi network over the building. I need to use sixteen access points (AP). My previous configurations was simple deployment of this access points with laborious configuration of each AP. And there were many channels, and things, that I must configure.

So I create centralized Access Point management setup for office environment that is scalable to many Access Point. This can be done by setting up Controlled Access Point system Manager (CAPsMAN) on your router and connecting Controlled Access Points (CAPs) to it. I have two bands: 2,4GHz and 5GHz. Everything with one SSID. I use this howto:

https://wiki.mikrotik.com/wiki/Manual:Simple_CAPsMAN_setup

As CAPSMAN I used powerfull hardware: MikroTik CCR1009-7G-1C-1S+. As CAPs I will use HAP AC – dual band wifi AP.

I assume, that you have some skills with Mikrotiks and configuration. So I will use only terminal commands in this post with explanation.

So, lets begin.

Assume, that we have default VLAN 600, with no DHCP and now internet connection. Its dummy vlan, lead to nowhere. Than we have more 3 VLANs. One vlan is management (3), one si for guests (4) and one for employees (5). Routing between this vlans provides linux router beyond our scope here. We used:

  • 192.168.1.0/24 – management vlan ID 3
  • 192.168.2.0/24 – management vlan ID 4
  • 192.168.3.0/24 – management vlan ID 5

Create a Bond with four links, to high bandwidth, with default vlan 600:

/system identity set name=CAPSMAN
/interface bonding add slaves=ether1,ether2,ether3,ether4 mode=802.3ad lacp-rate=30secs link-monitoring=mii transmit-hash-policy=layer-2-and-3
/interface bridge add name=bridge1 vlan-filtering=no pvid=600
/interface bridge port add bridge=bridge1 interface=bond1 pvid=600

At bridge configuration, create setting for vlan:

/interface bridge vlan
add bridge=bridge1 tagged=bridge1,bond1 vlan-ids=3
add bridge=bridge1 untagged=bridge1,bond1 vlan-ids=600
add bridge=bridge1 tagged=bridge1,bond1 vlan-ids=4
add bridge=bridge1 tagged=bridge1,bond1 vlan-ids=5

Now we set each vlan: name and interfaces, and IP addres for management vlan.

/interface vlan add interface=bridge1 vlan-id=3 name=vlan-management
/ip address add address=192.168.1.2 interface=vlan-management
/ip route add dst-address=192.168.2.0/24 gateway=192.168.1.1
/ip route add dst-address=192.168.3.0/24 gateway=192.168.1.1
/interface vlan add interface=bridge1 vlan-id=4 name=vlan-guests
/interface vlan add interface=bridge1 vlan-id=5 name=vlan-users

And now, we set vlan-filtering, to ensure, that this configuration start working:

/interface bridge set bridge1 vlan-filtering=yes

Corresponding to this, we must set appropriate switch device for bonding in 802.3ad. I use Cisco switch:

interface port-channel 1
description PCH:to-CAPSMAN
switchport mode trunk
no macro auto smartport
no eee enable
switchport trunk allowed vlan add 3
switchport trunk allowed vlan add 4
switchport trunk allowed vlan add 5
switchport trunk native vlan 600
flowcontrol off
exit
interface range giga 1-4
no macro auto smartport
no eee enable
channel-group 1 mode auto
description upport:CAPSMAN
no shutdown
exit
write

Now set some more thinks, like timezone, clock, disable Winbox connect via MAC.

/system clock set time-zone-name=Europe/Bratislava
/system ntp client set enabled=yes primary-ntp=192.168.1.1
/system clock print
/tool mac-server set allowed-interface-list=none
/tool mac-server mac-winbox set allowed-interface-list=none
/tool mac-server ping set enabled=no
/passwd
#I use: test123

I create a CA (Certificate Authority), which ensure, that only approved CAPs will connect and with encrypted data. So:

/certificate
add name=CA-CAPSMAN common-name=CA country=SK key-size=4096 organization=AAA state=Slovakia
add name=CAPSMAN common-name=CAPSMAN
/certificate sign CA-CAPSMAN-new ca-crl-host=192.168.1.2 name=CA
#wait minute for complete
/system resource print
/certificate sign CAPSMAN ca=CA name=CAPSMAN
/certificate export-certificate CA export-passphrase=test123
/certificate scep-server add ca-cert=CA path=/scep/CAPSMAN
/caps-man manager set ca-certificate=CA certificate=CAPSMAN
/caps-man manager set require-peer-certificate=yes

Now, create some configs for CAPs. Security and so on…

/caps-man security
add name="home-employees" authentication-types=wpa2-eap eap-methods=passthrough eap-radius-accounting=yes
add name="home-guests" authentication-types=wpa2-psk passphrase="test12345"
/caps-man configuration
add name="Config_AAA-guests_2-4" ssid="AAA-guests" country=slovakia installation=indoor security=home-guests datapath.bridge=bridge1 datapath.vlan-mode=use-tag datapath.vlan-id=4 channel.band=2ghz-g/n
add name="Config_AAA-employees_2-4" ssid="AAA-employees" country=slovakia installation=indoor security=home-employees security.eap-radius-accounting=no datapath.bridge=bridge1 datapath.vlan-mode=use-tag datapath.vlan-id=5 channel.band=2ghz-g/n
add name="Config_AAA-employees_5" ssid="AAA-employees" country=slovakia installation=indoor security=AAA-employees security.eap-radius-accounting=no datapath.bridge=bridge1 datapath.vlan-mode=use-tag datapath.vlan-id=5 channel.band=5ghz-n/ac
add name="Config_AAA-guests_5" ssid="AAA-guests" country=slovakia installation=indoor security=AAA-guests datapath.bridge=bridge1 datapath.vlan-mode=use-tag datapath.vlan-id=4 channel.band=5ghz-n/ac

Now, we can configure our first CAP. This happened only once. Any WIFI setting will be configured via CAPSMAN itself. So I set CAPs up for using, accessing and sending data only via management vlan (vlan id = 3). Every traffic will be forwarded to the CAPSMAN.

/system identity set name=CAP1
/interface bridge
add name=bridge1 vlan-filtering=no pvid=600
/interface bridge port
add bridge=bridge1 interface=ether1 pvid=600
add bridge=bridge1 interface=ether2 pvid=3
/interface bridge vlan
add bridge=bridge1 tagged=bridge1,ether1 untagged=ether2 vlan-ids=3
add bridge=bridge1 untagged=ether1,bridge1 vlan-ids=600
/interface bridge set bridge1 protocol-mode=none
/interface vlan add interface=bridge1 vlan-id=3 name=vlan-management
/ip address add address=192.168.1.3/24 interface=vlan-management
/system clock set time-zone-name=Europe/Bratislava
/system ntp client set enabled=yes primary-ntp=192.168.1.1
/system clock print
/interface bridge set bridge1 vlan-filtering=yes
/tool mac-server set allowed-interface-list=none
/tool mac-server mac-winbox set allowed-interface-list=none
/tool mac-server ping set enabled=no
/ip service print
/ip service disable numbers=0,1,2,5,7
/password
#set password

Now, we download our CA public certificate from our CAPSMAN, import it. Then we create a local certificate, and send it as template to Scep server running on CAPSMAN. Then we must manually approve this template, and it will be signed by our previously created CA certificate on CAPSMAN. And this signed certificate will by user for encrypted communication between CAPs and CAPSMAN. This step must by manually set for each CAP separately.

/tool fetch address=192.168.1.2 src-path=cert_export_CA.crt user=admin password="test123" mode=ftp
/certificate import file-name=cert_export_CA.crt passphrase=test123
/certificate add name=CAP1 common-name=CAP1 country=SK key-size=4096 organization=AAA state=Slovakia
/certificate add-scep template=CAP1 scep-url="http://192.168.1.2/scep/CAPSMAN"

Now, we can see at CAPSMAN, that there is pending certificate for grant:

/certificate scep-server requests print
0 CA pending CAP1 feb/19/2020 12:21:11 5ceb9b622v8badde58316abtec0b7ecff6a
/certificate scep-server requests grant numbers=0
/certificate scep-server requests print

So, after we grant this certificate, we can continue on CAP1:

/interface wireless cap set certificate=CAP1
/interface wireless cap
set bridge=none discovery-interfaces=vlan-management enabled=yes interfaces=wlan1 lock-to-caps-man=yes caps-man-addresses=192.168.1.2

And finally, we set this on CAPSMAN for provision radio setting to CAP1, or next CAP2…We can limit these for MAC address of CAP1. This my setting allow to connect any CAP with certificate, that has been previously granted.

/caps-man provisioning
add action=create-dynamic-enabled master-configuration="Config_AAA-guests_2-4" slave-configurations=Config_AAA-employees_2-4,Config_AAA-employees_5,Config_AAA-guests_5 name-format=prefix-identity
/caps-man manager interface
set [ find default=yes ] forbid=yes
add disabled=no interface=vlan-management
/caps-man manager
set enabled=yes

And now, we can add next CAP, like CAP2:

/system identity set name=CAP2
/interface bridge
add name=bridge1 vlan-filtering=no pvid=600
/interface bridge port
add bridge=bridge1 interface=ether1 pvid=600
add bridge=bridge1 interface=ether2 pvid=3
/system logging add topics=caps
/system logging add topics=stp
/interface bridge vlan
add bridge=bridge1 tagged=bridge1,ether1 untagged=ether2 vlan-ids=3
add bridge=bridge1 untagged=ether1,bridge1 vlan-ids=600
/interface bridge set bridge1 protocol-mode=none
/interface vlan add interface=bridge1 vlan-id=3 name=vlan-management
/ip address add address=192.168.1.4/24 interface=vlan-management
/system clock set time-zone-name=Europe/Bratislava
/system ntp client set enabled=yes primary-ntp=192.168.1.1
/system clock print
/interface bridge set bridge1 vlan-filtering=yes
/tool mac-server set allowed-interface-list=none
/tool mac-server mac-winbox set allowed-interface-list=none
/tool mac-server ping set enabled=no
/password
/ip service print
/ip service disable numbers=0,1,2,5,7
/tool fetch address=192.168.1.2 src-path=cert_export_CA.crt user=admin password="test123" mode=ftp
/certificate import file-name=cert_export_CA.crt passphrase=test123
/certificate add name=CAP2 common-name=CAP2 country=SK key-size=4096 organization=AAA state=Slovakia
/certificate add-scep template=CAP2 scep-url="http://192.168.1.2/scep/CAPSMAN"
#### now approve certificate on CAPSMAN via: certificate scep-server requests print....
#### after grant we can continue:
/interface wireless cap set certificate=CAP2
/interface wireless cap
set bridge=none discovery-interfaces=vlan-management enabled=yes interfaces=wlan1 lock-to-caps-man=yes caps-man-addresses=192.168.1.2
Total Page Visits: 53562 - Today Page Visits: 12

How to install nextcloud on Centos 8 Stream

I create a basic installation of Centos 8 stream from iso: CentOS-Stream-8-x86_64-20191219-boot.iso

During installation I choose minimal applications and standard utilities. Please, enable, network time and set lvm for virtio disk. I set password for root and create a new user, which have root privileges.

After instalation, I create and LVM encrypted partition, to store encrypted data of nextcloud on it. I will not use nextcloud data encryption. Command below creates encrypted disk. We must enter a passphrase twice

 cryptsetup -y -v luksFormat /dev/vdb

Now, we open this partition and look at status:

cryptsetup luksOpen /dev/vdb vdb_crypt
cryptsetup -v status vdb_crypt

/dev/mapper/vdb_crypt is active.
   type:    LUKS2
   cipher:  aes-xts-plain64
   keysize: 512 bits
   key location: keyring
   device:  /dev/vdb
   sector size:  512
   offset:  32768 sectors
   size:    209682432 sectors
   mode:    read/write
 Command successful.

Now, I write 4GB zeros to this device to see, if everything is OK. It is possible, to full-up tho whole device, but it can take a long time. But the true reason is, that this will allocate block data with zeros. This ensures that outside world will see this as random data i.e. it protect against disclosure of usage patterns.

dd if=/dev/zero of=/dev/mapper/vdb_crypt bs=4M count=1000
4194304000 bytes (4.2 GB, 3.9 GiB) copied, 130.273 s, 32.2 MB/s

Now try close and open this encrypted device. And then, I create an lvm above the luks encrypted disk:

cryptsetup luksClose vdb_crypt
cryptsetup luksOpen /dev/vdb vdb_crypt
cryptsetup -v status vdb_crypt
pvcreate /dev/mapper/vdb_crypt
vgcreate nextcloud /dev/mapper/vdb_crypt
lvcreate -n data -L+30G nextcloud
mkdir /mnt/test
mkfs.xfs /dev/mapper/nextcloud-data
mount /dev/mapper/nextcloud-data /mnt/test/
touch /mnt/test/hello 
ll /mnt/test/hello
umount /mnt/test/

Installing nextcloud and prerequisites

And now, we can start with preparing our Centos for nextcloud

At first, update system. Via dnf (DNF is the next upcoming major version of YUM, a package manager for RPM-based Linux distributions. It roughly maintains CLI compatibility with YUM and defines a strict API for extensions and plugins.)

dnf update -y

Next, we install and create empty database for our nextcloud. Then we start it and enable for autostart after boot.
If you wish, you can skip installations of MariaDB and you can use built-in SQLite. Then you can continue with installing apache web server.

dnf -y install mariadb-server
...
systemctl start mariadb
systemctl enable mariadb

Now, we run post installation script to finish setting up mariaDB server:

mysql_secure_installation
Set root password? [Y/n] y
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

Now, we can create a database for nextcloud.

mysql -u root -p
...
CREATE DATABASE nextcloud;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextclouduser'@'localhost' IDENTIFIED BY 'YOURPASSWORD';
FLUSH PRIVILEGES;
exit;

Now, we install Apache web server, and we start it and enable for autostart after boot:

dnf install httpd -y
systemctl start httpd.service
systemctl enable httpd.service

And set up firewall fow port http/80 and ssh/20 only:

systemctl status httpd
firewall-cmd --list-all
firewall-cmd --zone=public --permanent --remove-service=dhcpv6-client
firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --reload

Now point your browser to this server and look, if you see a Apache test page.

Now we can install php. Nextcloud (at this time is version 18.0.1) and support PHP (7.1, 7.2 or 7.3). So I use remi repositories and install php 7.3:

dnf -y install dnf-utils http://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf module list php
dnf module reset php
dnf module enable php:remi-7.3
dnf info php
dnf install php php-gd php-mbstring php-intl php-pecl-apcu php-mysqlnd php-pecl-imagick.x86_64 php-ldap php-pecl-zip.x86_64 php-process.x86_64
php -v
php --ini |grep Loaded
sed -i "s/post_max_size = 8M/post_max_size = 500M/" /etc/php.ini
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 500M/" /etc/php.ini
sed -i "s/memory_limit = 128M/memory_limit = 512M/" /etc/php.ini
systemctl start php-fpm.service
systemctl enable php-fpm.service

And now, we can install nextcloud:

mkdir -p /var/www/html/nextcloud/data
cd /var/www/html/nextcloud/
mount /dev/mapper/nextcloud-data /var/www/html/nextcloud/data/
wget https://download.nextcloud.com/server/releases/nextcloud-18.0.1.zip
unzip nextcloud-18.0.1.zip
rm nextcloud-18.0.1.zip
mv nextcloud/* .
mv nextcloud/.htaccess .
mv nextcloud/.user.ini .
rmdir nextcloud/
mkdir /var/www/html/nextcloud/data
chown -R apache:apache /var/www/html/nextcloud/
find /var/www/html/nextcloud/ -type d -exec chmod 750 {} \; 
find /var/www/html/nextcloud/ -type f -exec chmod 640 {} \;

Now create configuration file for nextcloud in httpd:

vim /etc/httpd/conf.d/nextcloud.conf
<VirtualHost *:80>
  DocumentRoot /var/www/html/nextcloud/
  ServerName  your.server.com

  <Directory /var/www/html/nextcloud/>
    Require all granted
    AllowOverride All
    Options FollowSymLinks MultiViews

    <IfModule mod_dav.c>
      Dav off
    </IfModule>

  </Directory>
</VirtualHost>
apachectl graceful

Refer to nextcloud admin manual, you can run into permissions problems. Run these commands as root to adjust permissions:

semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/data(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/config(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/apps(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/.htaccess'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/.user.ini'
restorecon -Rv '/var/www/html/nextcloud/'

If you see error “-bash: semanage: command not found”, install packages:

dnf provides /usr/sbin/semanage
dnf install policycoreutils-python-utils-2.9-3.el8_1.1.noarch

Now, we can check via built-in php scripts, in what state we are:

cd /var/www/html/nextcloud/
sudo -u apache php occ -h
sudo -u apache php occ -V
sudo -u apache php occ status

And finally, we can access our nextcloud and set up administrators password via our web: http://you-ip/

If you see default httpd welcome page, disable all lines in: /etc/httpd/conf.d/welcome.conf
Now you must complete the installation via web interface. Set Administrator’s password and locate to MariaDB with used credentials:

Database user: nextclouduser
Database password: YOURPASSWORD
Database name: nextcloud
host: localhost

In settings of nextcloud, go to section Administration > Overview. You can see some problems. If so, try to fix it. I had three problems. No apcu memory cache configured. So add at nextcloud config.php:

'memcache.local' => '\OC\Memcache\APCu',

Then I must edit som php variables, to set properly opcache: edit and adjust:

vim /etc/php.d/10-opcache.ini

Then I must edit httpd setting, because .htaccess wont working. So change apache config:

vim /etc/httpd/conf/httpd.conf

section: Directory "/var/www/html"
AllowOverride None
change to: 
AllowOverride All

And gracefuly restart apache:

apachectl graceful

Next, I find out, that my nextcloud instance cannot connect to internet and checks for update. I think, that this is on selinux (enforcing mode). So run check and find out, what is happening:

sealert -a /var/log/audit/audit.log

And the result:

SELinux is preventing /usr/sbin/php-fpm from name_connect access on the tcp_socket port 80
Additional Information:
Source Context                system_u:system_r:httpd_t:s0
Source Path                   /usr/sbin/php-fpm
Port                          80
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
---------
If you believe that php-fpm should be allowed name_connect access on the port 80 tcp_socket by default.
If you want to allow httpd to can network connect
Then you must tell SELinux about this by enabling the 'httpd_can_network_connect' boolean.

So I allow httpd to can network connect via:

setsebool -P httpd_can_network_connect 1

And that is complete. If you wont secure http (https), try to find out another post on this page.

Have fun

Total Page Visits: 53562 - Today Page Visits: 12

Install WordPress on Centos-8-stream with apache (httpd)

I started on clean centos-8 server, created from netinstall cd. It is minimal instalation. So, lets begun. Check the version, to be installed:

dnf info httpd
Name         : httpd
 Version      : 2.4.37
 Release      : 11.module_el8.0.0+172+85fc1f40

So, let install it and allow http port on firewalld. And start apache server itself.

dnf install httpd
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
systemctl start httpd.service
systemctl enable httpd.service

Now, you can point you web browser to IP on this server and you should see the welcome page of apache web server on centos.

Now create a directory, where we place our content and simple web page to test, if its working.

mkdir -p /var/www/vhosts/com.example.www
vim /var/www/vhosts/com.example.www/index.html
<html>
  <head>
    <title>Welcome to www.example.com!</title>
  </head>
  <body>
    <h1>Success!  The www.example.com virtual host is working!</h1>
  </body>
</html>

And now, create for this page own configuration in httpd:

vim /etc/httpd/conf.d/com.example.www.conf
<VirtualHost *:80>
    ServerAdmin admin@example.com
    DocumentRoot "/var/www/vhosts/com.example.www"
    ServerName www.example.com

ErrorLog /var/log/httpd/com.example.www-error_log
CustomLog /var/log/httpd/com.example.www-access_log common
</VirtualHost>

And now, gracefully restart your web server and point your browser to you domain: www.example.com (I edit my /etc/hosts to point this domain at my internal IP).

apachectl graceful

If you test page is working, lets begin with more thinks. We must install additional packages (software) for wordpress. Its mysql server and php. As mysql server, I use mariadb. Then create an initial configuration for mysql and create database for wordpress. I set no password for mysql.

dnf install mariadb-server mariadb
systemctl start mariadb
systemctl enable mariadb
mysql_secure_installation
   Set root password? [Y/n] n
   Remove anonymous users? [Y/n] y
   Disallow root login remotely? [Y/n] y
   Remove test database and access to it? [Y/n] y
   Reload privilege tables now? [Y/n] y

mysql -u root -p
   CREATE DATABASE wordpress;
   CREATE USER wordpressuser@localhost IDENTIFIED BY 'BESTpassword';
   GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost IDENTIFIED BY 'BESTpassword';
   FLUSH PRIVILEGES;
   exit;

When we find, which version of php will be standard installed, I decided to use another package sources and install newer php version 7.3

dnf info php
 Available Packages
 Name         : php
 Version      : 7.2.11

dnf install http://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf update
dnf install php73
dnf install php73-php-fpm.x86_64 php73-php-mysqlnd.x86_64
systemctl start php73-php-fpm.service
systemctl enable php73-php-fpm.service
ln -s /usr/bin/php73 /usr/bin/php
php -v
   PHP 7.3.10 (cli) (built: Sep 24 2019 09:20:18) ( NTS )

Now, create simple test php page, to view php by apache if its working.

vim /var/www/vhosts/com.example.www/foo.php
<?php
  phpinfo();
?>

Restart apache web server and point your browser to php:

systemctl restart httpd.service
www.example.com/foo.php

And now you can see informationa page about php on system.

Now we can download wordpress and unpack it.

cd ~ 
wget http://wordpress.org/latest.tar.gz
tar xzvf latest.tar.gz
rsync -avP wordpress/ /var/www/vhosts/com.example.www/
chown -R apache:apache /var/www/vhosts/

Now, we edit configuration and add directory variables about default loding index.php. And remove test files – foo.php, index.html.

rm /var/www/vhosts/com.example.www/foo.php
rm /var/www/vhosts/com.example.www/index.html
vim /etc/httpd/conf.d/com.example.www.conf
<Directory /var/www/vhosts/com.example.www>
DirectoryIndex index.php
</Directory>

And restart apache web server

systemctl restart httpd.service

Now we can continue with setting our wordpress via web browser and our www.example.com page (click refresh in your web browser). Follow the instructions and fill your variables (database name, user, password…).

My installation step 2 tells me, that it cannot write config.php in our content directory. So, I can manually creaty config.php, or find out, what happens. Install selinux troubleshoot packages and run command sealert, which tell us what happend.

dnf install setroubleshoot
sealert -a /var/log/audit/audit.log

I can see this messages:

SELinux is preventing /opt/remi/php73/root/usr/sbin/php-fpm from write access on the directory com.example.www.
If you want to allow php-fpm to have write access on the com.example.www directory
Then you need to change the label on 'com.example.www'
Do
# semanage fcontext -a -t httpd_sys_rw_content_t 'com.example.www'
# restorecon -v 'com.example.www'
Additional Information:
Source Context                system_u:system_r:httpd_t:s0
Target Context                unconfined_u:object_r:httpd_sys_content_t:s0
Target Objects                com.example.www [ dir ]

So I do, what it want. I adapt permissions, that apache/php can write into this diretory.

semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/vhosts/com.example.www(/.*)?'
restorecon -Rv /var/www/vhosts/com.example.www/

Now I can continue with installation. And everything works fine. Have a nice day.

Total Page Visits: 53562 - Today Page Visits: 12

Hardening iptables from “ACCEPT all” to “DROP all”

Now I write some rules, for hardening iptables. From default policy “accept” everything to “drop” everything except something I want to accept. This setup was made on Server Ubuntu 18.04.2 LTS.

This post is related to and made from sites:

https://help.ubuntu.com/community/IptablesHowTo

https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-using-iptables-on-ubuntu-14-0

By default, we can see, that everything is allowed:

iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination

So we start with allowing established sessions to receive traffic:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

-A INPUT: The -A flag appends a rule to the end of a chain. This is the portion of the command that tells iptables that we wish to add a new rule, that we want that rule added to the end of the chain, and that the chain we want to operate on is the INPUT chain.

And now, we can allow specific port or service, which we want to allow:

iptables -A INPUT -p tcp --dport ssh -j ACCEPT
iptables -A INPUT -p tcp --dport http -j ACCEPT
iptables -A INPUT -p tcp --dport https -j ACCEPT

And now, we block everything else commint to us:

iptables -A INPUT -j DROP

Now we can see our input chain in firewall:

iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:http
ACCEPT tcp -- anywhere anywhere tcp dpt:https
DROP all -- anywhere anywhere

Now we must add some rule for loopback. because we block it now. If we add it right now with above command, we add it at the end of chain (after drop all). So all traffic will be blocked. We must add it at the begining of this chain:

iptables -I INPUT 1 -i lo -j ACCEPT

-I INPUT 1: The -I flag tells iptables to insert a rule. This is different than the -A flag which appends a rule to the end. The -I flag takes a chain and the rule position where you want to insert the new rule.

-i lo: This component of the rule matches if the interface that the packet is using is the “lo” interface. The “lo” interface is another name for the loopback device. This means that any packet using that interface to communicate (packets generated on our server, for our server) should be accepted.

And now we can see it:

iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:http
ACCEPT tcp -- anywhere anywhere tcp dpt:https
DROP all -- anywhere anywhere

The first and the last lines looks very similar, so use the variable -v (verbose) os -S (list rules). See

iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- lo any anywhere anywhere
287 46814 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:http
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:https
211 45230 DROP all -- any any anywhere anywhere
iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -j DROP

Now we have five rules to ACCEPT packets, which we want. The we have the sixth rule for DROP all another packets.

The policy DROP everything can be done by two ways. We have the first way (Default policy of chain is ACCEPT everything. Our five rules catch certain packets and at the end we have the sixth rule to DROP all packet which catch all other remain packets). In case of breaking firewall, or accidentally flush our rules, we still can connect to our server (by default chain policy ACCEPT).

The second way is set default chain policy to DROP, and set our five rules first. So if packets are catch by one of this rules, is ACCEPTed. Then it is DROPPEd by default. There is a possibility, that if we flush our firewall rules, we never reach our server from network because the default chain policy is DROP. So first, we need the rules like above mentioned except the DROP rule. And then, at the end, change the default chain policy by command:

iptables -P INPUT DROP

And now look at this way of firewall:

iptables -S
-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

So we can see, that we DROP all packet, we want and ACCEPT packets we want. It can be done by this two ways. So pick one, which you want. I prefer the second way, because I have another access to server (via console-keyboard connected directly to server). So if something go wrong, I am still be able to connect it.

So if you choose the first way, you must add others rules before the DROP rule, because it will be matched by this rule. Like the loopback rule, you must insert it somewhere before the DROP rules. See the lines:

iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
3 ACCEPT tcp -- anywhere anywhere tcp dpt:http
4 ACCEPT tcp -- anywhere anywhere tcp dpt:https
5 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
6 DROP all -- anywhere anywhere

And now we can add another rule somewhere in the middle:

iptables -I INPUT 6 -p tcp --dport 5666 -j ACCEPT

And we see it:

iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
3 ACCEPT tcp -- anywhere anywhere tcp dpt:http
4 ACCEPT tcp -- anywhere anywhere tcp dpt:https
5 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
6 ACCEPT tcp -- anywhere anywhere tcp dpt:nrpe
7 DROP all -- anywhere anywhere

For save this rules and set it persistant after reboot, I use package:

apt-get install iptables-persistent

During installation you will be asked for some questions, like save this rules for permanent use and load next boot. If you haven’t yet, never mind. You can do it later with this:

iptables-save -c > /etc/iptables/rules.v4

Total Page Visits: 53562 - Today Page Visits: 12