<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jan-Otto Kröpke</title>
    <description>The latest articles on DEV Community by Jan-Otto Kröpke (@jkroepke).</description>
    <link>https://dev.to/jkroepke</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1277151%2F9c11b2b1-11d8-4c42-81e9-ea9181b2fa0c.png</url>
      <title>DEV Community: Jan-Otto Kröpke</title>
      <link>https://dev.to/jkroepke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jkroepke"/>
    <language>en</language>
    <item>
      <title>OpenVPN + SSO via OAUTH2</title>
      <dc:creator>Jan-Otto Kröpke</dc:creator>
      <pubDate>Fri, 09 Feb 2024 21:09:18 +0000</pubDate>
      <link>https://dev.to/jkroepke/openvpn-sso-via-oauth2-576k</link>
      <guid>https://dev.to/jkroepke/openvpn-sso-via-oauth2-576k</guid>
      <description>&lt;p&gt;Update: Check latest up2date docs: &lt;a href="https://github.com/jkroepke/openvpn-auth-oauth2/wiki"&gt;https://github.com/jkroepke/openvpn-auth-oauth2/wiki&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;We all love free Open Source software and OpenVPN is one of the most open source VPN solutions around the world.&lt;/p&gt;

&lt;p&gt;While OpenVPN works great on Small Business, issuing VPN certificates on a large enterprise environment can be an issue. Many companies are buying VPN appliances with Self-Service Portal to on board OpenVPN users.&lt;/p&gt;

&lt;p&gt;In history, a lot of solutions based on OpenVPN plugins or PAM modules together with OpenVPN PAM module. Another solution was OpenVPN LDAP module, but the experience for an MFA was terrible.&lt;/p&gt;

&lt;p&gt;After long reason, I figure out that OpenVPN 2.5 or higher supports deferred authentication. With deferred authentication method. OpenVPN can tell the users’ client to open a browser page. This pattern can be used to initialize SSO flows and fully delegates the authentication to an external programs.&lt;/p&gt;

&lt;p&gt;Using the clients’ browser to initiate the authentication has a lot of benefits. Looking to Azure AD or Keycloak, modern MFA technics a side from OTP can be used for a secure authentication, e.g. FIDO2 (WebAuth) or Microsoft Authenticator (push). Additional restrictions can be applied through an IDP like Keycloak for example restrict the client IP address or allow connections only from MDM devices (Intune; Conditional Access).&lt;/p&gt;




&lt;h1&gt;
  
  
  Setup OpenVPN
&lt;/h1&gt;

&lt;p&gt;[openvpn-auth-oauth2]&lt;a href="https://github.com/jkroepke/openvpn-auth-oauth2()"&gt;https://github.com/jkroepke/openvpn-auth-oauth2()&lt;/a&gt; just adds an additional authentication layer on OpenVPN. You can still use client certificates if you wish or omit them, if you no longer want to depend on them.&lt;/p&gt;

&lt;p&gt;openvpn-auth-oauth2 is a dedicated binary which start a HTTP server and connect to an OpenVPN management interface. You have to enable to management interface on your OpenVPN server first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /etc/openvpn/password.txt is a password file where the password must be on first line
management /run/openvpn/server.sock unix /etc/openvpn/password.txt
management-client-auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Keep in mind, never expose the management interface to the public internet!&lt;/strong&gt; You have to create as password.txt near to your OpenVPN configuration file. Put a strong password into the first line and save the file.&lt;/p&gt;

&lt;p&gt;Next, you have to create a standard OAUTH2 application on the IdP on your choice. As example, we will use Entra ID:&lt;/p&gt;

&lt;h1&gt;
  
  
  Create a App Registration in Entra ID
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Login as admin into your tenant&lt;/li&gt;
&lt;li&gt;Open &lt;a href="https://aad.portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps"&gt;App registrations&lt;/a&gt; in Azure AD portal&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;new registration&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pick a name, chose a “Supported account types”-option. Leave the default value, if you are not sure.&lt;/li&gt;
&lt;li&gt;For redirect uri, choice Web and enter the public endpoint of &lt;code&gt;openvpn-auth-oauth2&lt;/code&gt;, for example &lt;code&gt;https://openvpn-auth-oauth2.example.com/oauth2/callback&lt;/code&gt;. Behind the URL, the &lt;code&gt;openvpn-auth-oauth2&lt;/code&gt; binary should be accessible.&lt;/li&gt;
&lt;li&gt;Click Register.&lt;/li&gt;
&lt;li&gt;Copy the tenant-id and client-id. You need the both as configuration option for &lt;code&gt;openvpn-auth-oauth2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After creation, select &lt;code&gt;Certificates &amp;amp; secrets&lt;/code&gt; on the left side.&lt;/li&gt;
&lt;li&gt;Select the tab &lt;code&gt;Client secrets&lt;/code&gt; and create a new client secret.&lt;/li&gt;
&lt;li&gt;Copy the client-secret. You need it as configuration option for &lt;code&gt;openvpn-auth-oauth2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then, select Token configuration on the left side.&lt;/li&gt;
&lt;li&gt;Add optional claim&lt;/li&gt;
&lt;li&gt;On the right panel, select ID as token type&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;ipaddr&lt;/code&gt; from the list of claims.&lt;/li&gt;
&lt;li&gt;Select Add.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Setup openvpn-auth-oauth2
&lt;/h1&gt;

&lt;p&gt;After setup OpenVPN and you OAUTH2 App/Client, all prerequirements are met for openvpn-auth-oauth2.&lt;/p&gt;

&lt;p&gt;Download the binary from &lt;a href="https://github.com/jkroepke/openvpn-auth-oauth2/releases/latest"&gt;GitHub Releases&lt;/a&gt; and store the binary under &lt;code&gt;/usr/local/bin/openvpn-auth-oauth2&lt;/code&gt;. To run the binary, setup a systemd service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;OpenVPN authenticator&lt;/span&gt;
&lt;span class="py"&gt;Documentation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://github.com/jkroepke/openvpn-auth-oauth2&lt;/span&gt;
&lt;span class="py"&gt;Wants&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target openvpn.service&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target openvpn.service openvpn@.service openvpn-server@.service&lt;/span&gt;
&lt;span class="py"&gt;PartOf&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;openvpn.service openvpn@.service openvpn-server@.service&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;DynamicUser&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;nogroup&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/openvpn-auth-oauth2&lt;/span&gt;
&lt;span class="py"&gt;EnvironmentFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/etc/sysconfig/openvpn-auth-oauth2&lt;/span&gt;
&lt;span class="py"&gt;ProtectSystem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;strict&lt;/span&gt;
&lt;span class="py"&gt;ProtectHome&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;PrivateTmp&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;ConfigurationDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;openvpn-auth-oauth2&lt;/span&gt;
&lt;span class="py"&gt;ReadWritePaths&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;-/run/openvpn -/run/openvpn-server&lt;/span&gt;
&lt;span class="c"&gt;# CapabilityBoundingSet=CAP_NET_BIND_SERVICE
&lt;/span&gt;&lt;span class="py"&gt;NoExecPaths&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;
&lt;span class="py"&gt;ExecPaths&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/openvpn-auth-oauth2&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5s&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configure
&lt;/h1&gt;

&lt;p&gt;If you run the binary as systemd service, you can use the &lt;code&gt;/etc/sysconfig/openvpn-auth-oauth2&lt;/code&gt; file toset up the environment variables. If you are preferring Docker containers, use the known tools to declare environment variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;CONFIG_OAUTH2_ISSUER&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://login.microsoftonline.com/&amp;lt;tenant-id&amp;gt;/v2.0&lt;/span&gt;
&lt;span class="py"&gt;CONFIG_OAUTH2_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="py"&gt;CONFIG_OAUTH2_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="py"&gt;CONFIG_HTTP_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;  &lt;span class="c"&gt;# Define a random value with 16 or 24 chacters
&lt;/span&gt;&lt;span class="s"&gt;CONFIG_HTTP_BASEURL=https://  # Define the public http endpoint here.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After configuration, you can start the service with &lt;code&gt;systemctl enable --now openvpn-auth-ouath2&lt;/code&gt; and you are done.&lt;/p&gt;

</description>
      <category>openvpn</category>
      <category>oidc</category>
      <category>oauth</category>
      <category>keycloak</category>
    </item>
  </channel>
</rss>
