Red Hat Training
A Red Hat training course is available for RHEL 8
Securing networks
Configuring secured networks and network communication
Abstract
Making open source more inclusive
Red Hat is committed to replacing problematic language in our code, documentation, and web properties. We are beginning with these four terms: master, slave, blacklist, and whitelist. Because of the enormity of this endeavor, these changes will be implemented gradually over several upcoming releases. For more details, see our CTO Chris Wright’s message.
Providing feedback on Red Hat documentation
We appreciate your feedback on our documentation. Let us know how we can improve it.
Submitting comments on specific passages
- View the documentation in the Multi-page HTML format and ensure that you see the Feedback button in the upper right corner after the page fully loads.
- Use your cursor to highlight the part of the text that you want to comment on.
- Click the Add Feedback button that appears near the highlighted text.
- Add your feedback and click Submit.
Submitting feedback through Jira (account required)
- Log in to the Jira website.
- Click Create in the top navigation bar
- Enter a descriptive title in the Summary field.
- Enter your suggestion for improvement in the Description field. Include links to the relevant parts of the documentation.
- Click Create at the bottom of the dialogue.
Chapter 1. Using secure communications between two systems with OpenSSH
SSH (Secure Shell) is a protocol which provides secure communications between two systems using a client-server architecture and allows users to log in to server host systems remotely. Unlike other remote communication protocols, such as FTP or Telnet, SSH encrypts the login session, which prevents intruders to collect unencrypted passwords from the connection.
Red Hat Enterprise Linux includes the basic OpenSSH packages: the general openssh package, the openssh-server package and the openssh-clients package. Note that the OpenSSH packages require the OpenSSL package openssl-libs, which installs several important cryptographic libraries that enable OpenSSH to provide encrypted communications.
1.1. SSH and OpenSSH
SSH (Secure Shell) is a program for logging into a remote machine and executing commands on that machine. The SSH protocol provides secure encrypted communications between two untrusted hosts over an insecure network. You can also forward X11 connections and arbitrary TCP/IP ports over the secure channel.
The SSH protocol mitigates security threats, such as interception of communication between two systems and impersonation of a particular host, when you use it for remote shell login or file copying. This is because the SSH client and server use digital signatures to verify their identities. Additionally, all communication between the client and server systems is encrypted.
A host key authenticates hosts in the SSH protocol. Host keys are cryptographic keys that are generated automatically when OpenSSH is first installed, or when the host boots for the first time.
OpenSSH is an implementation of the SSH protocol supported by Linux, UNIX, and similar operating systems. It includes the core files necessary for both the OpenSSH client and server. The OpenSSH suite consists of the following user-space tools:
-
sshis a remote login program (SSH client). -
sshdis an OpenSSH SSH daemon. -
scpis a secure remote file copy program. -
sftpis a secure file transfer program. -
ssh-agentis an authentication agent for caching private keys. -
ssh-addadds private key identities tossh-agent. -
ssh-keygengenerates, manages, and converts authentication keys forssh. -
ssh-copy-idis a script that adds local public keys to theauthorized_keysfile on a remote SSH server. -
ssh-keyscangathers SSH public host keys.
Two versions of SSH currently exist: version 1, and the newer version 2. The OpenSSH suite in RHEL supports only SSH version 2. It has an enhanced key-exchange algorithm that is not vulnerable to exploits known in version 1.
OpenSSH, as one of core cryptographic subsystems of RHEL, uses system-wide crypto policies. This ensures that weak cipher suites and cryptographic algorithms are disabled in the default configuration. To modify the policy, the administrator must either use the update-crypto-policies command to adjust the settings or manually opt out of the system-wide crypto policies.
The OpenSSH suite uses two sets of configuration files: one for client programs (that is, ssh, scp, and sftp), and another for the server (the sshd daemon).
System-wide SSH configuration information is stored in the /etc/ssh/ directory. User-specific SSH configuration information is stored in ~/.ssh/ in the user’s home directory. For a detailed list of OpenSSH configuration files, see the FILES section in the sshd(8) man page.
Additional resources
-
Man pages listed by using the
man -k sshcommand - Using system-wide cryptographic policies
1.2. Configuring and starting an OpenSSH server
Use the following procedure for a basic configuration that might be required for your environment and for starting an OpenSSH server. Note that after the default RHEL installation, the sshd daemon is already started and server host keys are automatically created.
Prerequisites
-
The
openssh-serverpackage is installed.
Procedure
Start the
sshddaemon in the current session and set it to start automatically at boot time:# systemctl start sshd # systemctl enable sshd
To specify different addresses than the default
0.0.0.0(IPv4) or::(IPv6) for theListenAddressdirective in the/etc/ssh/sshd_configconfiguration file and to use a slower dynamic network configuration, add the dependency on thenetwork-online.targettarget unit to thesshd.serviceunit file. To achieve this, create the/etc/systemd/system/sshd.service.d/local.conffile with the following content:[Unit] Wants=network-online.target After=network-online.target
-
Review if OpenSSH server settings in the
/etc/ssh/sshd_configconfiguration file meet the requirements of your scenario. Optionally, change the welcome message that your OpenSSH server displays before a client authenticates by editing the
/etc/issuefile, for example:Welcome to ssh-server.example.com Warning: By accessing this server, you agree to the referenced terms and conditions.
Ensure that the
Banneroption is not commented out in/etc/ssh/sshd_configand its value contains/etc/issue:# less /etc/ssh/sshd_config | grep Banner Banner /etc/issueNote that to change the message displayed after a successful login you have to edit the
/etc/motdfile on the server. See thepam_motdman page for more information.Reload the
systemdconfiguration and restartsshdto apply the changes:# systemctl daemon-reload # systemctl restart sshd
Verification
Check that the
sshddaemon is running:# systemctl status sshd ● sshd.service - OpenSSH server daemon Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2019-11-18 14:59:58 CET; 6min ago Docs: man:sshd(8) man:sshd_config(5) Main PID: 1149 (sshd) Tasks: 1 (limit: 11491) Memory: 1.9M CGroup: /system.slice/sshd.service └─1149 /usr/sbin/sshd -D -oCiphers=aes128-ctr,aes256-ctr,aes128-cbc,aes256-cbc -oMACs=hmac-sha2-256,> Nov 18 14:59:58 ssh-server-example.com systemd[1]: Starting OpenSSH server daemon... Nov 18 14:59:58 ssh-server-example.com sshd[1149]: Server listening on 0.0.0.0 port 22. Nov 18 14:59:58 ssh-server-example.com sshd[1149]: Server listening on :: port 22. Nov 18 14:59:58 ssh-server-example.com systemd[1]: Started OpenSSH server daemon.Connect to the SSH server with an SSH client.
# ssh user@ssh-server-example.com ECDSA key fingerprint is SHA256:dXbaS0RG/UzlTTku8GtXSz0S1++lPegSy31v3L/FAEc. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'ssh-server-example.com' (ECDSA) to the list of known hosts. user@ssh-server-example.com's password:
Additional resources
-
sshd(8)andsshd_config(5)man pages.
1.3. Setting an OpenSSH server for key-based authentication
To improve system security, enforce key-based authentication by disabling password authentication on your OpenSSH server.
Prerequisites
-
The
openssh-serverpackage is installed. -
The
sshddaemon is running on the server.
Procedure
Open the
/etc/ssh/sshd_configconfiguration in a text editor, for example:# vi /etc/ssh/sshd_configChange the
PasswordAuthenticationoption tono:PasswordAuthentication no
On a system other than a new default installation, check that
PubkeyAuthentication nohas not been set and theChallengeResponseAuthenticationdirective is set tono. If you are connected remotely, not using console or out-of-band access, test the key-based login process before disabling password authentication.To use key-based authentication with NFS-mounted home directories, enable the
use_nfs_home_dirsSELinux boolean:# setsebool -P use_nfs_home_dirs 1Reload the
sshddaemon to apply the changes:# systemctl reload sshd
Additional resources
-
sshd(8),sshd_config(5), andsetsebool(8)man pages.
1.4. Generating SSH key pairs
Use this procedure to generate an SSH key pair on a local system and to copy the generated public key to an OpenSSH server. If the server is configured accordingly, you can log in to the OpenSSH server without providing any password.
If you complete the following steps as root, only root is able to use the keys.
Procedure
To generate an ECDSA key pair for version 2 of the SSH protocol:
$ ssh-keygen -t ecdsa Generating public/private ecdsa key pair. Enter file in which to save the key (/home/joesec/.ssh/id_ecdsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/joesec/.ssh/id_ecdsa. Your public key has been saved in /home/joesec/.ssh/id_ecdsa.pub. The key fingerprint is: SHA256:Q/x+qms4j7PCQ0qFd09iZEFHA+SqwBKRNaU72oZfaCI joesec@localhost.example.com The key's randomart image is: +---[ECDSA 256]---+ |.oo..o=++ | |.. o .oo . | |. .. o. o | |....o.+... | |o.oo.o +S . | |.=.+. .o | |E.*+. . . . | |.=..+ +.. o | | . oo*+o. | +----[SHA256]-----+You can also generate an RSA key pair by using the
-t rsaoption with thessh-keygencommand or an Ed25519 key pair by entering thessh-keygen -t ed25519command.To copy the public key to a remote machine:
$ ssh-copy-id joesec@ssh-server-example.com /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed joesec@ssh-server-example.com's password: ... Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'joesec@ssh-server-example.com'" and check to make sure that only the key(s) you wanted were added.If you do not use the
ssh-agentprogram in your session, the previous command copies the most recently modified~/.ssh/id*.pubpublic key if it is not yet installed. To specify another public-key file or to prioritize keys in files over keys cached in memory byssh-agent, use thessh-copy-idcommand with the-ioption.
If you reinstall your system and want to keep previously generated key pairs, back up the ~/.ssh/ directory. After reinstalling, copy it back to your home directory. You can do this for all users on your system, including root.
Verification
Log in to the OpenSSH server without providing any password:
$ ssh joesec@ssh-server-example.com Welcome message. ... Last login: Mon Nov 18 18:28:42 2019 from ::1
Additional resources
-
ssh-keygen(1)andssh-copy-id(1)man pages.
1.5. Using SSH keys stored on a smart card
Red Hat Enterprise Linux enables you to use RSA and ECDSA keys stored on a smart card on OpenSSH clients. Use this procedure to enable authentication using a smart card instead of using a password.
Prerequisites
-
On the client side, the
openscpackage is installed and thepcscdservice is running.
Procedure
List all keys provided by the OpenSC PKCS #11 module including their PKCS #11 URIs and save the output to the keys.pub file:
$ ssh-keygen -D pkcs11: > keys.pub $ ssh-keygen -D pkcs11: ssh-rsa AAAAB3NzaC1yc2E...KKZMzcQZzx pkcs11:id=%02;object=SIGN%20pubkey;token=SSH%20key;manufacturer=piv_II?module-path=/usr/lib64/pkcs11/opensc-pkcs11.so ecdsa-sha2-nistp256 AAA...J0hkYnnsM= pkcs11:id=%01;object=PIV%20AUTH%20pubkey;token=SSH%20key;manufacturer=piv_II?module-path=/usr/lib64/pkcs11/opensc-pkcs11.so
To enable authentication using a smart card on a remote server (example.com), transfer the public key to the remote server. Use the
ssh-copy-idcommand with keys.pub created in the previous step:$ ssh-copy-id -f -i keys.pub username@example.comTo connect to example.com using the ECDSA key from the output of the
ssh-keygen -Dcommand in step 1, you can use just a subset of the URI, which uniquely references your key, for example:$ ssh -i "pkcs11:id=%01?module-path=/usr/lib64/pkcs11/opensc-pkcs11.so" example.com Enter PIN for 'SSH key': [example.com] $You can use the same URI string in the
~/.ssh/configfile to make the configuration permanent:$ cat ~/.ssh/config IdentityFile "pkcs11:id=%01?module-path=/usr/lib64/pkcs11/opensc-pkcs11.so" $ ssh example.com Enter PIN for 'SSH key': [example.com] $
Because OpenSSH uses the
p11-kit-proxywrapper and the OpenSC PKCS #11 module is registered to PKCS#11 Kit, you can simplify the previous commands:$ ssh -i "pkcs11:id=%01" example.com Enter PIN for 'SSH key': [example.com] $
If you skip the id= part of a PKCS #11 URI, OpenSSH loads all keys that are available in the proxy module. This can reduce the amount of typing required:
$ ssh -i pkcs11: example.com
Enter PIN for 'SSH key':
[example.com] $Additional resources
- Fedora 28: Better smart card support in OpenSSH
-
p11-kit(8),opensc.conf(5),pcscd(8),ssh(1), andssh-keygen(1)man pages
1.6. Making OpenSSH more secure
The following tips help you to increase security when using OpenSSH. Note that changes in the /etc/ssh/sshd_config OpenSSH configuration file require reloading the sshd daemon to take effect:
# systemctl reload sshdThe majority of security hardening configuration changes reduce compatibility with clients that do not support up-to-date algorithms or cipher suites.
Disabling insecure connection protocols
- To make SSH truly effective, prevent the use of insecure connection protocols that are replaced by the OpenSSH suite. Otherwise, a user’s password might be protected using SSH for one session only to be captured later when logging in using Telnet. For this reason, consider disabling insecure protocols, such as telnet, rsh, rlogin, and ftp.
Enabling key-based authentication and disabling password-based authentication
Disabling passwords for authentication and allowing only key pairs reduces the attack surface and it also might save users’ time. On clients, generate key pairs using the
ssh-keygentool and use thessh-copy-idutility to copy public keys from clients on the OpenSSH server. To disable password-based authentication on your OpenSSH server, edit/etc/ssh/sshd_configand change thePasswordAuthenticationoption tono:PasswordAuthentication no
Key types
Although the
ssh-keygencommand generates a pair of RSA keys by default, you can instruct it to generate ECDSA or Ed25519 keys by using the-toption. The ECDSA (Elliptic Curve Digital Signature Algorithm) offers better performance than RSA at the equivalent symmetric key strength. It also generates shorter keys. The Ed25519 public-key algorithm is an implementation of twisted Edwards curves that is more secure and also faster than RSA, DSA, and ECDSA.OpenSSH creates RSA, ECDSA, and Ed25519 server host keys automatically if they are missing. To configure the host key creation in RHEL, use the
sshd-keygen@.serviceinstantiated service. For example, to disable the automatic creation of the RSA key type:# systemctl mask sshd-keygen@rsa.serviceNoteIn images with
cloud-initenabled, thessh-keygenunits are automatically disabled. This is because thessh-keygen templateservice can interfere with thecloud-inittool and cause problems with host key generation. To prevent these problems theetc/systemd/system/sshd-keygen@.service.d/disable-sshd-keygen-if-cloud-init-active.confdrop-in configuration file disables thessh-keygenunits ifcloud-initis running.To exclude particular key types for SSH connections, comment out the relevant lines in
/etc/ssh/sshd_config, and reload thesshdservice. For example, to allow only Ed25519 host keys:# HostKey /etc/ssh/ssh_host_rsa_key # HostKey /etc/ssh/ssh_host_ecdsa_key HostKey /etc/ssh/ssh_host_ed25519_key
ImportantThe Ed25519 algorithm is not FIPS-140-compliant, and OpenSSH does not work with Ed25519 keys in FIPS mode.
Non-default port
By default, the
sshddaemon listens on TCP port 22. Changing the port reduces the exposure of the system to attacks based on automated network scanning and therefore increase security through obscurity. You can specify the port using thePortdirective in the/etc/ssh/sshd_configconfiguration file.You also have to update the default SELinux policy to allow the use of a non-default port. To do so, use the
semanagetool from thepolicycoreutils-python-utilspackage:# semanage port -a -t ssh_port_t -p tcp <port_number>Furthermore, update
firewalldconfiguration:# firewall-cmd --add-port <port_number>/tcp # firewall-cmd --runtime-to-permanent
In the previous commands, replace <port_number> with the new port number specified using the
Portdirective.
No root login
If your particular use case does not require the possibility of logging in as the root user, you can set the
PermitRootLoginconfiguration directive tonoin the/etc/ssh/sshd_configfile. By disabling the possibility of logging in as the root user, the administrator can audit which users run what privileged commands after they log in as regular users and then gain root rights.Alternatively, set
PermitRootLogintoprohibit-password:PermitRootLogin prohibit-password
This enforces the use of key-based authentication instead of the use of passwords for logging in as root and reduces risks by preventing brute-force attacks.
Using the X Security extension
The X server in Red Hat Enterprise Linux clients does not provide the X Security extension. Therefore, clients cannot request another security layer when connecting to untrusted SSH servers with X11 forwarding. Most applications are not able to run with this extension enabled anyway.
By default, the
ForwardX11Trustedoption in the/etc/ssh/ssh_config.d/05-redhat.conffile is set toyes, and there is no difference between thessh -X remote_machine(untrusted host) andssh -Y remote_machine(trusted host) command.If your scenario does not require the X11 forwarding feature at all, set the
X11Forwardingdirective in the/etc/ssh/sshd_configconfiguration file tono.
Restricting access to specific users, groups, or domains
The
AllowUsersandAllowGroupsdirectives in the/etc/ssh/sshd_configconfiguration file server enable you to permit only certain users, domains, or groups to connect to your OpenSSH server. You can combineAllowUsersandAllowGroupsto restrict access more precisely, for example:AllowUsers *@192.168.1.*,*@10.0.0.*,!*@192.168.1.2 AllowGroups example-group
The previous configuration lines accept connections from all users from systems in 192.168.1.* and 10.0.0.* subnets except from the system with the 192.168.1.2 address. All users must be in the
example-groupgroup. The OpenSSH server denies all other connections.The OpenSSH server permits only connections that pass all Allow and Deny directives in
/etc/ssh/sshd_config. For example, if theAllowUsersdirective lists a user that is not part of a group listed in theAllowGroupsdirective, then the user cannot log in.Note that using allowlists (directives starting with Allow) is more secure than using blocklists (options starting with Deny) because allowlists block also new unauthorized users or groups.
Changing system-wide cryptographic policies
OpenSSH uses RHEL system-wide cryptographic policies, and the default system-wide cryptographic policy level offers secure settings for current threat models. To make your cryptographic settings more strict, change the current policy level:
# update-crypto-policies --set FUTURE Setting system policy to FUTUREWarningIf your system communicates on the internet, you might face interoperability problems due to the strict setting of the
FUTUREpolicy.
You can also disable only specific ciphers for the SSH protocol through the system-wide cryptographic policies. See the Customizing system-wide cryptographic policies with subpolicies section in the Security hardening document for more information.
To opt out of the system-wide cryptographic policies for your OpenSSH server, uncomment the line with the CRYPTO_POLICY= variable in the /etc/sysconfig/sshd file. After this change, values that you specify in the Ciphers, MACs, KexAlgoritms, and GSSAPIKexAlgorithms sections in the /etc/ssh/sshd_config file are not overridden.
See the sshd_config(5) man page for more information.
To opt out of system-wide cryptographic policies for your OpenSSH client, perform one of the following tasks:
-
For a given user, override the global
ssh_configwith a user-specific configuration in the~/.ssh/configfile. -
For the entire system, specify the cryptographic policy in a drop-in configuration file located in the
/etc/ssh/ssh_config.d/directory, with a two-digit number prefix smaller than 5, so that it lexicographically precedes the05-redhat.conffile, and with a.confsuffix, for example,04-crypto-policy-override.conf.
Additional resources
-
sshd_config(5),ssh-keygen(1),crypto-policies(7), andupdate-crypto-policies(8)man pages. - Using system-wide cryptographic policies in the Security hardening document.
- How to disable specific algorithms and ciphers for ssh service only article.
1.7. Connecting to a remote server using an SSH jump host
Use this procedure for connecting your local system to a remote server through an intermediary server, also called jump host.
Prerequisites
- A jump host accepts SSH connections from your local system.
- A remote server accepts SSH connections only from the jump host.
Procedure
Define the jump host by editing the
~/.ssh/configfile on your local system, for example:Host jump-server1 HostName jump1.example.com
-
The
Hostparameter defines a name or alias for the host you can use insshcommands. The value can match the real host name, but can also be any string. -
The
HostNameparameter sets the actual host name or IP address of the jump host.
-
The
Add the remote server jump configuration with the
ProxyJumpdirective to~/.ssh/configfile on your local system, for example:Host remote-server HostName remote1.example.com ProxyJump jump-server1
Use your local system to connect to the remote server through the jump server:
$ ssh remote-serverThe previous command is equivalent to the
ssh -J jump-server1 remote-servercommand if you omit the configuration steps 1 and 2.
You can specify more jump servers and you can also skip adding host definitions to the configurations file when you provide their complete host names, for example:
$ ssh -J jump1.example.com,jump2.example.com,jump3.example.com remote1.example.comChange the host name-only notation in the previous command if the user names or SSH ports on the jump servers differ from the names and ports on the remote server, for example:
$ ssh -J johndoe@jump1.example.com:75,johndoe@jump2.example.com:75,johndoe@jump3.example.com:75 joesec@remote1.example.com:220Additional resources
-
ssh_config(5)andssh(1)man pages.
1.8. Connecting to remote machines with SSH keys using ssh-agent
To avoid entering a passphrase each time you initiate an SSH connection, you can use the ssh-agent utility to cache the private SSH key. The private key and the passphrase remain secure.
Prerequisites
- You have a remote host with SSH daemon running and reachable through the network.
- You know the IP address or hostname and credentials to log in to the remote host.
- You have generated an SSH key pair with a passphrase and transferred the public key to the remote machine.
Procedure
Optional: Verify you can use the key to authenticate to the remote host:
Connect to the remote host using SSH:
$ ssh example.user1@198.51.100.1 hostnameEnter the passphrase you set while creating the key to grant access to the private key.
$ ssh example.user1@198.51.100.1 hostname host.example.com
Start the
ssh-agent.$ eval $(ssh-agent) Agent pid 20062Add the key to
ssh-agent.$ ssh-add ~/.ssh/id_rsa Enter passphrase for ~/.ssh/id_rsa: Identity added: ~/.ssh/id_rsa (example.user0@198.51.100.12)
Verification
Optional: Log in to the host machine using SSH.
$ ssh example.user1@198.51.100.1 Last login: Mon Sep 14 12:56:37 2020Note that you did not have to enter the passphrase.
1.9. Additional resources
-
sshd(8),ssh(1),scp(1),sftp(1),ssh-keygen(1),ssh-copy-id(1),ssh_config(5),sshd_config(5),update-crypto-policies(8), andcrypto-policies(7)man pages. - OpenSSH Home Page
- Configuring SELinux for applications and services with non-standard configurations
- Controlling network traffic using firewalld
Chapter 2. Configuring secure communication with the ssh System Roles
As an administrator, you can use the sshd System Role to configure SSH servers and the ssh System Role to configure SSH clients consistently on any number of RHEL systems at the same time by using Red Hat Ansible Automation Platform.
2.1. ssh Server System Role variables
In an sshd System Role playbook, you can define the parameters for the SSH configuration file according to your preferences and limitations.
If you do not configure these variables, the System Role produces an sshd_config file that matches the RHEL defaults.
In all cases, Booleans correctly render as yes and no in sshd configuration. You can define multi-line configuration items using lists. For example:
sshd_ListenAddress: - 0.0.0.0 - '::'
renders as:
ListenAddress 0.0.0.0 ListenAddress ::
Variables for the sshd System Role
sshd_enable-
If set to
false, the role is completely disabled. Defaults totrue. sshd_skip_defaults-
If set to
true, the System Role does not apply default values. Instead, you specify the complete set of configuration defaults by using either thesshddictionary orsshd_<OptionName>variables. Defaults tofalse. sshd_manage_service-
If set to
false, the service is not managed, which means it is not enabled on boot and does not start or reload. Defaults totrueexcept when running inside a container or AIX, because the Ansible service module does not currently supportenabledfor AIX. sshd_allow_reload-
If set to
false,sshddoes not reload after a change of configuration. This can help with troubleshooting. To apply the changed configuration, reloadsshdmanually. Defaults to the same value assshd_manage_serviceexcept on AIX, wheresshd_manage_servicedefaults tofalsebutsshd_allow_reloaddefaults totrue. sshd_install_serviceIf set to
true, the role installs service files for thesshdservice. This overrides files provided in the operating system. Do not set totrueunless you are configuring a second instance and you also change thesshd_servicevariable. Defaults tofalse.The role uses the files pointed by the following variables as templates:
sshd_service_template_service (default: templates/sshd.service.j2) sshd_service_template_at_service (default: templates/sshd@.service.j2) sshd_service_template_socket (default: templates/sshd.socket.j2)
sshd_service-
This variable changes the
sshdservice name, which is useful for configuring a secondsshdservice instance. sshdA dictionary that contains configuration. For example:
sshd: Compression: yes ListenAddress: - 0.0.0.0The
sshd_config(5)lists all options for thesshddictionary.sshd_<OptionName>You can define options by using simple variables consisting of the
sshd_prefix and the option name instead of a dictionary. The simple variables override values in thesshddictionary. For example:sshd_Compression: no
The
sshd_config(5)lists all options forsshd.sshd_manage_firewallSet this variable to
trueif you are using a different port than the default port22. When set totrue, thesshdrole uses thefirewallrole to automatically manage port access.NoteThe
sshd_manage_firewallvariable can only add ports. It cannot remove ports. To remove ports, use thefirewallSystem Role directly. For more information about managing ports by using thefirewallSystem Role, see Configuring ports by using System Roles.sshd_manage_selinuxSet this variable to
trueif you are using a different port than the default port22. When set totrue, thesshdrole uses theselinuxrole to automatically manage port access.NoteThe
sshd_manage_selinuxvariable can only add ports. It cannot remove ports. To remove ports, use theselinuxSystem Role directly.sshd_matchandsshd_match_1tosshd_match_9-
A list of dictionaries or just a dictionary for a Match section. Note that these variables do not override match blocks as defined in the
sshddictionary. All of the sources will be reflected in the resulting configuration file. sshd_backup-
When set to
false, the originalsshd_configfile is not backed up. Default istrue.
Secondary variables for the sshd System Role
You can use these variables to override the defaults that correspond to each supported platform.
sshd_packages- You can override the default list of installed packages using this variable.
sshd_config_owner,sshd_config_group, andsshd_config_mode-
You can set the ownership and permissions for the
opensshconfiguration file that this role produces using these variables. sshd_config_file-
The path where this role saves the
opensshserver configuration produced. sshd_config_namespaceThe default value of this variable is null, which means that the role defines the entire content of the configuration file including system defaults. Alternatively, you can use this variable to invoke this role from other roles or from multiple places in a single playbook on systems that do not support drop-in directory. The
sshd_skip_defaultsvariable is ignored and no system defaults are used in this case.When this variable is set, the role places the configuration that you specify to configuration snippets in an existing configuration file under the given namespace. If your scenario requires applying the role several times, you need to select a different namespace for each application.
NoteLimitations of the
opensshconfiguration file still apply. For example, only the first option specified in a configuration file is effective for most of the configuration options.Technically, the role places snippets in "Match all" blocks, unless they contain other match blocks, to ensure they are applied regardless of the previous match blocks in the existing configuration file. This allows configuring any non-conflicting options from different roles invocations.
sshd_binary-
The path to the
sshdexecutable ofopenssh. sshd_service-
The name of the
sshdservice. By default, this variable contains the name of thesshdservice that the target platform uses. You can also use it to set the name of the customsshdservice when the role uses thesshd_install_servicevariable. sshd_verify_hostkeys-
Defaults to
auto. When set toauto, this lists all host keys that are present in the produced configuration file, and generates any paths that are not present. Additionally, permissions and file owners are set to default values. This is useful if the role is used in the deployment stage to verify the service is able to start on the first attempt. To disable this check, set this variable to an empty list[]. sshd_hostkey_owner,sshd_hostkey_group,sshd_hostkey_mode-
Use these variables to set the ownership and permissions for the host keys from
sshd_verify_hostkeys. sshd_sysconfig-
On systems based on RHEL 8 and earlier versions, this variable configures additional details of the
sshdservice. If set totrue, this role manages also the/etc/sysconfig/sshdconfiguration file based on thesshd_sysconfig_override_crypto_policyandsshd_sysconfig_use_strong_rngvariables. Defaults tofalse. sshd_sysconfig_override_crypto_policyIn RHEL 8, setting it to
trueallows overriding the system-wide cryptographic policy by using the following configuration options in thesshddictionary or in thesshd_<OptionName>format:-
Ciphers -
MACs -
GSSAPIKexAlgorithms -
GSSAPIKeyExchange(FIPS-only) -
KexAlgorithms -
HostKeyAlgorithms -
PubkeyAcceptedKeyTypes CASignatureAlgorithmsDefaults to
false.In RHEL 9, this variable has no effect. Instead, you can override system-wide cryptographic policies by using the following configuration options in the
sshddictionary or in thesshd_<OptionName>format:-
Ciphers -
MACs -
GSSAPIKexAlgorithms -
GSSAPIKeyExchange(FIPS-only) -
KexAlgorithms -
HostKeyAlgorithms -
PubkeyAcceptedAlgorithms -
HostbasedAcceptedAlgorithms -
CASignatureAlgorithms RequiredRSASizeIf you enter these options into custom configuration files in the drop-in directory defined in the
sshd_config_filevariable, use a file name that lexicographically precedes the/etc/ssh/sshd_config.d/50-redhat.conffile that includes the cryptographic policies.
-
sshd_sysconfig_use_strong_rng-
On systems based on RHEL 8 and earlier versions, this variable can force
sshdto reseed theopensslrandom number generator with the number of bytes given as the argument. The default is0, which disables this functionality. Do not turn this on if the system does not have a hardware random number generator.
2.2. Configuring OpenSSH servers using the sshd System Role
You can use the sshd System Role to configure multiple SSH servers by running an Ansible playbook.
You can use the sshd System Role with other System Roles that change SSH and SSHD configuration, for example the Identity Management RHEL System Roles. To prevent the configuration from being overwritten, make sure that the sshd role uses namespaces (RHEL 8 and earlier versions) or a drop-in directory (RHEL 9).
Prerequisites
-
Access and permissions to one or more managed nodes, which are systems you want to configure with the
sshdSystem Role. Access and permissions to a control node, which is a system from which Red Hat Ansible Core configures other systems.
On the control node:
-
The
ansible-coreandrhel-system-rolespackages are installed.
-
The
RHEL 8.0-8.5 provided access to a separate Ansible repository that contains Ansible Engine 2.9 for automation based on Ansible. Ansible Engine contains command-line utilities such as ansible, ansible-playbook, connectors such as docker and podman, and many plugins and modules. For information about how to obtain and install Ansible Engine, see the How to download and install Red Hat Ansible Engine Knowledgebase article.
RHEL 8.6 and 9.0 have introduced Ansible Core (provided as the ansible-core package), which contains the Ansible command-line utilities, commands, and a small set of built-in Ansible plugins. RHEL provides this package through the AppStream repository, and it has a limited scope of support. For more information, see the Scope of support for the Ansible Core package included in the RHEL 9 and RHEL 8.6 and later AppStream repositories Knowledgebase article.
- An inventory file which lists the managed nodes.
Procedure
Copy the example playbook for the
sshdSystem Role:# cp /usr/share/doc/rhel-system-roles/sshd/example-root-login-playbook.yml path/custom-playbook.ymlOpen the copied playbook by using a text editor, for example:
# vim path/custom-playbook.yml --- - hosts: all tasks: - name: Configure sshd to prevent root and password login except from particular subnet include_role: name: rhel-system-roles.sshd vars: sshd: # root login and password login is enabled only from a particular subnet PermitRootLogin: no PasswordAuthentication: no Match: - Condition: "Address 192.0.2.0/24" PermitRootLogin: yes PasswordAuthentication: yesThe playbook configures the managed node as an SSH server configured so that:
-
password and
rootuser login is disabled -
password and
rootuser login is enabled only from the subnet192.0.2.0/24
You can modify the variables according to your preferences. For more details, see sshd System Role variables.
-
password and
Optional: Verify playbook syntax.
# ansible-playbook --syntax-check path/custom-playbook.ymlRun the playbook on your inventory file:
# ansible-playbook -i inventory_file path/custom-playbook.yml ... PLAY RECAP ************************************************** localhost : ok=12 changed=2 unreachable=0 failed=0 skipped=10 rescued=0 ignored=0
Verification
Log in to the SSH server:
$ ssh user1@10.1.1.1Where:
-
user1is a user on the SSH server. -
10.1.1.1is the IP address of the SSH server.
-
Check the contents of the
sshd_configfile on the SSH server:$ cat /etc/ssh/sshd_config … PasswordAuthentication no PermitRootLogin no … Match Address 192.0.2.0/24 PasswordAuthentication yes PermitRootLogin yes …Check that you can connect to the server as root from the
192.0.2.0/24subnet:Determine your IP address:
$ hostname -I 192.0.2.1If the IP address is within the
192.0.2.1-192.0.2.254range, you can connect to the server.Connect to the server as
root:$ ssh root@10.1.1.1
Additional resources
-
/usr/share/doc/rhel-system-roles/sshd/README.mdfile. -
ansible-playbook(1)man page.
2.3. ssh System Role variables
In an ssh System Role playbook, you can define the parameters for the client SSH configuration file according to your preferences and limitations.
If you do not configure these variables, the System Role produces a global ssh_config file that matches the RHEL defaults.
In all cases, booleans correctly render as yes or no in ssh configuration. You can define multi-line configuration items using lists. For example:
LocalForward: - 22 localhost:2222 - 403 localhost:4003
renders as:
LocalForward 22 localhost:2222 LocalForward 403 localhost:4003
The configuration options are case sensitive.
Variables for the ssh System Role
ssh_user-
You can define an existing user name for which the System Role modifies user-specific configuration. The user-specific configuration is saved in
~/.ssh/configof the given user. The default value is null, which modifies global configuration for all users. ssh_skip_defaults-
Defaults to
auto. If set toauto, the System Role writes the system-wide configuration file/etc/ssh/ssh_configand keeps the RHEL defaults defined there. Creating a drop-in configuration file, for example by defining thessh_drop_in_namevariable, automatically disables thessh_skip_defaultsvariable. ssh_drop_in_nameDefines the name for the drop-in configuration file, which is placed in the system-wide drop-in directory. The name is used in the template
/etc/ssh/ssh_config.d/{ssh_drop_in_name}.confto reference the configuration file to be modified. If the system does not support drop-in directory, the default value is null. If the system supports drop-in directories, the default value is00-ansible.WarningIf the system does not support drop-in directories, setting this option will make the play fail.
The suggested format is
NN-name, whereNNis a two-digit number used for ordering the configuration files andnameis any descriptive name for the content or the owner of the file.ssh- A dict that contains configuration options and their respective values.
ssh_OptionName-
You can define options by using simple variables consisting of the
ssh_prefix and the option name instead of a dict. The simple variables override values in thesshdict. ssh_additional_packages-
This role automatically installs the
opensshandopenssh-clientspackages, which are needed for the most common use cases. If you need to install additional packages, for example,openssh-keysignfor host-based authentication, you can specify them in this variable. ssh_config_fileThe path to which the role saves the configuration file produced. Default value:
-
If the system has a drop-in directory, the default value is defined by the template
/etc/ssh/ssh_config.d/{ssh_drop_in_name}.conf. -
If the system does not have a drop-in directory, the default value is
/etc/ssh/ssh_config. -
if the
ssh_uservariable is defined, the default value is~/.ssh/config.
-
If the system has a drop-in directory, the default value is defined by the template
ssh_config_owner,ssh_config_group,ssh_config_mode-
The owner, group and modes of the created configuration file. By default, the owner of the file is
root:root, and the mode is0644. Ifssh_useris defined, the mode is0600, and the owner and group are derived from the user name specified in thessh_uservariable.
2.4. Configuring OpenSSH clients using the ssh System Role
You can use the ssh System Role to configure multiple SSH clients by running an Ansible playbook.
You can use the ssh System Role with other System Roles that change SSH and SSHD configuration, for example the Identity Management RHEL System Roles. To prevent the configuration from being overwritten, make sure that the ssh role uses a drop-in directory (default from RHEL 8).
Prerequisites
-
Access and permissions to one or more managed nodes, which are systems you want to configure with the
sshSystem Role. Access and permissions to a control node, which is a system from which Red Hat Ansible Core configures other systems.
On the control node:
-
The
ansible-coreandrhel-system-rolespackages are installed.
-
The
RHEL 8.0-8.5 provided access to a separate Ansible repository that contains Ansible Engine 2.9 for automation based on Ansible. Ansible Engine contains command-line utilities such as ansible, ansible-playbook, connectors such as docker and podman, and many plugins and modules. For information about how to obtain and install Ansible Engine, see the How to download and install Red Hat Ansible Engine Knowledgebase article.
RHEL 8.6 and 9.0 have introduced Ansible Core (provided as the ansible-core package), which contains the Ansible command-line utilities, commands, and a small set of built-in Ansible plugins. RHEL provides this package through the AppStream repository, and it has a limited scope of support. For more information, see the Scope of support for the Ansible Core package included in the RHEL 9 and RHEL 8.6 and later AppStream repositories Knowledgebase article.
- An inventory file which lists the managed nodes.
Procedure
Create a new
playbook.ymlfile with the following content:--- - hosts: all tasks: - name: "Configure ssh clients" include_role: name: rhel-system-roles.ssh vars: ssh_user: root ssh: Compression: true GSSAPIAuthentication: no ControlMaster: auto ControlPath: ~/.ssh/.cm%C Host: - Condition: example Hostname: example.com User: user1 ssh_ForwardX11: noThis playbook configures the
rootuser’s SSH client preferences on the managed nodes with the following configurations:- Compression is enabled.
-
ControlMaster multiplexing is set to
auto. -
The
examplealias for connecting to theexample.comhost isuser1. -
The
examplehost alias is created, which represents a connection to theexample.comhost the withuser1user name. - X11 forwarding is disabled.
Optionally, you can modify these variables according to your preferences. For more details, see ssh System Role variables.
Optional: Verify playbook syntax.
# ansible-playbook --syntax-check path/custom-playbook.ymlRun the playbook on your inventory file:
# ansible-playbook -i inventory_file path/custom-playbook.yml
Verification
Verify that the managed node has the correct configuration by opening the SSH configuration file in a text editor, for example:
# vi ~root/.ssh/configAfter application of the example playbook shown above, the configuration file should have the following content:
# Ansible managed Compression yes ControlMaster auto ControlPath ~/.ssh/.cm%C ForwardX11 no GSSAPIAuthentication no Host example Hostname example.com User user1
2.5. Using the sshd System Role for non-exclusive configuration
Normally, applying the sshd System Role overwrites the entire configuration. This may be problematic if you have previously adjusted the configuration, for example with a different System Role or playbook. To apply the sshd System Role for only selected configuration options while keeping other options in place, you can use the non-exclusive configuration.
In RHEL 8 and earlier, you can apply the non-exclusive configuration with a configuration snippet.
Prerequisites
-
Access and permissions to one or more managed nodes, which are systems you want to configure with the
sshdSystem Role. Access and permissions to a control node, which is a system from which Red Hat Ansible Core configures other systems.
On the control node:
-
The
ansible-corepackage is installed. - An inventory file which lists the managed nodes.
- A playbook for a different RHEL System Role.
-
The
Procedure
Add a configuration snippet with the
sshd_config_namespacevariable to the playbook:--- - hosts: all tasks: - name: <Configure SSHD to accept some useful environment variables> include_role: name: rhel-system-roles.sshd vars: sshd_config_namespace: <my-application> sshd: # Environment variables to accept AcceptEnv: LANG LS_COLORS EDITOR
When you apply the playbook to the inventory, the role adds the following snippet, if not already present, to the
/etc/ssh/sshd_configfile.# BEGIN sshd system role managed block: namespace <my-application> Match all AcceptEnv LANG LS_COLORS EDITOR # END sshd system role managed block: namespace <my-application>
Verification
Optional: Verify playbook syntax.
# ansible-playbook --syntax-check playbook.yml -i inventory_file
Additional resources
-
/usr/share/doc/rhel-system-roles/sshd/README.mdfile. -
ansible-playbook(1)man page.
Chapter 3. Creating and managing TLS keys and certificates
You can encrypt communication transmitted between two systems by using the TLS (Transport Layer Security) protocol. This standard uses asymmetric cryptography with private and public keys, digital signatures, and certificates.
3.1. TLS certificates
TLS (Transport Layer Security) is a protocol that enables client-server applications to pass information securely. TLS uses a system of public and private key pairs to encrypt communication transmitted between clients and servers. TLS is the successor protocol to SSL (Secure Sockets Layer).
TLS uses X.509 certificates to bind identities, such as hostnames or organizations, to public keys using digital signatures. X.509 is a standard that defines the format of public key certificates.
Authentication of a secure application depends on the integrity of the public key value in the application’s certificate. If an attacker replaces the public key with its own public key, it can impersonate the true application and gain access to secure data. To prevent this type of attack, all certificates must be signed by a certification authority (CA). A CA is a trusted node that confirms the integrity of the public key value in a certificate.
A CA signs a public key by adding its digital signature and issues a certificate. A digital signature is a message encoded with the CA’s private key. The CA’s public key is made available to applications by distributing the certificate of the CA. Applications verify that certificates are validly signed by decoding the CA’s digital signature with the CA’s public key.
To have a certificate signed by a CA, you must generate a public key, and send it to a CA for signing. This is referred to as a certificate signing request (CSR). A CSR contains also a distinguished name (DN) for the certificate. The DN information that you can provide for either type of certificate can include a two-letter country code for your country, a full name of your state or province, your city or town, a name of your organization, your email address, and it can also be empty. Many current commercial CAs prefer the Subject Alternative Name extension and ignore DNs in CSRs.
RHEL provides two main toolkits for working with TLS certificates: GnuTLS and OpenSSL. You can create, read, sign, and verify certificates using the openssl utility from the openssl package. The certtool utility provided by the gnutls-utils package can do the same operations using a different syntax and above all a different set of libraries in the back end.
Additional resources
- RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
-
openssl(1),x509(1),ca(1),req(1), andcerttool(1)man pages
3.2. Creating a private CA using OpenSSL
Private certificate authorities (CA) are useful when your scenario requires verifying entities within your internal network. For example, use a private CA when you create a VPN gateway with authentication based on certificates signed by a CA under your control or when you do not want to pay a commercial CA. To sign certificates in such use cases, the private CA uses a self-signed certificate.
Prerequisites
-
You have
rootprivileges or permissions to enter administrative commands withsudo. Commands that require such privileges are marked with#.
Procedure
Generate a private key for your CA. For example, the following command creates a 256-bit Elliptic Curve Digital Signature Algorithm (ECDSA) key:
$ openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out <ca.key>The time for the key-generation process depends on the hardware and entropy of the host, the selected algorithm, and the length of the key.
Create a certificate signed using the private key generated in the previous command:
$ openssl req -key <ca.key> -new -x509 -days 3650 -addext keyUsage=critical,keyCertSign,cRLSign -subj "/CN=<Example CA>" -out <ca.crt>The generated
ca.crtfile is a self-signed CA certificate that you can use to sign other certificates for ten years. In the case of a private CA, you can replace <Example CA> with any string as the common name (CN).Set secure permissions on the private key of your CA, for example:
# chown <root>:<root> <ca.key> # chmod 600 <ca.key>
Next steps
To use a self-signed CA certificate as a trust anchor on client systems, copy the CA certificate to the client and add it to the clients' system-wide truststore as
root:# trust anchor <ca.crt>See Chapter 4, Using shared system certificates for more information.
Verification
Create a certificate signing request (CSR), and use your CA to sign the request. The CA must successfully create a certificate based on the CSR, for example:
$ openssl x509 -req -in <client-cert.csr> -CA <ca.crt> -CAkey <ca.key> -CAcreateserial -days 365 -extfile <openssl.cnf> -extensions <client-cert> -out <client-cert.crt> Signature ok subject=C = US, O = Example Organization, CN = server.example.com Getting CA Private KeySee Section 3.5, “Using a private CA to issue certificates for CSRs with OpenSSL” for more information.
Display the basic information about your self-signed CA:
$ openssl x509 -in <ca.crt> -text -noout Certificate: … X509v3 extensions: … X509v3 Basic Constraints: critical CA:TRUE X509v3 Key Usage: critical Certificate Sign, CRL Sign …Verify the consistency of the private key:
$ openssl pkey -check -in <ca.key> Key is valid -----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgcagSaTEBn74xZAwO 18wRpXoCVC9vcPki7WlT+gnmCI+hRANCAARb9NxIvkaVjFhOoZbGp/HtIQxbM78E lwbDP0BI624xBJ8gK68ogSaq2x4SdezFdV1gNeKScDcU+Pj2pELldmdF -----END PRIVATE KEY-----
Additional resources
-
openssl(1),ca(1),genpkey(1),x509(1), andreq(1)man pages
3.3. Creating a private key and a CSR for a TLS server certificate using OpenSSL
You can use TLS-encrypted communication channels only if you have a valid TLS certificate from a certificate authority (CA). To obtain the certificate, you must create a private key and a certificate signing request (CSR) for your server first.
Procedure
Generate a private key on your server system, for example:
$ openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out <server-private.key>Optional: Use a text editor of your choice to prepare a configuration file that simplifies creating your CSR, for example:
$ vim <example_server.cnf> [server-cert] keyUsage = critical, digitalSignature, keyEncipherment, keyAgreement extendedKeyUsage = serverAuth subjectAltName = @alt_name [req] distinguished_name = dn prompt = no [dn] C = <US> O = <Example Organization> CN = <server.example.com> [alt_name] DNS.1 = <example.com> DNS.2 = <server.example.com> IP.1 = <192.168.0.1> IP.2 = <::1> IP.3 = <127.0.0.1>
The
extendedKeyUsage = serverAuthoption limits the use of a certificate.Create a CSR using the private key you created previously:
$ openssl req -key <server-private.key> -config <example_server.cnf> -new -out <server-cert.csr>If you omit the
-configoption, therequtility prompts you for additional information, for example:You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]: <US> State or Province Name (full name) []: <Washington> Locality Name (eg, city) [Default City]: <Seattle> Organization Name (eg, company) [Default Company Ltd]: <Example Organization> Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []: <server.example.com> Email Address []: <server@example.com>
Next steps
- Submit the CSR to a CA of your choice for signing. Alternatively, for an internal use scenario within a trusted network, use your private CA for signing. See Section 3.5, “Using a private CA to issue certificates for CSRs with OpenSSL” for more information.
Verification
After you obtain the requested certificate from the CA, check that the human-readable parts of the certificate match your requirements, for example:
$ openssl x509 -text -noout -in <server-cert.crt> Certificate: … Issuer: CN = Example CA Validity Not Before: Feb 2 20:27:29 2023 GMT Not After : Feb 2 20:27:29 2024 GMT Subject: C = US, O = Example Organization, CN = server.example.com Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) … X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment, Key Agreement X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Subject Alternative Name: DNS:example.com, DNS:server.example.com, IP Address:192.168.0.1, IP …
Additional resources
-
openssl(1),x509(1),genpkey(1),req(1), andconfig(5)man pages
3.4. Creating a private key and a CSR for a TLS client certificate using OpenSSL
You can use TLS-encrypted communication channels only if you have a valid TLS certificate from a certificate authority (CA). To obtain the certificate, you must create a private key and a certificate signing request (CSR) for your client first.
Procedure
Generate a private key on your client system, for example:
$ openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out <client-private.key>Optional: Use a text editor of your choice to prepare a configuration file that simplifies creating your CSR, for example:
$ vim <example_client.cnf> [client-cert] keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth subjectAltName = @alt_name [req] distinguished_name = dn prompt = no [dn] CN = <client.example.com> [clnt_alt_name] email= <client@example.com>
The
extendedKeyUsage = clientAuthoption limits the use of a certificate.Create a CSR using the private key you created previously:
$ openssl req -key <client-private.key> -config <example_client.cnf> -new -out <client-cert.csr>If you omit the
-configoption, therequtility prompts you for additional information, for example:You are about to be asked to enter information that will be incorporated into your certificate request. … Common Name (eg, your name or your server's hostname) []: <client.example.com> Email Address []: <client@example.com>
Next steps
- Submit the CSR to a CA of your choice for signing. Alternatively, for an internal use scenario within a trusted network, use your private CA for signing. See Section 3.5, “Using a private CA to issue certificates for CSRs with OpenSSL” for more information.
Verification
Check that the human-readable parts of the certificate match your requirements, for example:
$ openssl x509 -text -noout -in <client-cert.crt> Certificate: … X509v3 Extended Key Usage: TLS Web Client Authentication X509v3 Subject Alternative Name: email:client@example.com …
Additional resources
-
openssl(1),x509(1),genpkey(1),req(1), andconfig(5)man pages
3.5. Using a private CA to issue certificates for CSRs with OpenSSL
To enable systems to establish a TLS-encrypted communication channel, a certificate authority (CA) must provide valid certificates to them. If you have a private CA, you can create the requested certificates by signing certificate signing requests (CSRs) from the systems.
Prerequisites
- You have already configured a private CA. See Section 3.2, “Creating a private CA using OpenSSL” for more information.
- You have a file containing a CSR. You can find an example of creating the CSR in Section 3.3, “Creating a private key and a CSR for a TLS server certificate using OpenSSL” .
Procedure
Optional: Use a text editor of your choice to prepare an OpenSSL configuration file for adding extensions to certificates, for example:
$ vim <openssl.cnf> [server-cert] extendedKeyUsage = serverAuth [client-cert] extendedKeyUsage = clientAuthUse the
x509utility to create a certificate based on a CSR, for example:$ openssl x509 -req -in <server-cert.csr> -CA <ca.crt> -CAkey <ca.key> -CAcreateserial -days 365 -extfile <openssl.cnf> -extensions <server-cert> -out <server-cert.crt> Signature ok subject=C = US, O = Example Organization, CN = server.example.com Getting CA Private KeyTo increase security, delete the serial-number file before you create another certificate from a CSR. This way, you ensure that the serial number is always random. If you omit the
CAserialoption for specifying a custom file name, the serial-number file name is the same as the file name of the certificate, but its extension is replaced with the.srlextension (server-cert.srlin the previous example).
Additional resources
-
openssl(1),ca(1), andx509(1)man pages
3.6. Creating a private CA using GnuTLS
Private certificate authorities (CA) are useful when your scenario requires verifying entities within your internal network. For example, use a private CA when you create a VPN gateway with authentication based on certificates signed by a CA under your control or when you do not want to pay a commercial CA. To sign certificates in such use cases, the private CA uses a self-signed certificate.
Prerequisites
-
You have
rootprivileges or permissions to enter administrative commands withsudo. Commands that require such privileges are marked with#. You have already installed GnuTLS on your system. If you did not, you can use this command:
$ yum install gnutls-utils
Procedure
Generate a private key for your CA. For example, the following command creates a 256-bit ECDSA (Elliptic Curve Digital Signature Algorithm) key:
$ certtool --generate-privkey --sec-param High --key-type=ecdsa --outfile <ca.key>The time for the key-generation process depends on the hardware and entropy of the host, the selected algorithm, and the length of the key.
Create a template file for a certificate.
Create a file with your favourite text editor, for example, vi:
$ vi <ca.cfg>Edit the file to include the necessary certification details:
organization = "Example Inc." state = "Example" country = EX cn = "Example CA" serial = 007 expiration_days = 365 ca cert_signing_key crl_signing_key
Create a certificate signed using the private key generated in step 1:
The generated <ca.crt> file is a self-signed CA certificate that you can use to sign other certificates for one year. <ca.crt> file is the public key (certificate). The loaded file <ca.key> is the private key. You should keep this file in safe location.
$ certtool --generate-self-signed --load-privkey <ca.key> --template <ca.cfg> --outfile <ca.crt>Set secure permissions on the private key of your CA, for example:
# chown <root>:<root> <ca.key> # chmod 600 <ca.key>
Next steps
To use a self-signed CA certificate as a trust anchor on client systems, copy the CA certificate to the client and add it to the clients' system-wide truststore as
root:# trust anchor <ca.crt>See Chapter 4, Using shared system certificates for more information.
Verification
Display the basic information about your self-signed CA:
$ certtool --certificate-info --infile <ca.crt> Certificate: … X509v3 extensions: … X509v3 Basic Constraints: critical CA:TRUE X509v3 Key Usage: critical Certificate Sign, CRL SignCreate a certificate signing request (CSR), and use your CA to sign the request. The CA must successfully create a certificate based on the CSR, for example:
Generate a private key for your CA:
$ certtool --generate-privkey --outfile <example-server.key>Create a file with your favourite text editor, for example, vi:
$ vi <example-server.cfg>Edit the file to include the necessary certification details:
signing_key encryption_key key_agreement tls_www_server country = "US" organization = "Example Organization" cn = "server.example.com" dns_name = "example.com" dns_name = "server.example.com" ip_address = "192.168.0.1" ip_address = "::1" ip_address = "127.0.0.1"
Generate a request with the previously created private key
$ certtool --generate-request --load-privkey <example-server.key> --template <example-server.cfg> --outfile <example-server.crq>Generate the certificate and sign it with private key of the CA:
$ certtool --generate-certificate --load-request <example-server.crq> --load-privkey <example-server.key> --load-ca-certificate <ca.crt> --load-ca-privkey <ca.key> --outfile <example-server.crt>Additional resources
-
certtool(1)andtrust(1)man pages
-
3.7. Creating a private key and a CSR for a TLS server certificate using GnuTLS
To obtain the certificate, you must create a private key and a certificate signing request (CSR) for your server first.
Procedure
Generate a private key on your server system, for example:
$ certtool --generate-privkey --sec-param High --outfile <example-server.key>Optional: Use a text editor of your choice to prepare a configuration file that simplifies creating your CSR, for example:
$ vim <example_server.cnf> signing_key encryption_key key_agreement tls_www_server country = "US" organization = "Example Organization" cn = "server.example.com" dns_name = "example.com" dns_name = "server.example.com" ip_address = "192.168.0.1" ip_address = "::1" ip_address = "127.0.0.1"Create a CSR using the private key you created previously:
$ certtool --generate-request --template <example-server.cfg> --load-privkey <example-server.key> --outfile <example-server.crq>If you omit the
--templateoption, thecertoolutility prompts you for additional information, for example:You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Generating a PKCS #10 certificate request... Country name (2 chars): <US> State or province name: <Washington> Locality name: <Seattle> Organization name: <Example Organization> Organizational unit name: Common name: <server.example.com>
Next steps
- Submit the CSR to a CA of your choice for signing. Alternatively, for an internal use scenario within a trusted network, use your private CA for signing. See Section 3.9, “Using a private CA to issue certificates for CSRs with GnuTLS” for more information.
Verification
After you obtain the requested certificate from the CA, check that the human-readable parts of the certificate match your requirements, for example:
$ certtool --certificate-info --infile <example-server.crt> Certificate: … Issuer: CN = Example CA Validity Not Before: Feb 2 20:27:29 2023 GMT Not After : Feb 2 20:27:29 2024 GMT Subject: C = US, O = Example Organization, CN = server.example.com Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) … X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment, Key Agreement X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Subject Alternative Name: DNS:example.com, DNS:server.example.com, IP Address:192.168.0.1, IP …
Additional resources
-
certtool(1)man page
3.8. Creating a private key and a CSR for a TLS client certificate using GnuTLS
To obtain the certificate, you must create a private key and a certificate signing request (CSR) for your client first.
Procedure
Generate a private key on your client system, for example:
$ certtool --generate-privkey --sec-param High --outfile <example-client.key>Optional: Use a text editor of your choice to prepare a configuration file that simplifies creating your CSR, for example:
$ vim <example_client.cnf> signing_key encryption_key tls_www_client cn = "client.example.com" email = "client@example.com"Create a CSR using the private key you created previously:
$ certtool --generate-request --template <example-client.cfg> --load-privkey <example-client.key> --outfile <example-client.crq>If you omit the
--templateoption, thecerttoolutility prompts you for additional information, for example:Generating a PKCS #10 certificate request... Country name (2 chars): <US> State or province name: <Washington> Locality name: <Seattle> Organization name: <Example Organization> Organizational unit name: Common name: <server.example.com>
Next steps
- Submit the CSR to a CA of your choice for signing. Alternatively, for an internal use scenario within a trusted network, use your private CA for signing. See Section 3.9, “Using a private CA to issue certificates for CSRs with GnuTLS” for more information.
Verification
Check that the human-readable parts of the certificate match your requirements, for example:
$ certtool --certificate-info --infile <example-client.crt> Certificate: … X509v3 Extended Key Usage: TLS Web Client Authentication X509v3 Subject Alternative Name: email:client@example.com …
Additional resources
-
certtool(1)man page
3.9. Using a private CA to issue certificates for CSRs with GnuTLS
To enable systems to establish a TLS-encrypted communication channel, a certificate authority (CA) must provide valid certificates to them. If you have a private CA, you can create the requested certificates by signing certificate signing requests (CSRs) from the systems.
Prerequisites
- You have already configured a private CA. See Section 3.6, “Creating a private CA using GnuTLS” for more information.
- You have a file containing a CSR. You can find an example of creating the CSR in Section 3.7, “Creating a private key and a CSR for a TLS server certificate using GnuTLS” .
Procedure
Optional: Use a text editor of your choice to prepare an GnuTLS configuration file for adding extensions to certificates, for example:
$ vi <server-extensions.cfg> honor_crq_extensions ocsp_uri = "http://ocsp.example.com"Use the
certtoolutility to create a certificate based on a CSR, for example:$ certtool --generate-certificate --load-request <example-server.crq> --load-ca-privkey <ca.key> --load-ca-certificate <ca.crt> --template <server-extensions.cfg> --outfile <example-server.crt>
Additional resources
-
certtool(1)man page
Chapter 4. Using shared system certificates
The shared system certificates storage enables NSS, GnuTLS, OpenSSL, and Java to share a default source for retrieving system certificate anchors and block-list information. By default, the truststore contains the Mozilla CA list, including positive and negative trust. The system allows updating the core Mozilla CA list or choosing another certificate list.
4.1. The system-wide truststore
In RHEL, the consolidated system-wide truststore is located in the /etc/pki/ca-trust/ and /usr/share/pki/ca-trust-source/ directories. The trust settings in /usr/share/pki/ca-trust-source/ are processed with lower priority than settings in /etc/pki/ca-trust/.
Certificate files are treated depending on the subdirectory they are installed to. For example, trust anchors belong to the /usr/share/pki/ca-trust-source/anchors/ or /etc/pki/ca-trust/source/anchors/ directory.
In a hierarchical cryptographic system, a trust anchor is an authoritative entity that other parties consider trustworthy. In the X.509 architecture, a root certificate is a trust anchor from which a chain of trust is derived. To enable chain validation, the trusting party must have access to the trust anchor first.
Additional resources
-
update-ca-trust(8)andtrust(1)man pages
4.2. Adding new certificates
To acknowledge applications on your system with a new source of trust, add the corresponding certificate to the system-wide store, and use the update-ca-trust command.
Prerequisites
-
The
ca-certificatespackage is present on the system.
Procedure
To add a certificate in the simple PEM or DER file formats to the list of CAs trusted on the system, copy the certificate file to the
/usr/share/pki/ca-trust-source/anchors/or/etc/pki/ca-trust/source/anchors/directory, for example:# cp ~/certificate-trust-examples/Cert-trust-test-ca.pem /usr/share/pki/ca-trust-source/anchors/To update the system-wide truststore configuration, use the
update-ca-trustcommand:# update-ca-trust
Even though the Firefox browser can use an added certificate without a prior execution of update-ca-trust, enter the update-ca-trust command after every CA change. Also note that browsers, such as Firefox, Chromium, and GNOME Web cache files, and you might have to clear your browser’s cache or restart your browser to load the current system certificate configuration.
Additional resources
-
update-ca-trust(8)andtrust(1)man pages
4.3. Managing trusted system certificates
The trust command provides a convenient way for managing certificates in the shared system-wide truststore.
To list, extract, add, remove, or change trust anchors, use the
trustcommand. To see the built-in help for this command, enter it without any arguments or with the--helpdirective:$ trust usage: trust command <args>... Common trust commands are: list List trust or certificates extract Extract certificates and trust extract-compat Extract trust compatibility bundles anchor Add, remove, change trust anchors dump Dump trust objects in internal format See 'trust <command> --help' for more informationTo list all system trust anchors and certificates, use the
trust listcommand:$ trust list pkcs11:id=%d2%87%b4%e3%df%37%27%93%55%f6%56%ea%81%e5%36%cc%8c%1e%3f%bd;type=cert type: certificate label: ACCVRAIZ1 trust: anchor category: authority pkcs11:id=%a6%b3%e1%2b%2b%49%b6%d7%73%a1%aa%94%f5%01%e7%73%65%4c%ac%50;type=cert type: certificate label: ACEDICOM Root trust: anchor category: authority ...To store a trust anchor into the system-wide truststore, use the
trust anchorsub-command and specify a path to a certificate. Replace <path.to/certificate.crt> by a path to your certificate and its file name:# trust anchor <path.to/certificate.crt>To remove a certificate, use either a path to a certificate or an ID of a certificate:
# trust anchor --remove <path.to/certificate.crt> # trust anchor --remove "pkcs11:id=<%AA%BB%CC%DD%EE>;type=cert"
Additional resources
All sub-commands of the
trustcommands offer a detailed built-in help, for example:$ trust list --help usage: trust list --filter=<what> --filter=<what> filter of what to export ca-anchors certificate anchors ... --purpose=<usage> limit to certificates usable for the purpose server-auth for authenticating servers ...
Additional resources
-
update-ca-trust(8)andtrust(1)man pages
Chapter 5. Planning and implementing TLS
TLS (Transport Layer Security) is a cryptographic protocol used to secure network communications. When hardening system security settings by configuring preferred key-exchange protocols, authentication methods, and encryption algorithms, it is necessary to bear in mind that the broader the range of supported clients, the lower the resulting security. Conversely, strict security settings lead to limited compatibility with clients, which can result in some users being locked out of the system. Be sure to target the strictest available configuration and only relax it when it is required for compatibility reasons.
5.1. SSL and TLS protocols
The Secure Sockets Layer (SSL) protocol was originally developed by Netscape Corporation to provide a mechanism for secure communication over the Internet. Subsequently, the protocol was adopted by the Internet Engineering Task Force (IETF) and renamed to Transport Layer Security (TLS).
The TLS protocol sits between an application protocol layer and a reliable transport layer, such as TCP/IP. It is independent of the application protocol and can thus be layered underneath many different protocols, for example: HTTP, FTP, SMTP, and so on.
| Protocol version | Usage recommendation |
|---|---|
| SSL v2 | Do not use. Has serious security vulnerabilities. Removed from the core crypto libraries since RHEL 7. |
| SSL v3 | Do not use. Has serious security vulnerabilities. Removed from the core crypto libraries since RHEL 8. |
| TLS 1.0 |
Not recommended to use. Has known issues that cannot be mitigated in a way that guarantees interoperability, and does not support modern cipher suites. In RHEL 8, enabled only in the |
| TLS 1.1 |
Use for interoperability purposes where needed. Does not support modern cipher suites. In RHEL 8, enabled only in the |
| TLS 1.2 | Supports the modern AEAD cipher suites. This version is enabled in all system-wide crypto policies, but optional parts of this protocol contain vulnerabilities and TLS 1.2 also allows outdated algorithms. |
| TLS 1.3 | Recommended version. TLS 1.3 removes known problematic options, provides additional privacy by encrypting more of the negotiation handshake and can be faster thanks usage of more efficient modern cryptographic algorithms. TLS 1.3 is also enabled in all system-wide crypto policies. |
Additional resources
5.2. Security considerations for TLS in RHEL 8
In RHEL 8, cryptography-related considerations are significantly simplified thanks to the system-wide crypto policies. The DEFAULT crypto policy allows only TLS 1.2 and 1.3. To allow your system to negotiate connections using the earlier versions of TLS, you need to either opt out from following crypto policies in an application or switch to the LEGACY policy with the update-crypto-policies command. See Using system-wide cryptographic policies for more information.
The default settings provided by libraries included in RHEL 8 are secure enough for most deployments. The TLS implementations use secure algorithms where possible while not preventing connections from or to legacy clients or servers. Apply hardened settings in environments with strict security requirements where legacy clients or servers that do not support secure algorithms or protocols are not expected or allowed to connect.
The most straightforward way to harden your TLS configuration is switching the system-wide cryptographic policy level to FUTURE using the update-crypto-policies --set FUTURE command.
Algorithms disabled for the LEGACY cryptographic policy do not conform to Red Hat’s vision of RHEL 8 security, and their security properties are not reliable. Consider moving away from using these algorithms instead of re-enabling them. If you do decide to re-enable them, for example for interoperability with old hardware, treat them as insecure and apply extra protection measures, such as isolating their network interactions to separate network segments. Do not use them across public networks.
If you decide to not follow RHEL system-wide crypto policies or create custom cryptographic policies tailored to your setup, use the following recommendations for preferred protocols, cipher suites, and key lengths on your custom configuration:
5.2.1. Protocols
The latest version of TLS provides the best security mechanism. Unless you have a compelling reason to include support for older versions of TLS, allow your systems to negotiate connections using at least TLS version 1.2.
Note that even though RHEL 8 supports TLS version 1.3, not all features of this protocol are fully supported by RHEL 8 components. For example, the 0-RTT (Zero Round Trip Time) feature, which reduces connection latency, is not yet fully supported by the Apache web server.
5.2.2. Cipher suites
Modern, more secure cipher suites should be preferred to old, insecure ones. Always disable the use of eNULL and aNULL cipher suites, which do not offer any encryption or authentication at all. If at all possible, ciphers suites based on RC4 or HMAC-MD5, which have serious shortcomings, should also be disabled. The same applies to the so-called export cipher suites, which have been intentionally made weaker, and thus are easy to break.
While not immediately insecure, cipher suites that offer less than 128 bits of security should not be considered for their short useful life. Algorithms that use 128 bits of security or more can be expected to be unbreakable for at least several years, and are thus strongly recommended. Note that while 3DES ciphers advertise the use of 168 bits, they actually offer 112 bits of security.
Always prefer cipher suites that support (perfect) forward secrecy (PFS), which ensures the confidentiality of encrypted data even in case the server key is compromised. This rules out the fast RSA key exchange, but allows for the use of ECDHE and DHE. Of the two, ECDHE is the faster and therefore the preferred choice.
You should also prefer AEAD ciphers, such as AES-GCM, over CBC-mode ciphers as they are not vulnerable to padding oracle attacks. Additionally, in many cases, AES-GCM is faster than AES in CBC mode, especially when the hardware has cryptographic accelerators for AES.
Note also that when using the ECDHE key exchange with ECDSA certificates, the transaction is even faster than a pure RSA key exchange. To provide support for legacy clients, you can install two pairs of certificates and keys on a server: one with ECDSA keys (for new clients) and one with RSA keys (for legacy ones).
5.2.3. Public key length
When using RSA keys, always prefer key lengths of at least 3072 bits signed by at least SHA-256, which is sufficiently large for true 128 bits of security.
The security of your system is only as strong as the weakest link in the chain. For example, a strong cipher alone does not guarantee good security. The keys and the certificates are just as important, as well as the hash functions and keys used by the Certification Authority (CA) to sign your keys.
Additional resources
- System-wide crypto policies in RHEL 8.
-
update-crypto-policies(8)man page.
5.3. Hardening TLS configuration in applications
In RHEL, system-wide crypto policies provide a convenient way to ensure that your applications using cryptographic libraries do not allow known insecure protocols, ciphers, or algorithms.
If you want to harden your TLS-related configuration with your customized cryptographic settings, you can use the cryptographic configuration options described in this section, and override the system-wide crypto policies just in the minimum required amount.
Regardless of the configuration you choose to use, always ensure that your server application enforces server-side cipher order, so that the cipher suite to be used is determined by the order you configure.
5.3.1. Configuring the Apache HTTP server to use TLS
The Apache HTTP Server can use both OpenSSL and NSS libraries for its TLS needs. RHEL 8 provides the mod_ssl functionality through eponymous packages:
# yum install mod_ssl
The mod_ssl package installs the /etc/httpd/conf.d/ssl.conf configuration file, which can be used to modify the TLS-related settings of the Apache HTTP Server.
Install the httpd-manual package to obtain complete documentation for the Apache HTTP Server, including TLS configuration. The directives available in the /etc/httpd/conf.d/ssl.conf configuration file are described in detail in the /usr/share/httpd/manual/mod/mod_ssl.html file. Examples of various settings are described in the /usr/share/httpd/manual/ssl/ssl_howto.html file.
When modifying the settings in the /etc/httpd/conf.d/ssl.conf configuration file, be sure to consider the following three directives at the minimum:
SSLProtocol- Use this directive to specify the version of TLS or SSL you want to allow.
SSLCipherSuite- Use this directive to specify your preferred cipher suite or disable the ones you want to disallow.
SSLHonorCipherOrder-
Uncomment and set this directive to
onto ensure that the connecting clients adhere to the order of ciphers you specified.
For example, to use only the TLS 1.2 and 1.3 protocol:
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
See the Configuring TLS encryption on an Apache HTTP Server chapter in the Deploying different types of servers document for more information.
5.3.2. Configuring the Nginx HTTP and proxy server to use TLS
To enable TLS 1.3 support in Nginx, add the TLSv1.3 value to the ssl_protocols option in the server section of the /etc/nginx/nginx.conf configuration file:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
....
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers
....
}See the Adding TLS encryption to an Nginx web server chapter in the Deploying different types of servers document for more information.
5.3.3. Configuring the Dovecot mail server to use TLS
To configure your installation of the Dovecot mail server to use TLS, modify the /etc/dovecot/conf.d/10-ssl.conf configuration file. You can find an explanation of some of the basic configuration directives available in that file in the /usr/share/doc/dovecot/wiki/SSL.DovecotConfiguration.txt file, which is installed along with the standard installation of Dovecot.
When modifying the settings in the /etc/dovecot/conf.d/10-ssl.conf configuration file, be sure to consider the following three directives at the minimum:
ssl_protocols- Use this directive to specify the version of TLS or SSL you want to allow or disable.
ssl_cipher_list- Use this directive to specify your preferred cipher suites or disable the ones you want to disallow.
ssl_prefer_server_ciphers-
Uncomment and set this directive to
yesto ensure that the connecting clients adhere to the order of ciphers you specified.
For example, the following line in /etc/dovecot/conf.d/10-ssl.conf allows only TLS 1.1 and later:
ssl_protocols = !SSLv2 !SSLv3 !TLSv1
Additional resources
Chapter 6. Configuring a VPN with IPsec
In RHEL 8, a virtual private network (VPN) can be configured using the IPsec protocol, which is supported by the Libreswan application.
6.1. Libreswan as an IPsec VPN implementation
In RHEL, a Virtual Private Network (VPN) can be configured using the IPsec protocol, which is supported by the Libreswan application. Libreswan is a continuation of the Openswan application, and many examples from the Openswan documentation are interchangeable with Libreswan.
The IPsec protocol for a VPN is configured using the Internet Key Exchange (IKE) protocol. The terms IPsec and IKE are used interchangeably. An IPsec VPN is also called an IKE VPN, IKEv2 VPN, XAUTH VPN, Cisco VPN or IKE/IPsec VPN. A variant of an IPsec VPN that also uses the Layer 2 Tunneling Protocol (L2TP) is usually called an L2TP/IPsec VPN, which requires the xl2tpd package provided by the optional repository.
Libreswan is an open-source, user-space IKE implementation. IKE v1 and v2 are implemented as a user-level daemon. The IKE protocol is also encrypted. The IPsec protocol is implemented by the Linux kernel, and Libreswan configures the kernel to add and remove VPN tunnel configurations.
The IKE protocol uses UDP port 500 and 4500. The IPsec protocol consists of two protocols:
- Encapsulated Security Payload (ESP), which has protocol number 50.
- Authenticated Header (AH), which has protocol number 51.
The AH protocol is not recommended for use. Users of AH are recommended to migrate to ESP with null encryption.
The IPsec protocol provides two modes of operation:
- Tunnel Mode (the default)
- Transport Mode.
You can configure the kernel with IPsec without IKE. This is called manual keying. You can also configure manual keying using the ip xfrm commands, however, this is strongly discouraged for security reasons. Libreswan communicates with the Linux kernel using the Netlink interface. The kernel performs packet encryption and decryption.
Libreswan uses the Network Security Services (NSS) cryptographic library. NSS is certified for use with the Federal Information Processing Standard (FIPS) Publication 140-2.
IKE/IPsec VPNs, implemented by Libreswan and the Linux kernel, is the only VPN technology recommended for use in RHEL. Do not use any other VPN technology without understanding the risks of doing so.
In RHEL, Libreswan follows system-wide cryptographic policies by default. This ensures that Libreswan uses secure settings for current threat models including IKEv2 as a default protocol. See Using system-wide crypto policies for more information.
Libreswan does not use the terms "source" and "destination" or "server" and "client" because IKE/IPsec are peer to peer protocols. Instead, it uses the terms "left" and "right" to refer to end points (the hosts). This also allows you to use the same configuration on both end points in most cases. However, administrators usually choose to always use "left" for the local host and "right" for the remote host.
The leftid and rightid options serve as identification of the respective hosts in the authentication process. See the ipsec.conf(5) man page for more information.
6.2. Authentication methods in Libreswan
Libreswan supports several authentication methods, each of which fits a different scenario.
Pre-Shared key (PSK)
Pre-Shared Key (PSK) is the simplest authentication method. For security reasons, do not use PSKs shorter than 64 random characters. In FIPS mode, PSKs must comply with a minimum-strength requirement depending on the integrity algorithm used. You can set PSK by using the authby=secret connection.
Raw RSA keys
Raw RSA keys are commonly used for static host-to-host or subnet-to-subnet IPsec configurations. Each host is manually configured with the public RSA keys of all other hosts, and Libreswan sets up an IPsec tunnel between each pair of hosts. This method does not scale well for large numbers of hosts.
You can generate a raw RSA key on a host using the ipsec newhostkey command. You can list generated keys by using the ipsec showhostkey command. The leftrsasigkey= line is required for connection configurations that use CKA ID keys. Use the authby=rsasig connection option for raw RSA keys.
X.509 certificates
X.509 certificates are commonly used for large-scale deployments with hosts that connect to a common IPsec gateway. A central certificate authority (CA) signs RSA certificates for hosts or users. This central CA is responsible for relaying trust, including the revocations of individual hosts or users.
For example, you can generate X.509 certificates using the openssl command and the NSS certutil command. Because Libreswan reads user certificates from the NSS database using the certificates' nickname in the leftcert= configuration option, provide a nickname when you create a certificate.
If you use a custom CA certificate, you must import it to the Network Security Services (NSS) database. You can import any certificate in the PKCS #12 format to the Libreswan NSS database by using the ipsec import command.
Libreswan requires an Internet Key Exchange (IKE) peer ID as a subject alternative name (SAN) for every peer certificate as described in section 3.1 of RFC 4945. Disabling this check by changing the require-id-on-certificated= option can make the system vulnerable to man-in-the-middle attacks.
Use the authby=rsasig connection option for authentication based on X.509 certificates using RSA with SHA-1 and SHA-2. You can further limit it for ECDSA digital signatures using SHA-2 by setting authby= to ecdsa and RSA Probabilistic Signature Scheme (RSASSA-PSS) digital signatures based authentication with SHA-2 through authby=rsa-sha2. The default value is authby=rsasig,ecdsa.
The certificates and the authby= signature methods should match. This increases interoperability and preserves authentication in one digital-signature system.
NULL authentication
NULL authentication is used to gain mesh encryption without authentication. It protects against passive attacks but not against active attacks. However, because IKEv2 allows asymmetric authentication methods, NULL authentication can also be used for internet-scale opportunistic IPsec. In this model, clients authenticate the server, but servers do not authenticate the client. This model is similar to secure websites using TLS. Use authby=null for NULL authentication.
Protection against quantum computers
In addition to the previously mentioned authentication methods, you can use the Post-quantum Pre-shared Key (PPK) method to protect against possible attacks by quantum computers. Individual clients or groups of clients can use their own PPK by specifying a PPK ID that corresponds to an out-of-band configured pre-shared key.
Using IKEv1 with pre-shared keys provides protection against quantum attackers. The redesign of IKEv2 does not offer this protection natively. Libreswan offers the use of Post-quantum Pre-shared Key (PPK) to protect IKEv2 connections against quantum attacks.
To enable optional PPK support, add ppk=yes to the connection definition. To require PPK, add ppk=insist. Then, each client can be given a PPK ID with a secret value that is communicated out-of-band (and preferably quantum safe). The PPK’s should be very strong in randomness and not based on dictionary words. The PPK ID and PPK data are stored in ipsec.secrets, for example:
@west @east : PPKS "user1" "thestringismeanttobearandomstr"
The PPKS option refers to static PPKs. This experimental function uses one-time-pad-based Dynamic PPKs. Upon each connection, a new part of the one-time pad is used as the PPK. When used, that part of the dynamic PPK inside the file is overwritten with zeros to prevent re-use. If there is no more one-time-pad material left, the connection fails. See the ipsec.secrets(5) man page for more information.
The implementation of dynamic PPKs is provided as an unsupported Technology Preview. Use with caution.
6.3. Installing Libreswan
This procedure describes the steps for installing and starting the Libreswan IPsec/IKE VPN implementation.
Prerequisites
-
The
AppStreamrepository is enabled.
Procedure
Install the
libreswanpackages:# yum install libreswanIf you are re-installing Libreswan, remove its old database files and create a new database:
# systemctl stop ipsec # rm /etc/ipsec.d/*db # ipsec initnss
Start the
ipsecservice, and enable the service to be started automatically on boot:# systemctl enable ipsec --nowConfigure the firewall to allow 500 and 4500/UDP ports for the IKE, ESP, and AH protocols by adding the
ipsecservice:# firewall-cmd --add-service="ipsec" # firewall-cmd --runtime-to-permanent
6.4. Creating a host-to-host VPN
To configure [application]Libreswan to create a host-to-host IPsec VPN between two hosts referred to as left and right using authentication by raw RSA keys, enter the following commands on both of the hosts:
Prerequisites
-
Libreswan is installed and the
ipsecservice is started on each node.
Procedure
Generate a raw RSA key pair on each host:
# ipsec newhostkeyThe previous step returned the generated key’s
ckaid. Use thatckaidwith the following command on left, for example:# ipsec showhostkey --left --ckaid 2d3ea57b61c9419dfd6cf43a1eb6cb306c0e857dThe output of the previous command generated the
leftrsasigkey=line required for the configuration. Do the same on the second host (right):# ipsec showhostkey --right --ckaid a9e1f6ce9ecd3608c24e8f701318383f41798f03In the
/etc/ipsec.d/directory, create a newmy_host-to-host.conffile. Write the RSA host keys from the output of theipsec showhostkeycommands in the previous step to the new file. For example:conn mytunnel leftid=@west left=192.1.2.23 leftrsasigkey=0sAQOrlo+hOafUZDlCQmXFrje/oZm [...] W2n417C/4urYHQkCvuIQ== rightid=@east right=192.1.2.45 rightrsasigkey=0sAQO3fwC6nSSGgt64DWiYZzuHbc4 [...] D/v8t5YTQ== authby=rsasigAfter importing keys, restart the
ipsecservice:# systemctl restart ipsecLoad the connection:
# ipsec auto --add mytunnelEstablish the tunnel:
# ipsec auto --up mytunnelTo automatically start the tunnel when the
ipsecservice is started, add the following line to the connection definition:auto=start
6.5. Configuring a site-to-site VPN
To create a site-to-site IPsec VPN, by joining two networks, an IPsec tunnel between the two hosts, is created. The hosts thus act as the end points, which are configured to permit traffic from one or more subnets to pass through. Therefore you can think of the host as gateways to the remote portion of the network.
The configuration of the site-to-site VPN only differs from the host-to-host VPN in that one or more networks or subnets must be specified in the configuration file.
Prerequisites
- A host-to-host VPN is already configured.
Procedure
Copy the file with the configuration of your host-to-host VPN to a new file, for example:
# cp /etc/ipsec.d/my_host-to-host.conf /etc/ipsec.d/my_site-to-site.confAdd the subnet configuration to the file created in the previous step, for example:
conn mysubnet also=mytunnel leftsubnet=192.0.1.0/24 rightsubnet=192.0.2.0/24 auto=start conn mysubnet6 also=mytunnel leftsubnet=2001:db8:0:1::/64 rightsubnet=2001:db8:0:2::/64 auto=start # the following part of the configuration file is the same for both host-to-host and site-to-site connections: conn mytunnel leftid=@west left=192.1.2.23 leftrsasigkey=0sAQOrlo+hOafUZDlCQmXFrje/oZm [...] W2n417C/4urYHQkCvuIQ== rightid=@east right=192.1.2.45 rightrsasigkey=0sAQO3fwC6nSSGgt64DWiYZzuHbc4 [...] D/v8t5YTQ== authby=rsasig
6.6. Configuring a remote access VPN
Road warriors are traveling users with mobile clients and a dynamically assigned IP address. The mobile clients authenticate using X.509 certificates.
The following example shows configuration for IKEv2, and it avoids using the IKEv1 XAUTH protocol.
On the server:
conn roadwarriors
ikev2=insist
# support (roaming) MOBIKE clients (RFC 4555)
mobike=yes
fragmentation=yes
left=1.2.3.4
# if access to the LAN is given, enable this, otherwise use 0.0.0.0/0
# leftsubnet=10.10.0.0/16
leftsubnet=0.0.0.0/0
leftcert=gw.example.com
leftid=%fromcert
leftxauthserver=yes
leftmodecfgserver=yes
right=%any
# trust our own Certificate Agency
rightca=%same
# pick an IP address pool to assign to remote users
# 100.64.0.0/16 prevents RFC1918 clashes when remote users are behind NAT
rightaddresspool=100.64.13.100-100.64.13.254
# if you want remote clients to use some local DNS zones and servers
modecfgdns="1.2.3.4, 5.6.7.8"
modecfgdomains="internal.company.com, corp"
rightxauthclient=yes
rightmodecfgclient=yes
authby=rsasig
# optionally, run the client X.509 ID through pam to allow or deny client
# pam-authorize=yes
# load connection, do not initiate
auto=add
# kill vanished roadwarriors
dpddelay=1m
dpdtimeout=5m
dpdaction=clearOn the mobile client, the road warrior’s device, use a slight variation of the previous configuration:
conn to-vpn-server
ikev2=insist
# pick up our dynamic IP
left=%defaultroute
leftsubnet=0.0.0.0/0
leftcert=myname.example.com
leftid=%fromcert
leftmodecfgclient=yes
# right can also be a DNS hostname
right=1.2.3.4
# if access to the remote LAN is required, enable this, otherwise use 0.0.0.0/0
# rightsubnet=10.10.0.0/16
rightsubnet=0.0.0.0/0
fragmentation=yes
# trust our own Certificate Agency
rightca=%same
authby=rsasig
# allow narrowing to the server’s suggested assigned IP and remote subnet
narrowing=yes
# support (roaming) MOBIKE clients (RFC 4555)
mobike=yes
# initiate connection
auto=start6.7. Configuring a mesh VPN
A mesh VPN network, which is also known as an any-to-any VPN, is a network where all nodes communicate using IPsec. The configuration allows for exceptions for nodes that cannot use IPsec. The mesh VPN network can be configured in two ways:
- To require IPsec.
- To prefer IPsec but allow a fallback to clear-text communication.
Authentication between the nodes can be based on X.509 certificates or on DNS Security Extensions (DNSSEC).
You can use any regular IKEv2 authentication method for opportunistic IPsec, because these connections are regular Libreswan configurations, except for the opportunistic IPsec that is defined by right=%opportunisticgroup entry. A common authentication method is for hosts to authenticate each other based on X.509 certificates using a commonly shared certification authority (CA). Cloud deployments typically issue certificates for each node in the cloud as part of the standard procedure.
Do not use PreSharedKey (PSK) authentication because one compromised host would result in group PSK secret being compromised as well.
You can use NULL authentication to deploy encryption between nodes without authentication, which protects only against passive attackers.
The following procedure uses X.509 certificates. You can generate these certificates by using any kind of CA management system, such as the Dogtag Certificate System. Dogtag assumes that the certificates for each node are available in the PKCS #12 format (.p12 files), which contain the private key, the node certificate, and the Root CA certificate used to validate other nodes' X.509 certificates.
Each node has an identical configuration with the exception of its X.509 certificate. This allows for adding new nodes without reconfiguring any of the existing nodes in the network. The PKCS #12 files require a "friendly name", for which we use the name "node" so that the configuration files referencing the friendly name can be identical for all nodes.
Prerequisites
-
Libreswan is installed, and the
ipsecservice is started on each node. A new NSS database is initialized.
If you already have an old NSS database, remove the old database files:
# systemctl stop ipsec # rm /etc/ipsec.d/*db
You can initialize a new database with the following command:
# ipsec initnss
Procedure
On each node, import PKCS #12 files. This step requires the password used to generate the PKCS #12 files:
# ipsec import nodeXXX.p12Create the following three connection definitions for the
IPsec required(private),IPsec optional(private-or-clear), andNo IPsec(clear) profiles:# cat /etc/ipsec.d/mesh.conf conn clear auto=ondemand 1 type=passthrough authby=never left=%defaultroute right=%group conn private auto=ondemand type=transport authby=rsasig failureshunt=drop negotiationshunt=drop ikev2=insist left=%defaultroute leftcert=nodeXXXX leftid=%fromcert 2 rightid=%fromcert right=%opportunisticgroup conn private-or-clear auto=ondemand type=transport authby=rsasig failureshunt=passthrough negotiationshunt=passthrough # left left=%defaultroute leftcert=nodeXXXX 3 leftid=%fromcert leftrsasigkey=%cert # right rightrsasigkey=%cert rightid=%fromcert right=%opportunisticgroup
- 1
- The
autovariable has several options:You can use the
ondemandconnection option with opportunistic IPsec to initiate the IPsec connection, or for explicitly configured connections that do not need to be active all the time. This option sets up a trap XFRM policy in the kernel, enabling the IPsec connection to begin when it receives the first packet that matches that policy.You can effectively configure and manage your IPsec connections, whether you use Opportunistic IPsec or explicitly configured connections, by using the following options:
- The
addoption -
Loads the connection configuration and prepares it for responding to remote initiations. However, the connection is not automatically initiated from the local side. You can manually start the IPsec connection by using the command
ipsec auto --up. - The
startoption - Loads the connection configuration and prepares it for responding to remote initiations. Additionally, it immediately initiates a connection to the remote peer. You can use this option for permanent and always active connections.
- The
- 2
leftidandrightidvariables identifies the right and the left channel of the IPsec tunnel connection. You can use these variables to obtain the value of the local IP address or the subject DN of the local certificate, if you have configured one.- 3
leftcertvariable defines the nickname of the NSS database, which you want to use.Add the IP address of the network to the corresponding category. For example, if all nodes reside in the 10.15.0.0/16 network, and all nodes must use IPsec encryption:
# echo "10.15.0.0/16" >> /etc/ipsec.d/policies/privateTo allow certain nodes, for example, 10.15.34.0/24, to work with and without IPsec, add those nodes to the private-or-clear group:
# echo "10.15.34.0/24" >> /etc/ipsec.d/policies/private-or-clearTo define a host, for example, 10.15.1.2, that is not capable of IPsec into the clear group, use:
# echo "10.15.1.2/32" >> /etc/ipsec.d/policies/clearYou have the option to create the files in the
/etc/ipsec.d/policiesdirectory from a template for each new node, or you can provision them by using Puppet or Ansible.Note that every node has the same list of exceptions or different traffic flow expectations. Two nodes, therefore, might not be able to communicate because one requires IPsec and the other cannot use IPsec.
Restart the node to add it to the configured mesh:
# systemctl restart ipsec
Verification
You can verify the procedure by opening a IPsec tunnel between two nodes.
Open an IPsec tunnel by using the
pingcommand:# ping <nodeYYY>Display the NSS database with the imported certification:
# certutil -L -d sql:/etc/ipsec.d Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI west u,u,u ca CT,,See which tunnels a node has opened:
# ipsec trafficstatus 006 #2: "private#10.15.0.0/16"[1] ...nodeYYY, type=ESP, add_time=1691399301, inBytes=512, outBytes=512, maxBytes=2^63B, id='C=US, ST=NC, O=Example Organization, CN=east'
Additional resources
-
ipsec.conf(5)man page. -
For more information about the
authbyvariable, see 6.2. Authentication methods in Libreswan.
6.8. Deploying a FIPS-compliant IPsec VPN
Use this procedure to deploy a FIPS-compliant IPsec VPN solution based on Libreswan. The following steps also enable you to identify which cryptographic algorithms are available and which are disabled for Libreswan in FIPS mode.
Prerequisites
-
The
AppStreamrepository is enabled.
Procedure
Install the
libreswanpackages:# yum install libreswanIf you are re-installing Libreswan, remove its old NSS database:
# systemctl stop ipsec # rm /etc/ipsec.d/*db
Start the
ipsecservice, and enable the service to be started automatically on boot:# systemctl enable ipsec --nowConfigure the firewall to allow 500 and 4500/UDP ports for the IKE, ESP, and AH protocols by adding the
ipsecservice:# firewall-cmd --add-service="ipsec" # firewall-cmd --runtime-to-permanent
Switch the system to FIPS mode:
# fips-mode-setup --enableRestart your system to allow the kernel to switch to FIPS mode:
# reboot
Verification
To confirm Libreswan is running in FIPS mode:
# ipsec whack --fipsstatus 000 FIPS mode enabledAlternatively, check entries for the
ipsecunit in thesystemdjournal:$ journalctl -u ipsec ... Jan 22 11:26:50 localhost.localdomain pluto[3076]: FIPS Product: YES Jan 22 11:26:50 localhost.localdomain pluto[3076]: FIPS Kernel: YES Jan 22 11:26:50 localhost.localdomain pluto[3076]: FIPS Mode: YESTo see the available algorithms in FIPS mode:
# ipsec pluto --selftest 2>&1 | head -11 FIPS Product: YES FIPS Kernel: YES FIPS Mode: YES NSS DB directory: sql:/etc/ipsec.d Initializing NSS Opening NSS database "sql:/etc/ipsec.d" read-only NSS initialized NSS crypto library initialized FIPS HMAC integrity support [enabled] FIPS mode enabled for pluto daemon NSS library is running in FIPS mode FIPS HMAC integrity verification self-test passedTo query disabled algorithms in FIPS mode:
# ipsec pluto --selftest 2>&1 | grep disabled Encryption algorithm CAMELLIA_CTR disabled; not FIPS compliant Encryption algorithm CAMELLIA_CBC disabled; not FIPS compliant Encryption algorithm SERPENT_CBC disabled; not FIPS compliant Encryption algorithm TWOFISH_CBC disabled; not FIPS compliant Encryption algorithm TWOFISH_SSH disabled; not FIPS compliant Encryption algorithm NULL disabled; not FIPS compliant Encryption algorithm CHACHA20_POLY1305 disabled; not FIPS compliant Hash algorithm MD5 disabled; not FIPS compliant PRF algorithm HMAC_MD5 disabled; not FIPS compliant PRF algorithm AES_XCBC disabled; not FIPS compliant Integrity algorithm HMAC_MD5_96 disabled; not FIPS compliant Integrity algorithm HMAC_SHA2_256_TRUNCBUG disabled; not FIPS compliant Integrity algorithm AES_XCBC_96 disabled; not FIPS compliant DH algorithm MODP1024 disabled; not FIPS compliant DH algorithm MODP1536 disabled; not FIPS compliant DH algorithm DH31 disabled; not FIPS compliantTo list all allowed algorithms and ciphers in FIPS mode:
# ipsec pluto --selftest 2>&1 | grep ESP | grep FIPS | sed "s/^.*FIPS//" {256,192,*128} aes_ccm, aes_ccm_c {256,192,*128} aes_ccm_b {256,192,*128} aes_ccm_a [*192] 3des {256,192,*128} aes_gcm, aes_gcm_c {256,192,*128} aes_gcm_b {256,192,*128} aes_gcm_a {256,192,*128} aesctr {256,192,*128} aes {256,192,*128} aes_gmac sha, sha1, sha1_96, hmac_sha1 sha512, sha2_512, sha2_512_256, hmac_sha2_512 sha384, sha2_384, sha2_384_192, hmac_sha2_384 sha2, sha256, sha2_256, sha2_256_128, hmac_sha2_256 aes_cmac null null, dh0 dh14 dh15 dh16 dh17 dh18 ecp_256, ecp256 ecp_384, ecp384 ecp_521, ecp521
Additional resources
6.9. Protecting the IPsec NSS database by a password
By default, the IPsec service creates its Network Security Services (NSS) database with an empty password during the first start. Add password protection by using the following steps.
In the previous releases of RHEL up to version 6.6, you had to protect the IPsec NSS database with a password to meet the FIPS 140-2 requirements because the NSS cryptographic libraries were certified for the FIPS 140-2 Level 2 standard. In RHEL 8, NIST certified NSS to Level 1 of this standard, and this status does not require password protection for the database.
Prerequisites
-
The
/etc/ipsec.d/directory contains NSS database files.
Procedure
Enable password protection for the
NSSdatabase for Libreswan:# certutil -N -d sql:/etc/ipsec.d Enter Password or Pin for "NSS Certificate DB": Enter a password which will be used to encrypt your keys. The password should be at least 8 characters long, and should contain at least one non-alphabetic character. Enter new password:Create the
/etc/ipsec.d/nsspasswordfile containing the password you have set in the previous step, for example:# cat /etc/ipsec.d/nsspassword NSS Certificate DB:MyStrongPasswordHereNote that the
nsspasswordfile use the following syntax:token_1_name:the_password token_2_name:the_password
The default NSS software token is
NSS Certificate DB. If your system is running in FIPS mode, the name of the token isNSS FIPS 140-2 Certificate DB.Depending on your scenario, either start or restart the
ipsecservice after you finish thensspasswordfile:# systemctl restart ipsec
Verification
Check that the
ipsecservice is running after you have added a non-empty password to its NSS database:# systemctl status ipsec ● ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec Loaded: loaded (/usr/lib/systemd/system/ipsec.service; enabled; vendor preset: disable> Active: active (running)...Optionally, check that the
Journallog contains entries confirming a successful initialization:# journalctl -u ipsec ... pluto[6214]: Initializing NSS using read-write database "sql:/etc/ipsec.d" pluto[6214]: NSS Password from file "/etc/ipsec.d/nsspassword" for token "NSS Certificate DB" with length 20 passed to NSS pluto[6214]: NSS crypto library initialized ...
Additional resources
-
certutil(1)man page. - Government Standards Knowledgebase article.
6.10. Configuring an IPsec VPN to use TCP
Libreswan supports TCP encapsulation of IKE and IPsec packets as described in RFC 8229. With this feature, you can establish IPsec VPNs on networks that prevent traffic transmitted via UDP and Encapsulating Security Payload (ESP). You can configure VPN servers and clients to use TCP either as a fallback or as the main VPN transport protocol. Because TCP encapsulation has bigger performance costs, use TCP as the main VPN protocol only if UDP is permanently blocked in your scenario.
Prerequisites
- A remote-access VPN is already configured.
Procedure
Add the following option to the
/etc/ipsec.conffile in theconfig setupsection:listen-tcp=yes
To use TCP encapsulation as a fallback option when the first attempt over UDP fails, add the following two options to the client’s connection definition:
enable-tcp=fallback tcp-remoteport=4500
Alternatively, if you know that UDP is permanently blocked, use the following options in the client’s connection configuration:
enable-tcp=yes tcp-remoteport=4500
Additional resources
6.11. Configuring automatic detection and usage of ESP hardware offload to accelerate an IPsec connection
Offloading Encapsulating Security Payload (ESP) to the hardware accelerates IPsec connections over Ethernet. By default, Libreswan detects if hardware supports this feature and, as a result, enables ESP hardware offload. In case that the feature was disabled or explicitly enabled, you can switch back to automatic detection.
Prerequisites
- The network card supports ESP hardware offload.
- The network driver supports ESP hardware offload.
- The IPsec connection is configured and works.
Procedure
-
Edit the Libreswan configuration file in the
/etc/ipsec.d/directory of the connection that should use automatic detection of ESP hardware offload support. -
Ensure the
nic-offloadparameter is not set in the connection’s settings. If you removed
nic-offload, restart theipsecservice:# systemctl restart ipsec
Verification
If the network card supports ESP hardware offload support, following these steps to verify the result:
Display the
tx_ipsecandrx_ipseccounters of the Ethernet device the IPsec connection uses:# ethtool -S enp1s0 | egrep "_ipsec" tx_ipsec: 10 rx_ipsec: 10Send traffic through the IPsec tunnel. For example, ping a remote IP address:
# ping -c 5 remote_ip_addressDisplay the
tx_ipsecandrx_ipseccounters of the Ethernet device again:# ethtool -S enp1s0 | egrep "_ipsec" tx_ipsec: 15 rx_ipsec: 15If the counter values have increased, ESP hardware offload works.
Additional resources
6.12. Configuring ESP hardware offload on a bond to accelerate an IPsec connection
Offloading Encapsulating Security Payload (ESP) to the hardware accelerates IPsec connections. If you use a network bond for fail-over reasons, the requirements and the procedure to configure ESP hardware offload are different from those using a regular Ethernet device. For example, in this scenario, you enable the offload support on the bond, and the kernel applies the settings to the ports of the bond.
Prerequisites
- All network cards in the bond support ESP hardware offload.
-
The network driver supports ESP hardware offload on a bond device. In RHEL, only the
ixgbedriver supports this feature. - The bond is configured and works.
-
The bond uses the
active-backupmode. The bonding driver does not support any other modes for this feature. - The IPsec connection is configured and works.
Procedure
Enable ESP hardware offload support on the network bond:
# nmcli connection modify bond0 ethtool.feature-esp-hw-offload onThis command enables ESP hardware offload support on the
bond0connection.Reactivate the
bond0connection:# nmcli connection up bond0Edit the Libreswan configuration file in the
/etc/ipsec.d/directory of the connection that should use ESP hardware offload, and append thenic-offload=yesstatement to the connection entry:conn example ... nic-offload=yes
Restart the
ipsecservice:# systemctl restart ipsec
Verification
Display the active port of the bond:
# grep "Currently Active Slave" /proc/net/bonding/bond0 Currently Active Slave: enp1s0
Display the
tx_ipsecandrx_ipseccounters of the active port:# ethtool -S enp1s0 | egrep "_ipsec" tx_ipsec: 10 rx_ipsec: 10Send traffic through the IPsec tunnel. For example, ping a remote IP address:
# ping -c 5 remote_ip_addressDisplay the
tx_ipsecandrx_ipseccounters of the active port again:# ethtool -S enp1s0 | egrep "_ipsec" tx_ipsec: 15 rx_ipsec: 15If the counter values have increased, ESP hardware offload works.
Additional resources
6.13. Configuring IPsec connections that opt out of the system-wide crypto policies
Overriding system-wide crypto-policies for a connection
The RHEL system-wide cryptographic policies create a special connection called %default. This connection contains the default values for the ikev2, esp, and ike options. However, you can override the default values by specifying the mentioned option in the connection configuration file.
For example, the following configuration allows connections that use IKEv1 with AES and SHA-1 or SHA-2, and IPsec (ESP) with either AES-GCM or AES-CBC:
conn MyExample ... ikev2=never ike=aes-sha2,aes-sha1;modp2048 esp=aes_gcm,aes-sha2,aes-sha1 ...
Note that AES-GCM is available for IPsec (ESP) and for IKEv2, but not for IKEv1.
Disabling system-wide crypto policies for all connections
To disable system-wide crypto policies for all IPsec connections, comment out the following line in the /etc/ipsec.conf file:
include /etc/crypto-policies/back-ends/libreswan.config
Then add the ikev2=never option to your connection configuration file.
Additional resources
6.14. Troubleshooting IPsec VPN configurations
Problems related to IPsec VPN configurations most commonly occur due to several main reasons. If you are encountering such problems, you can check if the cause of the problem corresponds to any of the following scenarios, and apply the corresponding solution.
Basic connection troubleshooting
Most problems with VPN connections occur in new deployments, where administrators configured endpoints with mismatched configuration options. Also, a working configuration can suddenly stop working, often due to newly introduced incompatible values. This could be the result of an administrator changing the configuration. Alternatively, an administrator may have installed a firmware update or a package update with different default values for certain options, such as encryption algorithms.
To confirm that an IPsec VPN connection is established:
# ipsec trafficstatus
006 #8: "vpn.example.com"[1] 192.0.2.1, type=ESP, add_time=1595296930, inBytes=5999, outBytes=3231, id='@vpn.example.com', lease=100.64.13.5/32If the output is empty or does not show an entry with the connection name, the tunnel is broken.
To check that the problem is in the connection:
Reload the vpn.example.com connection:
# ipsec auto --add vpn.example.com 002 added connection description "vpn.example.com"Next, initiate the VPN connection:
# ipsec auto --up vpn.example.com
Firewall-related problems
The most common problem is that a firewall on one of the IPsec endpoints or on a router between the endpoints is dropping all Internet Key Exchange (IKE) packets.
For IKEv2, an output similar to the following example indicates a problem with a firewall:
# ipsec auto --up vpn.example.com 181 "vpn.example.com"[1] 192.0.2.2 #15: initiating IKEv2 IKE SA 181 "vpn.example.com"[1] 192.0.2.2 #15: STATE_PARENT_I1: sent v2I1, expected v2R1 010 "vpn.example.com"[1] 192.0.2.2 #15: STATE_PARENT_I1: retransmission; will wait 0.5 seconds for response 010 "vpn.example.com"[1] 192.0.2.2 #15: STATE_PARENT_I1: retransmission; will wait 1 seconds for response 010 "vpn.example.com"[1] 192.0.2.2 #15: STATE_PARENT_I1: retransmission; will wait 2 seconds for ...For IKEv1, the output of the initiating command looks like:
# ipsec auto --up vpn.example.com 002 "vpn.example.com" #9: initiating Main Mode 102 "vpn.example.com" #9: STATE_MAIN_I1: sent MI1, expecting MR1 010 "vpn.example.com" #9: STATE_MAIN_I1: retransmission; will wait 0.5 seconds for response 010 "vpn.example.com" #9: STATE_MAIN_I1: retransmission; will wait 1 seconds for response 010 "vpn.example.com" #9: STATE_MAIN_I1: retransmission; will wait 2 seconds for response ...
Because the IKE protocol, which is used to set up IPsec, is encrypted, you can troubleshoot only a limited subset of problems using the tcpdump tool. If a firewall is dropping IKE or IPsec packets, you can try to find the cause using the tcpdump utility. However, tcpdump cannot diagnose other problems with IPsec VPN connections.
To capture the negotiation of the VPN and all encrypted data on the
eth0interface:# tcpdump -i eth0 -n -n esp or udp port 500 or udp port 4500 or tcp port 4500
Mismatched algorithms, protocols, and policies
VPN connections require that the endpoints have matching IKE algorithms, IPsec algorithms, and IP address ranges. If a mismatch occurs, the connection fails. If you identify a mismatch by using one of the following methods, fix it by aligning algorithms, protocols, or policies.
If the remote endpoint is not running IKE/IPsec, you can see an ICMP packet indicating it. For example:
# ipsec auto --up vpn.example.com ... 000 "vpn.example.com"[1] 192.0.2.2 #16: ERROR: asynchronous network error report on wlp2s0 (192.0.2.2:500), complainant 198.51.100.1: Connection refused [errno 111, origin ICMP type 3 code 3 (not authenticated)] ...Example of mismatched IKE algorithms:
# ipsec auto --up vpn.example.com ... 003 "vpn.example.com"[1] 193.110.157.148 #3: dropping unexpected IKE_SA_INIT message containing NO_PROPOSAL_CHOSEN notification; message payloads: N; missing payloads: SA,KE,NiExample of mismatched IPsec algorithms:
# ipsec auto --up vpn.example.com ... 182 "vpn.example.com"[1] 193.110.157.148 #5: STATE_PARENT_I2: sent v2I2, expected v2R2 {auth=IKEv2 cipher=AES_GCM_16_256 integ=n/a prf=HMAC_SHA2_256 group=MODP2048} 002 "vpn.example.com"[1] 193.110.157.148 #6: IKE_AUTH response contained the error notification NO_PROPOSAL_CHOSENA mismatched IKE version could also result in the remote endpoint dropping the request without a response. This looks identical to a firewall dropping all IKE packets.
Example of mismatched IP address ranges for IKEv2 (called Traffic Selectors - TS):
# ipsec auto --up vpn.example.com ... 1v2 "vpn.example.com" #1: STATE_PARENT_I2: sent v2I2, expected v2R2 {auth=IKEv2 cipher=AES_GCM_16_256 integ=n/a prf=HMAC_SHA2_512 group=MODP2048} 002 "vpn.example.com" #2: IKE_AUTH response contained the error notification TS_UNACCEPTABLEExample of mismatched IP address ranges for IKEv1:
# ipsec auto --up vpn.example.com ... 031 "vpn.example.com" #2: STATE_QUICK_I1: 60 second timeout exceeded after 0 retransmits. No acceptable response to our first Quick Mode message: perhaps peer likes no proposalWhen using PreSharedKeys (PSK) in IKEv1, if both sides do not put in the same PSK, the entire IKE message becomes unreadable:
# ipsec auto --up vpn.example.com ... 003 "vpn.example.com" #1: received Hash Payload does not match computed value 223 "vpn.example.com" #1: sending notification INVALID_HASH_INFORMATION to 192.0.2.23:500In IKEv2, the mismatched-PSK error results in an AUTHENTICATION_FAILED message:
# ipsec auto --up vpn.example.com ... 002 "vpn.example.com" #1: IKE SA authentication request rejected by peer: AUTHENTICATION_FAILED
Maximum transmission unit
Other than firewalls blocking IKE or IPsec packets, the most common cause of networking problems relates to an increased packet size of encrypted packets. Network hardware fragments packets larger than the maximum transmission unit (MTU), for example, 1500 bytes. Often, the fragments are lost and the packets fail to re-assemble. This leads to intermittent failures, when a ping test, which uses small-sized packets, works but other traffic fails. In this case, you can establish an SSH session but the terminal freezes as soon as you use it, for example, by entering the 'ls -al /usr' command on the remote host.
To work around the problem, reduce MTU size by adding the mtu=1400 option to the tunnel configuration file.
Alternatively, for TCP connections, enable an iptables rule that changes the MSS value:
# iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
If the previous command does not solve the problem in your scenario, directly specify a lower size in the set-mss parameter:
# iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1380Network address translation (NAT)
When an IPsec host also serves as a NAT router, it could accidentally remap packets. The following example configuration demonstrates the problem:
conn myvpn
left=172.16.0.1
leftsubnet=10.0.2.0/24
right=172.16.0.2
rightsubnet=192.168.0.0/16
…The system with address 172.16.0.1 have a NAT rule:
iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
If the system on address 10.0.2.33 sends a packet to 192.168.0.1, then the router translates the source 10.0.2.33 to 172.16.0.1 before it applies the IPsec encryption.
Then, the packet with the source address 10.0.2.33 no longer matches the conn myvpn configuration, and IPsec does not encrypt this packet.
To solve this problem, insert rules that exclude NAT for target IPsec subnet ranges on the router, in this example:
iptables -t nat -I POSTROUTING -s 10.0.2.0/24 -d 192.168.0.0/16 -j RETURN
Kernel IPsec subsystem bugs
The kernel IPsec subsystem might fail, for example, when a bug causes a desynchronizing of the IKE user space and the IPsec kernel. To check for such problems:
$ cat /proc/net/xfrm_stat
XfrmInError 0
XfrmInBufferError 0
...Any non-zero value in the output of the previous command indicates a problem. If you encounter this problem, open a new support case, and attach the output of the previous command along with the corresponding IKE logs.
Libreswan logs
Libreswan logs using the syslog protocol by default. You can use the journalctl command to find log entries related to IPsec. Because the corresponding entries to the log are sent by the pluto IKE daemon, search for the “pluto” keyword, for example:
$ journalctl -b | grep pluto
To show a live log for the ipsec service:
$ journalctl -f -u ipsec
If the default level of logging does not reveal your configuration problem, enable debug logs by adding the plutodebug=all option to the config setup section in the /etc/ipsec.conf file.
Note that debug logging produces a lot of entries, and it is possible that either the journald or syslogd service rate-limits the syslog messages. To ensure you have complete logs, redirect the logging to a file. Edit the /etc/ipsec.conf, and add the logfile=/var/log/pluto.log in the config setup section.
Additional resources
- Troubleshooting problems using log files.
-
tcpdump(8)andipsec.conf(5)man pages. - Using and configuring firewalld
6.15. Additional resources
-
ipsec(8),ipsec.conf(5),ipsec.secrets(5),ipsec_auto(8), andipsec_rsasigkey(8)man pages. -
/usr/share/doc/libreswan-version/directory. - The website of the upstream project.
- The Libreswan Project Wiki.
- All Libreswan man pages.
- NIST Special Publication 800-77: Guide to IPsec VPNs.
Chapter 7. Configuring VPN connections with IPsec by using the vpn RHEL System Role
With the vpn System Role, you can configure VPN connections on RHEL systems by using Red Hat Ansible Automation Platform. You can use it to set up host-to-host, network-to-network, VPN Remote Access Server, and mesh configurations.
For host-to-host connections, the role sets up a VPN tunnel between each pair of hosts in the list of vpn_connections using the default parameters, including generating keys as needed. Alternatively, you can configure it to create an opportunistic mesh configuration between all hosts listed. The role assumes that the names of the hosts under hosts are the same as the names of the hosts used in the Ansible inventory, and that you can use those names to configure the tunnels.
The vpn RHEL System Role currently supports only Libreswan, which is an IPsec implementation, as the VPN provider.
7.1. Creating a host-to-host VPN with IPsec using the vpn System Role
You can use the vpn System Role to configure host-to-host connections by running an Ansible playbook on the control node, which will configure all the managed nodes listed in an inventory file.
Prerequisites
-
Access and permissions to one or more managed nodes, which are systems you want to configure with the
vpnSystem Role. Access and permissions to a control node, which is a system from which Red Hat Ansible Core configures other systems.
On the control node:
-
The
ansible-coreandrhel-system-rolespackages are installed.
-
The
RHEL 8.0-8.5 provided access to a separate Ansible repository that contains Ansible Engine 2.9 for automation based on Ansible. Ansible Engine contains command-line utilities such as ansible, ansible-playbook, connectors such as docker and podman, and many plugins and modules. For information about how to obtain and install Ansible Engine, see the How to download and install Red Hat Ansible Engine Knowledgebase article.
RHEL 8.6 and 9.0 have introduced Ansible Core (provided as the ansible-core package), which contains the Ansible command-line utilities, commands, and a small set of built-in Ansible plugins. RHEL provides this package through the AppStream repository, and it has a limited scope of support. For more information, see the Scope of support for the Ansible Core package included in the RHEL 9 and RHEL 8.6 and later AppStream repositories Knowledgebase article.
- An inventory file which lists the managed nodes.
Procedure
Create a new
playbook.ymlfile with the following content:- name: Host to host VPN hosts: managed_node1, managed_node2 roles: - rhel-system-roles.vpn vars: vpn_connections: - hosts: managed_node1: managed_node2: vpn_manage_firewall: true vpn_manage_selinux: true
This playbook configures the connection
managed_node1-to-managed_node2using pre-shared key authentication with keys auto-generated by the system role. Becausevpn_manage_firewallandvpn_manage_selinuxare both set totrue, thevpnrole uses thefirewallandselinuxroles to manage the ports used by thevpnrole.Optional: Configure connections from managed hosts to external hosts that are not listed in the inventory file by adding the following section to the
vpn_connectionslist of hosts:vpn_connections: - hosts: managed_node1: managed_node2: external_node: hostname: 192.0.2.2This configures two additional connections:
managed_node1-to-external_nodeandmanaged_node2-to-external_node.
The connections are configured only on the managed nodes and not on the external node.
Optional: You can specify multiple VPN connections for the managed nodes by using additional sections within
vpn_connections, for example a control plane and a data plane:- name: Multiple VPN hosts: managed_node1, managed_node2 roles: - rhel-system-roles.vpn vars: vpn_connections: - name: control_plane_vpn hosts: managed_node1: hostname: 192.0.2.0 # IP for the control plane managed_node2: hostname: 192.0.2.1 - name: data_plane_vpn hosts: managed_node1: hostname: 10.0.0.1 # IP for the data plane managed_node2: hostname: 10.0.0.2
-
Optional: You can modify the variables according to your preferences. For more details, see the
/usr/share/doc/rhel-system-roles/vpn/README.mdfile. Optional: Verify playbook syntax.
# ansible-playbook --syntax-check /path/to/file/playbook.yml -i /path/to/file/inventory_fileRun the playbook on your inventory file:
# ansible-playbook -i /path/to/file/inventory_file /path/to/file/playbook.yml
Verification
On the managed nodes, confirm that the connection is successfully loaded:
# ipsec status | grep connection.nameReplace connection.name with the name of the connection from this node, for example
managed_node1-to-managed_node2.
By default, the role generates a descriptive name for each connection it creates from the perspective of each system. For example, when creating a connection between managed_node1 and managed_node2, the descriptive name of this connection on managed_node1 is managed_node1-to-managed_node2 but on managed_node2 the connection is named managed_node2-to-managed_node1.
On the managed nodes, confirm that the connection is successfully started:
# ipsec trafficstatus | grep connection.nameOptional: If a connection did not successfully load, manually add the connection by entering the following command. This will provide more specific information indicating why the connection failed to establish:
# ipsec auto --add connection.nameNoteAny errors that may have occurred during the process of loading and starting the connection are reported in the logs, which can be found in
/var/log/pluto.log. Because these logs are hard to parse, try to manually add the connection to obtain log messages from the standard output instead.
7.2. Creating an opportunistic mesh VPN connection with IPsec by using the vpn System Role
You can use the vpn System Role to configure an opportunistic mesh VPN connection that uses certificates for authentication by running an Ansible playbook on the control node, which will configure all the managed nodes listed in an inventory file.
Authentication with certificates is configured by defining the auth_method: cert parameter in the playbook. The vpn System Role assumes that the IPsec Network Security Services (NSS) crypto library, which is defined in the /etc/ipsec.d directory, contains the necessary certificates. By default, the node name is used as the certificate nickname. In this example, this is managed_node1. You can define different certificate names by using the cert_name attribute in your inventory.
In the following example procedure, the control node, which is the system from which you will run the Ansible playbook, shares the same classless inter-domain routing (CIDR) number as both of the managed nodes (192.0.2.0/24) and has the IP address 192.0.2.7. Therefore, the control node falls under the private policy which is automatically created for CIDR 192.0.2.0/24.
To prevent SSH connection loss during the play, a clear policy for the control node is included in the list of policies. Note that there is also an item in the policies list where the CIDR is equal to default. This is because this playbook overrides the rule from the default policy to make it private instead of private-or-clear.
Prerequisites
Access and permissions to one or more managed nodes, which are systems you want to configure with the
vpnSystem Role.-
On all the managed nodes, the NSS database in the
/etc/ipsec.ddirectory contains all the certificates necessary for peer authentication. By default, the node name is used as the certificate nickname.
-
On all the managed nodes, the NSS database in the
Access and permissions to a control node, which is a system from which Red Hat Ansible Core configures other systems.
On the control node:
-
The
ansible-coreandrhel-system-rolespackages are installed.
-
The
RHEL 8.0-8.5 provided access to a separate Ansible repository that contains Ansible Engine 2.9 for automation based on Ansible. Ansible Engine contains command-line utilities such as ansible, ansible-playbook, connectors such as docker and podman, and many plugins and modules. For information about how to obtain and install Ansible Engine, see the How to download and install Red Hat Ansible Engine Knowledgebase article.
RHEL 8.6 and 9.0 have introduced Ansible Core (provided as the ansible-core package), which contains the Ansible command-line utilities, commands, and a small set of built-in Ansible plugins. RHEL provides this package through the AppStream repository, and it has a limited scope of support. For more information, see the Scope of support for the Ansible Core package included in the RHEL 9 and RHEL 8.6 and later AppStream repositories Knowledgebase article.
- An inventory file which lists the managed nodes.
Procedure
Create a new
playbook.ymlfile with the following content:- name: Mesh VPN hosts: managed_node1, managed_node2, managed_node3 roles: - rhel-system-roles.vpn vars: vpn_connections: - opportunistic: true auth_method: cert policies: - policy: private cidr: default - policy: private-or-clear cidr: 198.51.100.0/24 - policy: private cidr: 192.0.2.0/24 - policy: clear cidr: 192.0.2.7/32 vpn_manage_firewall: true vpn_manage_selinux: trueNoteBecause
vpn_manage_firewallandvpn_manage_selinuxare both set totrue, thevpnrole uses thefirewallandselinuxroles to manage the ports used by thevpnrole.-
Optional: You can modify the variables according to your preferences. For more details, see the
/usr/share/doc/rhel-system-roles/vpn/README.mdfile. Optional: Verify playbook syntax.
# ansible-playbook --syntax-check playbook.ymlRun the playbook on your inventory file:
# ansible-playbook -i inventory_file /path/to/file/playbook.yml
7.3. Additional resources
-
For details about the parameters used in the
vpnSystem Role and additional information about the role, see the/usr/share/doc/rhel-system-roles/vpn/README.mdfile. -
For details about the
ansible-playbookcommand, see theansible-playbook(1)man page.
Chapter 8. Using MACsec to encrypt layer-2 traffic in the same physical network
You can use MACsec to secure the communication between two devices (point-to-point). For example, your branch office is connected over a Metro-Ethernet connection with the central office, you can configure MACsec on the two hosts that connect the offices to increase the security.
Media Access Control security (MACsec) is a layer 2 protocol that secures different traffic types over the Ethernet links including:
- dynamic host configuration protocol (DHCP)
- address resolution protocol (ARP)
-
Internet Protocol version 4 / 6 (
IPv4/IPv6) and - any traffic over IP such as TCP or UDP
MACsec encrypts and authenticates all traffic in LANs, by default with the GCM-AES-128 algorithm, and uses a pre-shared key to establish the connection between the participant hosts. If you want to change the pre-shared key, you need to update the NM configuration on all hosts in the network that uses MACsec.
A MACsec connection uses an Ethernet device, such as an Ethernet network card, VLAN, or tunnel device, as parent. You can either set an IP configuration only on the MACsec device to communicate with other hosts only using the encrypted connection, or you can also set an IP configuration on the parent device. In the latter case, you can use the parent device to communicate with other hosts using an unencrypted connection and the MACsec device for encrypted connections.
MACsec does not require any special hardware. For example, you can use any switch, except if you want to encrypt traffic only between a host and a switch. In this scenario, the switch must also support MACsec.
In other words, there are 2 common methods to configure MACsec;
- host to host and
- host to switch then switch to other host(s)
You can use MACsec only between hosts that are in the same (physical or virtual) LAN.
8.1. Configuring a MACsec connection using nmcli
You can configure Ethernet interfaces to use MACsec using the nmcli utility. For example, you can create a MACsec connection between two hosts that are connected over Ethernet.
Procedure
On the first host on which you configure MACsec:
Create the connectivity association key (CAK) and connectivity-association key name (CKN) for the pre-shared key:
Create a 16-byte hexadecimal CAK:
# dd if=/dev/urandom count=16 bs=1 2> /dev/null | hexdump -e '1/2 "%04x"' 50b71a8ef0bd5751ea76de6d6c98c03a
Create a 32-byte hexadecimal CKN:
# dd if=/dev/urandom count=32 bs=1 2> /dev/null | hexdump -e '1/2 "%04x"' f2b4297d39da7330910a74abc0449feb45b5c0b9fc23df1430e1898fcf1c4550
- On both hosts you want to connect over a MACsec connection:
Create the MACsec connection:
# nmcli connection add type macsec con-name macsec0 ifname macsec0 connection.autoconnect yes macsec.parent enp1s0 macsec.mode psk macsec.mka-cak 50b71a8ef0bd5751ea76de6d6c98c03a macsec.mka-ckn f2b4297d39da7330910a74abc0449feb45b5c0b9fc23df1430e1898fcf1c4550Use the CAK and CKN generated in the previous step in the
macsec.mka-cakandmacsec.mka-cknparameters. The values must be the same on every host in the MACsec-protected network.Configure the IP settings on the MACsec connection.
Configure the
IPv4settings. For example, to set a staticIPv4address, network mask, default gateway, and DNS server to themacsec0connection, enter:# nmcli connection modify macsec0 ipv4.method manual ipv4.addresses '192.0.2.1/24' ipv4.gateway '192.0.2.254' ipv4.dns '192.0.2.253'Configure the
IPv6settings. For example, to set a staticIPv6address, network mask, default gateway, and DNS server to themacsec0connection, enter:# nmcli connection modify macsec0 ipv6.method manual ipv6.addresses '2001:db8:1::1/32' ipv6.gateway '2001:db8:1::fffe' ipv6.dns '2001:db8:1::fffd'
Activate the connection:
# nmcli connection up macsec0
Verification
Verify that the traffic is encrypted:
# tcpdump -nn -i enp1s0Optional: Display the unencrypted traffic:
# tcpdump -nn -i macsec0Display MACsec statistics:
# ip macsec showDisplay individual counters for each type of protection: integrity-only (encrypt off) and encryption (encrypt on)
# ip -s macsec show
8.2. Additional resources
Chapter 9. Using and configuring firewalld
A firewall is a way to protect machines from any unwanted traffic from outside. It enables users to control incoming network traffic on host machines by defining a set of firewall rules. These rules are used to sort the incoming traffic and either block it or allow through.
firewalld is a firewall service daemon that provides a dynamic customizable host-based firewall with a D-Bus interface. Being dynamic, it enables creating, changing, and deleting the rules without the necessity to restart the firewall daemon each time the rules are changed.
firewalld uses the concepts of zones and services, that simplify the traffic management. Zones are predefined sets of rules. Network interfaces and sources can be assigned to a zone. The traffic allowed depends on the network your computer is connected to and the security level this network is assigned. Firewall services are predefined rules that cover all necessary settings to allow incoming traffic for a specific service and they apply within a zone.
Services use one or more ports or addresses for network communication. Firewalls filter communication based on ports. To allow network traffic for a service, its ports must be open. firewalld blocks all traffic on ports that are not explicitly set as open. Some zones, such as trusted, allow all traffic by default.
Note that firewalld with nftables backend does not support passing custom nftables rules to firewalld, using the --direct option.
9.1. Getting started with firewalld
The following is an introduction to firewalld features, such as services and zones, and how to manage the firewalld systemd service.
9.1.1. When to use firewalld, nftables, or iptables
The following is a brief overview in which scenario you should use one of the following utilities:
-
firewalld: Use thefirewalldutility for simple firewall use cases. The utility is easy to use and covers the typical use cases for these scenarios. -
nftables: Use thenftablesutility to set up complex and performance-critical firewalls, such as for a whole network. -
iptables: Theiptablesutility on Red Hat Enterprise Linux uses thenf_tableskernel API instead of thelegacyback end. Thenf_tablesAPI provides backward compatibility so that scripts that useiptablescommands still work on Red Hat Enterprise Linux. For new firewall scripts, Red Hat recommends to usenftables.
To prevent the different firewall services from influencing each other, run only one of them on a RHEL host, and disable the other services.
9.1.2. Zones
firewalld can be used to separate networks into different zones according to the level of trust that the user has decided to place on the interfaces and traffic within that network. A connection can only be part of one zone, but a zone can be used for many network connections.
NetworkManager notifies firewalld of the zone of an interface. You can assign zones to interfaces with:
-
NetworkManager -
firewall-configtool -
firewall-cmdcommand-line tool - The RHEL web console
The latter three can only edit the appropriate NetworkManager configuration files. If you change the zone of the interface using the web console, firewall-cmd or firewall-config, the request is forwarded to NetworkManager and is not handled by firewalld.
The predefined zones are stored in the /usr/lib/firewalld/zones/ directory and can be instantly applied to any available network interface. These files are copied to the /etc/firewalld/zones/ directory only after they are modified. The default settings of the predefined zones are as follows:
block-
Any incoming network connections are rejected with an icmp-host-prohibited message for
IPv4and icmp6-adm-prohibited forIPv6. Only network connections initiated from within the system are possible. dmz- For computers in your demilitarized zone that are publicly-accessible with limited access to your internal network. Only selected incoming connections are accepted.
drop- Any incoming network packets are dropped without any notification. Only outgoing network connections are possible.
external- For use on external networks with masquerading enabled, especially for routers. You do not trust the other computers on the network to not harm your computer. Only selected incoming connections are accepted.
home- For use at home when you mostly trust the other computers on the network. Only selected incoming connections are accepted.
internal- For use on internal networks when you mostly trust the other computers on the network. Only selected incoming connections are accepted.
public- For use in public areas where you do not trust other computers on the network. Only selected incoming connections are accepted.
trusted- All network connections are accepted.
work- For use at work where you mostly trust the other computers on the network. Only selected incoming connections are accepted.
One of these zones is set as the default zone. When interface connections are added to NetworkManager, they are assigned to the default zone. On installation, the default zone in firewalld is set to be the public zone. The default zone can be changed.
The network zone names should be self-explanatory and to allow users to quickly make a reasonable decision. To avoid any security problems, review the default zone configuration and disable any unnecessary services according to your needs and risk assessments.
Additional resources
-
The
firewalld.zone(5)man page.
9.1.3. Predefined services
A service can be a list of local ports, protocols, source ports, and destinations, as well as a list of firewall helper modules automatically loaded if a service is enabled. Using services saves users time because they can achieve several tasks, such as opening ports, defining protocols, enabling packet forwarding and more, in a single step, rather than setting up everything one after another.
Service configuration options and generic file information are described in the firewalld.service(5) man page. The services are specified by means of individual XML configuration files, which are named in the following format: service-name.xml. Protocol names are preferred over service or application names in firewalld.
Services can be added and removed using the graphical firewall-config tool, firewall-cmd, and firewall-offline-cmd.
Alternatively, you can edit the XML files in the /etc/firewalld/services/ directory. If a service is not added or changed by the user, then no corresponding XML file is found in /etc/firewalld/services/. The files in the /usr/lib/firewalld/services/ directory can be used as templates if you want to add or change a service.
Additional resources
-
The
firewalld.service(5)man page
9.1.4. Starting firewalld
Procedure
To start
firewalld, enter the following command asroot:# systemctl unmask firewalld # systemctl start firewalld
To ensure
firewalldstarts automatically at system start, enter the following command asroot:# systemctl enable firewalld
9.1.5. Stopping firewalld
Procedure
To stop
firewalld, enter the following command asroot:# systemctl stop firewalldTo prevent
firewalldfrom starting automatically at system start:# systemctl disable firewalldTo make sure firewalld is not started by accessing the
firewalldD-Businterface and also if other services requirefirewalld:# systemctl mask firewalld
9.1.6. Verifying the permanent firewalld configuration
In certain situations, for example after manually editing firewalld configuration files, administrators want to verify that the changes are correct. You can use the firewall-cmd utility to verify the configuration.
Prerequisites
-
The
firewalldservice is running.
Procedure
Verify the permanent configuration of the
firewalldservice:# firewall-cmd --check-config successIf the permanent configuration is valid, the command returns
success. In other cases, the command returns an error with further details, such as the following:# firewall-cmd --check-config Error: INVALID_PROTOCOL: 'public.xml': 'tcpx' not from {'tcp'|'udp'|'sctp'|'dccp'}
9.2. Viewing the current status and settings of firewalld
To monitor the firewalld service, you can display the status, allowed services, and settings.
9.2.1. Viewing the current status of firewalld
The firewall service, firewalld, is installed on the system by default. Use the firewalld CLI interface to check that the service is running.
Procedure
To see the status of the service:
# firewall-cmd --stateFor more information about the service status, use the
systemctl statussub-command:# systemctl status firewalld firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor pr Active: active (running) since Mon 2017-12-18 16:05:15 CET; 50min ago Docs: man:firewalld(1) Main PID: 705 (firewalld) Tasks: 2 (limit: 4915) CGroup: /system.slice/firewalld.service └─705 /usr/bin/python3 -Es /usr/sbin/firewalld --nofork --nopid
9.2.2. Viewing allowed services using GUI
To view the list of services using the graphical firewall-config tool, press the Super key to enter the Activities Overview, type firewall, and press Enter. The firewall-config tool appears. You can now view the list of services under the Services tab.
You can start the graphical firewall configuration tool using the command-line.
Prerequisites
-
You installed the
firewall-configpackage.
Procedure
To start the graphical firewall configuration tool using the command-line:
$ firewall-config
The Firewall Configuration window opens. Note that this command can be run as a normal user, but you are prompted for an administrator password occasionally.
9.2.3. Viewing firewalld settings using CLI
With the CLI client, it is possible to get different views of the current firewall settings. The --list-all option shows a complete overview of the firewalld settings.
firewalld uses zones to manage the traffic. If a zone is not specified by the --zone option, the command is effective in the default zone assigned to the active network interface and connection.
Procedure
To list all the relevant information for the default zone:
# firewall-cmd --list-all public target: default icmp-block-inversion: no interfaces: sources: services: ssh dhcpv6-client ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:To specify the zone for which to display the settings, add the
--zone=zone-nameargument to thefirewall-cmd --list-allcommand, for example:# firewall-cmd --list-all --zone=home home target: default icmp-block-inversion: no interfaces: sources: services: ssh mdns samba-client dhcpv6-client ...To see the settings for particular information, such as services or ports, use a specific option. See the
firewalldmanual pages or get a list of the options using the command help:# firewall-cmd --helpTo see which services are allowed in the current zone:
# firewall-cmd --list-services ssh dhcpv6-client
Listing the settings for a certain subpart using the CLI tool can sometimes be difficult to interpret. For example, you allow the SSH service and firewalld opens the necessary port (22) for the service. Later, if you list the allowed services, the list shows the SSH service, but if you list open ports, it does not show any. Therefore, it is recommended to use the --list-all option to make sure you receive a complete information.
9.3. Controlling network traffic using firewalld
The firewalld package installs a large number of predefined service files and you can add more or customize them. You can then use these service definitions to open or close ports for services without knowing the protocol and port numbers they use.
9.3.1. Disabling all traffic in case of emergency using CLI
In an emergency situation, such as a system attack, it is possible to disable all network traffic and cut off the attacker.
Procedure
To immediately disable networking traffic, switch panic mode on:
# firewall-cmd --panic-onImportantEnabling panic mode stops all networking traffic. For this reason, it should be used only when you have the physical access to the machine or if you are logged in using a serial console.
Switching off panic mode reverts the firewall to its permanent settings. To switch panic mode off, enter:
# firewall-cmd --panic-off
Verification
To see whether panic mode is switched on or off, use:
# firewall-cmd --query-panic
9.3.2. Controlling traffic with predefined services using CLI
The most straightforward method to control traffic is to add a predefined service to firewalld. This opens all necessary ports and modifies other settings according to the service definition file.
Procedure
Check that the service is not already allowed:
# firewall-cmd --list-services ssh dhcpv6-clientList all predefined services:
# firewall-cmd --get-services RH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client dns docker-registry ...Add the service to the allowed services:
# firewall-cmd --add-service=<service_name>Make the new settings persistent:
# firewall-cmd --runtime-to-permanent
9.3.3. Controlling traffic with predefined services using GUI
You can control the network traffic with predefined services using graphical user interface.
Prerequisites
-
You installed the
firewall-configpackage
Procedure
To enable or disable a predefined or custom service:
- Start the firewall-config tool and select the network zone whose services are to be configured.
-
Select the
Zonestab and then theServicestab below. - Select the check box for each type of service you want to trust or clear the check box to block a service in the selected zone.
To edit a service:
- Start the firewall-config tool.
-
Select
Permanentfrom the menu labeledConfiguration. Additional icons and menu buttons appear at the bottom of the Services window. - Select the service you want to configure.
The Ports, Protocols, and Source Port tabs enable adding, changing, and removing of ports, protocols, and source port for the selected service. The modules tab is for configuring Netfilter helper modules. The Destination tab enables limiting traffic to a particular destination address and Internet Protocol (IPv4 or IPv6).
It is not possible to alter service settings in the Runtime mode.
9.3.4. Adding new services
Services can be added and removed using the graphical firewall-config tool, firewall-cmd, and firewall-offline-cmd. Alternatively, you can edit the XML files in /etc/firewalld/services/. If a service is not added or changed by the user, then no corresponding XML file are found in /etc/firewalld/services/. The files /usr/lib/firewalld/services/ can be used as templates if you want to add or change a service.
Service names must be alphanumeric and can, additionally, include only _ (underscore) and - (dash) characters.
Procedure
To add a new service in a terminal, use firewall-cmd, or firewall-offline-cmd in case of not active firewalld.
Enter the following command to add a new and empty service:
$ firewall-cmd --new-service=<service_name> --permanentTo add a new service using a local file, use the following command:
$ firewall-cmd --new-service-from-file=<service_xml_file> --permanentYou can change the service name with the additional
--name=<service_name>option.As soon as service settings are changed, an updated copy of the service is placed into
/etc/firewalld/services/.As
root, you can enter the following command to copy a service manually:# cp /usr/lib/firewalld/services/service-name.xml /etc/firewalld/services/service-name.xml
firewalld loads files from /usr/lib/firewalld/services in the first place. If files are placed in /etc/firewalld/services and they are valid, then these will override the matching files from /usr/lib/firewalld/services. The overridden files in /usr/lib/firewalld/services are used as soon as the matching files in /etc/firewalld/services have been removed or if firewalld has been asked to load the defaults of the services. This applies to the permanent environment only. A reload is needed to get these fallbacks also in the runtime environment.
9.3.5. Opening ports using GUI
To permit traffic through the firewall to a certain port, you can open the port in the GUI.
Prerequisites
-
You installed the
firewall-configpackage
Procedure
- Start the firewall-config tool and select the network zone whose settings you want to change.
-
Select the
Portstab and click the Add button on the right-hand side. ThePort and Protocolwindow opens. - Enter the port number or range of ports to permit.
-
Select
tcporudpfrom the list.
9.3.6. Controlling traffic with protocols using GUI
To permit traffic through the firewall using a certain protocol, you can use the GUI.
Prerequisites
-
You installed the
firewall-configpackage
Procedure
- Start the firewall-config tool and select the network zone whose settings you want to change.
-
Select the
Protocolstab and click theAddbutton on the right-hand side. TheProtocolwindow opens. -
Either select a protocol from the list or select the
Other Protocolcheck box and enter the protocol in the field.
9.3.7. Opening source ports using GUI
To permit traffic through the firewall from a certain port, you can use the GUI.
Prerequisites
-
You installed the
firewall-configpackage
Procedure
- Start the firewall-config tool and select the network zone whose settings you want to change.
-
Select the
Source Porttab and click theAddbutton on the right-hand side. TheSource Portwindow opens. -
Enter the port number or range of ports to permit. Select
tcporudpfrom the list.
9.4. Controlling ports using CLI
Ports are logical devices that enable an operating system to receive and distinguish network traffic and forward it accordingly to system services. These are usually represented by a daemon that listens on the port, that is it waits for any traffic coming to this port.
Normally, system services listen on standard ports that are reserved for them. The httpd daemon, for example, listens on port 80. However, system administrators by default configure daemons to listen on different ports to enhance security or for other reasons.
9.4.1. Opening a port
Through open ports, the system is accessible from the outside, which represents a security risk. Generally, keep ports closed and only open them if they are required for certain services.
Procedure
To get a list of open ports in the current zone:
List all allowed ports:
# firewall-cmd --list-portsAdd a port to the allowed ports to open it for incoming traffic:
# firewall-cmd --add-port=port-number/port-typeThe port types are either
tcp,udp,sctp, ordccp. The type must match the type of network communication.Make the new settings persistent:
# firewall-cmd --runtime-to-permanentThe port types are either
tcp,udp,sctp, ordccp. The type must match the type of network communication.
9.4.2. Closing a port
When an open port is no longer needed, close that port in firewalld. It is highly recommended to close all unnecessary ports as soon as they are not used because leaving a port open represents a security risk.
Procedure
To close a port, remove it from the list of allowed ports:
List all allowed ports:
# firewall-cmd --list-portsWarningThis command will only give you a list of ports that have been opened as ports. You will not be able to see any open ports that have been opened as a service. Therefore, you should consider using the
--list-alloption instead of--list-ports.Remove the port from the allowed ports to close it for the incoming traffic:
# firewall-cmd --remove-port=port-number/port-typeMake the new settings persistent:
# firewall-cmd --runtime-to-permanent
9.5. Working with firewalld zones
Zones represent a concept to manage incoming traffic more transparently. The zones are connected to networking interfaces or assigned a range of source addresses. You manage firewall rules for each zone independently, which enables you to define complex firewall settings and apply them to the traffic.
9.5.1. Listing zones
You can list zones using the command line.
Procedure
To see which zones are available on your system:
# firewall-cmd --get-zonesThe
firewall-cmd --get-zonescommand displays all zones that are available on the system, but it does not show any details for particular zones.To see detailed information for all zones:
# firewall-cmd --list-all-zonesTo see detailed information for a specific zone:
# firewall-cmd --zone=zone-name --list-all
9.5.2. Modifying firewalld settings for a certain zone
The Controlling traffic with predefined services using cli and Controlling ports using cli explain how to add services or modify ports in the scope of the current working zone. Sometimes, it is required to set up rules in a different zone.
Procedure
To work in a different zone, use the
--zone=<zone_name>option. For example, to allow theSSHservice in the zonepublic:# firewall-cmd --add-service=ssh --zone=public
9.5.3. Changing the default zone
System administrators assign a zone to a networking interface in its configuration files. If an interface is not assigned to a specific zone, it is assigned to the default zone. After each restart of the firewalld service, firewalld loads the settings for the default zone and makes it active.
Procedure
To set up the default zone:
Display the current default zone:
# firewall-cmd --get-default-zoneSet the new default zone:
# firewall-cmd --set-default-zone <zone_name>NoteFollowing this procedure, the setting is a permanent setting, even without the
--permanentoption.
9.5.4. Assigning a network interface to a zone
It is possible to define different sets of rules for different zones and then change the settings quickly by changing the zone for the interface that is being used. With multiple interfaces, a specific zone can be set for each of them to distinguish traffic that is coming through them.
Procedure
To assign the zone to a specific interface:
List the active zones and the interfaces assigned to them:
# firewall-cmd --get-active-zonesAssign the interface to a different zone:
# firewall-cmd --zone=zone_name --change-interface=interface_name --permanent
9.5.5. Assigning a zone to a connection using nmcli
You can add a firewalld zone to a NetworkManager connection using the nmcli utility.
Procedure
Assign the zone to the
NetworkManagerconnection profile:# nmcli connection modify profile connection.zone zone_nameActivate the connection:
# nmcli connection up profile
9.5.6. Manually assigning a zone to a network connection in an ifcfg file
When the connection is managed by NetworkManager, it must be aware of a zone that it uses. For every network connection, a zone can be specified, which provides the flexibility of various firewall settings according to the location of the computer with portable devices. Thus, zones and settings can be specified for different locations, such as company or home.
Procedure
To set a zone for a connection, edit the
/etc/sysconfig/network-scripts/ifcfg-connection_namefile and add a line that assigns a zone to this connection:ZONE=zone_name
9.5.7. Creating a new zone
To use custom zones, create a new zone and use it just like a predefined zone. New zones require the --permanent option, otherwise the command does not work.
Procedure
Create a new zone:
# firewall-cmd --permanent --new-zone=zone-nameCheck if the new zone is added to your permanent settings:
# firewall-cmd --get-zonesMake the new settings persistent:
# firewall-cmd --runtime-to-permanent
9.5.8. Zone configuration files
Zones can also be created using a zone configuration file. This approach can be helpful when you need to create a new zone, but want to reuse the settings from a different zone and only alter them a little.
A firewalld zone configuration file contains the information for a zone. These are the zone description, services, ports, protocols, icmp-blocks, masquerade, forward-ports and rich language rules in an XML file format. The file name has to be zone-name.xml where the length of zone-name is currently limited to 17 chars. The zone configuration files are located in the /usr/lib/firewalld/zones/ and /etc/firewalld/zones/ directories.
The following example shows a configuration that allows one service (SSH) and one port range, for both the TCP and UDP protocols:
<?xml version="1.0" encoding="utf-8"?> <zone> <short>My Zone</short> <description>Here you can describe the characteristic features of the zone.</description> <service name="ssh"/> <port protocol="udp" port="1025-65535"/> <port protocol="tcp" port="1025-65535"/> </zone>
To change settings for that zone, add or remove sections to add ports, forward ports, services, and so on.
Additional resources
-
firewalld.zonemanual page
9.5.9. Using zone targets to set default behavior for incoming traffic
For every zone, you can set a default behavior that handles incoming traffic that is not further specified. Such behavior is defined by setting the target of the zone. There are four options:
-
ACCEPT: Accepts all incoming packets except those disallowed by specific rules. -
REJECT: Rejects all incoming packets except those allowed by specific rules. Whenfirewalldrejects packets, the source machine is informed about the rejection. -
DROP: Drops all incoming packets except those allowed by specific rules. Whenfirewallddrops packets, the source machine is not informed about the packet drop. -
default: Similar behavior as forREJECT, but with special meanings in certain scenarios. For details, see theOptions to Adapt and Query Zones and Policiessection in thefirewall-cmd(1)man page.
Procedure
To set a target for a zone:
List the information for the specific zone to see the default target:
# firewall-cmd --zone=zone-name --list-allSet a new target in the zone:
# firewall-cmd --permanent --zone=zone-name --set-target=<default|ACCEPT|REJECT|DROP>
Additional resources
-
firewall-cmd(1)man page
9.6. Using zones to manage incoming traffic depending on a source
You can use zones to manage incoming traffic based on its source. That enables you to sort incoming traffic and route it through different zones to allow or disallow services that can be reached by that traffic.
If you add a source to a zone, the zone becomes active and any incoming traffic from that source will be directed through it. You can specify different settings for each zone, which is applied to the traffic from the given sources accordingly. You can use more zones even if you only have one network interface.
9.6.1. Adding a source
To route incoming traffic into a specific zone, add the source to that zone. The source can be an IP address or an IP mask in the classless inter-domain routing (CIDR) notation.
In case you add multiple zones with an overlapping network range, they are ordered alphanumerically by zone name and only the first one is considered.
To set the source in the current zone:
# firewall-cmd --add-source=<source>To set the source IP address for a specific zone:
# firewall-cmd --zone=zone-name --add-source=<source>
The following procedure allows all incoming traffic from 192.168.2.15 in the trusted zone:
Procedure
List all available zones:
# firewall-cmd --get-zonesAdd the source IP to the trusted zone in the permanent mode:
# firewall-cmd --zone=trusted --add-source=192.168.2.15Make the new settings persistent:
# firewall-cmd --runtime-to-permanent
9.6.2. Removing a source
Removing a source from the zone cuts off the traffic coming from it.
Procedure
List allowed sources for the required zone:
# firewall-cmd --zone=zone-name --list-sourcesRemove the source from the zone permanently:
# firewall-cmd --zone=zone-name --remove-source=<source>Make the new settings persistent:
# firewall-cmd --runtime-to-permanent
9.6.3. Adding a source port
To enable sorting the traffic based on a port of origin, specify a source port using the --add-source-port option. You can also combine this with the --add-source option to limit the traffic to a certain IP address or IP range.
Procedure
To add a source port:
# firewall-cmd --zone=zone-name --add-source-port=<port-name>/<tcp|udp|sctp|dccp>
9.6.4. Removing a source port
By removing a source port you disable sorting the traffic based on a port of origin.
Procedure
To remove a source port:
# firewall-cmd --zone=zone-name --remove-source-port=<port-name>/<tcp|udp|sctp|dccp>
9.6.5. Using zones and sources to allow a service for only a specific domain
To allow traffic from a specific network to use a service on a machine, use zones and source. The following procedure allows only HTTP traffic from the 192.0.2.0/24 network while any other traffic is blocked.
When you configure this scenario, use a zone that has the default target. Using a zone that has the target set to ACCEPT is a security risk, because for traffic from 192.0.2.0/24, all network connections would be accepted.
Procedure
List all available zones:
# firewall-cmd --get-zones block dmz drop external home internal public trusted workAdd the IP range to the
internalzone to route the traffic originating from the source through the zone:# firewall-cmd --zone=internal --add-source=192.0.2.0/24Add the
httpservice to theinternalzone:# firewall-cmd --zone=internal --add-service=httpMake the new settings persistent:
# firewall-cmd --runtime-to-permanent
Verification
Check that the
internalzone is active and that the service is allowed in it:# firewall-cmd --zone=internal --list-all internal (active) target: default icmp-block-inversion: no interfaces: sources: 192.0.2.0/24 services: cockpit dhcpv6-client mdns samba-client ssh http ...
Additional resources
-
firewalld.zones(5)man page
9.7. Filtering forwarded traffic between zones
With a policy object, users can group different identities that require similar permissions in the policy. You can apply policies depending on the direction of the traffic.
The policy objects feature provides forward and output filtering in firewalld. You can use firewalld to filter traffic between different zones to allow access to locally hosted VMs to connect the host.
9.7.1. The relationship between policy objects and zones
Policy objects allow the user to attach firewalld’s primitives’ such as services, ports, and rich rules to the policy. You can apply the policy objects to traffic that passes between zones in a stateful and unidirectional manner.
# firewall-cmd --permanent --new-policy myOutputPolicy # firewall-cmd --permanent --policy myOutputPolicy --add-ingress-zone HOST # firewall-cmd --permanent --policy myOutputPolicy --add-egress-zone ANY
HOST and ANY are the symbolic zones used in the ingress and egress zone lists.
-
The
HOSTsymbolic zone allows policies for the traffic originating from or has a destination to the host running firewalld. -
The
ANYsymbolic zone applies policy to all the current and future zones.ANYsymbolic zone acts as a wildcard for all zones.
9.7.2. Using priorities to sort policies
Multiple policies can apply to the same set of traffic, therefore, priorities should be used to create an order of precedence for the policies that may be applied.
To set a priority to sort the policies:
# firewall-cmd --permanent --policy mypolicy --set-priority -500In the above example -500 is a lower priority value but has higher precedence. Thus, -500 will execute before -100. Higher priority values have precedence over lower values.
The following rules apply to policy priorities:
- Policies with negative priorities apply before rules in zones.
- Policies with positive priorities apply after rules in zones.
- Priority 0 is reserved and hence is unusable.
9.7.3. Using policy objects to filter traffic between locally hosted Containers and a network physically connected to the host
The policy objects feature allows users to filter their container and virtual machine traffic.
Procedure
Create a new policy.
# firewall-cmd --permanent --new-policy podmanToHostBlock all traffic.
# firewall-cmd --permanent --policy podmanToHost --set-target REJECT # firewall-cmd --permanent --policy podmanToHost --add-service dhcp # firewall-cmd --permanent --policy podmanToHost --add-service dns
NoteRed Hat recommends that you block all traffic to the host by default and then selectively open the services you need for the host.
Define the ingress zone to use with the policy.
# firewall-cmd --permanent --policy podmanToHost --add-ingress-zone podmanDefine the egress zone to use with the policy.
# firewall-cmd --permanent --policy podmanToHost --add-egress-zone ANY
Verification
Verify information about the policy.
# firewall-cmd --info-policy podmanToHost
9.7.4. Setting the default target of policy objects
You can specify --set-target options for policies. The following targets are available:
-
ACCEPT- accepts the packet -
DROP- drops the unwanted packets -
REJECT- rejects unwanted packets with an ICMP reply CONTINUE(default) - packets will be subject to rules in following policies and zones.# firewall-cmd --permanent --policy mypolicy --set-target CONTINUE
Verification
Verify information about the policy
# firewall-cmd --info-policy mypolicy
9.8. Configuring NAT using firewalld
With firewalld, you can configure the following network address translation (NAT) types:
- Masquerading
- Source NAT (SNAT)
- Destination NAT (DNAT)
- Redirect
9.8.1. NAT types
These are the different network address translation (NAT) types:
- Masquerading and source NAT (SNAT)
Use one of these NAT types to change the source IP address of packets. For example, Internet Service Providers (ISPs) do not route private IP ranges, such as
10.0.0.0/8. If you use private IP ranges in your network and users should be able to reach servers on the internet, map the source IP address of packets from these ranges to a public IP address.Masquerading and SNAT are very similar to one another. The differences are:
- Masquerading automatically uses the IP address of the outgoing interface. Therefore, use masquerading if the outgoing interface uses a dynamic IP address.
- SNAT sets the source IP address of packets to a specified IP and does not dynamically look up the IP of the outgoing interface. Therefore, SNAT is faster than masquerading. Use SNAT if the outgoing interface uses a fixed IP address.
- Destination NAT (DNAT)
- Use this NAT type to rewrite the destination address and port of incoming packets. For example, if your web server uses an IP address from a private IP range and is, therefore, not directly accessible from the internet, you can set a DNAT rule on the router to redirect incoming traffic to this server.
- Redirect
- This type is a special case of DNAT that redirects packets to the local machine depending on the chain hook. For example, if a service runs on a different port than its standard port, you can redirect incoming traffic from the standard port to this specific port.
9.8.2. Configuring IP address masquerading
You can enable IP masquerading on your system. IP masquerading hides individual machines behind a gateway when accessing the internet.
Procedure
To check if IP masquerading is enabled (for example, for the
externalzone), enter the following command asroot:# firewall-cmd --zone=external --query-masqueradeThe command prints
yeswith exit status0if enabled. It printsnowith exit status1otherwise. Ifzoneis omitted, the default zone will be used.To enable IP masquerading, enter the following command as
root:# firewall-cmd --zone=external --add-masquerade-
To make this setting persistent, pass the
--permanentoption to the command. To disable IP masquerading, enter the following command as
root:# firewall-cmd --zone=external --remove-masqueradeTo make this setting permanent, pass the
--permanentoption to the command.
9.9. Using DNAT to forward HTTPS traffic to a different host
If your web server runs in a DMZ with private IP addresses, you can configure destination network address translation (DNAT) to enable clients on the internet to connect to this web server. In this case, the host name of the web server resolves to the public IP address of the router. When a client establishes a connection to a defined port on the router, the router forwards the packets to the internal web server.
Prerequisites
- The DNS server resolves the host name of the web server to the router’s IP address.
You know the following settings:
- The private IP address and port number that you want to forward
- The IP protocol to be used
- The destination IP address and port of the web server where you want to redirect the packets
Procedure
Create a firewall policy:
# firewall-cmd --permanent --new-policy ExamplePolicyThe policies, as opposed to zones, allow packet filtering for input, output, and forwarded traffic. This is important, because forwarding traffic to endpoints on locally run web servers, containers, or virtual machines requires such capability.
Configure symbolic zones for the ingress and egress traffic to also enable the router itself to connect to its local IP address and forward this traffic:
# firewall-cmd --permanent --policy=ExamplePolicy --add-ingress-zone=HOST # firewall-cmd --permanent --policy=ExamplePolicy --add-egress-zone=ANY
The
--add-ingress-zone=HOSToption refers to packets generated locally, which are transmitted out of the local host. The--add-egress-zone=ANYoption refers to traffic destined to any zone.Add a rich rule that forwards traffic to the web server:
# firewall-cmd --permanent --policy=ExamplePolicy --add-rich-rule='rule family="ipv4" destination address="192.0.2.1" forward-port port="443" protocol="tcp" to-port="443" to-addr="192.51.100.20"'The rich rule forwards TCP traffic from port 443 on the router’s IP address 192.0.2.1 to port 443 of the web server’s IP 192.51.100.20. The rule uses the
ExamplePolicyto ensure that the router can also connect to its local IP address.Reload the firewall configuration files:
# firewall-cmd --reload successActivate routing of 127.0.0.0/8 in the kernel:
# echo "net.ipv4.conf.all.route_localnet=1" > /etc/sysctl.d/90-enable-route-localnet.conf # sysctl -p /etc/sysctl.d/90-enable-route-localnet.conf
Verification
Connect to the router’s IP address and port that you have forwarded to the web server:
# curl https://192.0.2.1:443Optional: Verify that
net.ipv4.conf.all.route_localnetis active:# sysctl net.ipv4.conf.all.route_localnet net.ipv4.conf.all.route_localnet = 1Verify that
ExamplePolicyis active and contains the settings you need. Especially the source IP address and port, protocol to be used, and the destination IP address and port:# firewall-cmd --info-policy=ExamplePolicy ExamplePolicy (active) priority: -1 target: CONTINUE ingress-zones: HOST egress-zones: ANY services: ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: rule family="ipv4" destination address="192.0.2.1" forward-port port="443" protocol="tcp" to-port="443" to-addr="192.51.100.20"
Additional resources
-
firewall-cmd(1),firewalld.policies(5),firewalld.richlanguage(5),sysctl(8), andsysctl.conf(5)man pages - Using configuration files in /etc/sysctl.d/ to adjust kernel parameters
9.10. Managing ICMP requests
The Internet Control Message Protocol (ICMP) is a supporting protocol that is used by various network devices to send error messages and operational information indicating a connection problem, for example, that a requested service is not available. ICMP differs from transport protocols such as TCP and UDP because it is not used to exchange data between systems.
Unfortunately, it is possible to use the ICMP messages, especially echo-request and echo-reply, to reveal information about your network and misuse such information for various kinds of fraudulent activities. Therefore, firewalld enables blocking the ICMP requests to protect your network information.
9.10.1. Listing and blocking ICMP requests
Listing ICMP requests
The ICMP requests are described in individual XML files that are located in the /usr/lib/firewalld/icmptypes/ directory. You can read these files to see a description of the request. The firewall-cmd command controls the ICMP requests manipulation.
To list all available
ICMPtypes:#
firewall-cmd --get-icmptypesThe
ICMPrequest can be used by IPv4, IPv6, or by both protocols. To see for which protocol theICMPrequest has used:#
firewall-cmd --info-icmptype=<icmptype>The status of an
ICMPrequest showsyesif the request is currently blocked ornoif it is not. To see if anICMPrequest is currently blocked:#
firewall-cmd --query-icmp-block=<icmptype>
Blocking or unblocking ICMP requests
When your server blocks ICMP requests, it does not provide the information that it normally would. However, that does not mean that no information is given at all. The clients receive information that the particular ICMP request is being blocked (rejected). Blocking the ICMP requests should be considered carefully, because it can cause communication problems, especially with IPv6 traffic.
To see if an
ICMPrequest is currently blocked:#
firewall-cmd --query-icmp-block=<icmptype>To block an
ICMPrequest:#
firewall-cmd --add-icmp-block=<icmptype>To remove the block for an
ICMPrequest:#
firewall-cmd --remove-icmp-block=<icmptype>
Blocking ICMP requests without providing any information at all
Normally, if you block ICMP requests, clients know that you are blocking it. So, a potential attacker who is sniffing for live IP addresses is still able to see that your IP address is online. To hide this information completely, you have to drop all ICMP requests.
-
To block and drop all
ICMPrequests: Set the target of your zone to
DROP:#
firewall-cmd --permanent --set-target=DROP
Now, all traffic, including ICMP requests, is dropped, except traffic which you have explicitly allowed.
To block and drop certain ICMP requests and allow others:
Set the target of your zone to
DROP:#
firewall-cmd --permanent --set-target=DROPAdd the ICMP block inversion to block all
ICMPrequests at once:#
firewall-cmd --add-icmp-block-inversionAdd the ICMP block for those
ICMPrequests that you want to allow:#
firewall-cmd --add-icmp-block=<icmptype>Make the new settings persistent:
#
firewall-cmd --runtime-to-permanent
The block inversion inverts the setting of the ICMP requests blocks, so all requests, that were not previously blocked, are blocked because of the target of your zone changes to DROP. The requests that were blocked are not blocked. This means that if you want to unblock a request, you must use the blocking command.
To revert the block inversion to a fully permissive setting:
Set the target of your zone to
defaultorACCEPT:#
firewall-cmd --permanent --set-target=defaultRemove all added blocks for
ICMPrequests:#
firewall-cmd --remove-icmp-block=<icmptype>Remove the
ICMPblock inversion:#
firewall-cmd --remove-icmp-block-inversionMake the new settings persistent:
#
firewall-cmd --runtime-to-permanent
9.10.2. Configuring the ICMP filter using GUI
-
To enable or disable an
ICMPfilter, start the firewall-config tool and select the network zone whose messages are to be filtered. Select theICMP Filtertab and select the check box for each type ofICMPmessage you want to filter. Clear the check box to disable a filter. This setting is per direction and the default allows everything. -
To enable inverting the
ICMP Filter, click theInvert Filtercheck box on the right. Only markedICMPtypes are now accepted, all other are rejected. In a zone using the DROP target, they are dropped.
9.11. Setting and controlling IP sets using firewalld
To see the list of IP set types supported by firewalld, enter the following command as root.
# firewall-cmd --get-ipset-types
hash:ip hash:ip,mark hash:ip,port hash:ip,port,ip hash:ip,port,net hash:mac hash:net hash:net,iface hash:net,net hash:net,port hash:net,port,net
Red Hat does not recommend using IP sets that are not managed through firewalld. To use such IP sets, a permanent direct rule is required to reference the set, and a custom service must be added to create these IP sets. This service needs to be started before firewalld starts, otherwise firewalld is not able to add the direct rules using these sets. You can add permanent direct rules with the /etc/firewalld/direct.xml file.
9.11.1. Configuring IP set options using CLI
IP sets can be used in firewalld zones as sources and also as sources in rich rules. In Red Hat Enterprise Linux, the preferred method is to use the IP sets created with firewalld in a direct rule.
To list the IP sets known to
firewalldin the permanent environment, use the following command asroot:# firewall-cmd --permanent --get-ipsetsTo add a new IP set, use the following command using the permanent environment as
root:# firewall-cmd --permanent --new-ipset=test --type=hash:net successThe previous command creates a new IP set with the name test and the
hash:nettype forIPv4. To create an IP set for use withIPv6, add the--option=family=inet6option. To make the new setting effective in the runtime environment, reloadfirewalld.List the new IP set with the following command as
root:# firewall-cmd --permanent --get-ipsets testTo get more information about the IP set, use the following command as
root:# firewall-cmd --permanent --info-ipset=test test type: hash:net options: entries:Note that the IP set does not have any entries at the moment.
To add an entry to the test IP set, use the following command as
root:# firewall-cmd --permanent --ipset=test --add-entry=192.168.0.1 successThe previous command adds the IP address 192.168.0.1 to the IP set.
To get the list of current entries in the IP set, use the following command as
root:# firewall-cmd --permanent --ipset=test --get-entries 192.168.0.1Create the
iplist.txtfile that contains a list of IP addresses, for example:192.168.0.2 192.168.0.3 192.168.1.0/24 192.168.2.254
The file with the list of IP addresses for an IP set should contain an entry per line. Lines starting with a hash, a semi-colon, or empty lines are ignored.
To add the addresses from the iplist.txt file, use the following command as
root:# firewall-cmd --permanent --ipset=test --add-entries-from-file=iplist.txt successTo see the extended entries list of the IP set, use the following command as
root:# firewall-cmd --permanent --ipset=test --get-entries 192.168.0.1 192.168.0.2 192.168.0.3 192.168.1.0/24 192.168.2.254To remove the addresses from the IP set and to check the updated entries list, use the following commands as
root:# firewall-cmd --permanent --ipset=pass:_test_ --remove-entries-from-file=iplist.txt success # firewall-cmd --permanent --ipset=test --get-entries 192.168.0.1
You can add the IP set as a source to a zone to handle all traffic coming in from any of the addresses listed in the IP set with a zone. For example, to add the test IP set as a source to the drop zone to drop all packets coming from all entries listed in the test IP set, use the following command as
root:# firewall-cmd --permanent --zone=drop --add-source=ipset:test successThe
ipset:prefix in the source showsfirewalldthat the source is an IP set and not an IP address or an address range.
Only the creation and removal of IP sets is limited to the permanent environment, all other IP set options can be used also in the runtime environment without the --permanent option.
9.12. Prioritizing rich rules
By default, rich rules are organized based on their rule action. For example, deny rules have precedence over allow rules. The priority parameter in rich rules provides administrators fine-grained control over rich rules and their execution order.
9.12.1. How the priority parameter organizes rules into different chains
You can set the priority parameter in a rich rule to any number between -32768 and 32767, and lower values have higher precedence.
The firewalld service organizes rules based on their priority value into different chains:
-
Priority lower than 0: the rule is redirected into a chain with the
_presuffix. -
Priority higher than 0: the rule is redirected into a chain with the
_postsuffix. -
Priority equals 0: based on the action, the rule is redirected into a chain with the
_log,_deny, or_allowthe action.
Inside these sub-chains, firewalld sorts the rules based on their priority value.
9.12.2. Setting the priority of a rich rule
The following is an example of how to create a rich rule that uses the priority parameter to log all traffic that is not allowed or denied by other rules. You can use this rule to flag unexpected traffic.
Procedure
Add a rich rule with a very low precedence to log all traffic that has not been matched by other rules:
# firewall-cmd --add-rich-rule='rule priority=32767 log prefix="UNEXPECTED: " limit value="5/m"'The command additionally limits the number of log entries to
5per minute.
Verification
Display the
nftablesrule that the command in the previous step created:# nft list chain inet firewalld filter_IN_public_post table inet firewalld { chain filter_IN_public_post { log prefix "UNEXPECTED: " limit rate 5/minute } }
9.13. Configuring firewall lockdown
Local applications or services are able to change the firewall configuration if they are running as root (for example, libvirt). With this feature, the administrator can lock the firewall configuration so that either no applications or only applications that are added to the lockdown allow list are able to request firewall changes. The lockdown settings default to disabled. If enabled, the user can be sure that there are no unwanted configuration changes made to the firewall by local applications or services.
9.13.1. Configuring lockdown using CLI
You can enable or disable the lockdown feature using the command line.
Procedure
To query whether lockdown is enabled, use the following command as
root:# firewall-cmd --query-lockdownThe command prints
yeswith exit status0if lockdown is enabled. It printsnowith exit status1otherwise.To enable lockdown, enter the following command as
root:# firewall-cmd --lockdown-onTo disable lockdown, use the following command as
root:# firewall-cmd --lockdown-off
9.13.2. Configuring lockdown allowlist options using CLI
The lockdown allowlist can contain commands, security contexts, users and user IDs. If a command entry on the allowlist ends with an asterisk "*", then all command lines starting with that command will match. If the "*" is not there then the absolute command including arguments must match.
The context is the security (SELinux) context of a running application or service. To get the context of a running application use the following command:
$ ps -e --contextThat command returns all running applications. Pipe the output through the grep tool to get the application of interest. For example:
$ ps -e --context | grep example_programTo list all command lines that are in the allowlist, enter the following command as
root:# firewall-cmd --list-lockdown-whitelist-commandsTo add a command command to the allowlist, enter the following command as
root:# firewall-cmd --add-lockdown-whitelist-command='/usr/bin/python3 -Es /usr/bin/command'To remove a command command from the allowlist, enter the following command as
root:# firewall-cmd --remove-lockdown-whitelist-command='/usr/bin/python3 -Es /usr/bin/command'To query whether the command command is in the allowlist, enter the following command as
root:# firewall-cmd --query-lockdown-whitelist-command='/usr/bin/python3 -Es /usr/bin/command'The command prints
yeswith exit status0if true. It printsnowith exit status1otherwise.To list all security contexts that are in the allowlist, enter the following command as
root:# firewall-cmd --list-lockdown-whitelist-contextsTo add a context context to the allowlist, enter the following command as
root:# firewall-cmd --add-lockdown-whitelist-context=contextTo remove a context context from the allowlist, enter the following command as
root:# firewall-cmd --remove-lockdown-whitelist-context=contextTo query whether the context context is in the allowlist, enter the following command as
root:# firewall-cmd --query-lockdown-whitelist-context=contextPrints
yeswith exit status0, if true, printsnowith exit status1otherwise.To list all user IDs that are in the allowlist, enter the following command as
root:# firewall-cmd --list-lockdown-whitelist-uidsTo add a user ID uid to the allowlist, enter the following command as
root:# firewall-cmd --add-lockdown-whitelist-uid=uidTo remove a user ID uid from the allowlist, enter the following command as
root:# firewall-cmd --remove-lockdown-whitelist-uid=uidTo query whether the user ID uid is in the allowlist, enter the following command:
$ firewall-cmd --query-lockdown-whitelist-uid=uidPrints
yeswith exit status0, if true, printsnowith exit status1otherwise.To list all user names that are in the allowlist, enter the following command as
root:# firewall-cmd --list-lockdown-whitelist-usersTo add a user name user to the allowlist, enter the following command as
root:# firewall-cmd --add-lockdown-whitelist-user=userTo remove a user name user from the allowlist, enter the following command as
root:# firewall-cmd --remove-lockdown-whitelist-user=userTo query whether the user name user is in the allowlist, enter the following command:
$ firewall-cmd --query-lockdown-whitelist-user=userPrints
yeswith exit status0, if true, printsnowith exit status1otherwise.
9.13.3. Configuring lockdown allowlist options using configuration files
The default allowlist configuration file contains the NetworkManager context and the default context of libvirt. The user ID 0 is also on the list.
+ The allowlist configuration files are stored in the /etc/firewalld/ directory.
<?xml version="1.0" encoding="utf-8"?> <whitelist> <selinux context="system_u:system_r:NetworkManager_t:s0"/> <selinux context="system_u:system_r:virtd_t:s0-s0:c0.c1023"/> <user id="0"/> </whitelist>
Following is an example allowlist configuration file enabling all commands for the firewall-cmd utility, for a user called user whose user ID is 815:
<?xml version="1.0" encoding="utf-8"?> <whitelist> <command name="/usr/libexec/platform-python -s /bin/firewall-cmd*"/> <selinux context="system_u:system_r:NetworkManager_t:s0"/> <user id="815"/> <user name="user"/> </whitelist>
This example shows both user id and user name, but only one option is required. Python is the interpreter and is prepended to the command line. You can also use a specific command, for example:
# /usr/bin/python3 /bin/firewall-cmd --lockdown-on
In that example, only the --lockdown-on command is allowed.
In Red Hat Enterprise Linux, all utilities are placed in the /usr/bin/ directory and the /bin/ directory is sym-linked to the /usr/bin/ directory. In other words, although the path for firewall-cmd when entered as root might resolve to /bin/firewall-cmd, /usr/bin/firewall-cmd can now be used. All new scripts should use the new location. But be aware that if scripts that run as root are written to use the /bin/firewall-cmd path, then that command path must be added in the allowlist in addition to the /usr/bin/firewall-cmd path traditionally used only for non-root users.
The * at the end of the name attribute of a command means that all commands that start with this string match. If the * is not there then the absolute command including arguments must match.
9.14. Enabling traffic forwarding between different interfaces or sources within a firewalld zone
Intra-zone forwarding is a firewalld feature that enables traffic forwarding between interfaces or sources within a firewalld zone.
9.14.1. The difference between intra-zone forwarding and zones with the default target set to ACCEPT
When intra-zone forwarding is enabled, the traffic within a single firewalld zone can flow from one interface or source to another interface or source. The zone specifies the trust level of interfaces and sources. If the trust level is the same, communication between interfaces or sources is possible.
Note that, if you enable intra-zone forwarding in the default zone of firewalld, it applies only to the interfaces and sources added to the current default zone.
The trusted zone of firewalld uses a default target set to ACCEPT. This zone accepts all forwarded traffic, and intra-zone forwarding is not applicable for it.
As for other default target values, forwarded traffic is dropped by default, which applies to all standard zones except the trusted zone.
9.14.2. Using intra-zone forwarding to forward traffic between an Ethernet and Wi-Fi network
You can use intra-zone forwarding to forward traffic between interfaces and sources within the same firewalld zone. For example, use this feature to forward traffic between an Ethernet network connected to enp1s0 and a Wi-Fi network connected to wlp0s20.
Procedure
Enable packet forwarding in the kernel:
# echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf # sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
Ensure that interfaces between which you want to enable intra-zone forwarding are not assigned to a zone different than the
internalzone:# firewall-cmd --get-active-zonesIf the interface is currently assigned to a zone other than
internal, reassign it:# firewall-cmd --zone=internal --change-interface=interface_name --permanentAdd the
enp1s0andwlp0s20interfaces to theinternalzone:# firewall-cmd --zone=internal --add-interface=enp1s0 --add-interface=wlp0s20Enable intra-zone forwarding:
# firewall-cmd --zone=internal --add-forward
Verification
The following verification steps require that the nmap-ncat package is installed on both hosts.
-
Log in to a host that is in the same network as the
enp1s0interface of the host you enabled zone forwarding on. Start an echo service with
ncatto test connectivity:# ncat -e /usr/bin/cat -l 12345-
Log in to a host that is in the same network as the
wlp0s20interface. Connect to the echo server running on the host that is in the same network as the
enp1s0:# ncat <other_host> 12345- Type something and press Enter, and verify the text is sent back.
Additional resources
-
firewalld.zones(5)man page
9.15. Configuring firewalld by using RHEL System Roles
You can use the firewall System Role to configure settings of the firewalld service on multiple clients at once. This solution:
- Provides an interface with efficient input settings.
-
Keeps all intended
firewalldparameters in one place.
After you run the firewall role on the control node, the System Role applies the firewalld parameters to the managed node immediately and makes them persistent across reboots.
9.15.1. Introduction to the firewall RHEL System Role
RHEL System Roles is a set of contents for the Ansible automation utility. This content together with the Ansible automation utility provides a consistent configuration interface to remotely manage multiple systems.
The rhel-system-roles.firewall role from the RHEL System Roles was introduced for automated configurations of the firewalld service. The rhel-system-roles package contains this System Role, and also the reference documentation.
To apply the firewalld parameters on one or more systems in an automated fashion, use the firewall System Role variable in a playbook. A playbook is a list of one or more plays that is written in the text-based YAML format.
You can use an inventory file to define a set of systems that you want Ansible to configure.
With the firewall role you can configure many different firewalld parameters, for example:
- Zones.
- The services for which packets should be allowed.
- Granting, rejection, or dropping of traffic access to ports.
- Forwarding of ports or port ranges for a zone.
Additional resources
-
README.mdandREADME.htmlfiles in the/usr/share/doc/rhel-system-roles/firewall/directory - Working with playbooks
- How to build your inventory
9.15.2. Resetting the firewalld settings by using a RHEL System Role
With the firewall RHEL system role, you can reset the firewalld settings to their default state. If you add the previous:replaced parameter to the variable list, the System Role removes all existing user-defined settings and resets firewalld to the defaults. If you combine the previous:replaced parameter with other settings, the firewall role removes all existing settings before applying new ones.
Perform this procedure on the Ansible control node.
Prerequisites
- You have prepared the control node and the managed nodes
- You are logged in to the control node as a user who can run playbooks on the managed nodes.
-
The account you use to connect to the managed nodes has
sudopermissions on the them. - The managed nodes or groups of managed nodes on which you want to run this playbook are listed in the Ansible inventory file.
Procedure
Create a playbook file, for example
~/reset-firewalld.yml, with the following content:--- - name: Reset firewalld example hosts: managed-node-01.example.com tasks: - name: Reset firewalld include_role: name: rhel-system-roles.firewall vars: firewall: - previous: replacedRun the playbook:
# ansible-playbook ~/reset-firewalld.yml
Verification
Run this command as
rooton the managed node to check all the zones:# firewall-cmd --list-all-zones
Additional resources
-
/usr/share/ansible/roles/rhel-system-roles.firewall/README.md
9.15.3. Forwarding incoming traffic in firewalld from one local port to a different local port by using a RHEL System Role
With the firewall role you can remotely configure firewalld parameters with persisting effect on multiple managed hosts.
Perform this procedure on the Ansible control node.
Prerequisites
- You have prepared the control node and the managed nodes
- You are logged in to the control node as a user who can run playbooks on the managed nodes.
-
The account you use to connect to the managed nodes has
sudopermissions on the them. - The managed nodes or groups of managed nodes on which you want to run this playbook are listed in the Ansible inventory file.
Procedure
Create a playbook file, for example
~/port_forwarding.yml, with the following content:--- - name: Configure firewalld hosts: managed-node-01.example.com tasks: - name: Forward incoming traffic on port 8080 to 443 include_role: name: rhel-system-roles.firewall vars: firewall: - { forward_port: 8080/tcp;443;, state: enabled, runtime: true, permanent: true }Run the playbook:
# ansible-playbook ~/port_forwarding.yml
Verification
On the managed host, display the
firewalldsettings:# firewall-cmd --list-forward-ports
Additional resources
-
/usr/share/ansible/roles/rhel-system-roles.firewall/README.md
9.15.4. Managing ports in firewalld by using a RHEL System Role
You can use the RHEL firewall System Role to open or close ports in the local firewall for incoming traffic and make the new configuration persist across reboots. For example you can configure the default zone to permit incoming traffic for the HTTPS service.
Perform this procedure on the Ansible control node.
Prerequisites
- You have prepared the control node and the managed nodes
- You are logged in to the control node as a user who can run playbooks on the managed nodes.
-
The account you use to connect to the managed nodes has
sudopermissions on the them. - The managed nodes or groups of managed nodes on which you want to run this playbook are listed in the Ansible inventory file.
Procedure
Create a playbook file, for example
~/opening-a-port.yml, with the following content:--- - name: Configure firewalld hosts: managed-node-01.example.com tasks: - name: Allow incoming HTTPS traffic to the local host include_role: name: rhel-system-roles.firewall vars: firewall: - port: 443/tcp service: http state: enabled runtime: true permanent: trueThe
permanent: trueoption makes the new settings persistent across reboots.Run the playbook:
# ansible-playbook ~/opening-a-port.yml
Verification
On the managed node, verify that the
443/tcpport associated with theHTTPSservice is open:# firewall-cmd --list-ports 443/tcp
Additional resources
-
/usr/share/ansible/roles/rhel-system-roles.firewall/README.md
9.15.5. Configuring a firewalld DMZ zone by using a RHEL System Role
As a system administrator, you can use the firewall System Role to configure a dmz zone on the enp1s0 interface to permit HTTPS traffic to the zone. In this way, you enable external users to access your web servers.
Perform this procedure on the Ansible control node.
Prerequisites
- You have prepared the control node and the managed nodes
- You are logged in to the control node as a user who can run playbooks on the managed nodes.
-
The account you use to connect to the managed nodes has
sudopermissions on the them. - The managed nodes or groups of managed nodes on which you want to run this playbook are listed in the Ansible inventory file.
Procedure
Create a playbook file, for example
~/configuring-a-dmz.yml, with the following content:--- - name: Configure firewalld hosts: managed-node-01.example.com tasks: - name: Creating a DMZ with access to HTTPS port and masquerading for hosts in DMZ include_role: name: rhel-system-roles.firewall vars: firewall: - zone: dmz interface: enp1s0 service: https state: enabled runtime: true permanent: trueRun the playbook:
# ansible-playbook ~/configuring-a-dmz.yml
Verification
On the managed node, view detailed information about the
dmzzone:# firewall-cmd --zone=dmz --list-all dmz (active) target: default icmp-block-inversion: no interfaces: enp1s0 sources: services: https ssh ports: protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks:
Additional resources
-
/usr/share/ansible/roles/rhel-system-roles.firewall/README.md
9.16. Additional resources
-
firewalld(1)man page -
firewalld.conf(5)man page -
firewall-cmd(1)man page -
firewall-config(1)man page -
firewall-offline-cmd(1)man page -
firewalld.icmptype(5)man page -
firewalld.ipset(5)man page -
firewalld.service(5)man page -
firewalld.zone(5)man page -
firewalld.direct(5)man page -
firewalld.lockdown-whitelist(5) -
firewalld.richlanguage(5) -
firewalld.zones(5)man page -
firewalld.dbus(5)man page
Chapter 10. Getting started with nftables
The nftables framework classifies packets and it is the successor to the iptables, ip6tables, arptables, ebtables, and ipset utilities. It offers numerous improvements in convenience, features, and performance over previous packet-filtering tools, most notably:
- Built-in lookup tables instead of linear processing
-
A single framework for both the
IPv4andIPv6protocols - All rules applied atomically instead of fetching, updating, and storing a complete rule set
-
Support for debugging and tracing in the rule set (
nftrace) and monitoring trace events (in thenfttool) - More consistent and compact syntax, no protocol-specific extensions
- A Netlink API for third-party applications
The nftables framework uses tables to store chains. The chains contain individual rules for performing actions. The nft utility replaces all tools from the previous packet-filtering frameworks. You can use the libnftnl library for low-level interaction with nftables Netlink API through the libmnl library.
To display the effect of rule set changes, use the nft list ruleset command. Because these utilities add tables, chains, rules, sets, and other objects to the nftables rule set, be aware that nftables rule-set operations, such as the nft flush ruleset command, might affect rule sets installed using the iptables command.
10.1. Migrating from iptables to nftables
If your firewall configuration still uses iptables rules, you can migrate your iptables rules to nftables.
10.1.1. When to use firewalld, nftables, or iptables
The following is a brief overview in which scenario you should use one of the following utilities:
-
firewalld: Use thefirewalldutility for simple firewall use cases. The utility is easy to use and covers the typical use cases for these scenarios. -
nftables: Use thenftablesutility to set up complex and performance-critical firewalls, such as for a whole network. -
iptables: Theiptablesutility on Red Hat Enterprise Linux uses thenf_tableskernel API instead of thelegacyback end. Thenf_tablesAPI provides backward compatibility so that scripts that useiptablescommands still work on Red Hat Enterprise Linux. For new firewall scripts, Red Hat recommends to usenftables.
To prevent the different firewall services from influencing each other, run only one of them on a RHEL host, and disable the other services.
10.1.2. Converting iptables and ip6tables rule sets to nftables
Use the iptables-restore-translate and ip6tables-restore-translate utilities to translate iptables and ip6tables rule sets to nftables.
Prerequisites
-
The
nftablesandiptablespackages are installed. -
The system has
iptablesandip6tablesrules configured.
Procedure
Write the
iptablesandip6tablesrules to a file:# iptables-save >/root/iptables.dump # ip6tables-save >/root/ip6tables.dump
Convert the dump files to
nftablesinstructions:# iptables-restore-translate -f /root/iptables.dump > /etc/nftables/ruleset-migrated-from-iptables.nft # ip6tables-restore-translate -f /root/ip6tables.dump > /etc/nftables/ruleset-migrated-from-ip6tables.nft
-
Review and, if needed, manually update the generated
nftablesrules. To enable the
nftablesservice to load the generated files, add the following to the/etc/sysconfig/nftables.conffile:include "/etc/nftables/ruleset-migrated-from-iptables.nft" include "/etc/nftables/ruleset-migrated-from-ip6tables.nft"
Stop and disable the
iptablesservice:# systemctl disable --now iptablesIf you used a custom script to load the
iptablesrules, ensure that the script no longer starts automatically and reboot to flush all tables.Enable and start the
nftablesservice:# systemctl enable --now nftables
Verification
Display the
nftablesrule set:# nft list ruleset
Additional resources
10.1.3. Converting single iptables and ip6tables rules to nftables
Red Hat Enterprise Linux provides the iptables-translate and ip6tables-translate utilities to convert an iptables or ip6tables rule into the equivalent one for nftables.
Prerequisites
-
The
nftablespackage is installed.
Procedure
Use the
iptables-translateorip6tables-translateutility instead ofiptablesorip6tablesto display the correspondingnftablesrule, for example:# iptables-translate -A INPUT -s 192.0.2.0/24 -j ACCEPT nft add rule ip filter INPUT ip saddr 192.0.2.0/24 counter accept
Note that some extensions lack translation support. In these cases, the utility prints the untranslated rule prefixed with the
#sign, for example:# iptables-translate -A INPUT -j CHECKSUM --checksum-fill nft # -A INPUT -j CHECKSUM --checksum-fill
Additional resources
-
iptables-translate --help
10.1.4. Comparison of common iptables and nftables commands
The following is a comparison of common iptables and nftables commands:
Listing all rules:
iptables nftables iptables-savenft list rulesetListing a certain table and chain:
iptables nftables iptables -Lnft list table ip filteriptables -L INPUTnft list chain ip filter INPUTiptables -t nat -L PREROUTINGnft list chain ip nat PREROUTINGThe
nftcommand does not pre-create tables and chains. They exist only if a user created them manually.Listing rules generated by firewalld:
# nft list table inet firewalld # nft list table ip firewalld # nft list table ip6 firewalld
10.1.5. Additional resources
10.2. Writing and executing nftables scripts
The major benefit of using the nftables` framework is that the execution of scripts is atomic. This means that the system either applies the whole script or prevents the execution if an error occurs. This guarantees that the firewall is always in a consistent state.
Additionally, with the nftables script environment, you can:
- Add comments
- Define variables
- Include other rule-set files
When you install the nftables package, Red Hat Enterprise Linux automatically creates *.nft scripts in the /etc/nftables/ directory. These scripts contain commands that create tables and empty chains for different purposes.
10.2.1. Supported nftables script formats
You can write scripts in the nftables scripting environment in the following formats:
The same format as the
nft list rulesetcommand displays the rule set:#!/usr/sbin/nft -f # Flush the rule set flush ruleset table inet example_table { chain example_chain { # Chain for incoming packets that drops all packets that # are not explicitly allowed by any rule in this chain type filter hook input priority 0; policy drop; # Accept connections to port 22 (ssh) tcp dport ssh accept } }The same syntax as for
nftcommands:#!/usr/sbin/nft -f # Flush the rule set flush ruleset # Create a table add table inet example_table # Create a chain for incoming packets that drops all packets # that are not explicitly allowed by any rule in this chain add chain inet example_table example_chain { type filter hook input priority 0 ; policy drop ; } # Add a rule that accepts connections to port 22 (ssh) add rule inet example_table example_chain tcp dport ssh accept
10.2.2. Running nftables scripts
You can run an nftables script either by passing it to the nft utility or by executing the script directly.
Procedure
To run an
nftablesscript by passing it to thenftutility, enter:# nft -f /etc/nftables/<example_firewall_script>.nftTo run an
nftablesscript directly:For the single time that you perform this:
Ensure that the script starts with the following shebang sequence:
#!/usr/sbin/nft -f
ImportantIf you omit the
-fparameter, thenftutility does not read the script and displays:Error: syntax error, unexpected newline, expecting string.Optional: Set the owner of the script to
root:# chown root /etc/nftables/<example_firewall_script>.nftMake the script executable for the owner:
# chmod u+x /etc/nftables/<example_firewall_script>.nft
Run the script:
# /etc/nftables/<example_firewall_script>.nftIf no output is displayed, the system executed the script successfully.
Even if nft executes the script successfully, incorrectly placed rules, missing parameters, or other problems in the script can cause that the firewall behaves not as expected.
Additional resources
-
chown(1)man page -
chmod(1)man page - Automatically loading nftables rules when the system boots
10.2.3. Using comments in nftables scripts
The nftables scripting environment interprets everything to the right of a # character to the end of a line as a comment.
Comments can start at the beginning of a line, or next to a command:
... # Flush the rule set flush ruleset add table inet example_table # Create a table ...
10.2.4. Using variables in nftables script
To define a variable in an nftables script, use the define keyword. You can store single values and anonymous sets in a variable. For more complex scenarios, use sets or verdict maps.
- Variables with a single value
The following example defines a variable named
INET_DEVwith the valueenp1s0:define INET_DEV = enp1s0You can use the variable in the script by entering the
$sign followed by the variable name:... add rule inet example_table example_chain iifname $INET_DEV tcp dport ssh accept ...
- Variables that contain an anonymous set
The following example defines a variable that contains an anonymous set:
define DNS_SERVERS = { 192.0.2.1, 192.0.2.2 }You can use the variable in the script by writing the
$sign followed by the variable name:add rule inet example_table example_chain ip daddr $DNS_SERVERS accept
NoteCurly braces have special semantics when you use them in a rule because they indicate that the variable represents a set.
Additional resources
10.2.5. Including files in nftables scripts
In the nftables scripting environment, you can include other scripts by using the include statement.
If you specify only a file name without an absolute or relative path, nftables includes files from the default search path, which is set to /etc on Red Hat Enterprise Linux.
Example 10.1. Including files from the default search directory
To include a file from the default search directory:
include "example.nft"
Example 10.2. Including all *.nft files from a directory
To include all files ending with *.nft that are stored in the /etc/nftables/rulesets/ directory:
include "/etc/nftables/rulesets/*.nft"
Note that the include statement does not match files beginning with a dot.
Additional resources
-
The
Include filessection in thenft(8)man page
10.2.6. Automatically loading nftables rules when the system boots
The nftables systemd service loads firewall scripts that are included in the /etc/sysconfig/nftables.conf file.
Prerequisites
-
The
nftablesscripts are stored in the/etc/nftables/directory.
Procedure
Edit the
/etc/sysconfig/nftables.conffile.-
If you modified the
*.nftscripts that were created in/etc/nftables/with the installation of thenftablespackage, uncomment theincludestatement for these scripts. If you wrote new scripts, add
includestatements to include these scripts. For example, to load the/etc/nftables/example.nftscript when thenftablesservice starts, add:include "/etc/nftables/_example_.nft"
-
If you modified the
Optional: Start the
nftablesservice to load the firewall rules without rebooting the system:# systemctl start nftablesEnable the
nftablesservice.# systemctl enable nftables
Additional resources
10.3. Creating and managing nftables tables, chains, and rules
You can display nftables rule sets and manage them.
10.3.1. Basics of nftables tables
A table in nftables is a namespace that contains a collection of chains, rules, sets, and other objects.
Each table must have an address family assigned. The address family defines the packet types that this table processes. You can set one of the following address families when you create a table:
-
ip: Matches only IPv4 packets. This is the default if you do not specify an address family. -
ip6: Matches only IPv6 packets. -
inet: Matches both IPv4 and IPv6 packets. -
arp: Matches IPv4 address resolution protocol (ARP) packets. -
bridge: Matches packets that pass through a bridge device. -
netdev: Matches packets from ingress.
If you want to add a table, the format to use depends on your firewall script:
In scripts in native syntax, use:
table <table_address_family> <table_name> { }
In shell scripts, use:
nft add table <table_address_family> <table_name>
10.3.2. Basics of nftables chains
Tables consist of chains which in turn are containers for rules. The following two rule types exists:
- Base chain: You can use base chains as an entry point for packets from the networking stack.
-
Regular chain: You can use regular chains as a
jumptarget to better organize rules.
If you want to add a base chain to a table, the format to use depends on your firewall script:
In scripts in native syntax, use:
table <table_address_family> <table_name> { chain <chain_name> { type <type> hook <hook> priority <priority> policy <policy> ; } }
In shell scripts, use:
nft add chain <table_address_family> <table_name> <chain_name> { type <type> hook <hook> priority <priority> \; policy <policy> \; }To avoid that the shell interprets the semicolons as the end of the command, place the
\escape character in front of the semicolons.
Both examples create base chains. To create a regular chain, do not set any parameters in the curly brackets.
Chain types
The following are the chain types and an overview with which address families and hooks you can use them:
| Type | Address families | Hooks | Description |
|---|---|---|---|
|
| all | all | Standard chain type |
|
|
|
| Chains of this type perform native address translation based on connection tracking entries. Only the first packet traverses this chain type. |
|
|
|
| Accepted packets that traverse this chain type cause a new route lookup if relevant parts of the IP header have changed. |
Chain priorities
The priority parameter specifies the order in which packets traverse chains with the same hook value. You can set this parameter to an integer value or use a standard priority name.
The following matrix is an overview of the standard priority names and their numeric values, and with which address families and hooks you can use them:
| Textual value | Numeric value | Address families | Hooks |
|---|---|---|---|
|
|
|
| all |
|
|
|
| all |
|
|
|
|
|
|
|
|
| |
|
|
|
| all |
|
|
| all | |
|
|
|
| all |
|
|
|
|
|
|
|
|
| |
|
|
|
|
|
Chain policies
The chain policy defines whether nftables should accept or drop packets if rules in this chain do not specify any action. You can set one of the following policies in a chain:
-
accept(default) -
drop
10.3.3. Basics of nftables rules
Rules define actions to perform on packets that pass a chain that contains this rule. If the rule also contains matching expressions, nftables performs the actions only if all previous expressions apply.
If you want to add a rule to a chain, the format to use depends on your firewall script:
In scripts in native syntax, use:
table <table_address_family> <table_name> { chain <chain_name> { type <type> hook <hook> priority <priority> ; policy <policy> ; <rule> } }
In shell scripts, use:
nft add rule <table_address_family> <table_name> <chain_name> <rule>This shell command appends the new rule at the end of the chain. If you prefer to add a rule at the beginning of the chain, use the
nft insertcommand instead ofnft add.
10.3.4. Managing tables, chains, and rules using nft commands
To manage an nftables firewall on the command line or in shell scripts, use the nft utility.
The commands in this procedure do not represent a typical workflow and are not optimized. This procedure only demonstrates how to use nft commands to manage tables, chains, and rules in general.
Procedure
Create a table named
nftables_svcwith theinetaddress family so that the table can process both IPv4 and IPv6 packets:# nft add table inet nftables_svcAdd a base chain named
INPUT, that processes incoming network traffic, to theinet nftables_svctable:# nft add chain inet nftables_svc INPUT { type filter hook input priority filter \; policy accept \; }To avoid that the shell interprets the semicolons as the end of the command, escape the semicolons using the
\character.Add rules to the
INPUTchain. For example, allow incoming TCP traffic on port 22 and 443, and, as the last rule of theINPUTchain, reject other incoming traffic with an Internet Control Message Protocol (ICMP) port unreachable message:# nft add rule inet nftables_svc INPUT tcp dport 22 accept # nft add rule inet nftables_svc INPUT tcp dport 443 accept # nft add rule inet nftables_svc INPUT reject with icmpx type port-unreachable
If you enter the
nft add rulecommands as shown,nftadds the rules in the same order to the chain as you run the commands.Display the current rule set including handles:
# nft -a list table inet nftables_svc table inet nftables_svc { # handle 13 chain INPUT { # handle 1 type filter hook input priority filter; policy accept; tcp dport 22 accept # handle 2 tcp dport 443 accept # handle 3 reject # handle 4 } }
Insert a rule before the existing rule with handle 3. For example, to insert a rule that allows TCP traffic on port 636, enter:
# nft insert rule inet nftables_svc INPUT position 3 tcp dport 636 acceptAppend a rule after the existing rule with handle 3. For example, to insert a rule that allows TCP traffic on port 80, enter:
# nft add rule inet nftables_svc INPUT position 3 tcp dport 80 acceptDisplay the rule set again with handles. Verify that the later added rules have been added to the specified positions:
# nft -a list table inet nftables_svc table inet nftables_svc { # handle 13 chain INPUT { # handle 1 type filter hook input priority filter; policy accept; tcp dport 22 accept # handle 2 tcp dport 636 accept # handle 5 tcp dport 443 accept # handle 3 tcp dport 80 accept # handle 6 reject # handle 4 } }
Remove the rule with handle 6:
# nft delete rule inet nftables_svc INPUT handle 6To remove a rule, you must specify the handle.
Display the rule set, and verify that the removed rule is no longer present:
# nft -a list table inet nftables_svc table inet nftables_svc { # handle 13 chain INPUT { # handle 1 type filter hook input priority filter; policy accept; tcp dport 22 accept # handle 2 tcp dport 636 accept # handle 5 tcp dport 443 accept # handle 3 reject # handle 4 } }
Remove all remaining rules from the
INPUTchain:# nft flush chain inet nftables_svc INPUTDisplay the rule set, and verify that the
INPUTchain is empty:# nft list table inet nftables_svc table inet nftables_svc { chain INPUT { type filter hook input priority filter; policy accept } }
Delete the
INPUTchain:# nft delete chain inet nftables_svc INPUTYou can also use this command to delete chains that still contain rules.
Display the rule set, and verify that the
INPUTchain has been deleted:# nft list table inet nftables_svc table inet nftables_svc { }
Delete the
nftables_svctable:# nft delete table inet nftables_svcYou can also use this command to delete tables that still contain chains.
NoteTo delete the entire rule set, use the
nft flush rulesetcommand instead of manually deleting all rules, chains, and tables in separate commands.
Additional resources
nft(8) man page
10.4. Configuring NAT using nftables
With nftables, you can configure the following network address translation (NAT) types:
- Masquerading
- Source NAT (SNAT)
- Destination NAT (DNAT)
- Redirect
You can only use real interface names in iifname and oifname parameters, and alternative names (altname) are not supported.
10.4.1. NAT types
These are the different network address translation (NAT) types:
- Masquerading and source NAT (SNAT)
Use one of these NAT types to change the source IP address of packets. For example, Internet Service Providers (ISPs) do not route private IP ranges, such as
10.0.0.0/8. If you use private IP ranges in your network and users should be able to reach servers on the internet, map the source IP address of packets from these ranges to a public IP address.Masquerading and SNAT are very similar to one another. The differences are:
- Masquerading automatically uses the IP address of the outgoing interface. Therefore, use masquerading if the outgoing interface uses a dynamic IP address.
- SNAT sets the source IP address of packets to a specified IP and does not dynamically look up the IP of the outgoing interface. Therefore, SNAT is faster than masquerading. Use SNAT if the outgoing interface uses a fixed IP address.
- Destination NAT (DNAT)
- Use this NAT type to rewrite the destination address and port of incoming packets. For example, if your web server uses an IP address from a private IP range and is, therefore, not directly accessible from the internet, you can set a DNAT rule on the router to redirect incoming traffic to this server.
- Redirect
- This type is a special case of DNAT that redirects packets to the local machine depending on the chain hook. For example, if a service runs on a different port than its standard port, you can redirect incoming traffic from the standard port to this specific port.
10.4.2. Configuring masquerading using nftables
Masquerading enables a router to dynamically change the source IP of packets sent through an interface to the IP address of the interface. This means that if the interface gets a new IP assigned, nftables automatically uses the new IP when replacing the source IP.
Replace the source IP of packets leaving the host through the ens3 interface to the IP set on ens3.
Procedure
Create a table:
# nft add table natAdd the
preroutingandpostroutingchains to the table:# nft add chain nat postrouting { type nat hook postrouting priority 100 \; }ImportantEven if you do not add a rule to the
preroutingchain, thenftablesframework requires this chain to match incoming packet replies.Note that you must pass the
--option to thenftcommand to prevent the shell from interpreting the negative priority value as an option of thenftcommand.Add a rule to the
postroutingchain that matches outgoing packets on theens3interface:# nft add rule nat postrouting oifname "ens3" masquerade
10.4.3. Configuring source NAT using nftables
On a router, Source NAT (SNAT) enables you to change the IP of packets sent through an interface to a specific IP address. The router then replaces the source IP of outgoing packets.
Procedure
Create a table:
# nft add table natAdd the
preroutingandpostroutingchains to the table:# nft add chain nat postrouting { type nat hook postrouting priority 100 \; }ImportantEven if you do not add a rule to the
postroutingchain, thenftablesframework requires this chain to match outgoing packet replies.Note that you must pass the
--option to thenftcommand to prevent the shell from interpreting the negative priority value as an option of thenftcommand.Add a rule to the
postroutingchain that replaces the source IP of outgoing packets throughens3with192.0.2.1:# nft add rule nat postrouting oifname "ens3" snat to 192.0.2.1
Additional resources
10.4.4. Configuring destination NAT using nftables
Destination NAT (DNAT) enables you to redirect traffic on a router to a host that is not directly accessible from the internet.
For example, with DNAT the router redirects incoming traffic sent to port 80 and 443 to a web server with the IP address 192.0.2.1.
Procedure
Create a table:
# nft add table natAdd the
preroutingandpostroutingchains to the table:# nft -- add chain nat prerouting { type nat hook prerouting priority -100 \; } # nft add chain nat postrouting { type nat hook postrouting priority 100 \; }
ImportantEven if you do not add a rule to the
postroutingchain, thenftablesframework requires this chain to match outgoing packet replies.Note that you must pass the
--option to thenftcommand to prevent the shell from interpreting the negative priority value as an option of thenftcommand.Add a rule to the
preroutingchain that redirects incoming traffic to port80and443on theens3interface of the router to the web server with the IP address192.0.2.1:"# nft add rule nat prerouting iifname ens3 tcp dport { 80, 443 } dnat to 192.0.2.1Depending on your environment, add either a SNAT or masquerading rule to change the source address for packets returning from the web server to the sender:
If the
ens3interface uses a dynamic IP addresses, add a masquerading rule:# nft add rule nat postrouting oifname "ens3" masqueradeIf the
ens3interface uses a static IP address, add a SNAT rule. For example, if theens3uses the198.51.100.1IP address:# nft add rule nat postrouting oifname "ens3" snat to 198.51.100.1
Enable packet forwarding:
# echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf # sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
Additional resources
10.4.5. Configuring a redirect using nftables
The redirect feature is a special case of destination network address translation (DNAT) that redirects packets to the local machine depending on the chain hook.
For example, you can redirect incoming and forwarded traffic sent to port 22 of the local host to port 2222.
Procedure
Create a table:
# nft add table natAdd the
preroutingchain to the table:# nft -- add chain nat prerouting { type nat hook prerouting priority -100 \; }Note that you must pass the
--option to thenftcommand to prevent the shell from interpreting the negative priority value as an option of thenftcommand.Add a rule to the
preroutingchain that redirects incoming traffic on port22to port2222:# nft add rule nat prerouting tcp dport 22 redirect to 2222
Additional resources
10.5. Using sets in nftables commands
The nftables framework natively supports sets. You can use sets, for example, if a rule should match multiple IP addresses, port numbers, interfaces, or any other match criteria.
10.5.1. Using anonymous sets in nftables
An anonymous set contains comma-separated values enclosed in curly brackets, such as { 22, 80, 443 }, that you use directly in a rule. You can use anonymous sets also for IP addresses and any other match criteria.
The drawback of anonymous sets is that if you want to change the set, you must replace the rule. For a dynamic solution, use named sets as described in Using named sets in nftables.
Prerequisites
-
The
example_chainchain and theexample_tabletable in theinetfamily exists.
Procedure
For example, to add a rule to
example_chaininexample_tablethat allows incoming traffic to port22,80, and443:# nft add rule inet example_table example_chain tcp dport { 22, 80, 443 } acceptOptional: Display all chains and their rules in
example_table:# nft list table inet example_table table inet example_table { chain example_chain { type filter hook input priority filter; policy accept; tcp dport { ssh, http, https } accept } }
10.5.2. Using named sets in nftables
The nftables framework supports mutable named sets. A named set is a list or range of elements that you can use in multiple rules within a table. Another benefit over anonymous sets is that you can update a named set without replacing the rules that use the set.
When you create a named set, you must specify the type of elements the set contains. You can set the following types:
-
ipv4_addrfor a set that contains IPv4 addresses or ranges, such as192.0.2.1or192.0.2.0/24. -
ipv6_addrfor a set that contains IPv6 addresses or ranges, such as2001:db8:1::1or2001:db8:1::1/64. -
ether_addrfor a set that contains a list of media access control (MAC) addresses, such as52:54:00:6b:66:42. -
inet_protofor a set that contains a list of internet protocol types, such astcp. -
inet_servicefor a set that contains a list of internet services, such asssh. -
markfor a set that contains a list of packet marks. Packet marks can be any positive 32-bit integer value (0to2147483647).
Prerequisites
-
The
example_chainchain and theexample_tabletable exists.
Procedure
Create an empty set. The following examples create a set for IPv4 addresses:
To create a set that can store multiple individual IPv4 addresses:
# nft add set inet example_table example_set { type ipv4_addr \; }To create a set that can store IPv4 address ranges:
# nft add set inet example_table example_set { type ipv4_addr \; flags interval \; }
ImportantTo prevent the shell from interpreting the semicolons as the end of the command, you must escape the semicolons with a backslash.
Optional: Create rules that use the set. For example, the following command adds a rule to the
example_chainin theexample_tablethat will drop all packets from IPv4 addresses inexample_set.# nft add rule inet example_table example_chain ip saddr @example_set dropBecause
example_setis still empty, the rule has currently no effect.Add IPv4 addresses to
example_set:If you create a set that stores individual IPv4 addresses, enter:
# nft add element inet example_table example_set { 192.0.2.1, 192.0.2.2 }If you create a set that stores IPv4 ranges, enter:
# nft add element inet example_table example_set { 192.0.2.0-192.0.2.255 }When you specify an IP address range, you can alternatively use the Classless Inter-Domain Routing (CIDR) notation, such as
192.0.2.0/24in the above example.
10.5.3. Additional resources
-
The
Setssection in thenft(8)man page
10.6. Using verdict maps in nftables commands
Verdict maps, which are also known as dictionaries, enable nft to perform an action based on packet information by mapping match criteria to an action.
10.6.1. Using anonymous maps in nftables
An anonymous map is a { match_criteria : action } statement that you use directly in a rule. The statement can contain multiple comma-separated mappings.
The drawback of an anonymous map is that if you want to change the map, you must replace the rule. For a dynamic solution, use named maps as described in Using named maps in nftables.
For example, you can use an anonymous map to route both TCP and UDP packets of the IPv4 and IPv6 protocol to different chains to count incoming TCP and UDP packets separately.
Procedure
Create a new table:
# nft add table inet example_tableCreate the
tcp_packetschain inexample_table:# nft add chain inet example_table tcp_packetsAdd a rule to
tcp_packetsthat counts the traffic in this chain:# nft add rule inet example_table tcp_packets counterCreate the
udp_packetschain inexample_table# nft add chain inet example_table udp_packetsAdd a rule to
udp_packetsthat counts the traffic in this chain:# nft add rule inet example_table udp_packets counterCreate a chain for incoming traffic. For example, to create a chain named
incoming_trafficinexample_tablethat filters incoming traffic:# nft add chain inet example_table incoming_traffic { type filter hook input priority 0 \; }Add a rule with an anonymous map to
incoming_traffic:# nft add rule inet example_table incoming_traffic ip protocol vmap { tcp : jump tcp_packets, udp : jump udp_packets }The anonymous map distinguishes the packets and sends them to the different counter chains based on their protocol.
To list the traffic counters, display
example_table:# nft list table inet example_table table inet example_table { chain tcp_packets { counter packets 36379 bytes 2103816 } chain udp_packets { counter packets 10 bytes 1559 } chain incoming_traffic { type filter hook input priority filter; policy accept; ip protocol vmap { tcp : jump tcp_packets, udp : jump udp_packets } } }
The counters in the
tcp_packetsandudp_packetschain display both the number of received packets and bytes.
10.6.2. Using named maps in nftables
The nftables framework supports named maps. You can use these maps in multiple rules within a table. Another benefit over anonymous maps is that you can update a named map without replacing the rules that use it.
When you create a named map, you must specify the type of elements:
-
ipv4_addrfor a map whose match part contains an IPv4 address, such as192.0.2.1. -
ipv6_addrfor a map whose match part contains an IPv6 address, such as2001:db8:1::1. -
ether_addrfor a map whose match part contains a media access control (MAC) address, such as52:54:00:6b:66:42. -
inet_protofor a map whose match part contains an internet protocol type, such astcp. -
inet_servicefor a map whose match part contains an internet services name port number, such assshor22. -
markfor a map whose match part contains a packet mark. A packet mark can be any positive 32-bit integer value (0to2147483647). -
counterfor a map whose match part contains a counter value. The counter value can be any positive 64-bit integer value. -
quotafor a map whose match part contains a quota value. The quota value can be any positive 64-bit integer value.
For example, you can allow or drop incoming packets based on their source IP address. Using a named map, you require only a single rule to configure this scenario while the IP addresses and actions are dynamically stored in the map.
Procedure
Create a table. For example, to create a table named
example_tablethat processes IPv4 packets:# nft add table ip example_tableCreate a chain. For example, to create a chain named
example_chaininexample_table:# nft add chain ip example_table example_chain { type filter hook input priority 0 \; }ImportantTo prevent the shell from interpreting the semicolons as the end of the command, you must escape the semicolons with a backslash.
Create an empty map. For example, to create a map for IPv4 addresses:
# nft add map ip example_table example_map { type ipv4_addr : verdict \; }Create rules that use the map. For example, the following command adds a rule to
example_chaininexample_tablethat applies actions to IPv4 addresses which are both defined inexample_map:# nft add rule example_table example_chain ip saddr vmap @example_mapAdd IPv4 addresses and corresponding actions to
example_map:# nft add element ip example_table example_map { 192.0.2.1 : accept, 192.0.2.2 : drop }This example defines the mappings of IPv4 addresses to actions. In combination with the rule created above, the firewall accepts packet from
192.0.2.1and drops packets from192.0.2.2.Optional: Enhance the map by adding another IP address and action statement:
# nft add element ip example_table example_map { 192.0.2.3 : accept }Optional: Remove an entry from the map:
# nft delete element ip example_table example_map { 192.0.2.1 }Optional: Display the rule set:
# nft list ruleset table ip example_table { map example_map { type ipv4_addr : verdict elements = { 192.0.2.2 : drop, 192.0.2.3 : accept } } chain example_chain { type filter hook input priority filter; policy accept; ip saddr vmap @example_map } }
10.6.3. Additional resources
-
The
Mapssection in thenft(8)man page
10.7. Example: Protecting a LAN and DMZ using an nftables script
Use the nftables framework on a RHEL router to write and install a firewall script that protects the network clients in an internal LAN and a web server in a DMZ from unauthorized access from the internet and from other networks.
This example is only for demonstration purposes and describes a scenario with specific requirements.
Firewall scripts highly depend on the network infrastructure and security requirements. Use this example to learn the concepts of nftables firewalls when you write scripts for your own environment.
10.7.1. Network conditions
The network in this example has the following conditions:
The router is connected to the following networks:
-
The internet through interface
enp1s0 -
The internal LAN through interface
enp7s0 -
The DMZ through
enp8s0
-
The internet through interface
-
The internet interface of the router has both a static IPv4 address (
203.0.113.1) and IPv6 address (2001:db8:a::1) assigned. -
The clients in the internal LAN use only private IPv4 addresses from the range
10.0.0.0/24. Consequently, traffic from the LAN to the internet requires source network address translation (SNAT). -
The administrator PCs in the internal LAN use the IP addresses
10.0.0.100and10.0.0.200. -
The DMZ uses public IP addresses from the ranges
198.51.100.0/24and2001:db8:b::/56. -
The web server in the DMZ uses the IP addresses
198.51.100.5and2001:db8:b::5. - The router acts as a caching DNS server for hosts in the LAN and DMZ.
10.7.2. Security requirements to the firewall script
The following are the requirements to the nftables firewall in the example network:
The router must be able to:
- Recursively resolve DNS queries.
- Perform all connections on the loopback interface.
Clients in the internal LAN must be able to:
- Query the caching DNS server running on the router.
- Access the HTTPS server in the DMZ.
- Access any HTTPS server on the internet.
- The PCs of the administrators must be able to access the router and every server in the DMZ using SSH.
The web server in the DMZ must be able to:
- Query the caching DNS server running on the router.
- Access HTTPS servers on the internet to download updates.
Hosts on the internet must be able to:
- Access the HTTPS servers in the DMZ.
Additionally, the following security requirements exists:
- Connection attempts that are not explicitly allowed should be dropped.
- Dropped packets should be logged.
10.7.3. Configuring logging of dropped packets to a file
By default, systemd logs kernel messages, such as for dropped packets, to the journal. Additionally, you can configure the rsyslog service to log such entries to a separate file. To ensure that the log file does not grow infinitely, configure a rotation policy.
Prerequisites
-
The
rsyslogpackage is installed. -
The
rsyslogservice is running.
Procedure
Create the
/etc/rsyslog.d/nftables.conffile with the following content::msg, startswith, "nft drop" -/var/log/nftables.log & stop
Using this configuration, the
rsyslogservice logs dropped packets to the/var/log/nftables.logfile instead of/var/log/messages.Restart the
rsyslogservice:# systemctl restart rsyslogCreate the
/etc/logrotate.d/nftablesfile with the following content to rotate/var/log/nftables.logif the size exceeds 10 MB:/var/log/nftables.log { size +10M maxage 30 sharedscripts postrotate /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript }The
maxage 30setting defines thatlogrotateremoves rotated logs older than 30 days during the next rotation operation.
Additional resources
-
rsyslog.conf(5)man page -
logrotate(8)man page
10.7.4. Writing and activating the nftables script
This example is an nftables firewall script that runs on a RHEL router and protects the clients in an internal LAN and a web server in a DMZ. For details about the network and the requirements for the firewall used in the example, see Network conditions and Security requirements to the firewall script.
This nftables firewall script is only for demonstration purposes. Do not use it without adapting it to your environments and security requirements.
Prerequisites
- The network is configured as described in Network conditions.
Procedure
Create the
/etc/nftables/firewall.nftscript with the following content:# Remove all rules flush ruleset # Table for both IPv4 and IPv6 rules table inet nftables_svc { # Define variables for the interface name define INET_DEV = enp1s0 define LAN_DEV = enp7s0 define DMZ_DEV = enp8s0 # Set with the IPv4 addresses of admin PCs set admin_pc_ipv4 { type ipv4_addr elements = { 10.0.0.100, 10.0.0.200 } } # Chain for incoming trafic. Default policy: drop chain INPUT { type filter hook input priority filter policy drop # Accept packets in established and related state, drop invalid packets ct state vmap { established:accept, related:accept, invalid:drop } # Accept incoming traffic on loopback interface iifname lo accept # Allow request from LAN and DMZ to local DNS server iifname { $LAN_DEV, $DMZ_DEV } meta l4proto { tcp, udp } th dport 53 accept # Allow admins PCs to access the router using SSH iifname $LAN_DEV ip saddr @admin_pc_ipv4 tcp dport 22 accept # Last action: Log blocked packets # (packets that were not accepted in previous rules in this chain) log prefix "nft drop IN : " } # Chain for outgoing traffic. Default policy: drop chain OUTPUT { type filter hook output priority filter policy drop # Accept packets in established and related state, drop invalid packets ct state vmap { established:accept, related:accept, invalid:drop } # Accept outgoing traffic on loopback interface oifname lo accept # Allow local DNS server to recursively resolve queries oifname $INET_DEV meta l4proto { tcp, udp } th dport 53 accept # Last action: Log blocked packets log prefix "nft drop OUT: " } # Chain for forwarding traffic. Default policy: drop chain FORWARD { type filter hook forward priority filter policy drop # Accept packets in established and related state, drop invalid packets ct state vmap { established:accept, related:accept, invalid:drop } # IPv4 access from LAN and internet to the HTTPS server in the DMZ iifname { $LAN_DEV, $INET_DEV } oifname $DMZ_DEV ip daddr 198.51.100.5 tcp dport 443 accept # IPv6 access from internet to the HTTPS server in the DMZ iifname $INET_DEV oifname $DMZ_DEV ip6 daddr 2001:db8:b::5 tcp dport 443 accept # Access from LAN and DMZ to HTTPS servers on the internet iifname { $LAN_DEV, $DMZ_DEV } oifname $INET_DEV tcp dport 443 accept # Last action: Log blocked packets log prefix "nft drop FWD: " } # Postrouting chain to handle SNAT chain postrouting { type nat hook postrouting priority srcnat; policy accept; # SNAT for IPv4 traffic from LAN to internet iifname $LAN_DEV oifname $INET_DEV snat ip to 203.0.113.1 } }Include the
/etc/nftables/firewall.nftscript in the/etc/sysconfig/nftables.conffile:include "/etc/nftables/firewall.nft"
Enable IPv4 forwarding:
# echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf # sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
Enable and start the
nftablesservice:# systemctl enable --now nftables
Verification
Optional: Verify the
nftablesrule set:# nft list ruleset ...Try to perform an access that the firewall prevents. For example, try to access the router using SSH from the DMZ:
# ssh router.example.com ssh: connect to host router.example.com port 22: Network is unreachable
Depending on your logging settings, search:
The
systemdjournal for the blocked packets:# journalctl -k -g "nft drop" Oct 14 17:27:18 router kernel: nft drop IN : IN=enp8s0 OUT= MAC=... SRC=198.51.100.5 DST=198.51.100.1 ... PROTO=TCP SPT=40464 DPT=22 ... SYN ...
The
/var/log/nftables.logfile for the blocked packets:Oct 14 17:27:18 router kernel: nft drop IN : IN=enp8s0 OUT= MAC=... SRC=198.51.100.5 DST=198.51.100.1 ... PROTO=TCP SPT=40464 DPT=22 ... SYN ...
10.8. Configuring port forwarding using nftables
Port forwarding enables administrators to forward packets sent to a specific destination port to a different local or remote port.
For example, if your web server does not have a public IP address, you can set a port forwarding rule on your firewall that forwards incoming packets on port 80 and 443 on the firewall to the web server. With this firewall rule, users on the internet can access the web server using the IP or host name of the firewall.
10.8.1. Forwarding incoming packets to a different local port
You can use nftables to forward packets. For example, you can forward incoming IPv4 packets on port 8022 to port 22 on the local system.
Procedure
Create a table named
natwith theipaddress family:# nft add table ip natAdd the
preroutingandpostroutingchains to the table:# nft -- add chain ip nat prerouting { type nat hook prerouting priority -100 \; }NotePass the
--option to thenftcommand to prevent the shell from interpreting the negative priority value as an option of thenftcommand.Add a rule to the
preroutingchain that redirects incoming packets on port8022to the local port22:# nft add rule ip nat prerouting tcp dport 8022 redirect to :22
10.8.2. Forwarding incoming packets on a specific local port to a different host
You can use a destination network address translation (DNAT) rule to forward incoming packets on a local port to a remote host. This enables users on the internet to access a service that runs on a host with a private IP address.
For example, you can forward incoming IPv4 packets on the local port 443 to the same port number on the remote system with the 192.0.2.1 IP address.
Prerequisites
-
You are logged in as the
rootuser on the system that should forward the packets.
Procedure
Create a table named
natwith theipaddress family:# nft add table ip natAdd the
preroutingandpostroutingchains to the table:# nft -- add chain ip nat prerouting { type nat hook prerouting priority -100 \; } # nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
NotePass the
--option to thenftcommand to prevent the shell from interpreting the negative priority value as an option of thenftcommand.Add a rule to the
preroutingchain that redirects incoming packets on port443to the same port on192.0.2.1:# nft add rule ip nat prerouting tcp dport 443 dnat to 192.0.2.1Add a rule to the
postroutingchain to masquerade outgoing traffic:# nft add rule ip nat postrouting daddr 192.0.2.1 masqueradeEnable packet forwarding:
# echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf # sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
10.9. Using nftables to limit the amount of connections
You can use nftables to limit the number of connections or to block IP addresses that attempt to establish a given amount of connections to prevent them from using too many system resources.
10.9.1. Limiting the number of connections using nftables
The ct count parameter of the nft utility enables administrators to limit the number of connections.
Prerequisites
-
The base
example_chaininexample_tableexists.
Procedure
Create a dynamic set for IPv4 addresses:
# nft add set inet example_table example_meter { type ipv4_addr\; flags dynamic \;}Add a rule that allows only two simultaneous connections to the SSH port (22) from an IPv4 address and rejects all further connections from the same IP:
# nft add rule ip example_table example_chain tcp dport ssh meter example_meter { ip saddr ct count over 2 } counter rejectOptional: Display the set created in the previous step:
# nft list set inet example_table example_meter table inet example_table { meter example_meter { type ipv4_addr size 65535 elements = { 192.0.2.1 ct count over 2 , 192.0.2.2 ct count over 2 } } }
The
elementsentry displays addresses that currently match the rule. In this example,elementslists IP addresses that have active connections to the SSH port. Note that the output does not display the number of active connections or if connections were rejected.
10.9.2. Blocking IP addresses that attempt more than ten new incoming TCP connections within one minute
You can temporarily block hosts that are establishing more than ten IPv4 TCP connections within one minute.
Procedure
Create the
filtertable with theipaddress family:# nft add table ip filterAdd the
inputchain to thefiltertable:# nft add chain ip filter input { type filter hook input priority 0 \; }Add a rule that drops all packets from source addresses that attempt to establish more than ten TCP connections within one minute:
# nft add rule ip filter input ip protocol tcp ct state new, untracked meter ratemeter { ip saddr timeout 5m limit rate over 10/minute } dropThe
timeout 5mparameter defines thatnftablesautomatically removes entries after five minutes to prevent that the meter fills up with stale entries.
Verification
To display the meter’s content, enter:
# nft list meter ip filter ratemeter table ip filter { meter ratemeter { type ipv4_addr size 65535 flags dynamic,timeout elements = { 192.0.2.1 limit rate over 10/minute timeout 5m expires 4m58s224ms } } }
10.10. Debugging nftables rules
The nftables framework provides different options for administrators to debug rules and if packets match them.
10.10.1. Creating a rule with a counter
To identify if a rule is matched, you can use a counter.
-
For more information about a procedure that adds a counter to an existing rule, see Adding a counter to an existing rule in
Configuring and managing networking
Prerequisites
- The chain to which you want to add the rule exists.
Procedure
Add a new rule with the
counterparameter to the chain. The following example adds a rule with a counter that allows TCP traffic on port 22 and counts the packets and traffic that match this rule:# nft add rule inet example_table example_chain tcp dport 22 counter acceptTo display the counter values:
# nft list ruleset table inet example_table { chain example_chain { type filter hook input priority filter; policy accept; tcp dport ssh counter packets 6872 bytes 105448565 accept } }
10.10.2. Adding a counter to an existing rule
To identify if a rule is matched, you can use a counter.
-
For more information about a procedure that adds a new rule with a counter, see Creating a rule with the counter in
Configuring and managing networking
Prerequisites
- The rule to which you want to add the counter exists.
Procedure
Display the rules in the chain including their handles:
# nft --handle list chain inet example_table example_chain table inet example_table { chain example_chain { # handle 1 type filter hook input priority filter; policy accept; tcp dport ssh accept # handle 4 } }
Add the counter by replacing the rule but with the
counterparameter. The following example replaces the rule displayed in the previous step and adds a counter:# nft replace rule inet example_table example_chain handle 4 tcp dport 22 counter acceptTo display the counter values:
# nft list ruleset table inet example_table { chain example_chain { type filter hook input priority filter; policy accept; tcp dport ssh counter packets 6872 bytes 105448565 accept } }
10.10.3. Monitoring packets that match an existing rule
The tracing feature in nftables in combination with the nft monitor command enables administrators to display packets that match a rule. You can enable tracing for a rule an use it to monitoring packets that match this rule.
Prerequisites
- The rule to which you want to add the counter exists.
Procedure
Display the rules in the chain including their handles:
# nft --handle list chain inet example_table example_chain table inet example_table { chain example_chain { # handle 1 type filter hook input priority filter; policy accept; tcp dport ssh accept # handle 4 } }
Add the tracing feature by replacing the rule but with the
meta nftrace set 1parameters. The following example replaces the rule displayed in the previous step and enables tracing:# nft replace rule inet example_table example_chain handle 4 tcp dport 22 meta nftrace set 1 acceptUse the
nft monitorcommand to display the tracing. The following example filters the output of the command to display only entries that containinet example_table example_chain:# nft monitor | grep "inet example_table example_chain" trace id 3c5eb15e inet example_table example_chain packet: iif "enp1s0" ether saddr 52:54:00:17:ff:e4 ether daddr 52:54:00:72:2f:6e ip saddr 192.0.2.1 ip daddr 192.0.2.2 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 49710 ip protocol tcp ip length 60 tcp sport 56728 tcp dport ssh tcp flags == syn tcp window 64240 trace id 3c5eb15e inet example_table example_chain rule tcp dport ssh nftrace set 1 accept (verdict accept) ...WarningDepending on the number of rules with tracing enabled and the amount of matching traffic, the
nft monitorcommand can display a lot of output. Usegrepor other utilities to filter the output.
10.11. Backing up and restoring the nftables rule set
You can backup nftables rules to a file and later restoring them. Also, administrators can use a file with the rules to, for example, transfer the rules to a different server.
10.11.1. Backing up the nftables rule set to a file
You can use the nft utility to back up the nftables rule set to a file.
Procedure
To backup
nftablesrules:In a format produced by
nft list rulesetformat:# nft list ruleset > file.nftIn JSON format:
# nft -j list ruleset > file.json
10.11.2. Restoring the nftables rule set from a file
You can restore the nftables rule set from a file.
Procedure
To restore
nftablesrules:If the file to restore is in the format produced by
nft list rulesetor containsnftcommands directly:# nft -f file.nftIf the file to restore is in JSON format:
# nft -j -f file.json
10.12. Additional resources
Chapter 11. Securing network services
Red Hat Enterprise Linux 8 supports many different types of network servers. Their network services can expose the system security to risks of various types of attacks, such as denial of service attacks (DoS), distributed denial of service attacks (DDoS), script vulnerability attacks, and buffer overflow attacks.
To increase the system security against attacks, it is important to monitor active network services that you use. For example, when a network service is running on a machine, its daemon listens for connections on network ports, and this can reduce the security. To limit exposure to attacks over the network, all services that are unused should be turned off.
11.1. Securing the rpcbind service
The rpcbind service is a dynamic port-assignment daemon for remote procedure calls (RPC) services such as Network Information Service (NIS) and Network File System (NFS). Because it has weak authentication mechanisms and can assign a wide range of ports for the services it controls, it is important to secure rpcbind.
You can secure rpcbind by restricting access to all networks and defining specific exceptions using firewall rules on the server.
-
The
rpcbindservice is required onNFSv2andNFSv3servers. -
NFSv4does not require therpcbindservice to listen on the network.
Prerequisites
-
The
rpcbindpackage is installed. -
The
firewalldpackage is installed and the service is running.
Procedure
Add firewall rules, for example:
Limit TCP connection and accept packages only from the
192.168.0.0/24host via the111port:# firewall-cmd --add-rich-rule='rule family="ipv4" port port="111" protocol="tcp" source address="192.168.0.0/24" invert="True" drop'Limit TCP connection and accept packages only from local host via the
111port:# firewall-cmd --add-rich-rule='rule family="ipv4" port port="111" protocol="tcp" source address="127.0.0.1" accept'Limit UDP connection and accept packages only from the
192.168.0.0/24host via the111port:# firewall-cmd --permanent --add-rich-rule='rule family="ipv4" port port="111" protocol="udp" source address="192.168.0.0/24" invert="True" drop'To make the firewall settings permanent, use the
--permanentoption when adding firewall rules.
Reload the firewall to apply the new rules:
# firewall-cmd --reload
Verification steps
List the firewall rules:
# firewall-cmd --list-rich-rule rule family="ipv4" port port="111" protocol="tcp" source address="192.168.0.0/24" invert="True" drop rule family="ipv4" port port="111" protocol="tcp" source address="127.0.0.1" accept rule family="ipv4" port port="111" protocol="udp" source address="192.168.0.0/24" invert="True" drop
Additional resources
-
For more information about
NFSv4-onlyservers, see the Configuring an NFSv4-only server section. - Using and configuring firewalld
11.2. Securing the rpc.mountd service
The rpc.mountd daemon implements the server side of the NFS mount protocol. The NFS mount protocol is used by NFS version 2 (RFC 1904) and NFS version 3 (RFC 1813).
You can secure the rpc.mountd service by adding firewall rules to the server. You can restrict access to all networks and define specific exceptions using firewall rules.
Prerequisites
-
The
rpc.mountdpackage is installed. -
The
firewalldpackage is installed and the service is running.
Procedure
Add firewall rules to the server, for example:
Accept
mountdconnections from the192.168.0.0/24host:# firewall-cmd --add-rich-rule 'rule family="ipv4" service name="mountd" source address="192.168.0.0/24" invert="True" drop'Accept
mountdconnections from the local host:# firewall-cmd --permanent --add-rich-rule 'rule family="ipv4" source address="127.0.0.1" service name="mountd" accept'To make the firewall settings permanent, use the
--permanentoption when adding firewall rules.
Reload the firewall to apply the new rules:
# firewall-cmd --reload
Verification steps
List the firewall rules:
# firewall-cmd --list-rich-rule rule family="ipv4" service name="mountd" source address="192.168.0.0/24" invert="True" drop rule family="ipv4" source address="127.0.0.1" service name="mountd" accept
Additional resources
11.3. Securing the NFS service
You can secure Network File System version 4 (NFSv4) by authenticating and encrypting all file system operations using Kerberos. When using NFSv4 with Network Address Translation (NAT) or a firewall, you can turn off the delegations by modifying the /etc/default/nfs file. Delegation is a technique by which the server delegates the management of a file to a client. In contrast, NFSv2 and NFSv3 do not use Kerberos for locking and mounting files.
The NFS service sends the traffic using TCP in all versions of NFS. The service supports Kerberos user and group authentication, as part of the RPCSEC_GSS kernel module.
NFS allows remote hosts to mount file systems over a network and interact with those file systems as if they are mounted locally. You can merge the resources on centralized servers and additionally customize NFS mount options in the /etc/nfsmount.conf file when sharing the file systems.
11.3.1. Export options for securing an NFS server
The NFS server determines a list structure of directories and hosts about which file systems to export to which hosts in the /etc/exports file.
Extra spaces in the syntax of the exports file can lead to major changes in the configuration.
In the following example, the /tmp/nfs/ directory is shared with the bob.example.com host and has read and write permissions.
/tmp/nfs/ bob.example.com(rw)
The following example is the same as the previous one but shares the same directory to the bob.example.com host with read-only permissions and shares it to the world with read and write permissions due to a single space character after the hostname.
/tmp/nfs/ bob.example.com (rw)
You can check the shared directories on your system by entering the showmount -e <hostname> command.
Use the following export options on the /etc/exports file:
Export an entire file system because exporting a subdirectory of a file system is not secure. An attacker can possibly access the unexported part of a partially-exported file system.
- ro
-
Use the
rooption to export the NFS volume as read-only. - rw
Use the
rwoption to allow read and write requests on the NFS volume. Use this option cautiously because allowing write access increases the risk of attacks.NoteIf your scenario requires to mount the directories with the
rwoption, make sure they are not writable for all users to reduce possible risks.- root_squash
-
Use the
root_squashoption to map requests fromuid/gid0 to the anonymousuid/gid. This does not apply to any otheruidsorgidsthat might be equally sensitive, such as thebinuser or thestaffgroup. - no_root_squash
-
Use the
no_root_squashoption to turn off root squashing. By default, NFS shares change therootuser to thenobodyuser, which is an unprivileged user account. This changes the owner of all therootcreated files tonobody, which prevents the uploading of programs with thesetuidbit set. When using theno_root_squashoption, remote root users can change any file on the shared file system and leave applications infected by trojans for other users. - secure
-
Use the
secureoption to restrict exports to reserved ports. By default, the server allows client communication only through reserved ports. However, it is easy for anyone to become arootuser on a client on many networks, so it is rarely safe for the server to assume that communication through a reserved port is privileged. Therefore the restriction to reserved ports is of limited value; it is better to rely on Kerberos, firewalls, and restriction of exports to particular clients.
Additionally, consider the following best practices when exporting an NFS server:
- Exporting home directories is a risk because some applications store passwords in plain text or in a weakly encrypted format. You can reduce the risk by reviewing and improving the application code.
- Some users do not set passwords on SSH keys which again leads to risks with home directories. You can reduce these risks by enforcing the use of passwords or using Kerberos.
-
Restrict the NFS exports only to required clients. Use the
showmount -ecommand on the NFS server to review what the server is exporting. Do not export anything that is not specifically required. - Do not allow unnecessary users to log in to a server to reduce the risk of attacks. You can periodically check who and what can access the server.
Additional resources
- Secure NFS with Kerberos when using Red Hat Identity Management
- NFS server configuration.
-
exports(5)andnfs(5)man pages
11.3.2. Mount options for securing an NFS client
You can pass the following options to the mount command to increase the security of NFS-based clients:
- nosuid
-
Use the
nosuidoption to disable theset-user-identifierorset-group-identifierbits. This prevents remote users from gaining higher privileges by running asetuidprogram and you can use this option opposite tosetuidoption. - noexec
-
Use the
noexecoption to disable all executable files on the client. Use this to prevent users from accidentally executing files placed in the shared file system. - nodev
-
Use the
nodevoption to prevent the client’s processing of device files as a hardware device. - resvport
-
Use the
resvportoption to restrict communication to a reserved port and you can use a privileged source port to communicate with the server. The reserved ports are reserved for privileged users and processes such as therootuser. - sec
-
Use the
secoption on the NFS server to choose the RPCGSS security flavor for accessing files on the mount point. Valid security flavors arenone,sys,krb5,krb5i, andkrb5p.
The MIT Kerberos libraries provided by the krb5-libs package do not support the Data Encryption Standard (DES) algorithm in new deployments. DES is deprecated and disabled by default in Kerberos libraries because of security and compatibility reasons. Use newer and more secure algorithms instead of DES, unless your environment requires DES for compatibility reasons.
Additional resources
11.3.3. Securing NFS with firewall
To secure the firewall on an NFS server, keep only the required ports open. Do not use the NFS connection port numbers for any other service.
Prerequisites
-
The
nfs-utilspackage is installed. -
The
firewalldpackage is installed and running.
Procedure
-
On NFSv4, the firewall must open TCP port
2049. On NFSv3, open four additional ports with
2049:rpcbindservice assigns the NFS ports dynamically, which might cause problems when creating firewall rules. To simplify this process, use the/etc/nfs.conffile to specify which ports to use:-
Set TCP and UDP port for
mountd(rpc.mountd) in the[mountd]section inport=<value>format. -
Set TCP and UDP port for
statd(rpc.statd) in the[statd]section inport=<value>format.
-
Set TCP and UDP port for
Set the TCP and UDP port for the NFS lock manager (
nlockmgr) in the/etc/nfs.conffile:-
Set TCP port for
nlockmgr(rpc.statd) in the[lockd]section inport=valueformat. Alternatively, you can use thenlm_tcpportoption in the/etc/modprobe.d/lockd.conffile. -
Set UDP port for
nlockmgr(rpc.statd) in the[lockd]section inudp-port=valueformat. Alternatively, you can use thenlm_udpportoption in the/etc/modprobe.d/lockd.conffile.
-
Set TCP port for
Verification steps
List the active ports and RPC programs on the NFS server:
$ rpcinfo -p
Additional resources
- Secure NFS with Kerberos when using Red Hat Identity Management
-
exports(5)andnfs(5)man pages
11.4. Securing the FTP service
You can use the File Transfer Protocol (FTP) to transfer files over a network. Because all FTP transactions with the server, including user authentication, are unencrypted, you should ensure it is configured securely.
RHEL 8 provides two FTP servers:
- Red Hat Content Accelerator (tux) - a kernel-space web server with FTP capabilities.
- Very Secure FTP Daemon (vsftpd) - a standalone, security-oriented implementation of the FTP service.
The following security guidelines are for setting up the vsftpd FTP service.
11.4.1. Securing the FTP greeting banner
When a user connects to the FTP service, FTP shows a greeting banner, which by default includes version information that could be useful for attackers to identify weaknesses in a system. You can prevent the attackers from accessing this information by changing the default banner.
You can define a custom banner by editing the /etc/banners/ftp.msg file to either directly include a single-line message, or to refer to a separate file, which can contain a multi-line message.
Procedure
To define a single line message, add the following option to the
/etc/vsftpd/vsftpd.conffile:ftpd_banner=Hello, all activity on ftp.example.com is logged.
To define a message in a separate file:
Create a
.msgfile which contains the banner message, for example/etc/banners/ftp.msg:######### Hello, all activity on ftp.example.com is logged. #########
To simplify the management of multiple banners, place all banners into the
/etc/banners/directory.Add the path to the banner file to the
banner_fileoption in the/etc/vsftpd/vsftpd.conffile:banner_file=/etc/banners/ftp.msg
Verification
Display the modified banner:
$ ftp localhost Trying ::1… Connected to localhost (::1). Hello, all activity on ftp.example.com is logged.
11.4.2. Preventing anonymous access and uploads in FTP
By default, installing the vsftpd package creates the /var/ftp/ directory and a directory tree for anonymous users with read-only permissions on the directories. Because anonymous users can access the data, do not store sensitive data in these directories.
To increase the security of the system, you can configure the FTP server to allow anonymous users to upload files to a specific directory and prevent anonymous users from reading data. In the following procedure, the anonymous user must be able to upload files in the directory owned by the root user but not change it.
Procedure
Create a write-only directory in the
/var/ftp/pub/directory:# mkdir /var/ftp/pub/upload # chmod 730 /var/ftp/pub/upload # ls -ld /var/ftp/pub/upload drwx-wx---. 2 root ftp 4096 Nov 14 22:57 /var/ftp/pub/upload
Add the following lines to the
/etc/vsftpd/vsftpd.conffile:anon_upload_enable=YES anonymous_enable=YES
-
Optional: If your system has SELinux enabled and enforcing, enable SELinux boolean attributes
allow_ftpd_anon_writeandallow_ftpd_full_access.
Allowing anonymous users to read and write in directories might lead to the server becoming a repository for stolen software.
11.4.3. Securing user accounts for FTP
FTP transmits usernames and passwords unencrypted over insecure networks for authentication. You can improve the security of FTP by denying system users access to the server from their user accounts.
Perform as many of the following steps as applicable for your configuration.
Procedure
Disable all user accounts in the
vsftpdserver, by adding the following line to the/etc/vsftpd/vsftpd.conffile:local_enable=NO
-
Disable FTP access for specific accounts or specific groups of accounts, such as the
rootuser and users withsudoprivileges, by adding the usernames to the/etc/pam.d/vsftpdPAM configuration file. -
Disable user accounts, by adding the usernames to the
/etc/vsftpd/ftpusersfile.
11.4.4. Additional resources
-
ftpd_selinux(8)man page
11.5. Securing HTTP servers
11.5.1. Security enhancements in httpd.conf
You can enhance the security of the Apache HTTP server by configuring security options in the /etc/httpd/conf/httpd.conf file.
Always verify that all scripts running on the system work correctly before putting them into production.
Ensure that only the root user has write permissions to any directory containing scripts or Common Gateway Interfaces (CGI). To change the directory ownership to root user with write permissions, enter the following commands:
# chown root directory-name # chmod 755 directory-name
In the /etc/httpd/conf/httpd.conf file, you can configure the following options:
- FollowSymLinks
- This directive is enabled by default and follows symbolic links in the directory.
- Indexes
- This directive is enabled by default. Disable this directive to prevent visitors from browsing files on the server.
- UserDir
-
This directive is disabled by default because it can confirm the presence of a user account on the system. To activate user directory browsing for all user directories other than
/root/, use theUserDir enabledandUserDir disabledroot directives. To add users to the list of disabled accounts, add a space-delimited list of users on theUserDir disabledline. - ServerTokens
This directive controls the server response header field which is sent back to clients. You can use the following parameters to customize the information:
- ServerTokens Full
provides all available information such as web server version number, server operating system details, installed Apache modules, for example:
Apache/2.4.37 (Red Hat Enterprise Linux) MyMod/1.2
- ServerTokens Full-Release
provides all available information with release versions, for example:
Apache/2.4.37 (Red Hat Enterprise Linux) (Release 41.module+el8.5.0+11772+c8e0c271)
- ServerTokens Prod / ServerTokens ProductOnly
provides the web server name, for example:
Apache
- ServerTokens Major
provides the web server major release version, for example:
Apache/2
- ServerTokens Minor
provides the web server minor release version, for example:
Apache/2.4
- ServerTokens Min / ServerTokens Minimal
provides the web server minimal release version, for example:
Apache/2.4.37
- ServerTokens OS
provides the web server release version and operating system, for example:
Apache/2.4.37 (Red Hat Enterprise Linux)
Use the
ServerTokens Prodoption to reduce the risk of attackers gaining any valuable information about your system.
Do not remove the IncludesNoExec directive. By default, the Server Side Includes (SSI) module cannot execute commands. Changing this can allow an attacker to enter commands on the system.
Removing httpd modules
You can remove the httpd modules to limit the functionality of the HTTP server. To do so, edit configuration files in the /etc/httpd/conf.modules.d/ or /etc/httpd/conf.d/ directory. For example, to remove the proxy module:
echo '# All proxy modules disabled' > /etc/httpd/conf.modules.d/00-proxy.confAdditional resources
11.5.2. Securing the Nginx server configuration
Nginx is a high-performance HTTP and proxy server. You can harden your Nginx configuration with the following configuration options.
Procedure
To disable version strings, modify the
server_tokensconfiguration option:server_tokens off;
This option stops displaying additional details such as server version number. This configuration displays only the server name in all requests served by Nginx, for example:
$ curl -sI http://localhost | grep Server Server: nginxAdd extra security headers that mitigate certain known web application vulnerabilities in specific
/etc/nginx/conf files:For example, the
X-Frame-Optionsheader option denies any page outside of your domain to frame any content served by Nginx, mitigating clickjacking attacks:add_header X-Frame-Options "SAMEORIGIN";
For example, the
x-content-typeheader prevents MIME-type sniffing in certain older browsers:add_header X-Content-Type-Options nosniff;
For example, the
X-XSS-Protectionheader enables Cross-Site Scripting (XSS) filtering, which prevents browsers from rendering potentially malicious content included in a response by Nginx:add_header X-XSS-Protection "1; mode=block";
You can limit the services exposed to the public and limit what they do and accept from the visitors, for example:
limit_except GET { allow 192.168.1.0/32; deny all; }The snippet will limit access to all methods except
GETandHEAD.You can disable HTTP methods, for example:
# Allow GET, PUT, POST; return "405 Method Not Allowed" for all others. if ( $request_method !~ ^(GET|PUT|POST)$ ) { return 405; }- You can configure SSL to protect the data served by your Nginx web server, consider serving it over HTTPS only. Furthermore, you can generate a secure configuration profile for enabling SSL in your Nginx server using the Mozilla SSL Configuration Generator. The generated configuration ensures that known vulnerable protocols (for example, SSLv2 and SSLv3), ciphers, and hashing algorithms (for example, 3DES and MD5) are disabled. You can also use the SSL Server Test to verify that your configuration meets modern security requirements.
Additional resources
11.6. Securing PostgreSQL by limiting access to authenticated local users
PostgreSQL is an object-relational database management system (DBMS). In Red Hat Enterprise Linux, PostgreSQL is provided by the postgresql-server package.
You can reduce the risks of attacks by configuring client authentication. The pg_hba.conf configuration file stored in the database cluster’s data directory controls the client authentication. Follow the procedure to configure PostgreSQL for host-based authentication.
Procedure
Install PostgreSQL:
# yum install postgresql-serverInitialize a database storage area using one of the following options:
Using the
initdbutility:$ initdb -D /home/postgresql/db1/The
initdbcommand with the-Doption creates the directory you specify if it does not already exist, for example/home/postgresql/db1/. This directory then contains all the data stored in the database and also the client authentication configuration file.Using the
postgresql-setupscript:$ postgresql-setup --initdbBy default, the script uses the
/var/lib/pgsql/data/directory. This script helps system administrators with basic database cluster administration.
To allow any authenticated local users to access any database with their usernames, modify the following line in the
pg_hba.conffile:local all all trust
This can be problematic when you use layered applications that create database users and no local users. If you do not want to explicitly control all user names on the system, remove the
localline entry from thepg_hba.conffile.Restart the database to apply the changes:
# systemctl restart postgresqlThe previous command updates the database and also verifies the syntax of the configuration file.
11.7. Securing the Memcached service
Memcached is an open source, high-performance, distributed memory object caching system. It can improve the performance of dynamic web applications by lowering database load.
Memcached is an in-memory key-value store for small chunks of arbitrary data, such as strings and objects, from results of database calls, API calls, or page rendering. Memcached allows assigning memory from underutilized areas to applications that require more memory.
In 2018, vulnerabilities of DDoS amplification attacks by exploiting Memcached servers exposed to the public internet were discovered. These attacks took advantage of Memcached communication using the UDP protocol for transport. The attack was effective because of the high amplification ratio where a request with the size of a few hundred bytes could generate a response of a few megabytes or even hundreds of megabytes in size.
In most situations, the memcached service does not need to be exposed to the public Internet. Such exposure may have its own security problems, allowing remote attackers to leak or modify information stored in Memcached.
Follow the section to harden the system using Memcached service against possible DDoS attacks.
11.7.1. Hardening Memcached against DDoS
To mitigate security risks, perform as many of the following steps as applicable for your configuration.
Procedure
Configure a firewall in your LAN. If your Memcached server should be accessible only in your local network, do not route external traffic to ports used by the
memcachedservice. For example, remove the default port11211from the list of allowed ports:# firewall-cmd --remove-port=11211/udp # firewall-cmd --runtime-to-permanent
If you use a single Memcached server on the same machine as your application, set up
memcachedto listen to localhost traffic only. Modify theOPTIONSvalue in the/etc/sysconfig/memcachedfile:OPTIONS="-l 127.0.0.1,::1"
Enable Simple Authentication and Security Layer (SASL) authentication:
Modify or add the
/etc/sasl2/memcached.conffile:sasldb_path: /path.to/memcached.sasldb
Add an account in the SASL database:
# saslpasswd2 -a memcached -c cacheuser -f /path.to/memcached.sasldbEnsure that the database is accessible for the
memcacheduser and group:# chown memcached:memcached /path.to/memcached.sasldbEnable SASL support in Memcached by adding the
-Svalue to theOPTIONSparameter in the/etc/sysconfig/memcachedfile:OPTIONS="-S"
Restart the Memcached server to apply the changes:
# systemctl restart memcached- Add the username and password created in the SASL database to the Memcached client configuration of your application.
Encrypt communication between Memcached clients and servers with TLS:
Enable encrypted communication between Memcached clients and servers with TLS by adding the
-Zvalue to theOPTIONSparameter in the/etc/sysconfig/memcachedfile:OPTIONS="-Z"
-
Add the certificate chain file path in the PEM format using the
-o ssl_chain_certoption. -
Add a private key file path using the
-o ssl_keyoption.