OpenVPN is widely used as a VPN solution across different cloud and in house datacenter solutions. While OpenVPN has an Open Source edition, with the basic default setup used in many cases, the administrator provisions the certificate in a .ovpn
configuration file for each user in the organization. User can then connect to the VPN by importing the .ovpn
configuration file in an OpenVPN client application.
While this is a quick way to get started with an OpenVPN setup, scaling this setup as more and more users connect to the VPN can become tedious. Additionally, revoking and rotating the certificate would need to be redone separately for each user.
Depending on the use case, an alternate method to consider is using a common certificate for all users and then leverage an OIDC compatible Identity Provider, like Keycloak, for authenticating individual users. This can be setup using pam-keycloak-oidc
along with the PAM authentication support built-in to OpenVPN.
Keycloak
Keycloak is an open-source Identity and Access Management tool. For using OpenVPN with Keycloak, certain preliminary configurations need to be setup on Keycloak as mentioned in the pam-keycloak-oidc
documentation:
-
Create a Role, like
openvpn
-
Create a Client Scope, like
pam_roles
:- Protocol:
openid-connect
- Display On Consent Screen:
OFF
- Include in Token Scope:
ON
- Mapper:
- Name: e.g.
pam_roles
- Mapper Type:
User Realm Role
- Multivalued:
ON
- Token Claim Name:
pam_roles
(the name of the Client Scope) - Claim JSON Type:
String
- Add to ID token:
OFF
- Add to access token:
ON
- Add to userinfo:
OFF
- Name: e.g.
- Scope:
- Effective Roles:
openvpn
(the name of the Role)
- Effective Roles:
- Protocol:
-
Create a Client, like
openvpn
:- Client ID:
openvpn
(or whatever valid client name) - Enabled:
ON
- Consent Required:
OFF
- Client Protocol:
openid-connect
- Access Type:
confidential
- Standard Flow Enabled:
ON
- Implicit Flow Enabled:
OFF
- Direct Access Grants Enabled:
ON
- Service Accounts Enabled:
OFF
- Authorization Enabled:
OFF
- Valid Redirect URIs:
urn:ietf:wg:oauth:2.0:oob
- Fine Grain OpenID Connect Configuration:
- Access Token Signature Algorithm: e.g.
RS256
(we need to put this in the config file later)
- Access Token Signature Algorithm: e.g.
- Client Scopes:
- Assigned Default Client Scopes:
pam_roles
- Assigned Default Client Scopes:
- Scope:
- Full Scope Allowed:
OFF
- Effective Roles:
openvpn
- Full Scope Allowed:
- Client ID:
-
Assign the role
openvpn
to the relevant Group or User as required.
pam-keycloak-oidc
pam-keycloak-oidc
will be used with OpenVPN's built-in PAM authentication in order to connect to Keycloak for authentication. To configure pam-keycloak-oidc
on the OpenVPN server:
-
Download the pre-compiled binary from the GitHub releases. If the pre-compiled binary is not available for the required architecture, compile the golang application as needed.
-
Create a configuration file with the
.tml
extension such aspam-keycloak-oidc.tml
:
# name of the dedicated OIDC client at Keycloak
client-id="openvpn"
# the secret of the dedicated client
client-secret="<client-secret>"
# special callback address for no callback scenario
redirect-url="urn:ietf:wg:oauth:2.0:oob"
# OAuth2 scope to be requested, which contains the role information of a user
scope="openvpn"
# name of the role to be matched, only Keycloak users who is assigned with this role could be accepted
vpn-user-role="openvpn"
# retrieve from the meta-data at https://<keycloak-domain>/auth/realms/<openvpn-realm>/.well-known/openid-configuration
endpoint-auth-url="https://<keycloak-domain>/auth/realms/<openvpn-realm>/protocol/openid-connect/auth"
endpoint-token-url="https://<keycloak-domain>/auth/realms/<openvpn-realm>/protocol/openid-connect/token"
# 1:1 copy, to `fmt` substituion is required
username-format="%s"
# to be the same as the particular Keycloak client
access-token-signing-method="RS256"
# a key for XOR masking. treat it as a top secret
xor-key="scmi"
Fill in the required configuration for <client-secret>
, <keycloak-domain>
and <openvpn-realm>
.
- Test the PAM authentication with
pam-keycloak-oidc
and the configuration that was setup in the previous step:
If the above outputs an Authentication succeeded message, then the pam-keycloak-oidc
setup is complete!
OpenVPN
In order to use the pam-keycloak-oidc
module with the PAM authentication in OpenVPN, the configuration is needed both in the OpenVPN Server and in the .ovpn
configuration file used by the client. On the OpenVPN Server side:
- Add the following lines as required to the
openvpn.conf
:
# Enable PAM for user authentication
plugin /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so "openvpn login USERNAME password PASSWORD"
auth-gen-token 43200 # To set an expiry for the token (in seconds)
setenv deferred_auth_pam 1 # To perform the PAM based authentication in the background when the connection is initiated
duplicate-cn # To allow multiple connections from a single certificate
- Configure the
openvpn
PAM authentication method by adding the following to/etc/pam.d/openvpn
:
account required pam_permit.so
auth [success=1 default=ignore] pam_exec.so expose_authtok log=/var/log/pam-keycloak-oidc.log /opt/pam-keycloak-oidc/pam-keycloak-oidc
auth requisite pam_deny.so
auth required pam_permit.so
Configure the path for /var/log/pam-keycloak-oidc.log
and /opt/pam-keycloak-oidc/pam-keycloak-oidc
as per the locations of these files on the system.
- Configure the PAM session handler by adding the following to
/etc/pam.d/common-sesion
:
session required pam_mkhomedir.so skel=/etc/skel umask=0002
Next, in the OpenVPN Client configuration .ovpn
file, add the auth-user-pass
configuration. This option configures the OpenVPN client to prompt the user for a username and password in order to authenticate and connect to the VPN.
With this setup complete, OpenVPN is now integrated with Keycloak for authentication!
Next Steps
Using pam-keycloak-oidc
, it is possible to enforce the requirement of MFA with TOTPs for connecting to OpenVPN. Depending on the OpenVPN client used and the Authentication policy on the Keycloak server, the setup can be configured as described in the pam-keycloak-oidc
documentation.