security Package

security Package

Roles in this namespace are meant to configure security features in Debian distributions.

apparmor Module

class provy.more.debian.security.apparmor.AppArmorRole(prov, context)[source]

Bases: provy.core.roles.Role

This role provides AppArmor utilities for Debian distributions.

Warning

If you’re provisioning a Debian Wheezy server or older, it’s highly recommended you use SELinuxRole instead of this one.

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):

        with self.using(AppArmorRole) as apparmor:
            apparmor.disable("/bin/ping", "/sbin/dhclient")

        with self.using(AppArmorRole) as apparmor:
            apparmor.create("/usr/sbin/nginx", policy_groups=['networking', 'user-application'],
                            read=["/srv/my-site"], read_and_write=["/srv/my-site/uploads"])
audit(*executables)[source]

Puts the executables to audit mode - the policies are enforced, and all actions (legal and ilegal ones) will be logged -.

Parameters:executables (positional arguments of str) – The executables to change.

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):
        with self.using(AppArmorRole) as apparmor:
            apparmor.audit("/bin/ping", "/sbin/dhclient")
complain(*executables)[source]

Puts the executables to complain mode - the policies are not enforced, but when they’re broken, the action gets logged -.

Parameters:executables (positional arguments of str) – The executables to change.

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):
        with self.using(AppArmorRole) as apparmor:
            apparmor.complain("/bin/ping", "/sbin/dhclient")
create(executable, template=None, policy_groups=None, abstractions=None, read=[], read_and_write=[])[source]

Creates a profile for an executable. Please refer to the aa-easyprof manual pages for more documentation.

Parameters:
  • executable (str) – The executable to be referenced by the profile being created.
  • template (str) – If provided, will be used instead of the “default” one. Defaults to None.
  • policy_groups (iterable) – If provided, use its items as the policy groups. Defaults to None.
  • abstractions (iterable) – If provided, use its items as the abstractions. Defaults to None.
  • read (iterable) – If provided, paths to be readable by the executable. Defaults to [] (empty list).
  • read_and_write (iterable) – If provided, paths to be readable and writable by the executable (there’s no need to provide the “read” argument in this case). Defaults to [] (empty list).

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):
        with self.using(AppArmorRole) as apparmor:
            apparmor.create("/usr/sbin/nginx", policy_groups=['networking', 'user-application'],
                            read=["/srv/my-site"], read_and_write=["/srv/my-site/uploads"])
disable(*executables)[source]

Disables executables in AppArmor, removing them from confinement - that is, they will not be under vigilance anymore -.

Parameters:executables (positional arguments of str) – The executables to change.

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):
        with self.using(AppArmorRole) as apparmor:
            apparmor.disable("/bin/ping", "/sbin/dhclient")
enforce(*executables)[source]

Puts the executables to enforce mode - the policies are enforced, but only break attempts will be logged -.

Parameters:executables (positional arguments of str) – The executables to change.

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):
        with self.using(AppArmorRole) as apparmor:
            apparmor.enforce("/bin/ping", "/sbin/dhclient")
provision()[source]

Installs AppArmor profiles and utilities.

Example:

from provy.core import Role
from provy.more.debian import AppArmorRole

class MySampleRole(Role):
    def provision(self):
        self.provision_role(AppArmorRole) # no need to call this if using with block.

iptables Module

class provy.more.debian.security.iptables.IPTablesRole(prov, context)[source]

Bases: provy.core.roles.Role

This role provides iptables utilities for Debian distributions.

Note

There are two important behaviors to notice:

  1. Right after iptables is installed, this role allows TCP incoming connections to port 22, so that provy can still continue to provision the server through SSH.
  2. Right before exiting the with using(IPTablesRole) block, it blocks all other ports and protocols, so that the server is secure by default.

So, when using this role, remember to allow all the ports with protocols that you need, otherwise you might not be able to connect to the services you provision later on.

Parameters:block_on_finish (bool) – If False, doesn’t block other ports and protocols when finishing the usage of this role. Defaults to True.

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):

        # this example allows only incoming HTTP connections
        with self.using(IPTablesRole) as iptables:
            iptables.allow('http')

        # this example allows any incoming connections, but block SSH outgoing connections
        with self.using(IPTablesRole) as iptables:
            iptables.block_on_finish = False
            iptables.reject(22, direction="out") # here we used a number, but could be "ssh" as well

        # this example allows established sessions in interface eth0
        with self.using(IPTablesRole) as iptables:
            iptables.allow(interface='eth0', match='state', state='ESTABLISHED,RELATED')
DIRECTION_TO_CHAIN_MAP = {'forward': 'FORWARD', 'out': 'OUTPUT', 'in': 'INPUT'}
allow(port=None, direction='in', protocol='tcp', interface=None, match=None, **options)[source]

Allows connections to be made to or from the server.

Parameters:
  • port (int or str) – Port to be used. Defaults to None, which means all ports will be allowed. Defaults to None.
  • direction (str) – Direction of the connection related to the server. Can be either “in” (connections coming into the server), “out” (connections coming from the server to the outside) or “forward” (packet routing). Defaults to “in”.
  • protocol (str) – Protocol to be used - choose one that is understandable by iptables (like “udp”, “icmp” etc). Defaults to “tcp”.
  • interface (str) – The network interface to which the rule is bound to. Defaults to None (bound to all).
  • match (str) – Match filter. Defaults to None.
  • options (Keyword arguments of str) – Arbitrary of arbitrary options that will be used in conjunction to the match filters.

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        with self.using(IPTablesRole) as iptables:
            iptables.allow(port=11211, direction="out", protocol="udp") # allow UDP connections to an external Memcached server.
drop(port=None, direction='in', protocol='all', interface=None, match=None, **options)[source]

Drop connections to be made to or from the server, without responding anything to the client (drop packets on the ground).

Parameters:
  • port (int or str) – Port to be used. Defaults to None, which means all ports will be allowed.
  • direction (str) – Direction of the connection related to the server. Can be either “in” (connections coming into the server), “out” (connections coming from the server to the outside) or “forward” (packet routing). Defaults to “in”.
  • protocol (str) – Protocol to be used - choose one that is understandable by iptables (like “udp”, “icmp” etc). Defaults to “all”.
  • interface (str) – The network interface to which the rule is bound to. Defaults to None (bound to all).
  • match (str) – Match filter. Defaults to None.
  • options (Keyword arguments of str) – Arbitrary of arbitrary options that will be used in conjunction to the match filters.

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        with self.using(IPTablesRole) as iptables:
            iptables.drop(port=11211, direction="out", protocol="udp") # drop UDP connections to an external Memcached server.
list_rules()[source]

Lists the currently configured rules and returns them as a multiline string. Equivalent to running:

$ sudo iptables -L

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        with self.using(IPTablesRole) as iptables:
            iptables.list_rules()
list_rules_with_commands()[source]

Like list_rules(), but showing the rules as executable commands. Equivalent to running:

$ sudo iptables-save

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        with self.using(IPTablesRole) as iptables:
            iptables.list_rules_with_commands()
provision()[source]

Installs iptables and its dependencies, if they’re not already installed (though this is usually the case).

Also, it adds an ACCEPT rule for SSH (TCP/22), so that provy can continue to provision the server, and the user doesn’t get locked out of it.

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        self.provision_role(IPTablesRole) # no need to call this if using with block.
reject(port=None, direction='in', protocol='all', interface=None, match=None, **options)[source]

Rejects connections to be made to or from the server, responding with a “connection refused” packet.

Parameters:
  • port (int or str) – Port to be used. Defaults to None, which means all ports will be allowed.
  • direction (str) – Direction of the connection related to the server. Can be either “in” (connections coming into the server), “out” (connections coming from the server to the outside) or “forward” (packet routing). Defaults to “in”.
  • protocol (str) – Protocol to be used - choose one that is understandable by iptables (like “udp”, “icmp” etc). Defaults to “all”.
  • interface (str) – The network interface to which the rule is bound to. Defaults to None (bound to all).
  • match (str) – Match filter. Defaults to None.
  • options (Keyword arguments of str) – Arbitrary of arbitrary options that will be used in conjunction to the match filters.

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        with self.using(IPTablesRole) as iptables:
            iptables.reject(port=11211, direction="out", protocol="udp") # reject UDP connections to an external Memcached server.
schedule_cleanup()[source]

Apart from the core cleanup, this one also blocks other ports and protocols not allowed earlier (“catch-all” as the last rule) and saves the iptables rules to the iptables config file, so that it’s not lost upon restart.

Example:

from provy.core import Role
from provy.more.debian import IPTablesRole

class MySampleRole(Role):
    def provision(self):
        with self.using(IPTablesRole) as iptables:
            self.schedule_cleanup() # no need to call this explicitly

selinux Module

class provy.more.debian.security.selinux.SELinuxRole(prov, context)[source]

Bases: provy.core.roles.Role

This role provides SELinux utilities for Debian distributions.

Warning

If you’re provisioning a Ubuntu server, it’s highly recommended you use AppArmorRole instead of this one.

Please note that, for SELinux to be installed from scratch, you have to reboot the server so that it relabels all the files in the system for SELinux. So it’s also highly recommended that you provision a server that has SELinux installed and activated already.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.ensure_login_mapping("foo")
            selinux.map_login("foo", "staff_u")
            selinux.map_role("foo", ["staff_r", "sysadm_r"])
activate()[source]

Activates SELinux, confines generic users and puts the system into enforce mode.

This is executed during provisioning, so you can ignore this method.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.activate() # no need to call this directly.
enforce()[source]

Puts the system into enforce mode.

This is executed during provisioning, so you can ignore this method.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.enforce() # no need to call this directly.
ensure_login_mapping(user_or_group)[source]

Makes sure that a mapping exists for a login user to an SELinux user (if creating one now, sets it to the “user_u” SELinux user).

Parameters:user_or_group (str) – The user or group to be changed. If providing a group, pass it with an “@” before the group name (like “@my-group”).

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.ensure_login_mapping("foo")
            selinux.ensure_login_mapping("@bar")
install_packages()[source]

Installs the necessary packages to provision SELinux.

This is executed during provisioning, so you can ignore this method.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.install_packages() # no need to call this directly.
map_login(user_or_group, selinux_user)[source]

Maps a login user to an SELinux user.

If the login user has no mapping yet, the role creates one.

Parameters:
  • user_or_group (str) – The user or group to be changed. If providing a group, pass it with an “@” before the group name (like “@my-group”).
  • selinux_user (str) – The SELinux user to be referenced.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.map_login("foo", "staff_u")
map_role(user_or_group, selinux_roles)[source]

Maps a login user to one or more SELinux roles.

If the login user has no mapping yet, the role creates one.

Parameters:
  • user_or_group (str) – The user or group to be changed. If providing a group, pass it with an “@” before the group name (like “@my-group”).
  • selinux_roles (iterable) – The roles to be referenced.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        with self.using(SELinuxRole) as selinux:
            selinux.map_role("foo", ["staff_r", "sysadm_r"])
provision()[source]

Installs SELinux, its dependencies, its utilities and the Audit framework.

Also, it activates SELinux after installing the packages, puts the system in enforce mode and puts the generic users into confinement for enhanced security.

Example:

from provy.core import Role
from provy.more.debian import SELinuxRole

class MySampleRole(Role):
    def provision(self):
        self.provision_role(SELinuxRole) # no need to call this if using with block.

ufw Module

class provy.more.debian.security.ufw.UFWRole(prov, context)[source]

Bases: provy.core.roles.Role

This role provides UncomplicatedFireWall utilities for Debian distributions.

Note

There are two important behaviors to notice:

  1. Right after ufw is installed, this role allows TCP and UDP (in and out) connections to port 22, so that provy can still continue to provision the server through SSH.
  2. Right before exiting the “with using(UFWRole)” block, it enables ufw, which blocks all other ports and protocols, so that the server is secure by default.

So, when using this role, remember to allow all the ports with protocols that you need, otherwise you might not be able to connect to the services you provision later on.

Parameters:block_on_finish (bool) – If False, doesn’t block other ports and protocols when finishing the usage of this role. Defaults to True.

Example:

from provy.core import Role
from provy.more.debian import UFWRole

class MySampleRole(Role):
    def provision(self):

        # this example allows only incoming HTTP connections
        with self.using(UFWRole) as ufw:
            ufw.allow('http')

        # this example blocks SSH outgoing connections
        with self.using(UFWRole) as ufw:
            ufw.reject(22, direction="out") # here we used a number, but could be "ssh" as well
allow(port_or_query, protocol=None, direction=None)[source]

Allows connections to be made to or from the server.

Parameters:
  • port_or_query (str) – Port to be used, or a full query specification. If you use a full query, there’s no sense in providing the other arguments.
  • direction (str) – Direction of the connection related to the server. Can be either “in” (connections coming into the server) or “out” (connections coming from the server to the outside). Defaults to None, making ufw use the default of “in”.
  • protocol (str) – Protocol to be used - choose one that is understandable by ufw (like “udp”, “icmp” etc). By default, it changes for “tcp” and “udp”.

Example:

from provy.core import Role
from provy.more.debian import UFWRole

class MySampleRole(Role):
    def provision(self):
        with self.using(UFWRole) as ufw:
            ufw.allow(11211, protocol="udp", direction="out") # allow UDP connections to an external Memcached server.
drop(port_or_query, protocol=None, direction=None)[source]

Drop connections to be made to or from the server, without responding anything to the client (drop packets on the ground).

Parameters:
  • port_or_query (str) – Port to be used, or a full query specification. If you use a full query, there’s no sense in providing the other arguments.
  • direction (str) – Direction of the connection related to the server. Can be either “in” (connections coming into the server) or “out” (connections coming from the server to the outside). Defaults to None, making ufw use the default of “in”.
  • protocol (str) – Protocol to be used - choose one that is understandable by ufw (like “udp”, “icmp” etc). By default, it changes for “tcp” and “udp”.

Example:

from provy.core import Role
from provy.more.debian import UFWRole

class MySampleRole(Role):
    def provision(self):
        with self.using(UFWRole) as ufw:
            ufw.drop(port=11211, direction="out", protocol="udp") # drop UDP connections to an external Memcached server.
provision()[source]

Installs ufw and its dependencies, if they’re not already installed.

Also, it allows ssh (TCP+UDP/22), so that provy can continue to provision the server, and the user doesn’t get locked out of it.

Example:

from provy.core import Role
from provy.more.debian import UFWRole

class MySampleRole(Role):
    def provision(self):
        self.provision_role(UFWRole) # no need to call this if using with block.
reject(port_or_query, protocol=None, direction=None)[source]

Rejects connections to be made to or from the server, responding with a “connection refused” packet.

Parameters:
  • port_or_query (str) – Port to be used, or a full query specification. If you use a full query, there’s no sense in providing the other arguments.
  • direction (str) – Direction of the connection related to the server. Can be either “in” (connections coming into the server) or “out” (connections coming from the server to the outside). Defaults to None, making ufw use the default of “in”.
  • protocol (str) – Protocol to be used - choose one that is understandable by ufw (like “udp”, “icmp” etc). By default, it changes for “tcp” and “udp”.

Example:

from provy.core import Role
from provy.more.debian import UFWRole

class MySampleRole(Role):
    def provision(self):
        with self.using(UFWRole) as ufw:
            ufw.reject(port=11211, direction="out", protocol="udp") # reject UDP connections to an external Memcached server.
schedule_cleanup()[source]

Apart from the core cleanup, this one also enables the firewall.

Example:

from provy.core import Role
from provy.more.debian import UFWRole

class MySampleRole(Role):
    def provision(self):
        with self.using(UFWRole) as ufw:
            self.schedule_cleanup() # no need to call this explicitly