omitting init omitting init ApacheConfig has no keyword method Group has no keyword method JavaConfig has no keyword method NetworkConfiguration has no keyword method OSInfo has no keyword method PackageManager has no keyword method Passwd has no keyword method PHPConfig has no keyword method PythonConfig has no keyword method
A python based script was implemented to harden the configuration of components required to manage and run a content management system in a Shared-Hosting Environment, where a user usually does only have a restricted shell access.
Currently, the following components are supported:
- Operating system: Debian Linux
- Firewall rules: iptables
- Web server: Apache 2
- Remote Management: OpenSSH
- Programming language/Scripting environment: php, python, java
- Database management system: MySQL
- Content Management System: Liferay CE, Plone
To run the script, the following python package need to be installed:
- yaml
- netifaces
- six
- lxml
- psutil
We suggest that you use the package manager of your distribution to install the
required packages. In Debian Linux, the packages are named python-<package name> resp. python3-<package name>
; depending on which version of python you are using. E.g., you could install all requirements using the command
$ sudo apt-get install python3{,-{yaml,netifaces,six,lxml}}
The script can only be run from command line for now. It can be extended to support running as Web application.
You MUST run this script as non-privileged user, and you MUST use sudo
to do this. This is required because we need root privileges to modify any configuration files; and we disable root logins in your sshd configuration. To prevent you from locking out of our own system, we add the name of your currently logged in user to the sshd configuration as a user which is allowed to login using ssh.
We recommend installing coloredlogs
if you like to have colored logs on the console.
cd
into directory python
and run
$ sudo python hardening.py
$ python hardening.py --help
usage: hardening.py [-h] [--mode {interactive,diff,silent,checkonly}] [--log [logfile]]
[--lang {en_US,de_DE}] [--version] [--documentation]
optional arguments:
-h, --help show this help message and exit
--mode {interactive,diff,silent,checkonly}
select mode in which this script will run
--log [logfile] display a log of applied changes; use can use '-' as
filename to log to stdout
--lang {en_US,de_DE} select display language
--version display version
--documentation display full documentation in markdown format
- The script introduces the user with some information to inform about risks and usage of the script
- If the selected
mode
is notsilent
, a menu is displayed which enables the user to select modules to be run - There might be some certain general information the user has to enter. (For example which of the network interfaces shall be used for management access)
- Now the actual hardening takes place. For each so called Util the user will be informed about the action that will be performed. If the interactive mode (
--mode=ask
) is enabled the user will be prompted to confirm each change. - All hardening steps are performed on temporary files first and will be committed to the original files as soon as all changes are accomplished.
If difference mode (
--mode=diff
) is enabled, the user will be prompted to confirm the sum of all changes to a file - For each file to be adjusted the script creates a backup file (the destination can be configured using the global
Backup.Basedir
-property)
Currently, no rollback is possible, all directly changed configuration files are copied to the backup directory, while maintaining the original folder structure. You can copy those files back, if you need too. Be aware that some hardening steps require the execution of system commands (such as usermod
or a2enmod
), which cannot be rolled back by copying some files
- After a short notification about the backups folder, the script exits.
All configuration files use the YAML syntax, with the following extensions:
- property values are interpolated (see Interpolation)
- references (*) can refer to anchors (&) in different files. All YAML files are merged before references are resolved by the YAML parser.
The configuration of this toolset is separated into multiple files:
Filename | Description |
---|---|
config.yml |
Global Configuration file for the whole toolset |
modules/ <mycomponent> .yml |
Configuration file used for the component <mycomponent> . For example, the configuration for hardening sshd is stored in modules/sshd.yml |
Interpolation is a features which replaces a certain part of a string (substring) by some other string, using the following rules:
-
if the substring starts with
info:
, then Interpolation starts by- detecting the interpolated substring
- replacing the interpolated substring by its value
-
interpolation is run once by string, for all matching substrings of a string.
Every interpolated substring consists of parts, which are alphanumeric values and are separated by colon (:). For example, if the substrings info:example:group
and info:example:mark
interpolate to world
and !
, resp.; the string
"hello, info:example:group info:example:mark"
is interpolated to
"hello, world !"
Substring | Replacement |
---|---|
info:apache:apache_config |
returns the absolute path of the local apache2.conf file Normally, the path should be /etc/apache2/apache2.conf in Debian Linux |
info:apache:security_config |
returns the absolute path of the local security.conf file Normally, the path should be /etc/apache2/conf-available/security.conf in Debian Linux |
info:apache:ssl_config |
returns the absolute path of the local ssl_config file Normally, the path should be /etc/apache2/mods-available/ssl_config in Debian Linux |
info:condition:false |
evaluates to False |
info:condition:hardening_for_joomla |
returns True if the configuration must be tailored for Joomla |
info:condition:hardening_for_liferay |
returns True if the configuration must be tailored for Liferay |
info:condition:hardening_for_plone |
returns True if the configuration must be tailored for Plone |
info:condition:hardening_for_typo3 |
returns True if the configuration must be tailored for Typo3 |
info:condition:hardening_for_wordpress |
returns True if the configuration must be tailored for Wordpress |
info:condition:has_apache_installed |
returns True if Apache (apache2) is installed |
info:condition:has_network_interface:<index> |
returns True if a specific interface exists. All network interfaces are internally indexed, starting with 0 ; the interfaces lo is omitted. So, the first interfaces may be externally reachable has the index 0 |
info:condition:has_package_installed:<package> |
returns True if package is installed on the local system |
info:condition:has_php_installed |
returns True if PHP (php-fpm) is installed |
info:condition:true |
evaluates to True |
info:env:<var_name> |
interpolates the given environment variable |
info:net:default_gw |
returns the IP address of the default gateway |
info:net:gateway:<index> |
returns the gateway ip address of the interface with the given index |
info:net:inet_address:<index> |
returns the ip address of the interface with the given index |
info:net:interface:<index> |
returns the name of the interface with the given index |
info:net:interface_info:<index>:<infoname> |
returns some specific information of the interface with the given index Supported values for infoname are addr , netmask and peer |
info:net:interfaces |
returns the names of all network interfaces (excluding lo ) |
info:net:management_address |
returns the IP address which shall be used by management services, such as SSH |
info:net:nameservers |
returns a list of ip addresses, representing name servers |
info:net:netmask:<index> |
returns the subnet mask of the interface with the given index |
info:net:public_address |
returns the IP address which shall be used by services which are publicly available |
info:net:resolv_conf |
returns the current DNS configuration |
info:net:static_addresses |
returns a list of all ip addresses (excluding 127.0.0.1 ) |
info:php:php_ini |
returns the absolute path of the global php configuration file. Currently, we simply return /etc/php5/fpm/php.ini |
info:resolve_key:<keyname> |
Uses entries in config.yml to interpolate. Each keyname is mapped to an associative list, where the key is a regular expression that is matched against the result of OSInfo::distribution_name(). If the distribution name matches the given regular expression, then the interpolated string is replaced by the value of the associative list from config.yml |
info:user:logname |
returns the name with which the user has logged in to the current system. This is normally your current username. But: If you used sudo to become another user, then this interpolates to your username you had before you invoked sudo |
Example:
Logging:
LogLevel: DEBUG
LogHandler: StreamHandler
Verbose: True
RunModules: [network, apache, sshd, php, WordPress, debian, java, python]
Backup:
BaseDir: "$HOME/hardening-backup"
HardeningSettings: {
ssh-runtime-user: &ssh-runtime-user "sshd",
ssh-runtime-group: &ssh-runtime-group "ssh",
ssh-listening-port: &ssh-listening-port "22"
}
Setting | Description |
---|---|
Logging/LogLevel |
specifies how verbose the toolset shall be. Valid values (with increasing verbosity) are CRITICAL , ERROR , WARNING , INFO , DEBUG |
Logging/LogHandler |
Name of a class from package logging.handlers . Valid values are StreamHandler , FileHandler or NullHandler |
RunModules |
a list of modules which shall be run. Each entry in this list refers to a YAML file int the modules directory. |
Backup/BaseDir |
Name of the directory where backup files will be stored |
HardeningSettings |
Here, a lot of global settings can be specified, so that it is not necessary anymore to edit any YAML files. All settings here should be marked with an anchor (&). |
The configuration of any module is divided into two parts:
RunSections
contains a list of sections names. For each entry in this list there should be a Section in the next part of the module- Each Section is a associative array with the following content:
RunUtils
contains a list of associative array, each of which names a class from theutils
package and contains options. For every entry in list list, an instance of the specified class is being created, using the options specifiedOptions
is an associative array which contains options that have to be applied for everyRunUtils
-entry.
util class | option | is required? | meaning |
---|---|---|---|
utils.HardeningUtil |
|||
apache.ApacheDismod |
this module runs a2dismod to disable an apache module | ||
modname |
True | name of the apache module to be disabled | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
apache.ApacheEnmod |
this module runs a2enmod to enable an apache module | ||
modname |
True | name of the apache module to be enabled | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
configfile.ApacheConfigEntry |
ApacheConfigEntry is a specialized version of ConfigFileEntry which is able to find a specific section inside the config file and put the requested value into this section | ||
transaction |
True | path of the apache config file | |
key |
True | name of the configuration setting | |
value |
True | value to be set for the configuration setting | |
section |
False | section inside the config file where setting must be placed in | |
listseparator |
False | if the value is a list then this options specifies how the distinct values must be separated | |
separator |
False | the string that divides setting name and setting value in the config file | |
commentchar |
False | all characters in a line after the comment character are ignored | |
multiple |
False | if this is set to true then existing settings with the same key and different value are not overwritten, but a new line is being inserted | |
before-key |
False | describes a key in the config file BEFORE which the current setting will be inserted. | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
configfile.ConfigFileEntry |
searches through the given configuration file if there already exists a setting whose name matches that of the given key. If a matching entry is found, it is being updated. If no matching entry is found, the setting will be appended to the file. If the user has set multiple to True , than also the value will be used to find a matching value. This allows to add multiple settings with the same key, but different value, to a file. |
||
transaction |
True | path of the config file | |
key |
True | name of the configuration setting | |
value |
True | value to be set for the configuration setting | |
separator |
False | the string that divides setting name and setting value in the config file | |
listseparator |
False | if the value is a list then this options specifies how the distinct values must be separated | |
commentchar |
False | all characters in a line after the comment character are ignored | |
multiple |
False | if this is set to true then existing settings with the same key and different value are not overwritten, but a new line is being inserted | |
before-key |
False | describes a key in the config file BEFORE which the current setting will be inserted. | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
configfile.ConfigLine |
|||
configfile.IniFileEntry |
|||
transaction |
True | path of the apache config file | |
key |
True | name of the configuration setting | |
value |
True | value to be set for the configuration setting | |
section |
False | section inside the config file where setting must be placed in | |
listseparator |
False | if the value is a list then this options specifies how the distinct values must be separated | |
separator |
False | the string that divides setting name and setting value in the config file | |
commentchar |
False | all characters in a line after the comment character are ignored | |
multiple |
False | if this is set to true then existing settings with the same key and different value are not overwritten, but a new line is being inserted | |
before-key |
False | describes a key in the config file BEFORE which the current setting will be inserted. | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
configfile.XmlFileEntry |
|||
transaction |
True | path of the config file | |
xslt |
True | XML transform to be applied to the configuration file | |
xmlns |
False | default XML namespace used in the file | |
namespace-prefix |
False | XML namespace prefix used in the file | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
filesystem.ChangeOwner |
this class can be used to change the owner (and, if necessary, the owning group) of a file | ||
user |
True | name of the new owner | |
group |
False | name of the owning group | |
recursive |
False | additional parameter for ChangeOwner | |
apply-to-files |
False | ||
apply-to-directories |
False | ||
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
filesystem.ChangePermissions |
this class can be used to change the access permissions of a file. The mode must be a valid octal number between 000 and 777 . |
||
mode |
True | mode to be used as new access permissions | |
recursive |
False | additional parameter for ChangeOwner | |
apply-to-files |
False | ||
apply-to-directories |
False | ||
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
filesystem.DeleteFile |
this class can be used to delete a file from the filesystem. wildcards for filenames are currently not supported | ||
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
filesystem.Directory |
creates a directory | ||
path |
True | complete path of the new directory | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
module.EnterModule |
|||
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
net.Firewall |
creates a firewall rule. Be aware that the default policy for all chains is "DROP", which cannot be altered using configuration files | ||
protocol |
True | name of the protocol. must be either tcp , udp or icmp |
|
src |
False | name or ip address of the sending host | |
dst |
False | name of ip address of the receiving host | |
action |
False | specifies what shoud be done with matching packets. Default value is ACCEPT |
|
chain |
False | name of the chain where the rule must be inserted. Should be INPUT , OUTPUT or FORWARD |
|
srcport |
False | source port of the packet. Only valid for tcp and udp |
|
dstport |
False | destination port of the packet. Only valid for tcp and udp |
|
icmp-type |
False | ICMP type. Please run iptables -p icmp -h to see which values are supported on your system |
|
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
net.StaticIP |
uses the current network configuration, no matter if its being configured statically or dynamically, and writes a network configuration file, so that the current configuration is static from now on. No dhcp will be used afterwards | ||
interface |
True | name of the interface to be configured | |
inet-address |
True | IPv4 network address | |
netmask |
False | subnet mask, defaults to 255.255.255.0 | |
gateway |
False | IPv4 address of the default gateay, if any | |
dns-nameservers |
False | IPv4 addresses of DNS name servers | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
os.CheckVersion |
compares the version of an installed component with a version that is specified as parameter | ||
key |
True | specifies which version you are interested in. must be one of php , java or python |
|
version |
True | specifies a version with which the installed version should be compared | |
operation |
True | must be greater_then |
|
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
os.ConfigureService |
this class is used to enable, disable, start or stop a service | ||
servicename |
True | unique name of the service | |
action |
True | specifies what must be done with the service. must be one of enable , disable , start or stop |
|
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run | |
os.UserItem |
creates a user. If the user already exists, it will be modified. Be aware: this class does not use Transactions, so there is no rollback possible. | ||
name |
True | name of the user to be created | |
home |
False | home directory | |
shell |
False | login shell | |
meta |
False | contains information about that specific hardening step | |
run-if |
False | specifies under which condition this util will be run |
For all automatically changed files the script will create backup files in the backup folder, which can be configured using the Backup/BaseDir
property. Inside the backup directory, a new folder with the name <timestamp>
will be created. For all files in this directory, subdirectories will be created in a way that they match to the original directories on the local system. The original filenames will be maintained.
If you specify the --log
parameter, a log documenting the changes applied to the system is created. If you specify a filename as option to this parameter, the log will be saved to that file. Otherwise, the log will be written to stdout
.