Saturday, 18 January 2014

SELinux and Changing Ports

As with many little Linux projects, what was intended to be a 2 minute activity turned into a 20 minute activity, this time in thanks to our friend SELinux.

In the past, I've always just disabled SELinux- what's the need, after all, as I'm usually just setting up projects out of my home lab and SELinux seems like a bit of overkill.  What's more, even in the Red Hat Certified System Admin course, they have you turn it off, as managing SELinux is more of a RHCE task.

Well, as it so happens, I'm currently studying for my RHCE and figured now is as good a time as any to get some practice in, if only inadvertently.

So the task at hand: change the SSH listening port from 22 to 443 so I can safely browse the interwebs and circumvent those pesky proxies.  So to do so, I log in and edit /etc/ssh/sshd_config:

#       $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/bin:/bin:/usr/bin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options change a
# default value.

#Port 22
Port 443
#AddressFamily any
#ListenAddress 0.0.0.0

#ListenAddress ::

I add a rule in iptables to allow 443:
[username@localhost ~]$ sudo iptables -I INPUT 4 -p tcp --dport https -j ACCEPT

Then I restart sshd:
[username@localhost ~]$ sudo service sshd restart

and attempt to SSH via 443 from my laptop:
[username@laptop ~]$ ssh usernam@centos01 -p 443
ssh: connect to host centos01 port 443: Connection refused

... WTF? I try telnet:
[username@localhost ~]$ telnet centos01 443
Trying 10.21.4.10... 
telnet: connect to address 10.21.4.10: Connection refused telnet: Unable to connect to remote host
Ah, so we're either blocking or not listening on 443. Let's try locally on the box:
[username@centos01 ~]$ ssh username@localhost -p 443
ssh: connect to host localhost port 443: Connection refused

So we're not listening. Weird. Perhaps this has something to do with SELinux:
[username@localhost ~]$ cat /selinux/enforced
1

Yep, we're enabled. So I temporarily disable SELinux:
[username@localhost ~]$ sudo echo 0> /selinux/enforce 

And let's try that again:

[username@localhost ~]$ ssh username@localhost -p 443
[username@localhost ~]$ The authenticity of host 'centos01 (10.5.10.10)' can't be established.
RSA key fingerprint is 94:21:69:84:1a:87:a7:94:98:64:95:f5:9e:ab:97:c4.
Are you sure you want to continue connecting (yes/no)?

Hooraw! Sure enough, it looks like SELinux is gumming up the works. So how do we allow SSH to listen on port 443? Well a bit of Googling tells us we need a tool called semanage, but it's not installed. Right then:
[username@localhost ~]$ sudo yum provides /usr/sbin/semanage
Loaded plugins: rhnplugin
policycoreutils-python-2.0.83-19.8.el6_0.x86_64 : SELinux policy core python utilities
Repo        : rhel-x86_64-server-6
Matched from:
Filename    : /usr/sbin/semanage
policycoreutils-python-2.0.83-19.1.el6.x86_64 : SELinux policy core python utilities
Repo        : rhel-x86_64-server-6
Matched from:

Filename    : /usr/sbin/semanage
[username@localhost ~]$ sudo yum install policycoreutils-python

Alright, so we have semanage installed, no it's time to append port 443 to the ssh_port_t:
[username@localhost ~]$ sudo semanage port -l | grep ssh
[username@localhost ~]$ ssh_port_t tcp 22
[username@localhost ~]$ sudo semanage port -a -t ssh_port_t -p tcp 443
[username@localhost ~]$ /usr/sbin/semanage: Port tcp/443 already defined 

Balls. Okay, so apparently you can only define a TCP port in one SELinux policy. Makes sense. Where is 443 defined?
[username@localhost ~]$ sudo semanage port -l | grep 443
[username@localhost ~]$ http_port_t tcp 80, 443, 488, 8008, 8009, 8443

Ah, of course. It's defined for HTTP. Now then, let's just remove it from HTTP and add it to SSH:
[username@localhost ~]$ sudo semanage port -d -t http_port_t -p tcp 443
[username@localhost ~]$ /usr/sbin/semanage: Port tcp/443 is defined in policy, cannot be deleted

Double balls. Alright, so we apparently have to modify the port to be included in ssh_port_t:
[username@localhost ~]$ sudo semanage port -m -t ssh_port_t -p tcp 443

[username@localhost ~]$ sudo semanage port -l | grep 443

http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
pki_ca_port_t                  tcp      829, 9180, 9701, 9443-9447
pki_kra_port_t                 tcp      10180, 10701, 10443-10446
pki_ocsp_port_t                tcp      11180, 11701, 11443-11446
pki_tks_port_t                 tcp      13180, 13701, 13443-13446
ssh_port_t                     tcp      443, 1255, 22

Sweet! Done and done. Now we can re-enable SELinux enforcement and ssh to our host! Hat tip to m4ccum4ccu for his helpful blog post which I've borrowed from heavily for this one.