A factorio init script for linux with an optional SELINUX policy add-on. This is a fork of https://github.com/Bisa/factorio-init
You need unhindered/unlimited root access with unconfined_u:unconfined_r:unconfined_t context (cannot be any constraints or confinement unless global permissive), SELINUX should be enabled. Enforcing or Permissive. Cannot be disabled.
You need to have ready the following:
- Factorio Online Username
- Factorio Token Key
- Factorio server title
- Factorio server description
umask 0022;
yum -y install git; git clone --recurse-submodules https://github.com/jhawkwind/factorio-SEinit /opt/factorio-init; chown -R root:root /opt/factorio-init/
semanage permissive -a unconfined_t; # This is safer.
chcon -R -u unconfined_u -r unconfined_r -t home_t -v /opt/factorio-init/; chcon -R -u unconfined_u -r unconfined_r -t home_bin_t -v /opt/factorio-init/unattended-centos-build.sh;
chown -R root:root /opt/factorio-init/
chmod 755 /opt/factorio-init/
chmod 755 /opt/factorio-init/unattended-centos-build.sh
/opt/factorio-init/unattended-centos-build.sh '<USERNAME>' '<TOKEN>' '<SERVER NAME>' '<SERVER DESCRIPTION>'
semanage permissive -d unconfined_t; # Return configuration.
systemctl enable factorio
systemctl start factorio
Don't forget the firewall settings:
firewall-cmd --new-service=factorio-multiplayer --permanent
firewall-cmd --service=factorio-multiplayer --set-description="Factorio multi-player lock step sychronization replication protocol" --permanent
firewall-cmd --service=factorio-multiplayer --add-port=34197/udp --permanent
firewall-cmd --add-service=factorio-multiplayer --permanent
firewall-cmd --reload
- TCP/UDP port controls (factorio_net_t).
- firewall-cmd commands built-in to scripts.
- SELINUX Boolean values for certain functions such as network access, sockets, user home reads, server commands through FIFO, etc.
- SELINUX_u user and roles (factorio_u:factorio_r).
- Clean up: proper transition points from init-script.
- Clean up: organize policy files.
- Clean up: CentOS deployment scripts.
- Clean up: Break out functions of the init-script.
- Verify updater works correctly.
- Tighten up policy rules to explicits.
- wget package - If you are planning to use the installer.
- python-requests package - If you are planning to use the updater script. It will likely install the following dependencies:
- python-backports
- python-backports-ssl_match_hostname
- python-ipaddress
- python-six
- python-urllib3
- git
- glibc-devel
- glibc
- make
- gcc-c++ - C++ component for glibc (optional)
- texinfo - documentation output for glibc
- libselinux-devel - SELINUX aware glibc
- audit-libs-devel - SELINUX auditing aware
- libcap-devel - root privileges partitioning for glibc
- SELINUX installed and enabled.
setenforce 1
- If you do not know what this command does, STOP! DO NOT PROCEED! Please read up on SELINUX Administration.- coreutils package - Required in all cases.
- policycoreutils package - Required in all cases.
You will not need this if you use the RPM.
- policycoreutils-python package - Optional if using RPM. Required if compiling yourself.
- policycoreutils-devel package - Optional if using RPM or just making small adjustments. Required if debugging.
- setools-console package - Required if debugging, optional in other cases.
If you find yourself wondering why stuff is not working the way you expect:
- Check the logs, I suggest you
tail -f /opt/factorio/factorio-current.log
in a separate session - Enable debugging in the config and/or:
- Try running the same commands as the factorio user (
/opt/factorio-init/factorio invocation
will tell you what the factorio user tries to run at start)
/opt/factorio-init/factorio invocation
# Run this as the factorio user, example:
sudo -u factorio 'whatever invocation gave you'
# You should see some output in your terminal here, hopefully giving
# you a hint of what is going wrong
- You may need to study the audit logs at
/var/log/audit/audit.log
and see what is being blocked. - You may need to disable the
dontaudit
flag and force auditing to get the output to the audit log with more answers:semodule --disable_dontaudit --build
- If you followed hardening guides, you may need to adjust the umask temporarily back to
umask 022
which was the default, or run:
find /opt/glibc-2.18 -type d -exec chmod 755 {} \;
find /opt/factorio-init -type d -exec chmod 755 {} \;
find /opt/factorio -type d -exec chmod 755 {} \;
- Create a directory where you want to store this script along with configuration. Cloning from github assuming /opt/factorio-init as the directory:
yum install git wget python-requests
cd '/opt'
git clone --recurse-submodules https://github.com/jhawkwind/factorio-SEinit /opt/factorio-init
- Rename /opt/factorio-init/config.example to /opt/factorio-init/config and modify the values within according to your setup.
- The config has options for declaring an alternate glibc root, don't forget to configure it.
- Compile the required GLIBC 2.18 and install it side-by-side with the OS version.
yum install glibc-devel glibc gcc make gcc-c++ autoconf texinfo libselinux-devel audit-libs-devel libcap-devel
cd /opt/factorio-init/glibc
git apply ../patches/test-installation.pl.patch
mkdir glibc-build
cd glibc-build
../configure --prefix='/opt/glibc-2.18' --with-selinux
make
make install
- You must set
SELINUX=1
in the config file to have the init script change context into the factorio_t domain. - The policy expects you to have the INIT script, Factorio, and GLIBC-2.18 in either /opt or /data. If you put them anywhere else, you will need to modify selinux/factorio.fc and (of course) the config to tell it the new locations, and manually compile and install the SELINUX policy modules.
- File location format:
- /opt (or /data)
- /factorio/
- /factorio-init/
- /glibc-2.18/
- lib/
- ld-2.18.so
- lib/
- /opt (or /data)
- Via the RPM, just run:
rpm -Uvh /opt/factorio-init/selinux/Factorio-SEinit-1.1-0.el7.src.rpm restorecon -R -v /opt/factorio-init restorecon -R -v /opt/glibc-2.18
- Compiling the module manually:
yum install policycoreutils-python policycoreutils-devel setools-console cd /opt/factorio-init/selinux make -f /usr/share/selinux/devel/Makefile factorio.pp semodule -i factorio.pp restorecon -R -v /opt/factorio-init restorecon -R -v /opt/glibc-2.18
- If you don't have Factorio installed already, use the
install
command:
useradd -c "Factorio Server account" -d /opt/factorio -M -s /usr/sbin/nologin -r factorio
/opt/factorio-init/factorio install # see help for options
-
The installation routine creates Factorio's
config.ini
automatically. -
If you previously ran Factorio without this script, the existing
config.ini
should work fine, just apply the security contexts:restorecon -R -v /opt/factorio
- Copy/Symlink or source the bash_autocompletion file
ln -s /opt/factorio-init/bash_autocomplete /etc/bash_completion.d/factorio
OR:
echo "source /opt/factorio-init/bash_autocomplete" >> ~/.bashrc
# restart your shell to verify that it worked
- Copy the example service, adjust & reload
cp /opt/factorio-init/factorio.service.example /etc/systemd/system/factorio.service
# Edit the service file to suit your environment then reload systemd
systemctl daemon-reload
- Verify that the server starts
systemctl start factorio
systemctl status -l factorio
# Remember to enable the service at startup if you want that:
systemctl enable factorio
- You know we just installed a bunch of stuff earlier? This yum command should remove everything we no longer need:
yum remove glibc-devel gcc gcc-c++ autoconf texinfo libselinux-devel audit-libs-devel libcap-devel libsepol-devel pcre-devel libstdc++-devel git setools-console policycoreutils-devel perl-Git mpfr libmpc kernel-headers glibc-headers cpp m4 selinux-policy-devel
- You can resecure the umask with
umask 0077
- The following firewalld rules will come in handy. As a "TODO" is to automate this as part of the installation process.
firewall-cmd --new-service=factorio-multiplayer --permanent
firewall-cmd --service=factorio-multiplayer --set-description="Factorio multi-player lock step sychronization replication protocol" --permanent
firewall-cmd --service=factorio-multiplayer --add-port=34197/udp --permanent
firewall-cmd --add-service=factorio-multiplayer --permanent
firewall-cmd --reload
You know that the Factorio process is boxed in when you run
ps auxZ | grep factorio
You should get this:
system_u:system_r:factorio_t:s0 factorio 1835 0.0 0.0 107988 360 ? S 21:19 0:00 tail -f /opt/factorio/bin/x64/../../server.fifo
system_u:system_r:factorio_t:s0 factorio 1836 39.0 1.6 301224 63052 ? Sl 21:19 0:00 /opt/glibc-2.18/lib/ld-2.18.so --library-path /opt/glibc-2.18/lib /opt/factorio/bin/x64/factorio --config /opt/factorio/config/config.ini --port 34197 --start-server-load-latest --server-settings /opt/factorio/data/server-settings.json --executable-path /opt/factorio/bin/x64/factorio
Where system_u:system_r:factorio_t:s0 indicates that it is running within the factorio_t domain context; and the factorio immediately after is the user it is running on. If you can login and the server runs correctly, you are done!
I haven't updated the SELINUX permissions and the way it executes the updater. It is currently and incorrectly, using the factorio_t domain to update, which is not what I want; since that provides the running domain with too much permissions. We want the "higher privileged" factorio_init_t to initiate the updater at privilege with factorio_update_t that can access everything in factorio_t, but with added temp_dir permissions. So somewhere between factorio_init_t's level of access and factorio_t's level of access.
For now, do this as a unconfined root user to update as the workaround:
systemctl stop factorio;
systemctl disable factorio;
semanage permissive -a factorio_t;
semanage permissive -a factorio_init_t;
sudo -u factorio -- /bin/runcon -t factorio_init_t -r system_r -u system_u -- /opt/factorio-init/factorio update;
semanage permissive -d factorio_t;
semanage permissive -d factorio_init_t;
semanage permissive -a unconfined_t;
restorecon -vFR /opt/factorio-init/;
restorecon -vFR /opt/factorio/;
semanage permissive -d unconfined_t;
systemctl enable factorio;
systemctl start factorio;
- To all who find this script useful in one way or the other
- A big thank you to Wube for making Factorio
- A special thanks to NoPantsMcDance, Oxyd, HanziQ, TheFactorioCube and all other frequent users of the #factorio channel @ esper.net
- Thank you to Salzig for pointing Bisa in the right direction when it comes to input redirection
- The user millisa over on the factorio forums for creating a wonderful guide to follow on making an alternate glibc root.
- Please report any (SE)init issues you find.
- At last, but not least; Thank you to all (SE)init contributors and users posting mainline issues in Bisa's original github project or on the factorio forums
You are all a great source of motivation, thank you.
This code is realeased with the MIT license, see the LICENSE file.