Changing SSH Port on SELinux – Error: Bind to port failed: Permission denied
In case you want to change the default SSH port 22 on your system and you are running into the following error:
Error: Bind to port failed: Permission denied
You will probably using a Linux distribution on which SELinux (Security-Enhanced Linux) is enabled.
Security-Enhanced Linux (SELinux) is a Linux kernel security module that provides a mechanism for supporting access control security policies, including mandatory access controls (MAC).
SELinux is a set of kernel modifications and user-space tools that have been added to various Linux distributions. Its architecture strives to separate enforcement of security decisions from the security policy, and streamlines the amount of software involved with security policy enforcement. The key concepts underlying SELinux can be traced to several earlier projects by the United States National Security Agency (NSA).
SELinux is available since 2005 as part of Red Hat Enterprise Linux (RHEL) version 4 and all future releases.
Source: https://en.wikipedia.org/wiki/Security-Enhanced_Linux
Common Linux distributions that by default had enabled SELinux are Red Hat Enterprise Linux (RHEL) as used below for this post, CentOS, AlmaLinux, Rocky Linux, Fedora, Oracle Linux and Amazon Linux 2.
Available but not enabled by default are Debian, Ubuntu, openSUSE, SUSE Linux Enterprise Server, Gentoo and Arch Linux.
Ubuntu, openSUSE and Debian by default using SELinux’s counterpart AppAmor.
To see if SELinux is enabled on your system you can use the sestatus command.
# sestatus or for verbose output # sestatus -v
As mentioned for this post I will use Red Hat Enterprise Linux 9 (RHEL). Here you will already see a notification within the /etc/ssh/sshd_config file that if we want to change the SSH port, we first need to tell SELinux about this change. There is also shown the command we need to execute to add a custom port (adjusting the policy) for the sshd daemon and SELinux.
Otherwise we will run into the error below when trying to restart the sshd daemon.
By checking the logs using the journalctl -xeu sshd.service command we will get more details about the problem. In our case because SELinux is enabled here we first need to adjust the so called targeted policy to allow a different SSH port than 22.
We can first check the actual targeted policy for our SSH port by executing:
semanage port -l | grep ssh
When running a service on a custom port, you must change the configuration file for the service and also add an SELinux port definition. Without the port definition, the service will fail to start and log an error similar to “cannot bind to port”.
Source: https://www.redhat.com/sysadmin/semanage-keep-selinux-enforcing
Adjust the port definition to also allow tcp port 2222 will be used by the sshd daemon with:
# semanage port -a -t ssh_port_t -p tcp 2222 -a, --add -> Add a record of the specified object type -t TYPE, --type TYPE -> SELinux type for the object
In case you want to remove the default SSH port by using the -d flag for this policy you will run into the following error:
# semanage port -d -t ssh_port_t -p tcp 22
ValueError: Port tcp/22 is defined in policy, cannot be deleted
Already default defined policies can’t be deleted, therefore you have to create your own policy.
Another option to bind a custom port for our sshd daemon is either to change the mode which SELinux is running or by completely disabling SELinux.
SELinux can run in one of two modes: enforcing or permissive.
Disabling or running SELinux in permissive mode is not recommended!
When SELinux is disabled or running in permissive mode, SELinux policy is not enforced.Read also first the following article Benefits of running SELinux https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/using_selinux/getting-started-with-selinux_using-selinux#benefits-of-selinux_getting-started-with-selinux
# vi /etc/selinux/config
To change the mode from enforcing to permissive, open the vi /etc/selinux/config file and change the SELINUX value from enforcing to permissive.
Finally we need to reboot the system.
After the system restarts, confirm that the getenforce command returns Permissive.
To disable SELinux in RHEL 8 you can still use the deprecated method by also adjusting the /etc/selinux/config file. Here you just need to change the SELINUX value to disabled and reboot the system.
In RHEL 9 we need to configure the boot loader to disable SELinux. Therefore we can use the grubby tool
grubby is a command line tool for updating and displaying information about the configuration files for various architecture specific bootloaders. It is primarily designed to be used from scripts which install new kernels and need to find information about the current boot environment.
Configure your boot loader to add selinux=0 to the kernel command line:
# grubby --update-kernel ALL --args selinux=0
Finally reboot the system.
After the reboot, confirm that the getenforce command returns Disabled.
To get information about the current state of SELinux, we can use either getenforce or sestatus.
Links
What is SELinux (Security-Enhanced Linux)?
https://www.redhat.com/en/topics/linux/what-is-selinuxFour semanage commands to keep SELinux in enforcing mode
https://www.redhat.com/sysadmin/semanage-keep-selinux-enforcingChanging SELinux states and modes
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/using_selinux/changing-selinux-states-and-modes_using-selinuxGetting started with SELinux
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/using_selinux/getting-started-with-selinux_using-selinuxConfiguring SELinux
https://documentation.suse.com/sles/15-SP5/html/SLES-all/cha-selinux.htmlMaking persistent changes to the GRUB boot loader
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/assembly_making-persistent-changes-to-the-grub-boot-loader_managing-monitoring-and-updating-the-kernel