Skip to content

Instantly share code, notes, and snippets.

@icedream
Last active March 29, 2024 20:57
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save icedream/75135f63f433ec52d652c7245dd17e30 to your computer and use it in GitHub Desktop.
Save icedream/75135f63f433ec52d652c7245dd17e30 to your computer and use it in GitHub Desktop.
Adjusting SELinux to change SSH port in Fedora CoreOS

See coreos/fedora-coreos-tracker#396 (comment) for a bit of explanation.

Warning: The script will trigger warning messages in the systemd journal log that look like this:

systemd[1]: sshd.service: Found left-over process 4270 (conmon) in control group while starting unit. Ignoring.
systemd[1]: This usually indicates unclean termination of a previous run, or service implementation deficiencies.

This is probably a side effect of the script booting up podman containers to run semanage - I don't know how to get rid of this properly if it's possible at all but I think this can be ignored for now.

SSH daemon can take quite a long while to start for the first time due to the one-time image build.

variant: fcos
version: 1.0.0
# …
storage:
files:
# SELinux fix script
- path: /usr/local/bin/sshd_fix_selinux
mode: 0744
contents:
inline: |
#!/bin/bash -e
# This script runs right before SSH server boots up via Systemd.
# It is required to be run when on Fedora CoreOS and changing the port SSH is listening on.
#
# The script builds a Fedora image with semanage installed (if already built it will not build again).
# After that it will run semanage to update which ports SSH is allowed to listen on.
#
# Suggested path of this script: /usr/local/bin/sshd_fix_selinux
#
# Author: Carl Kittelberger <icedream@icedream.pw>
# Just used to get a guaranteed empty Docker context dir
empty_dir="$(mktemp -d)"
dockerfile="$(mktemp)"
cleanup() {
if [ -d "$empty_dir" ]
then
rm -rf "$empty_dir"
fi
if [ -f "$dockerfile" ]
then
rm -f "$dockerfile"
fi
}
trap cleanup EXIT
# NOTE - not sure if policycoreutils-devel is necessary here, didn't test it with it removed
cat >"$dockerfile" <<DEOF
FROM fedora
RUN yum install -y policycoreutils-python-utils policycoreutils-devel && yum clean all
DEOF
image_name="$(podman build -f "$dockerfile" "$empty_dir" | tail -n1)"
secontainer() {
podman run --privileged --rm \
-v /var/run:/var/run \
-v /etc/selinux:/etc/selinux \
-v /proc:/proc \
-v /sys:/sys \
"$image_name" "$@"
}
# Delete any old custom SSH port rules
secontainer semanage port -D -t ssh_port_t -p tcp || true
# Read SSH port straight from the sshd_config, default to 22.
ssh_port="$(grep -Po '^\s*Port\s+\K\d+' /etc/ssh/sshd_config || printf '%s' 22)"
secontainer semanage port -a -t ssh_port_t -p tcp "$ssh_port"
# workaround from https://github.com/coreos/fedora-coreos-tracker/issues/701 to keep selinux policy files in base config state
rsync -rcl /usr/etc/selinux/ /etc/selinux/
systemd:
units:
- name: sshd.service
enabled: true
dropins:
# Run SELinux fix script before SSH daemon starts up
- name: 00-sshd-fix-selinux.conf
contents: |
[Service]
ExecStartPre=/usr/local/bin/sshd_fix_selinux
[Service]
ExecStartPre=/usr/local/bin/sshd_fix_selinux
#!/bin/bash -e
# This script runs right before SSH server boots up via Systemd.
# It is required to be run when on Fedora CoreOS and changing the port SSH is listening on.
#
# The script builds a Fedora image with semanage installed (if already built it will not build again).
# After that it will run semanage to update which ports SSH is allowed to listen on.
#
# Suggested path of this script: /usr/local/bin/sshd_fix_selinux
#
# Author: Carl Kittelberger <icedream@icedream.pw>
# Just used to get a guaranteed empty Docker context dir
empty_dir="$(mktemp -d)"
dockerfile="$(mktemp)"
cleanup() {
if [ -d "$empty_dir" ]
then
rm -rf "$empty_dir"
fi
if [ -f "$dockerfile" ]
then
rm -f "$dockerfile"
fi
}
trap cleanup EXIT
# NOTE - not sure if policycoreutils-devel is necessary here, didn't test it with it removed
cat >"$dockerfile" <<DEOF
FROM fedora
RUN yum install -y policycoreutils-python-utils policycoreutils-devel && yum clean all
DEOF
image_name="$(podman build -f "$dockerfile" "$empty_dir" | tail -n1)"
secontainer() {
podman run --privileged --rm \
-v /var/run:/var/run \
-v /etc/selinux:/etc/selinux \
-v /proc:/proc \
-v /sys:/sys \
"$image_name" "$@"
}
# Delete any old custom SSH port rules
secontainer semanage port -D -t ssh_port_t -p tcp || true
# Read SSH port straight from the sshd_config, default to 22.
ssh_port="$(grep -Po '^\s*Port\s+\K\d+' /etc/ssh/sshd_config || printf '%s' 22)"
secontainer semanage port -a -t ssh_port_t -p tcp "$ssh_port"
# workaround from https://github.com/coreos/fedora-coreos-tracker/issues/701 to keep selinux policy files in base config state
rsync -rcl /usr/etc/selinux/ /etc/selinux/
@OrvilleQ
Copy link

OrvilleQ commented Oct 1, 2022

Hello!

Thanks to your great solution, but I found out this might cause some issue with Calico and Kubernetes.

Refers to This issue I opened. Seems like in the default auto IP dectect mode (first-found), there is a good chance that calico will found IP address from interface podman0 which left over after the container running.

There is no need for this container running with network so maybe we could run it with Slirp4netns mode (Could we do that on a Root container?) or could podman run contianer without network? I don't whink we could delete the netbridge after cause then we have to set the kubernetes service run after this service with might take long time to finish.

@cyl3x
Copy link

cyl3x commented Nov 11, 2023

Nice work, thanks!

NOTE - not sure if policycoreutils-devel is necessary here, didn't test it with it removed

policycoreutils-devel is not needed

Also, instead of using just reading sshd_config for port changes, you can dump the ssh config with sshd -T, e.g. sshd -T | sed -n 's/^port \(.*\)/\1/p'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment