30.4. Configuring an IPsec mesh VPN with certificate-based authentication by using the vpn RHEL system role


An IPsec mesh creates a fully interconnected network where every server can communicate securely and directly with every other server. By using the vpn RHEL system role, you can automate configuring a VPN mesh with certificate-based authentication among managed nodes.

An IPsec mesh is ideal for distributed database clusters or high-availability environments that span multiple data centers or cloud providers. Establishing a direct, encrypted tunnel between each pair of servers ensures secure communication without a central bottleneck.

For authentication, using digital certificates managed by a Certificate Authority (CA) offers a highly secure and scalable solution. Each host in the mesh presents a certificate signed by a trusted CA. This method provides strong, verifiable authentication and simplifies user management. Access can be granted or revoked centrally at the CA, and Libreswan enforces this by checking each certificate against a certificate revocation list (CRL), denying access if a certificate appears on the list.

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 for these nodes.
  • You prepared a PKCS #12 file for each managed node:

    • Each file contains:

      • The private key of the server
      • The server certificate
      • The CA certificate
      • If required, intermediate certificates
    • The files are named <managed_node_name_as_in_the_inventory>.p12.
    • The files are stored in the same directory as the playbook.
    • The server certificate contains the following fields:

      • Extended Key Usage (EKU) is set to TLS Web Server Authentication.
      • Common Name (CN) or Subject Alternative Name (SAN) is set to the fully-qualified domain name (FQDN) of the host.
      • X509v3 CRL distribution points contain URLs to Certificate Revocation Lists (CRLs).

Procedure

  1. Edit the ~/inventory file, and append the cert_name variable:

    managed-node-01.example.com cert_name=managed-node-01.example.com
    managed-node-02.example.com cert_name=managed-node-02.example.com
    managed-node-03.example.com cert_name=managed-node-03.example.com

    Set the cert_name variable to the value of the common name (CN) field used in the certificate for each host. Typically, the CN field is set to the fully-qualified domain name (FQDN).

  2. Store your sensitive variables in an encrypted file:

    1. Create the vault:

      $ ansible-vault create ~/vault.yml
      New Vault password: <vault_password>
      Confirm New Vault password: <vault_password>
    2. After the ansible-vault create command opens an editor, enter the sensitive data in the <key>: <value> format:

      pkcs12_pwd: <password>
    3. Save the changes, and close the editor. Ansible encrypts the data in the vault.
  3. Create a playbook file, for example, ~/playbook.yml, with the following content:

    - name: Configuring VPN
      hosts: managed-node-01.example.com, managed-node-02.example.com, managed-node-03.example.com
      vars_files:
        - ~/vault.yml
      tasks:
        - name: Install LibreSwan
          ansible.builtin.package:
            name: libreswan
            state: present
    
        - name: Identify the path to IPsec NSS database
          ansible.builtin.set_fact:
            nss_db_dir: "{{ '/etc/ipsec.d/' if
              ansible_distribution in ['CentOS', 'RedHat']
              and ansible_distribution_major_version is version('8', '=')
              else '/var/lib/ipsec/nss/' }}"
    
        - name: Locate IPsec NSS database files
          ansible.builtin.find:
            paths: "{{ nss_db_dir }}"
            patterns: "*.db"
          register: db_files
    
        - name: Initialize IPsec NSS database if not initialized
          ansible.builtin.command:
            cmd: ipsec initnss
          when: db_files.matched == 0
    
        - name: Copy PKCS #12 file to the managed node
          ansible.builtin.copy:
            src: "~/{{ inventory_hostname }}.p12"
            dest: "/etc/ipsec.d/{{ inventory_hostname }}.p12"
            mode: 0600
    
        - name: Import PKCS #12 file in IPsec NSS database
          ansible.builtin.shell:
            cmd: 'pk12util -d {{ nss_db_dir }} -i /etc/ipsec.d/{{ inventory_hostname }}.p12 -W "{{ pkcs12_pwd }}"'
    
        - name: Remove PKCS #12 file
          ansible.builtin.file:
            path: "/etc/ipsec.d/{{ inventory_hostname }}.p12"
            state: absent
    
        - name: Opportunistic mesh IPsec VPN with certificate-based authentication
          ansible.builtin.include_role:
            name: redhat.rhel_system_roles.vpn
          vars:
            vpn_connections:
              - opportunistic: true
                auth_method: cert
                policies:
                  - policy: private
                    cidr: default
                  - policy: private
                    cidr: 192.0.2.0/24
                  - policy: clear
                    cidr: 192.0.2.1/32
            vpn_manage_firewall: true
            vpn_manage_selinux: true

    The settings specified in the example playbook include the following:

    opportunistic: true
    Enables an opportunistic mesh among multiple hosts. The policies variable defines for which subnets and hosts traffic must or can be encrypted and which of them should continue using plain text connections.
    auth_method: cert
    Enables certificate-based authentication. This requires that you specify the nickname of each managed node’s certificate in the inventory.
    policies: <list_of_policies>

    Defines the Libreswan policies in YAML list format.

    The default policy is private-or-clear. To change it to private, the above playbook contains an according policy for the default cidr entry.

    To prevent a loss of the SSH connection during the execution of the playbook if the Ansible control node is in the same IP subnet as the managed nodes, add a clear policy for the control node’s IP address. For example, if the mesh should be configured for the 192.0.2.0/24 subnet and the control node uses the IP address 192.0.2.1, you require a clear policy for 192.0.2.1/32 as shown in the playbook.

    For details about policies, see the ipsec.conf(5) man page on a system with Libreswan installed.

    vpn_manage_firewall: true
    Defines that the role opens the required ports in the firewalld service on the managed nodes.
    vpn_manage_selinux: true
    Defines that the role sets the required SELinux port type on the IPsec ports.

    For details about all variables used in the playbook, see the /usr/share/ansible/roles/rhel-system-roles.vpn/README.md file on the control node.

  4. Validate the playbook syntax:

    $ ansible-playbook --ask-vault-pass --syntax-check ~/playbook.yml

    Note that this command only validates the syntax and does not protect against a wrong but valid configuration.

  5. Run the playbook:

    $ ansible-playbook --ask-vault-pass ~/playbook.yml

Verification

  1. On a node in the mesh, ping another node to activate the connection:

    [root@managed-node-01]# ping managed-node-02.example.com
  2. Confirm that the connection is active:

    [root@managed-node-01]# ipsec trafficstatus
    006 #2: "private#192.0.2.0/24"[1] ...192.0.2.2, type=ESP, add_time=1741938929, inBytes=372408, outBytes=545728, maxBytes=2^63B, id='CN=managed-node-02.example.com'
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2026 Red Hat
トップに戻る