Chapter 31. Configuring VPN connections with IPsec by using RHEL system roles With the vpn system role, you can configure VPN connections on RHEL systems by using Red Hat Ansible Automation Platform. You can use it to set up host-to-host, network-to-network, VPN Remote Access Server, and mesh configurations. For host-to-host connections, the role sets up a VPN tunnel between each pair of hosts in the list of vpn_connections using the default parameters, including generating keys as needed. Alternatively, you can configure it to create an opportunistic mesh configuration between all hosts listed. The role assumes that the names of the hosts under hosts are the same as the names of the hosts used in the Ansible inventory, and that you can use those names to configure the tunnels. Note The vpn RHEL system role currently supports only Libreswan, which is an IPsec implementation, as the VPN provider. 31.1. Creating a host-to-host VPN with IPsec by using the vpn RHEL system role You can use the vpn system role to configure host-to-host connections by running an Ansible playbook on the control node, which configures all managed nodes listed in an inventory file. Prerequisites You have prepared the control node and the managed nodes . You are logged in to the control node as a user who can run playbooks on the managed nodes. The account you use to connect to the managed nodes has sudo permissions on them. Procedure Create a playbook file, for example ~/playbook.yml , with the following content: - name: Host to host VPN hosts: managed-node-01.example.com, managed-node-02.example.com roles: - rhel-system-roles.vpn vars: vpn_connections: - hosts: managed-node-01.example.com: managed-node-02.example.com: vpn_manage_firewall: true vpn_manage_selinux: true This playbook configures the connection managed-node-01.example.com-to-managed-node-02.example.com by using pre-shared key authentication with keys auto-generated by the system role. Because vpn_manage_firewall and vpn_manage_selinux are both set to true , the vpn role uses the firewall and selinux roles to manage the ports used by the vpn role. To configure connections from managed hosts to external hosts that are not listed in the inventory file, add the following section to the vpn_connections list of hosts: vpn_connections: - hosts: managed-node-01.example.com: <external_node> : hostname: <IP_address_or_hostname> This configures one additional connection: managed-node-01.example.com-to- <external_node> Note The connections are configured only on the managed nodes and not on the external node. Optional: You can specify multiple VPN connections for the managed nodes by using additional sections within vpn_connections , for example, a control plane and a data plane: - name: Multiple VPN hosts: managed-node-01.example.com, managed-node-02.example.com roles: - rhel-system-roles.vpn vars: vpn_connections: - name: control_plane_vpn hosts: managed-node-01.example.com: hostname: 192.0.2.0 # IP for the control plane managed-node-02.example.com: hostname: 192.0.2.1 - name: data_plane_vpn hosts: managed-node-01.example.com: hostname: 10.0.0.1 # IP for the data plane managed-node-02.example.com: hostname: 10.0.0.2 Validate the playbook syntax: Note that this command only validates the syntax and does not protect against a wrong but valid configuration. Run the playbook: Verification On the managed nodes, confirm that the connection is successfully loaded: Replace <connection_name> with the name of the connection from this node, for example managed_node1-to-managed_node2 . Note By default, the role generates a descriptive name for each connection it creates from the perspective of each system. For example, when creating a connection between managed_node1 and managed_node2 , the descriptive name of this connection on managed_node1 is managed_node1-to-managed_node2 but on managed_node2 the connection is named managed_node2-to-managed_node1 . On the managed nodes, confirm that the connection is successfully started: Optional: If a connection does not successfully load, manually add the connection by entering the following command. This provides more specific information indicating why the connection failed to establish: Note Any errors that may occur during the process of loading and starting the connection are reported in the /var/log/pluto.log file. Because these logs are hard to parse, manually add the connection to obtain log messages from the standard output instead. Additional resources /usr/share/ansible/roles/rhel-system-roles.vpn/README.md file /usr/share/doc/rhel-system-roles/vpn/ directory 31.2. Creating an opportunistic mesh VPN connection with IPsec by using the vpn RHEL system role You can use the vpn system role to configure an opportunistic mesh VPN connection that uses certificates for authentication by running an Ansible playbook on the control node, which will configure all the managed nodes listed in an inventory file. Prerequisites You have prepared the control node and the managed nodes . You are logged in to the control node as a user who can run playbooks on the managed nodes. The account you use to connect to the managed nodes has sudo permissions on them. The IPsec Network Security Services (NSS) crypto library in the /etc/ipsec.d/ directory contains the necessary certificates. Procedure Create a playbook file, for example ~/playbook.yml , with the following content: - name: Mesh VPN hosts: managed-node-01.example.com, managed-node-02.example.com, managed-node-03.example.com roles: - rhel-system-roles.vpn vars: vpn_connections: - opportunistic: true auth_method: cert policies: - policy: private cidr: default - policy: private-or-clear cidr: 198.51.100.0/24 - policy: private cidr: 192.0.2.0/24 - policy: clear cidr: 192.0.2.7/32 vpn_manage_firewall: true vpn_manage_selinux: true Authentication with certificates is configured by defining the auth_method: cert parameter in the playbook. By default, the node name is used as the certificate nickname. In this example, this is managed-node-01.example.com . You can define different certificate names by using the cert_name attribute in your inventory. In this example procedure, the control node, which is the system from which you will run the Ansible playbook, shares the same classless inter-domain routing (CIDR) number as both of the managed nodes (192.0.2.0/24) and has the IP address 192.0.2.7. Therefore, the control node falls under the private policy which is automatically created for CIDR 192.0.2.0/24. To prevent SSH connection loss during the play, a clear policy for the control node is included in the list of policies. Note that there is also an item in the policies list where the CIDR is equal to default. This is because this playbook overrides the rule from the default policy to make it private instead of private-or-clear. Because vpn_manage_firewall and vpn_manage_selinux are both set to true , the vpn role uses the firewall and selinux roles to manage the ports used by the vpn role. Validate the playbook syntax: Note that this command only validates the syntax and does not protect against a wrong but valid configuration. Run the playbook: Additional resources /usr/share/ansible/roles/rhel-system-roles.vpn/README.md file /usr/share/doc/rhel-system-roles/vpn/ directory

Commands:
- name: Host to host VPN hosts: managed-node-01.example.com, managed-node-02.example.com roles: - rhel-system-roles.vpn vars: vpn_connections: - hosts: managed-node-01.example.com: managed-node-02.example.com: vpn_manage_firewall: true vpn_manage_selinux: true
vpn_connections: - hosts: managed-node-01.example.com: <external_node> : hostname: <IP_address_or_hostname>
- name: Multiple VPN hosts: managed-node-01.example.com, managed-node-02.example.com roles: - rhel-system-roles.vpn vars: vpn_connections: - name: control_plane_vpn hosts: managed-node-01.example.com: hostname: 192.0.2.0 # IP for the control plane managed-node-02.example.com: hostname: 192.0.2.1 - name: data_plane_vpn hosts: managed-node-01.example.com: hostname: 10.0.0.1 # IP for the data plane managed-node-02.example.com: hostname: 10.0.0.2
ansible-playbook --syntax-check ~/playbook.yml
ansible-playbook ~/playbook.yml
ipsec status | grep <connection_name>
ipsec trafficstatus | grep <connection_name>
ipsec auto --add <connection_name>
- name: Mesh VPN hosts: managed-node-01.example.com, managed-node-02.example.com, managed-node-03.example.com roles: - rhel-system-roles.vpn vars: vpn_connections: - opportunistic: true auth_method: cert policies: - policy: private cidr: default - policy: private-or-clear cidr: 198.51.100.0/24 - policy: private cidr: 192.0.2.0/24 - policy: clear cidr: 192.0.2.7/32 vpn_manage_firewall: true vpn_manage_selinux: true
ansible-playbook --syntax-check ~/playbook.yml
ansible-playbook ~/playbook.yml