Building a RHEL/CentOS/Fedora device

This post is primarily aimed as a primer for the installation and post-install config tasks for a RHEL-based Linux install. It’s by no means designed to cover everything that needs to be, or should be, actioned for a Linux device, but will hopefully touch on the main items that can be looked at to get you on your way with your new device.

This article isn’t designed to be a how-to-install RHEL. The assumption is that the OS is already installed. Given time, this process may evolve to implement automation to perform the config tasks. As with most things though, that takes time, knowledge and resources; We’ll keep that on the to-do list for now.

Some of the steps in this article assume that a basic installation of the operating system has been performed – That is, a bare-bones installation. Not all of the steps below may apply to all instances.

Enabling EPEL for RHEL 9

Extended Packages for Enterprise Linux (EPEL) is a repository maintained by Fedora packagers for use with CentOS Stream and RHEL and contains numerous packages that add value to a RHEL deployment.

subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

Install basic packages

Install packages that may not be included in the base build of the system.

dnf install -y vim bash-completion net-tools tcpdump wget bash-color-prompt rhc-worker-playbook

Basic app config

VIM defaults

Create a .vimrc file in the root of the home directory:

vim ~/.vimrc

Populate it with the following contents:

set nowrap
set ic
set paste

These settings:

  • Disable wrapping to the terminal width;
  • Ignores case for functions such as search;
  • Paste mode disables features such as auto indent. It may not be a good idea to enable this long term.

Disable SELinux

As described by Redhat, Security-Enhanced Linux (SELinux) is a security architecture for Linux systems that allows administrators to have more control over who can access the system. It defines access controls for the applications, processes, and files on a system. It uses security policies, which are a set of rules that tell SELinux what can or can’t be accessed, to enforce the access allowed by a policy.

In short, SELinux enforces process and file security based on defined policies. This can be extremely beneficial in maintaining system integrity and security, but it also brings with it a level of complexity and restrictions that can result in significant time lost in troubleshooting non-functioning applications.

For the purposes of this article we’ll be disabling SELinux. Be advised that doing so will lower the security posture of your system.

Edit /etc/selinux/config. Set the mode to disabled:

...
#
SELINUX=disabled
# SELINUXTYPE= can take one of these three values:
...

Prevent SELinux kernel loading at boot:

grubby --update-kernel ALL --args selinux=0

System crypto-policy

With the release of RHEL 9 (and it’s upstream equivalents, including Fedora and CentOS), it was decided to disable a number of weaker cryptographic algorithms and digests. For example:

  • Algorithms:
    • RSAMD5;
    • RSASHA1;
    • NSEC3RSASHA1;
    • DSA;
    • NSEC3DSA;
    • ECCGOST;
  • Digests:
    • SHA-1;
    • GOST;

This can cause some problems with systems and services that still implement and operate with these mechanisms. An example of this is the use of DNSSEC for validation. A lot of providers still operate using SHA-1, however with this mechanism disabled, a local BIND server is unable to validate authenticity.

One option to work around this is to change the system-wide crypto policy. Doing this, however, lowers the security posture of the system.

update-crypto-policies --show
DEFAULT
update-crypto-policies --set LEGACY
Setting system policy to LEGACY
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.

Graphical boot

Enable graphical boot

A basic OS install doesn’t include a graphical boot and sometimes the fast scrolling text of the boot process is a little busy and frantic. Install and configure plymouth to tidy up the boot process.

dnf install -y plymouth-theme-spinner
plymouth-set-default-theme
plymouth-set-default-theme --list
grubby --update-kernel ALL --args "rhgb quiet"

Disable graphical boot

Sometimes you don’t want a graphical boot loader or hidden boot process:

grubby --remove-args="rhgb quiet" --update-kernel ALL

Create SSH keys

SSH keys can provide a more secure method of authenticating to a system. Create a new key for root and add the public key to the authorized_keys file.

ssh-keygen -t ed25519 -f ~/.ssh/$HOSTNAME-$USER.id_ed25519
cat ~/.ssh/$HOSTNAME-$USER.id_ed25519.pub >> ~/.ssh/authorized_keys

Managing the GUI (GDM)

Switching to a GUI

There’s a couple of ways that you can switch to a UI.

  1. Set the default boot target to graphical.target
  2. Change the target for the current runtime: systemctl isolate graphical.target. This impacts the whole system and modifies service state based on the run-level.
  3. Simply call startx.

Setting the boot target

Switching the boot target to a text-based console reduces system resource usage:

systemctl get-default
multi-user.target
systemctl set-default multi-user.target

Enabling a graphical target is just as simple:

systemctl get-default
multi-user.target
systemctl set-default graphical.target

The various targets can be viewed:

systemctl list-units --type target
  UNIT                   LOAD   ACTIVE SUB    DESCRIPTION
  basic.target           loaded active active Basic System
  cryptsetup.target      loaded active active Local Encrypted Volumes
  getty.target           loaded active active Login Prompts
  integritysetup.target  loaded active active Local Integrity Protected Volumes
  local-fs-pre.target    loaded active active Preparation for Local File Systems
  local-fs.target        loaded active active Local File Systems
  multi-user.target      loaded active active Multi-User System
  network-online.target  loaded active active Network is Online
  network-pre.target     loaded active active Preparation for Network
  network.target         loaded active active Network
  nss-user-lookup.target loaded active active User and Group Name Lookups
  paths.target           loaded active active Path Units
  remote-fs-pre.target   loaded active active Preparation for Remote File Systems
  remote-fs.target       loaded active active Remote File Systems
  slices.target          loaded active active Slice Units
  sockets.target         loaded active active Socket Units
  sshd-keygen.target     loaded active active sshd-keygen.target
  swap.target            loaded active active Swaps
  sysinit.target         loaded active active System Initialization
  timers.target          loaded active active Timer Units
  veritysetup.target     loaded active active Local Verity Protected Volumes

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.
21 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
systemctl list-units --type target --all
...

Installing a graphical user interface

If you installed the system as a standard Server instance, that is no GUI, you can install the required packages post-installation:

dnf grouplist
Available Environment Groups:
   Server with GUI
   Minimal Install
   Workstation
   Custom Operating System
   Virtualization Host
Installed Environment Groups:
   Server
Installed Groups:
   Headless Management
   Container Management
Available Groups:
   Legacy UNIX Compatibility
   Scientific Support
   Network Servers
   Development Tools
   Console Internet Tools
   System Tools
   Security Tools
   Graphical Administration Tools
   Smart Card Support
   .NET Development
   RPM Development Tools
dnf group install GNOME base-x Fonts "Internet Browser"
...
Installing Groups:
 GNOME
 base-x
 Fonts

Transaction Summary
========================================================
Install  446 Packages
Upgrade    8 Packages

Total download size: 536 M
Is this ok [y/N]:y
...
Complete!

Disabling the user list on the login screen

You don’t always want to advertise which users have accounts on the system. Disable the login screen user list by following this procedure.

  1. Edit the file /etc/dconf/db/gdm.d/00-login-screen:
[org/gnome/login-screen]
# Do not show the user list
disable-user-list=true
  1. Update the dconf database and verify the setting:
dconf update
sudo -u gdm DCONF_PROFILE=gdm dconf read /org/gnome/login-screen/disable-user-list
true
  1. Restart the GDM service:
systemctl restart gdm.service

Firewall lock-down

The out-of-the-box configuration for firewalld is to associate the active interface (e.g. ens34) with the public zone and permit system management and critical network protocol flows – ssh, cockpit, DHCPv6. Due to the association with the network interface, this configuration makes public the fall-back zone.

To increase the security of the system, it’s recommended to lock-down the public zone and leverage additional zones with specific source and destination configuration, offering greater flexibility and control.

Change the default zone

For simplicity, you can change the default zone to allow for brevity in fireawalld configuration.

firewall-cmd --set-default-zone=trusted 
success
firewall-cmd --get-default-zone 
trusted
firewall-cmd --remove-interface=ens34 --zone=trusted
success
firewall-cmd --add-interface=ens34 --zone=public
success
firewall-cmd --runtime-to-permanent
success

Default drop

The firewalld service drops all TCP/UDP packets unless allowed by the policy. The target out-of-the box for the active zones is default. The default target permits ICMP but drops TCP/UDP if not explicitly permitted by policy. There are situations were you may want to drop any packet that is not explicitly permitted by your policy. To do this, change the default target for the firewall firewall zone to drop.

firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens34
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
firewall-cmd --set-target=DROP --zone=public --permanent
success
firewall-cmd --set-target=DROP --zone=trusted --permanent
success
firewall-cmd --reload
success
firewall-cmd --list-all
trusted (active)
  target: DROP
  icmp-block-inversion: yes
  interfaces: 
  sources: 192.168.0.0/24
  services: cockpit ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: echo-request
  rich rules: 

Configure the default zone

Configure the default zone (trusted) with source and service configuration of permitted flows.

firewall-cmd --add-source=192.168.0.0/24
success
firewall-cmd --add-service=ssh --add-service=cockpit
success
firewall-cmd --runtime-to-permanent
success

Clean-up the public zone

Remove unnecessary services from the public zone.

firewall-cmd --remove-service=ssh --remove-service=cockpit --remove-service=dhcpv6-client --zone=public
success
firewall-cmd --runtime-to-permanent
success

Allowing ICMP

With the target set to drop, we can manage which ICMP messages are permitted. Being a little counter-intuitive, as firewalld is now dropping all non-permitted flows, we have to enable ICMP inversion and add allowed ICMP messages with the add-icmp-block directive.

firewall-cmd --add-icmp-block-inversion --permanent
success
firewall-cmd --add-icmp-block=echo-request --permanent
success
firewall-cmd --reload
success
firewall-cmd --list-all
trusted (active)
  target: DROP
  icmp-block-inversion: yes
  interfaces: 
  sources: 192.168.0.0/24
  services: cockpit ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: echo-request
  rich rules: 

Posted

in

by