How to Remove SELinux Policy-Defined Ports (Like SSH) When semanage port -d Fails


5 views

When working with SELinux port definitions, you'll eventually hit this roadblock:

$ sudo semanage port -d -p tcp -t ssh_port_t
ValueError: Port ssh_port_t is defined in policy, cannot be deleted

The standard advice ("just leave it") ignores real-world scenarios where you need strict alignment between policy and reality - like when decommissioning services or implementing zero-trust networks.

SELinux distinguishes between two port types:

  • Policy-defined ports: Hardcoded in SELinux modules (e.g., ssh_port_t at 22)
  • Custom ports: Added via semanage port -a

The security model treats policy ports as immutable by design - they're considered core system requirements.

To truly remove policy-defined ports, you need to rebuild the policy module:

# 1. Extract the policy module containing the port
$ sudo semodule -E | grep ssh
base.pp
...

# 2. Decompile the module
$ sudo semodule -E base -o base.mod

# 3. Edit the .te file to remove port definitions
$ grep port_define base.mod
define(ssh_port_t', tcp, 22')
...

# 4. Recompile and reload
$ sudo make -f /usr/share/selinux/devel/Makefile base.pp
$ sudo semodule -i base.pp

For production systems, consider overriding instead of removing:

# Reassign the port to unlabeled type
$ sudo semanage port -m -t unlabeled_t -p tcp 22

# Verify change
$ sudo semanage port -l | grep 22
unlabeled_t    tcp      22

This maintains policy integrity while achieving your goal of port non-availability.

Method Use Case Persistence
Policy Rebuild Permanent removal Survives reboots
Port Reassignment Temporary changes Requires semanage to persist

Remember that policy modifications may break during OS updates - always document your changes.


When working with SELinux port labeling, you might encounter stubborn port definitions that resist deletion attempts:

$ sudo semanage port -d -p tcp 22
ValueError: Port ssh is defined in policy, cannot be deleted

This occurs because certain ports are hardcoded in SELinux policy modules (usually in .pp files) as default configurations. While the accepted answer suggests leaving them untouched, there are valid technical reasons for removal:

  • Port consistency between SELinux and actual service configuration
  • Security hardening through minimal port exposure
  • Clean configuration management in infrastructure-as-code environments

Method 1: Policy Module Modification

The most robust approach involves modifying the SELinux policy module containing the port definition:

# Identify the source module
$ sesearch -A -s sshd_t -c tcp_socket | grep name_bind
allow sshd_t port_type:tcp_socket name_bind;

# Find the policy package
$ rpm -qf /etc/selinux/targeted/policy/policy.31
selinux-policy-targeted-3.14.4-67.el7.noarch

# Create a local policy module to override
$ cat ssh_port.te
module ssh_port 1.0;

require {
    type sshd_t;
    class tcp_socket name_bind;
}

dontaudit sshd_t port_type:tcp_socket name_bind;

# Compile and install
$ make -f /usr/share/selinux/devel/Makefile ssh_port.pp
$ semodule -i ssh_port.pp

Method 2: Runtime Label Override

For temporary changes (lost on reboot), relabel the port:

# Find current label
$ semanage port -l | grep ssh
ssh_port_t                     tcp      22

# Apply new label
$ sudo semanage port -a -t http_port_t -p tcp 22

Method 3: Complete Policy Rebuild

For advanced users with custom policy needs:

# Install policy sources
$ yum install selinux-policy-devel

# Locate port definitions (typically in *.if files)
$ grep -r "define(\ssh_port_t'" /usr/share/selinux/devel/

# Modify and rebuild entire policy
$ cd /usr/share/selinux/devel/
$ make clean
$ make -j$(nproc)
$ make install

Before removing policy-defined ports:

  • Critical services like SSH may fail to start
  • System updates may revert your changes
  • Other security subsystems might depend on these definitions

Always test changes in a non-production environment and maintain proper backups of your SELinux policy.