Skip to main content

3 quick ways to reduce your attack surface on Linux

Start tightening up your server security by lowering your attack surface.
Three ways to reduce your attack surface on Linux

Linux systems are complicated things. Out of the box, every distribution includes a number of services meant to help you get things up and running. Some distributions enable fewer services by default, and some enable more. The difference is in convenience. Some distributions try to get you up and running quickly, so they have a large set of default services enabled to make it easier for you to get set up, logged in, and configured. Others take the opposite approach and install almost nothing by default.

This article is the start of a short series, where we’ll talk a bit about hardening, a bit about segmentation, and finally how to scan our networks to see if we got it right. So hang on and let me show you through a few layers of defense.

Install less software

When I install a new system, I try to install as little as possible. I start with the base package set and really install nothing else. It’s simple to add services after installation, so why complicate the process? Besides, if you’re doing this a lot, you’ll probably want to install from a Kickstart (or template) system. So, you’d want that set up as simply and generically as possible.

For this article, I installed a base Red Hat Enterprise Linux (RHEL) 7.6 system to do some real testing. I did the bare minimum during installation, selecting the base package set and setting up my passwords, usernames, and network. I also enabled the Network Time Protocol (NTP).

Identify open ports

After the installation, we can see the list of open ports. Ports are how services running on your server allow other systems to connect to them. A web server, for example, will bind ports 80 and 443 to the web server’s service. In this article, we’ll identify what services have open ports in your base installation, and then look at how to list services and disable the ones we don’t want.

On a Red Hat Enterprise Linux 7.6 system, we use the ss command to see this information. On systems that still ship with netstat, you’ll use the netstat command.

Running ss on our test system shows a few open ports:

[root@rhel76test ~]# ss -tulnp --no-header | awk '{print($1, $5, $7)}'
udp  *:68            users:(("dhclient",pid=3316,fd=6))
udp   users:(("chronyd",pid=2974,fd=1))
udp  ::1:323         users:(("chronyd",pid=2974,fd=2))
tcp  *:22            users:(("sshd",pid=3523,fd=3))
tcp    users:(("master",pid=3771,fd=13))
tcp  :::22           users:(("sshd",pid=3523,fd=4))
tcp  ::1:25          users:(("master",pid=3771,fd=14))

It looks like RHEL 7.6 base isn’t bad. Notice in the second column, some of the open ports show an IP and then a port, and others have a * and then a port. The entries that look like mean they’re just listening on localhost. This result means that they’re not remotely accessible. The services that look like *:22 mean they’re listening on any interface. Likewise, for the IPv6 addresses, we’ve got ::1:323, and :::22. The ::1 entries are localhost, the :::’s are wide open.

What all this means is that this system has only two IPv4 ports, and one IPv6 port, open to the world. The dhclient service is probably a good example of something we could disable (which would close its port), but only if your server isn't using DHCP to get its IP address. In the case of my test server, it is.

Disable services

Listing services and stopping/disabling them is relatively easy on Red Hat Enterprise Linux 7. We’ll use systemd to list all of the active units, and then tell it to stop and disable the ones we don’t want running.

To list all running services, you can use systemctl list-units --type=service --state=running. On my test system, the result shows a very modest 19 services, and most of them look like they’re necessary. We’ll pick one to demonstrate with, though:

[root@rhel76test ~]# systemctl list-units --type=service --state=running
auditd.service            loaded active running Security Auditing Service
chronyd.service           loaded active running NTP client/server
crond.service             loaded active running Command Scheduler
dbus.service              loaded active running D-Bus System Message Bus
firewalld.service         loaded active running firewalld - dynamic firewall daemon
getty@tty1.service        loaded active running Getty on tty1
lvm2-lvmetad.service      loaded active running LVM2 metadata daemon
NetworkManager.service    loaded active running Network Manager
polkit.service            loaded active running Authorization Manager
postfix.service           loaded active running Postfix Mail Transport Agent
qemu-guest-agent.service  loaded active running QEMU Guest Agent
rhnsd.service             loaded active running LSB: Starts the Spacewalk Daemon
rhsmcertd.service         loaded active running Enable periodic update of entitlement certificates.
rsyslog.service           loaded active running System Logging Service
sshd.service              loaded active running OpenSSH server daemon
systemd-journald.service  loaded active running Journal Service
systemd-logind.service    loaded active running Login Service
systemd-udevd.service     loaded active running udev Kernel Device Manager
tuned.service             loaded active running Dynamic System Tuning Daemon

Let’s say we didn’t want Postfix loaded at boot. We’d simply use systemctl stop postfix, and then systemctl disable postfix, like so:

[root@rhel76test ~]# systemctl stop postfix
[root@rhel76test ~]# systemctl disable postfix
Removed symlink /etc/systemd/system/
[root@rhel76test ~]# systemctl list-units --type=service --state=running | grep postfix

Now, you probably don’t want to disable Postfix, but you get the point.

Wrapping up

So, there you have it. I learned something today: Out of the box, Red Hat Enterprise Linux 7.6 is pretty neat and tidy. I hope you learned how to look for and disable services to lower your attack surface.

Tune in for the next installment of this series, where I’ll talk about network segmentation and firewalling

Thanks for reading!

Topics:   Linux   Security  
Author’s photo

Nathan Lager

Nate is a Technical Account Manager with Red Hat and an experienced sysadmin with 20 years in the industry.  He first encountered Linux (Red Hat 5.0) as a teenager, after deciding that software licensing was too expensive for a kid with no income, in the late 90’s.  Since then he’s run More about me

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.