DEBOPS.STUNNEL(5)

NAME
debops.stunnel - manage STunnel proxy using Ansible

SYNOPSIS

debops run service/stunnel [--limit group,host,...] [--diff] [--check] [--tags tag1,tag2,...] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

stunnel <https://stunnel.org/> can be used to create encrypted TCP tunnels between two service ports, either on the same host or on separate hosts.

Encryption is done using SSL certificates. This Ansible role can be used to create tunnels between two or more hosts, using Ansible inventory groups.

GETTING STARTED

debops.stunnel does not create any tunnels by default, they need to be defined by the user. A natural place for them is usually a host group in Ansible inventory.

  Example inventory

As an example, let's create an encrypted tunnel between two hosts, one of which acts as a MySQL server, and other is a client which connects through the tunnel to the server.

This is an example Ansible hosts file, located in inventory/hosts. It defines two host groups:

[mysql_encrypted_tunnel]
dbserver
dbclient
[debops_mysql]
dbserver
[debops_stunnel:children]
mysql_encrypted_tunnel

in inventory/group_vars/mysql_encrypted_tunnel/stunnel.yml you should define your MySQL tunnel connection:

---
stunnel_services:
  - name: 'mysql-ssl-tunnel'
    server_accept:  '3307'
    server_connect: '3306'
    client_accept:  '3306'
    client_connect: 'dbserver:3307'

debops.stunnel will try and select the correct host as a server/client automatically, using a number of factors. By default all hosts are treated as clients; if automatic detection of a server fails, you will be able to override it.

This configuration sets up only stunnel4 service, configuration of the firewall and TCP wrappers can be performed using additional configuration parameters. See Guides and examples for more details.

  Example playbook

This is an example playbook which can be used to configure stunnel on all hosts that use it - they should be present in [debops_stunnel] group, either directly or indirectly via a child group:

---
- name: Manage stunnel connections
  hosts: debops_stunnel
  roles:
    - role: debops.stunnel
      tags: stunnel

GUIDES AND EXAMPLES

  Example MySQL tunnel

This is an extended example of the MySQL tunnel defined in the Getting Started section. In addition to the stunnel4 configuration, debops.stunnel will also configure firewall and TCP wrappers to allow connections from a specified network

inventory/hosts:

[mysql_encrypted_tunnel]
dbserver
dbclient
[debops_mysql]
dbserver
[debops_stunnel:children]
mysql_encrypted_tunnel

inventory/group_vars/mysql_encrypted_tunnel/stunnel.yml:

---
inventory_mysql_tunnel_network: [ '2002:db8::/48', '192.0.2.0/24' ]
inventory_mysql_hosts: [ 'dbserver' ]
stunnel_services:
  - name: 'mysql-ssl-tunnel'
    # Register this client port in /etc/services
    port: '3307'
    # stunnel configuration
    server_accept:  ':::mysql-ssl-tunnel'
    server_connect: 'mysql'
    client_accept:  'mysql'
    client_connect: '{{ inventory_mysql_hosts }}'
    # Firewall configuration
    type: 'dport_accept'
    dport: [ 'mysql-ssl-tunnel' ]
    saddr: '{{ inventory_mysql_tunnel_network }}'
    # TCP wrappers configuration
    daemon: 'mysql-ssl-tunnel'
    client: '{{ inventory_mysql_tunnel_network }}'
    # Configure firewall and TCP wrappers only on
    # the server side of the tunnel
    enabled: '{{ inventory_mysql_hosts | intersect(stunnel_server_addresses) }}'

  Multiple tunnels at once

You can have multiple stunnel tunnels at the same time, by configuring them in separate dict variables and adding them in the main list:

stunnel_tunnel1:
  name: 'tunnel1'
stunnel_tunnel2:
  name: 'tunnel2'
stunnel_services:
  - '{{ stunnel_tunnel1 }}'
  - '{{ stunnel_tunnel2 }}'

  Configure tunnels separately on each host

If you don't want to, or can't use group_vars/ to configure tunnels on multiple hosts at once, you can still do this one host at a time:

# on host1:
stunnel_services:
  - name: 'tunnel'
    client_accept: '3306'
    client_connect: 'host2:3307'
# on host2:
stunnel_services:
  - name: 'tunnel'
    server_accept: ':::3307'
    server_connect: '3306'
    # Firewall
    type: 'dport_accept'
    dport: [ '3307' ]
    # TCP wrappers
    daemon: 'tunnel'
    # Accept connections from anywhere
    accept_any: True

TROUBLESHOOTING

You can increase the log verbosity by making stunnel_debug variable higher, for example '6' or '7'.

DEFAULT VARIABLES: CONFIGURATION

some of debops.stunnel default variables have more extensive configuration than simple strings or lists, here you can find documentation and examples for them.

  stunnel_services

This is a list of stunnel tunnel connections, each one defined as a YAML dict. Each "service" can define either one end of a connection, or both ends at once, when used in an Ansible group. Additional parameters can also be specified for other roles, such as firewall configuration, TCP wrappers configuration and registering a service in /etc/services database.

  stunnel parameters

These parameters are related to stunnel itself.

name
    String, required. Defines a name of the tunnel, which is used as the name of the configuration file and service name in /etc/services as well as daemon name in TCP wrappers.

    You should use only letters, numbers and a dash (-) character. You should pick an unique name for each service, preferably unique across your entire infrastructure. Check getent services database to avoid collisions with existing names.

client_accept
    String, optional. This parameter defines on what interface(s) and port this service will listen to for server connections. You should specify either a service port name or port number, which optional IP address on which to listen to.

    By default, stunnel binds to IPv4 connections only, to listen to IPv6 connections as well, specify the port as :::<port>.

    You need to define either client_accept or client_port in a service definition for stunnel to be configured correctly.

client_connect
    String or dict or list, optional. This key defines where a stunnel client will connect to. It can have 3 forms:

•   string: '<hostname>:<port>' or '<ip address>:<port>' or '<port>'

•   dict: { '<hostname>': '<port>', '<ip address>': '<port>' }

•   list: [ '<hostname>', '<ip address>' ]

    You can can use the string format if you have only one host you want to connect, or you want to connect to a local port.

    Dict format can be used to connect to multiple hosts with different ports.

    List format is useful when you need to connect to multiple hosts on the same port. The port is taken automatically either from server_accept key or server_port key, if present.

client_port
    String, optional. This key defines the port name or port number of the stunnel client. It can be used by the server_connect key (as a list) in case that client_accept is not specified, to specify the port number to which the stunnel server should connect.

    You need to define either client_port or client_accept in a service definition for stunnel to be configured correctly.

client_options
    Text block, optional. Add other options on the client side of the stunnel configuration, in the form of a YAML text block.

server_accept
    String, optional. This parameter defines on what interface(s) and port this service will listen to for client connections. You should specify either a service port name or port number, which optional IP address on which to listen to.

    By default, stunnel binds to IPv4 connections only, to listen to IPv6 connections as well, specify the port as :::<port>.

    You need to define either server_accept or server_port in a service definition for stunnel to be configured correctly.

server_connect
    String or dict or list, optional. This key defines where a stunnel server will connect to. It can have 3 forms:

•   string: '<hostname>:<port>' or '<ip address>:<port>' or '<port>'

•   dict: { '<hostname>': '<port>', '<ip address>': '<port>' }

•   list: [ '<hostname>', '<ip address>' ]

    You can can use the string format if you have only one host you want to connect, or you want to connect to a local port.

    Dict format can be used to connect to multiple hosts with different ports.

    List format is useful when you need to connect to multiple hosts on the same port. The port is taken automatically either from client_accept key or client_port key, if present.

server_port
    String, optional. This key defines the port name or port number of the stunnel server. It can be used by the client_connect key (as a list) in case that server_accept is not specified, to specify the port number to which the stunnel client should connect.

    You need to define either server_port or server_accept in a service definition for stunnel to be configured correctly.

server_options
    Text block, optional. Add other options on the server side of the stunnel configuration, in the form of a YAML text block.

ssl_opts
    List, optional. SSL options for stunnel configuration. Will override the defaults.

  /etc/services parameters

If you want to, you can assign a user-friendly name to a client port number (server port number is probably already present, for example 3306 = mysql). To do that, you can use debops.etc_services Ansible role, which manages /etc/services database.

In the future the services database might be converted from the local files to a central LDAP database. Because of that it's suggested that you use unique port numbers and service names across your entire infrastructure.

port
    String, optional. This parameter is the port number which you want to reserve for the particular tunnel connection. Service name will be taken from the name parameter. Both TCP as well as UDP service name will be reserved.

    When you specify this parameter, the /etc/services support is activated using role dependencies. After that, you can use the service name in place of all client ports, in server_accept, server_port and client_connect parameters, as well as the firewall configuration (dport parameter).

comment
    String, optional. A comment with short description will be added in the /etc/services database, as well as in the TCP wrappers /etc/hosts.allow file.

  ferm (iptables/ip6tables) parameters

By default, debops.stunnel role does not configure the firewall to enable access to the server port from the outside. To do that, you can add the parameters below to the tunnel definition. debops.ferm role will be used to configure the iptables/ip6tables firewall using ferm.

Firewall configuration will be performed on all hosts by default. To only configure firewall on the server hosts (stunnel clients do not require it), look below for the enabled parameter.

type
    String, optional. Enables the firewall configuration support and specifies the rule type to use. See the debops.ferm role for available rule types. Usually, dport_accept is the correct choice.

    The type of the firewall rule to use will affect the keys used, so choose the rule carefully to avoid unintended effects.

dport
    List, optional. Specify port numbers or service names to configure in the firewall. You can use the service name if /etc/services support has been enabled (see above).

saddr
    List, optional. Specify list of hostnames, IP addresses or CIDR networks which are allowed to connect to specified ports. If it's not specified, no connections are allowed, unless accept_any parameter is enabled (see below).

    This list is similar to client list, but they are not fully compatible.

  TCP wrappers parameters

stunnel uses TCP wrappers on Debian to secure connections from remote hosts. By default, debops.stunnel role does not configure TCP wrapper entries in /etc/hosts.allow, but you can do that by adding the parameters below. debops.tcpwrappers role will be used to configure /etc/hosts.allow entries.

TCP wrappers configuration will be performed on all hosts by default. To only configure host access on the server hosts (stunnel clients do not require it), look below for the enabled parameter.

daemon
    String, optional. Enables configuration of TCP wrappers. Name of the "daemon" that TCP wrappers will allow/deny connections to. Should be the same as name parameter.

client
    List, optional. Specify list of IP addresses, CIDR networks or domain names of hosts which are allowed to connect to the stunnel server. If no hosts are specified, TCP wrappers will deny remote connections from anywhere unless accept_any parameter is enabled (see below).

    This list is similar to saddr list, but they are not fully compatible.

  Shared firewall & TCP wrappers parameters

Some of the parameters are shared between firewall (debops.ferm) and TCP wrappers (debops.tcpwrappers) roles.

accept_any
    Boolean, optional. Enable or disable access to the stunnel server from any host or network. Useful if you have a separate firewall in front of your servers or want to allow connections from anywhere to a particular service.

enabled
    List, optional. By default TCP wrappers and firewall are configured on all hosts - clients and servers alike, it's how Ansible works.

    To only configure firewall and TCP wrappers on the server side of stunnel connections, you can use the enabled parameter as a list. Specify a list of stunnel servers, either hostnames or FQDN names, and intersect it with stunnel_server_addresses list. For example:

    tunnel_servers: [ 'hostname' ]
    stunnel_services:
      - name: 'tunnel'
        enabled: '{{ tunnel_servers | intersect(stunnel_server_addresses) }}'

    Relevant roles will still generate the necessary configuration files, but on the client hosts, the resulting list will be empty, disabling the firewall and TCP wrappers configuration. On server hosts, it will be not empty, and configuration will be enabled.

  Other parameters

filename
    String, optional. Will influence the filename of generated configuration files in all roles, which by default is based on the name parameter.

weight
    String, optional. This is a 2-digit number added at the beginning of the filename in some roles, which helps in ordering of the configuration files.

other parameters
    You can add other parameters from default variables by dropping the stunnel_ prefix from the variable name. For example:

    stunnel_services:
      - name: 'tunnel'
        pki_realm: 'domain'

AUTHOR
Maciej Delmanowski

COPYRIGHT
2014-2024, Maciej Delmanowski, Nick Janetakis, Robin Schneider and others