core icon indicating copy to clipboard operation
core copied to clipboard

OpenVPN not applying CSO settings in some server modes (with workaround)

Open cluck opened this issue 1 year ago • 9 comments

Important notices

Before you add a new report, we ask you kindly to acknowledge the following:

  • [x] I have read the contributing guide lines at https://github.com/opnsense/core/blob/master/CONTRIBUTING.md
  • [x] I am convinced that my issue is new after having checked both open and closed issues at https://github.com/opnsense/core/issues?q=is%3Aissue

Describe the bug

I'm configuring an OpenVPN Server (legacy settings) in Remote Access ( SSL/TLS + User Auth ) mode. I have clients successfully connecting to the server and receiving traffic. But whatever CSO configuration I create for the clients, it is ignored. I have a need to match certificate common names to fixed IP addresses. If looks as if the generated OpenVPN config file is missing a client-connect stanza.

To Reproduce

An OpenVPN Server is configured with these settings (some defaults omitted):

  • Description: server2
  • Server Mode: Remote Access ( SSL/TLS + User Auth )
  • Backend for authentication: Local Database
  • TLS Authentication: Enabled - Authentication only
  • Peer Certificate Authority: set
  • Peer Revocation List: None
  • Server Certificate: set
  • Strict User/CN Matching: no
  • IPv4 Tunnel Network: set to /27
  • IPv4 Local Network: set to /32
  • Inter-client communication: yes
  • Duplicate connections: no
  • Dynamic IP: yes
  • Topology: yes
  • Use common name: yes
  • Force CSO Login Matching: no

Clients are set up to be identified by the certificate common name (not the login user), and the objective is to assign each CN a pre-determined IP address (each client will be BGP router of its dedicated AS),

For each CN, a CSO entry is configured, e.g.:

  • Server: server2
  • Common name: rou-fw-01
  • IPv4 Tunnel Network: /32

Describe alternatives you considered

From the source code it seems that /usr/local/opnsense/scripts/openvpn/ovpn_event.py is in charge of creating the necessary CSO configuration snippet during connection. But no configuration stanza in /var/etc/openvpn/server2.conf directs openvpn into running this script any earlier than upon client disconnection: i.e. the configuration contains a client-disconnect stanza but no client-connect stanza, as I would have naively expected.

Wondering if adding a client-connect stanza would fix the problem, I added the line client-connect "/usr/local/opnsense/scripts/openvpn/ovpn_event.py '2'" into the "Advanced" custom configuration of my server, and I can confirm that the CSO settings have become effective immediately.

Some of the code I suspect is buggy seems to be in /etc/inc/plugins.inc.d/openvpn.inc:

https://github.com/opnsense/core/blob/70d6dc03b8ef2f6177bf071b9bec5015a593c0cf/src/etc/inc/plugins.inc.d/openvpn.inc#L553-L575

I can see why this code is not generating a client-connect stanza in my case. And I think there are other configurations where ovpn_event.py is expected to be called both at connection and disconnection time, but isn't.

Environment

Software version used and hardware type if relevant, e.g.:

OPNsense 23.7.12-amd64 AMD Ryzen Threadripper 3970X 32-Core Processor

cluck avatar Jan 18 '24 21:01 cluck

Related issues:

  • #6768 (probably very similar issue)
  • #5296 ("solution" was to evade the bug by changing configuration)
  • #2624 (hacked the same code)

Also note that things sometimes "start to work", e.g. after the client disconnects (under certain circumstances an equivalent file is generated under /var/etc/openvpn-csc, in other occasions this file seems to be temporarily generated in /tmp).

cluck avatar Jan 18 '24 22:01 cluck

https://github.com/opnsense/core/blob/70d6dc03b8ef2f6177bf071b9bec5015a593c0cf/src/etc/inc/plugins.inc.d/openvpn.inc#L672

Is probably what you’re looking for, it’s unlikely cso’s don’t work at all, but the logs will tell you what the server did (auth sequence and cso matching). Usually these are other misconfigurations, such as non compatible netblock choices, which for us is out of community support scope. OpenVPN can be picky and doesn’t always communicate very clearly about non supported options in cso’s.

AdSchellevis avatar Jan 19 '24 09:01 AdSchellevis

Thanks to your hint, I looked at ovpn_event.py once more. I have a theory why I observe a "fix" when manually adding a call to client-connect in my config. What we have here, is, likely, a concurrency bug, and I guess it was introduced when support for deferred authentication was added.

The script ovpn_event.py branches off into different code sections according to what script_type it is called for. For our types user-pass-verify and client-connect it will exec either user_pass_verify.php or client_connect.php, and both call openvpn_csc_conf_write() to create the temporary CSO file, so at first sight it feels right to skip the client-connect call when a call to user-pass-verify call is configured too.

But while ovpn_event.py execs into user_pass_verify.php synchronously for the client-connect type, it instead forks into background and immediately returns to OpenVPN signalling deferred authentication, and only then, in background, client_connect.php gets eventually exec'd and the temporary CSO file created, too late for OpenVPN which already missed the file and continued without it.

cluck avatar Jan 21 '24 12:01 cluck

I don’t expect that, haven’t seen it either. If I’m not mistaken the (official) radius auth uses the same spot. When using authentication, you can’t know the full picture unit authenticated (networks maybe provisioned).

AdSchellevis avatar Jan 21 '24 12:01 AdSchellevis

I don't have the testbench anymore, just the logs. There is a recurring pattern:

<37>1 2024-01-19T05:21:13+01:00 [..] TEST FILE '/var/etc/openvpn-csc/2/vpnclient.example.com' [0]
<37>1 2024-01-19T05:21:13+01:00 [..] TEST FILE '/var/etc/openvpn-csc/2/DEFAULT' [0]
<37>1 2024-01-19T05:21:13+01:00 [..] TEST FILE '/tmp/openvpn_cc_5cf7c3237dbe531a12cf56d86a994dee.tmp' [0]
<37>1 2024-01-19T05:21:13+01:00 [..] MULTI: problem deleting temporary file: /tmp/openvpn_cc_5680d8d0d87657e4403ecaae6b70959.tmp

OpenVPN is reporting that none of the CSC files exist when it is looking for them.

Another similar section:

<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="7"] 192.0.2.1:64289 VERIFY SCRIPT OK: depth=1, C=**, ST=****, L=****, O=****, [email protected], CN=****
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="8"] 192.0.2.1:64289 VERIFY OK: depth=1, C=**, ST=****, L=****, O=****, [email protected], CN=****
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="9"] 192.0.2.1:64289 VERIFY SCRIPT OK: depth=0, C=**, ST=****, L=****, O=****, [email protected], CN=****
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="10"] 192.0.2.1:64289 VERIFY OK: depth=0, C=**, ST=****, L=****, O=****, [email protected], CN=****
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="11"] 192.0.2.1:64289 peer info: IV_VER=2.6.8
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="12"] 192.0.2.1:64289 peer info: IV_PLAT=freebsd
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="13"] 192.0.2.1:64289 peer info: IV_TCPNL=1
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="14"] 192.0.2.1:64289 peer info: IV_MTU=1600
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="15"] 192.0.2.1:64289 peer info: IV_NCP=2
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="16"] 192.0.2.1:64289 peer info: IV_CIPHERS=AES-256-GCM:AES-128-GCM:**A**A20-POLY1305
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="17"] 192.0.2.1:64289 peer info: IV_PROTO=990
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="18"] 192.0.2.1:64289 peer info: IV_LZO_STUB=1
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="19"] 192.0.2.1:64289 peer info: IV_COMP_STUB=1
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="20"] 192.0.2.1:64289 peer info: IV_COMP_STUBv2=1
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="21"] 192.0.2.1:64289 TLS: Username/Password authentication deferred for username 'vpnuser'
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="22"] 192.0.2.1:64289 TLS: move_session: dest=TM_ACTIVE src=TM_INITIAL reinit_src=1
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="23"] 192.0.2.1:64289 TLS: tls_multi_process: initial untrusted session promoted to semi-trusted
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="24"] 192.0.2.1:64289 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384, peer certificate: 2048 bits RSA, signature: RSA-SHA256, peer temporary key: 253 bits X25519
<29>1 2024-01-19T04:04:59+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="25"] 192.0.2.1:64289 [****] Peer Connection Initiated with [AF_INET6]::ffff:****:64289 (via ::ffff:****%vtnet0)
<37>1 2024-01-19T04:05:00+01:00 vpn.example.com openvpn 54933 - [meta sequenceId="26"] Locate overwrite for 'vpnuser' using server '1' (vpnid: 1)
<37>1 2024-01-19T04:05:00+01:00 vpn.example.com openvpn 54933 - [meta sequenceId="27"] user 'vpnuser' authenticated using 'Local Database'
<29>1 2024-01-19T04:05:00+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="28"] ****/192.0.2.1:64289 MULTI_sva: pool returned IPv4=****, IPv6=(Not enabled)
<27>1 2024-01-19T04:05:01+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="29"] ****/192.0.2.1:64289 MULTI: problem deleting temporary file: /tmp/openvpn_cc_7f6b4b6a4048e39645da90e5a006de40.tmp
<29>1 2024-01-19T04:05:01+01:00 vpn.example.com openvpn_server1 79556 - [meta sequenceId="30"] ****/192.0.2.1:64289 MULTI: Learn: 10.10.252.6 -> ****/192.0.2.1:64289


I also observed that the directory /var/etc/openvpn-csc/2 usually remained empty (if files ever landed there, they were short-lived and I didn't see them). In one instance, though, I disabled user authentication on the server (going to just peer-to-peer) and then edited the CSO of client with CN vpnclient.example.com, which resulted in /var/etc/openvpn-csc/2/vpnclient.example.com being generated. This file survived when I switched user authentication back on again. I basically had one client that worked with the given static IP, while all others continued to pick random IPs from the pool.

cluck avatar Jan 21 '24 14:01 cluck

When properly matched, the log should contain:

https://github.com/opnsense/core/blob/98878a9eb90c1150b232bfbc7e9a012a3e3462a0/src/opnsense/scripts/openvpn/user_pass_verify.php#L137

AdSchellevis avatar Jan 21 '24 15:01 AdSchellevis

Exactly. I get such lines when I change the server mode. That's the bug (see title).

cluck avatar Jan 21 '24 16:01 cluck

My point as well, these lines do not depend on synchronicity, which point to some configuration issue… (mismatch between common name and username being the most common)

AdSchellevis avatar Jan 21 '24 17:01 AdSchellevis

I would like to politely oppose the notion of this being a configuration issue. The elephant in the room is that there is a call for client-disconnect but no call for client-connect in the generated configuration file: something sure isn't working as planned. I would also like to remind that adding the apparently missing client-connect call fulfills the intended outcome of the configuration.

But, anyway, I feel I need to let you know that my usecase has vanished, as I learned that a mesh of OpenVPN servers won't support dynamic routing anyway (I'm back to IPsec+NAT-T+GRE).

cluck avatar Apr 27 '24 12:04 cluck

This issue has been automatically timed-out (after 180 days of inactivity).

For more information about the policies for this repository, please read https://github.com/opnsense/core/blob/master/CONTRIBUTING.md for further details.

If someone wants to step up and work on this issue, just let us know, so we can reopen the issue and assign an owner to it.

OPNsense-bot avatar Jul 16 '24 20:07 OPNsense-bot