Securing Files & Directories using ACLs in Linux

Our top priority is to secure and protect data from unauthorized access. We are all aware of the permissions we set using some handy Linux commands like chmod, chown & chgrp. However, these default permissions sets have some limitations and at times do not work to meet our requirements. For example, we cannot set different permissions sets for different users on the same directory or file. This is where Access Control Lists (ACLs) come into place.
 
Linux Access Control Lists
Let’s say, you have two users, ‘user1‘, and ‘user2‘. Each having a common group say ‘qhgroup’. User ‘user1‘ want that only ‘user2‘ user can read and access files owned by ‘user1‘ and no one else should have any access to that.
 
ACLs (Access Control Lists) enable us to do the above trick. These ACLs allow us to grant permissions to a user, group, and any set of users that are not in a user’s group list.


How to Check ACL Support in Linux Systems

Before proceeding, you must have support for ACLs on the current Kernel and mounted file systems.
Run the following command to check ACL Support for file system and POSIX_ACL=Y option (if there is N instead of Y, then it means Kernel doesn’t support ACL and needs to be recompiled).
 
[root@quantumhost ~]# grep -i acl /boot/config*

CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_REISERFS_FS_POSIX_ACL=y
CONFIG_JFS_POSIX_ACL=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_FS_POSIX_ACL=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_JFFS2_FS_POSIX_ACL=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFSD_V2_ACL=y
CONFIG_NFSD_V3_ACL=y
CONFIG_NFS_ACL_SUPPORT=m
CONFIG_CEPH_FS_POSIX_ACL=y
CONFIG_CIFS_ACL=y
CONFIG_9P_FS_POSIX_ACL=y


Install Required Packages

Before starting playing with ACLs make sure that you have the required packages installed. Assuming you are on a Debian based system
 
[root@quantumhost ~]# apt-get install nfs4-acl-tools acl

 

Check Mounted File System for ACLs Support

Now, check the mounted file system that whether it is mounted with the ACL option or not. We can use ‘mount‘ command for checking the same as shown below.

[root@quantumhost ~]# mount | grep -i /dev/sda1

/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro)

 
But in our case ACL is not shown by default. So, following we have the option to remount the mounted partition using the ACL option. But, before we continue, we have one more option to make sure the partition is mounted with the ACL option or not, because for the recent system it can be integrated with the default mount option as this is in our case.
 
[root@quantumhost ~]# tune2fs -l /dev/sda1 | grep acl
Default mount options: user_xattr acl
In the above output, you can see that the default mount option already has support for ACL.
 


Before Setting Default ACLs
To determine the default ACLs for a specific file or directory, use the ‘getfacl‘ command. In the example below, the getfacl is used to get the default ACLs for a folder ‘Music‘.
 
[root@quantumhost ~]# getfacl Music/

# file: Music/
# owner: root
# group: root
user::rwx
group::r-x
other::r-x
default:user::rwx
default:group::r-x
default:other::rw-

 
Setting Default ACLs
To set the default ACLs for a specific file or directory, use the ‘setfacl‘ command. In the example below, the setfacl command will set a new ACLs (read and execute) on a folder ‘Music’.
 
[root@quantumhost ~]# setfacl -m d:o:rx Music/

 
Show permissions after setting the ACLs

[root@quantumhost ~]# getfacl Music/

# file: Music/
# owner: root
# group: root
user::rwx
group::r-x
other::r-x
default:user::rwx
default:group::r-x
default:other::r-x


How to Set New ACLs on a File

Use the ‘setfacl’ command for setting or modifying on any file or directory. For example, to give read and write permissions to user ‘user1‘ on a file.
  
# setfacl -m u:user1:rw /user1/file
 


How to Set New ACLs on a Folder

Use the ‘setfacl’ command for setting or modifying any file or directory. For example, to give read, write and execute permissions to user ‘user1‘ on a folder recursively.
  
# setfacl -Rm u:user1:rwx /user1/folder
 


How to View ACLs

Use the ‘getfacl‘ command for viewing ACL on any file or directory. For example, to view ACL on ‘/user1/file‘ use below command.
 
# getfacl /user1/file

# file: /user1/file
# owner: user1
# group: user1
user::rwx
user:user1:rwx
group::rwx
mask::rwx
other::---


How to Remove ACLs

For removing ACL from any file/directory, we use x and b options as shown below.
 
Remove only specified ACL from file/directory;
 
# setfacl -x ACL file/directory


Removing all ACL from file/directory

# setfacl -b file/directory


Note
: After implementing ACL, you will see an extra ‘+‘ sign for ‘ls –l’ output as below.
 
[root@quantumhost user1]# ls -la

total 4
drwxrwx---+ 2 user1 user1 4096 Apr 17 17:01 file
 

Transfer files with Rsync

What is Rsync?

Rsync stands for “remote synchronization”. It is a remote and local file synchronization tool that helps you efficiently transfer files.

Rsync is faster than tools like Secure Copy Protocol (SCP) as it uses the delta-transfer algorithm that minimizes the data transfer by copying only the sections of a file that have been changed.

Some of the extra features included with Rsync:

  • Pipelines file transfers to minimize latency costs
  • Supports copying links, devices, owners, groups, and permissions

With that said, you are able to transfer files from local  to  remote, or remote  to  local. Rsync does not support remote  to  remote file transfers.


Rsync in action

Now we know what Rsync is, let’s see how it works.

Rsync works similarly to other remote server management tools like SSH and SCP.

Basic syntax of Rsync.
rsync [options] source destination

Transfer a file from your local system to a remote server. It is also called a “push” operation.
rsync local_filepath user@remote-host:remote_filepath

Transfer a file from a remote server to your local system, also called a “pull” operation.
rsync user@destination-server:destination_filepath source_filepath

Keep in mind that Rsync uses SSH for remote file-transfers by nature. Make sure you have SSH (Secure Shell) enabled on the destination system.


Rsync lets you add additional options. Let’s look at a few useful options.

Transfer recursively

A recursive file transfer can be executed if you add the -r option. This is useful when working with folders. Here is an example:

rsync -r user@remote-host:remote_folder/ local_folder

Archive option

The archive option (-a) preserves special and device files, modification times, permissions from the source folder, and is also used to preserve symbolic links while transferring files.

The archive option also syncs files recursively, so it is used more than the recursive option. Here is how you use it:

rsync -a user@remote-host:remote_folder/ local_folder

Use Compression

You can also compress files using the -z option. Compressing files will reduce the network load and speed up the file transfer.

rsync -az user@remote-host:remote_folder/ local_folder

Show the progress

For large file transfers, it is useful to see or follow the progress of the operation. You can use the -P option to know the progress of the file transfer. As Rsync is a very robust file transfer tool by nature, you can also resume file transfers if they are interrupted.

rsync -aP user@remote-host:remote_folder/ local_folder

Verbose option

The verbose option (-v) can help you understand every step of the file transfer.

rsync -av user@remote-host:remote_folder/ local_folder

To get a list of all the options, use the help command
rsync --help

How to set Rsync speed limit for bandwidth control with –bwlimit option

Syntax:

rsync --bwlimit=KBPS source destination
rsync --bwlimit=KBPS [options] source destination

Examples:

You set I/O limit in 5000 KBytes per second:

Local transfer

rsync --bwlimit=5000 source_filepath destination_filepath

Local to remote transfer

rsync --bwlimit=5000 source_filepath user@destination-server:destination_filepath

Another option is to use trickle, It is a userspace bandwidth manager.

Syntax:

trickle -u uploadLimit program
trickle -d downloadLimit rsync
trickle -u {UPLOAD_LIMIT} -d {DOWNLOAD_LIMIT} program-binary

For example:

trickle -s -d 5000 -u 5000 rsync source_filepath destination_filepath
trickle -s -d 5000 -u 5000 rsync -avr source_filepath user@destination-server:destination_filepath

Conclusion

Rsync simplifies the whole file transfer process by offering a robust, versatile, and flexible tool compared to alternatives like SCP.

Rsync is great for maintenance operations, backups, and general file operations between local and remote machines.

Mitigate attacks with iptables, fail2ban and ipset

In this short article, we will describe useful steps to prevent attacks and other malicious attempts.

Assuming we do the configuration on a Debian-based system.


First of all, we need to install the necessary tools
apt-get install ipset iptables-persistent fail2ban

Let’s start adding some rules to iptables.

Drop invalid packets to the mangle table
iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP

Drop TCP packets that are new and are not SYN
iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

Drop SYN packets with suspicious MSS value
iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

Block packets with bogus TCP flags
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

SSH brute-force protection
iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --set
iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 10 -j DROP

Protect against port scanning
iptables -N port-scanning 
iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN 
iptables -A port-scanning -j DROP

Save the rules to the iptables start-up config
/sbin/iptables-save > /etc/iptables/rules

Let’s take a look at fail2ban

Enable fail2ban on startup and start the service
systemctl enable fail2ban
systemctl start fail2ban

Now we need to setup ipset and his blacklist

Create blacklist with ipset utility (once)
ipset create blacklist hash:ip hashsize 4096

At this stage we have ipset blacklist create.

It’s time to set more iptables rules to match with blacklist and drop traffic
iptables -I INPUT -m set --match-set blacklist src -j DROP
iptables -I FORWARD -m set --match-set blacklist src -j DROP

Don’t forget to save the rules to the start-up config

/sbin/iptables-save > /etc/iptables/rules

Now you can manually fill the blacklist

Take a look in /var/log/fail2ban.log to see who attempted to get access to your server.

tail -40 /var/log/fail2ban.log

Add a specific IP address to your newly created blacklist
ipset add blacklist <write here the ip you want block>

That’s it. If you want to check which IP addresses are on your list
ipset list blacklist

At this point, we have decent security for common script kiddies. But if we want to have more view on our connections we need to use the ss command:

Usage: ss [ OPTIONS ]
 ss [ OPTIONS ] [ FILTER ]
 -h, --help this message
 -V, --version output version information
 -n, --numeric don't resolve service names
 -r, --resolve resolve host names
 -a, --all display all sockets
 -l, --listening display listening sockets
 -o, --options show timer information
 -e, --extended show detailed socket information
 -m, --memory show socket memory usage
 -p, --processes show process using socket
 -i, --info show internal TCP information
 -s, --summary show socket usage summary
 -b, --bpf show bpf filter socket information
 -E, --events continually display sockets as they are destroyed
 -Z, --context display process SELinux security contexts
 -z, --contexts display process and socket SELinux security contexts
 -N, --net switch to the specified network namespace name

-4, --ipv4 display only IP version 4 sockets
 -6, --ipv6 display only IP version 6 sockets
 -0, --packet display PACKET sockets
 -t, --tcp display only TCP sockets
 -S, --sctp display only SCTP sockets
 -u, --udp display only UDP sockets
 -d, --dccp display only DCCP sockets
 -w, --raw display only RAW sockets
 -x, --unix display only Unix domain sockets
 -f, --family=FAMILY display sockets of type FAMILY
 FAMILY := {inet|inet6|link|unix|netlink|help}

-K, --kill forcibly close sockets, display what was closed
 -H, --no-header Suppress header line

-A, --query=QUERY, --socket=QUERY
 QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]

-D, --diag=FILE Dump raw information about TCP sockets to FILE
 -F, --filter=FILE read filter information from FILE
 FILTER := [ state STATE-FILTER ] [ EXPRESSION ]
 STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}
 TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listen|closing}
 connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
 synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
 bucket := {syn-recv|time-wait}
 big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listen|closing}

Check who is connected at the moment to your server with ipv4
ss -t4 state established = check who is connected at the moment to your server with ipv4