ლ(ಠ益ಠლ)

RHEL & CentOS 7: SELinux Enabled - Change SSH Default Port to a Custom Port

The following are helpful tools and commands to diagnose an SSH connectivity issue on a RHEL and/or CentOS 7 server with SELinux enabled.

In this scenario, the OpenSSH service configuration (/etc/ssh/sshd_config) was updated to customize the listening port; however, SSH connectivity was then lost.

Discovery

Let’s look at /var/log/messages:

1
2
3
4
systemd: PID file /var/run/sshd.pid not readable (yet?) after start.
systemd: sshd.service never wrote its PID file. Failing.
systemd: Unit sshd.service entered failed state.
systemd: sshd.service failed.

Unfortunately, that’s not very helpful.

If the Linux auditd service is running, SELinux denial messages will be written to /var/log/audit/audit.log by default:

1
2
3
4
5
$ grep denied /var/log/audit/audit.log
type=AVC msg=audit(1487806964.654:34): avc:  denied  { name_bind } for  pid=761 comm="sshd" \
src=9999 scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023 \
tcontext=system_u:object_r:unreserved_port_t:s0 \
tclass=tcp_socket

Much better!

We now have confirmed SELinux is enforcing one of it’s security policies and is preventing the OpenSSH server from binding to our custom port.

Solution

Install the following tools via rescue (or whatever method works for you). This will drag in a lot of dependencies.

1
$ yum install setroubleshoot setroubleshoot-server

The tool ‘setroubleshoot’ listens for AVC audit messages and runs them through a database looking for a match. If you’re in the position of administering a server with SELinux enabled, this tool is a must-have.

Restart the OpenSSH service again to ensure an error propagates in the server logs:

1
$ systemctl restart sshd

Now check /var/log/messages:

1
2
setroubleshoot: SELinux is preventing /usr/sbin/sshd from name_bind access on the tcp_socket port 9999.
For complete SELinux messages. run sealert -l 6dec987e-da3e-427f-b217-a9bfdc72ec8d

The tool ‘sealert’ is the setroubleshoot client utility.

The command provided (above) will lookup the SELinux alert by its unique ID and return all the corresponding alerts.

1
2
3
4
5
6
7
8
9
10
11
$ sealert -l 6dec987e-da3e-427f-b217-a9bfdc72ec8d

SELinux is preventing /usr/sbin/sshd from name_bind access on the tcp_socket port 9999.

*****  Plugin bind_ports (92.2 confidence) suggests   ************************

If you want to allow /usr/sbin/sshd to bind to network port 9999
Then you need to modify the port type.
Do
# semanage port -a -t PORT_TYPE -p tcp 9999
    where PORT_TYPE is one of the following: ssh_port_t, vnc_port_t, xserver_port_t.

Run the recommended command using a PORT_TYPE of “ssh_port_t”:

1
$ semanage port -a -t ssh_port_t -p tcp 9999

Restart the OpenSSH service:

1
$ systemctl restart sshd

Connectivity should now be restored!

Did you know?

The -Z Option

Red Hat has done an excellent job with integrating SELinux throughout the operating system application user-land. In many cases, you can supply a command a -Z option to view SELinux security contexts.

For instance, to list contexts of a specific file, such as /etc/passwd:

1
2
$ ls -Z /etc/passwd
-rw-r--r--. root root system_u:object_r:passwd_file_t:s0 /etc/passwd

More esoteric, to display listening network sockets and their corresponding context:

1
2
3
4
5
$ ss -plntZ

State      Recv-Q Send-Q           Local Address:Port                          Peer Address:Port
LISTEN     0      128                          *:9999                                     *:*
users:(("sshd",pid=9160,proc_ctx=system_u:system_r:sshd_t:s0-s0:c0.c1023,fd=3))

Email Notifications

You can configure SELinux to send email messages when a problem is detected. Explore the following files:

1
2
3
4
5
$ rpm -ql setroubleshoot-server | grep "/etc/setroubleshoot" | grep conf
/etc/setroubleshoot/setroubleshoot.conf

$ rpm -ql setroubleshoot-server | grep email_alert_recipients
/var/lib/setroubleshoot/email_alert_recipients

Sealert Analyze Option

I was recently troubleshooting an issue with OpenDKIM–the service was unable to bind to a custom port:

1
2
3
4
5
systemd: Starting DomainKeys Identified Mail (DKIM) Milter...
systemd: Started DomainKeys Identified Mail (DKIM) Milter.
systemd: opendkim.service: main process exited, code=exited, status=69/n/a
systemd: Unit opendkim.service entered failed state.
systemd: opendkim.service failed.

Of course it’s obvious that SELinux was causing this–confirmed by the contents of the audit log:

1
2
3
type=AVC msg=audit(1488772833.670:14323): avc:  denied  { name_bind } for pid=19463 \
comm="opendkim" src=XXXX scontext=system_u:system_r:dkim_milter_t:s0 \
tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket

Unfortunately, the setroubleshoot subsystem had not been invoked to produce a more graceful, human-readable error report that we’ve grown accustomed to.

We can use the sealert analyze option (-a), to force an error report:

1
$ sealert -a /var/log/audit/audit.log
1
2
3
4
5
6
7
8
SELinux is preventing /usr/sbin/opendkim from name_bind access on the tcp_socket port XXXX.

*****  Plugin bind_ports (92.2 confidence) suggests   ************************

If you want to allow /usr/sbin/opendkim to bind to network port XXXX
Then you need to modify the port type.
Do
# semanage port -a -t milter_port_t -p tcp XXXX

Keep SELinux enabled!

Comments