Note: This was originally posted on Red Hat’s Enable Sysadmin blog.

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 less services by default, some enable more. The difference is in convenience. Some distributions are trying to get you up and running quickly, so they have a large set of default services enabled, intended to make it easier for you to get your system up, and get logged in to get it configured.  Others take the opposite approach, and install almost nothing by default.  

This article is the start of a short series, we’re going to talk a little bit about hardening, a little 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. 

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 in services after install, so why complicate the OS install 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 as simple and generic as possible.  

For this article, I installed a base RHEL 7.6 system, to do some real testing.  I did the bare minimum during install, selecting the “base” package set, and setting up my passwords/usernames and network.  I also enabled NTP. 

After the install, 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 servers service. In this article we’re going to identify what services have open ports in your base install, and then look at how to list services, and disable the ones we don’t want.  On a RHEL 7.6 system we use ‘ss’ to see this, on systems that still ship with netstat, you’ll use ‘netstat’. 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 have an IP, then a port, and others have a * then a port?  The entries that look like “” mean they’re just listening on localhost. This means they’re not remotely accessible.  The service 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, this system has only two IPv4, and one IPv6 port open to the world.  Dhclient is probably a good example of something we could disable, but only if your server isnt using DHCP to get its IP address.  In the case of my test server, it is!  

Listing services, and stopping and disabling them is relatively easy on RHEL7, we’ll use systemd’s tools 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, it’s a very modest 19 services.  And most of them look like they’re necessary. We’ll pick on one to demonstrate though.  

[root@rhel76test ~]# systemctl list-units --type=service --state=running
UNIT                     LOAD   ACTIVE SUB     DESCRIPTION
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. 

[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. 

So there you have it!  I learned something today, that out of the box, RHEL 7.6 is actually 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!