As an administrator I would like to selectively enforce 2FA authentication.
If implemented a user would log into a VPN client with their password + OTP token. Once authenticated and a VPN connection is established, the user would then be able to log into internal applications using only their password.
We plan to enforce 2FA for logging into the VPN client – Implementation of that scenario is pretty straight forward by generating tokens and selecting the 2FA authentication type by user. However we do not want to enforce 2FA when logging into the internal applications.
We use LDAP groups to control who has access to which application – i.e. membership in the vpn LDAP group allows that user to log into the VPN client. This is where I was asking if its possible to design & add a HBAC rule that would only enforce 2FA for that specific group.
Membership in other LDAP groups grants access to other applications. For these apps we do not want to require 2FA. Since the HBAC rule that I suggested above is not associated with those groups, 2FA would not be enforced.
Please consider my suggestion to selectively enforce 2FA, either at the LDAP group level or any other approach that would make sense.
In the meantime a workaround I found online describes creating two FreeIPA accounts for each user. One account would require 2FA and would only be used for logging into the VPN client. The other account would not require 2FA and would be used to log into all other internal applications. While this approach does work, it is cumbersome and not scalable.
Select 2FA authentication type by user and issue a token
User must use password + token when logging into any application managed by LDAP authentication.
Only specific applications managed by LDAP authentication would require password + token.
FreeIPA, version: 4.6.6
NA
This is already implemented in IPA 4.6 and newer.
1) Enable password authentication and otp either globally with ipa config-mod or on a per-user basis with ipa user-mod username --user-auth-type=password --user-auth-type=otp 2) For Kerberos-based authentication set the auth indicator of the service, e.g. ipa service-mod VPN/gateway.vpn.example--auth-ind=otp 3) For LDAP-based authentication the client has to send a simple bind request with a critical server control 2.16.840.1.113730.3.8.10.7 to indicate that an OTP is required. The server control instructs the LDAP server to check for OTP and refuse binds without a valid OTP.
ipa config-mod
ipa user-mod username --user-auth-type=password --user-auth-type=otp
ipa service-mod VPN/gateway.vpn.example--auth-ind=otp
2.16.840.1.113730.3.8.10.7
import ldap from ldap.controls import RequestControl REQUIRE_OTP_OID = "2.16.840.1.113730.3.8.10.7" class RequireOTPControl(RequestControl): def __init__(self): super().__init__(REQUIRE_OTP_OID, True) conn = ldap.initialize(f"ldap://server.ipa.example") conn.start_tls_s() conn.simple_bind_s(userdn, password_otp, serverctrls=[RequireOTPControl()])
It is not possible to distinguish ldap binds from different applications, so if applications couldn't send the ldap control as described by @cheimes, there's no way to enforce 2fa over that request.
As an experiment I tried setting the auth-type flags as described in step 1 for myself and setting the auth-ind for our host to 'otp'. But 2FA was not enforced and I was still able to log into all of our apps with only a password.
Regardless we use OpenVPN for our VPN solution. Listed below are my current ldap configuration settings. Are you able to advise how to adapt the authentication solution you described to my settings to achieve my goal?
# LDAP server URL URL ldap://10.10.10.10
# Bind DN (If your LDAP server doesn't support anonymous binds) BindDN
"uid=ldapadmin,cn=sysaccounts,cn=etc,dc=ipa,dc=mydomain,dc=biz"
# Bind Password Password mypassword # Network timeout (in seconds) Timeout 15 # Enable Start TLS TLSEnable no # Follow LDAP Referrals (anonymously) FollowReferrals yes # TLS CA Certificate Directory TLSCACertDir /etc/ssl/certs
# Base DN BaseDN "dc=ipa,dc=mydomain,dc=biz"
# User Search Filter # SearchFilter "(&(uid=%u)(accountStatus=active))" SearchFilter "(&(uid=%u)
(memberOf=cn=vpn,cn=groups,cn=accounts,dc=ipa,dc=mydomain,dc=biz))"
# Require Group Membership RequireGroup false
Thanks
-----Original Message----- From: Christian Heimes pagure@pagure.io Sent: Wednesday, June 24, 2020 12:49 AM To: bcalder@clarityinnovates.com Subject: [freeipa] Issue #8380: Request for enhancement to selectiveley enforce 2FA authentication
cheimes added a new comment to an issue you are following: `` This is already implemented in IPA 4.6 and newer.
``
To reply, visit the link below or just reply to this email https://pagure.io/freeipa/issue/8380
@abbra The way we distinguish access to different applications in a bind request is with group membership. For example . . .
This filter included in a bind request from OpenVPN allows a vpn connection to be made. "(&(uid=testuser55) (memberOf=cn=vpn,cn=groups,cn=accounts,dc=ipa,dc=mydomain,dc=biz))"
This filter included in a bind request from gitlab allows access to Gitlab. "(&(uid=testuser55) (memberOf=cn=gitlab,cn=groups,cn=accounts,dc=ipa,dc=mydomain,dc=biz))"
This filter included in a bind request from SonarQube allows access to SonarQube. "(&(uid=testuser55) (memberOf=cn=sonar,cn=groups,cn=accounts,dc=ipa,dc=mydomain,dc=biz))"
etc.
If a user is not a member of the specified group then they cannot access it. Using groups in this way is what led me to asking if there is a way to enforce 2FA by group.
In the meantime I'll continue trying to adapt my use case to @cheimes recommendation. But it's a struggle.
The way we distinguish access to different applications in a bind request is with group membership.
This is not what I am talking about. The content of your filter is irrelevant for the LDAP bind request itself because bind request itself has no filter supplied. In addition, you are mixing up authentication and authorization steps.
The way how it works is that an application for authentication step: - opens an LDAP connection - sends LDAP BIND request for its own configured bind DN - sends LDAP SEARCH request with a filter that captures what it wants to query - waits for the LDAP SEARCH response - analyzes the received response and generates user DN - sends LDAP BIND request as a user DN - waits until the request succeeds
The authentication step might skip LDAP search step if an application has a prior knowledge of how a user DN would look like. For example, some applications allow to specify base DN and user DN templates so that instead of searching a user by a certain attribute set it would simply do construct a DN like uid=foobar,cn=users,cn=accounts,dc=ipa,dc=mydomain,dc=biz and attempt to do LDAP BIND as that DN right away.
uid=foobar,cn=users,cn=accounts,dc=ipa,dc=mydomain,dc=biz
Next step is authorization where an application:
When LDAP server receives the BIND request with user DN, it does not have any idea who sendt that BIND request. There is no relation between the LDAP connection and user bind DN in terms of enforcing a particular behavior to require or not 2FA authentication -- unless the application itself would add a special LDAP control that asks for 2FA authentication, as @cheimes explained.
The filter examples you are showing are part of authorization step which is applied after the BIND as that user already succeeded. Sure, some applications reverse the steps and first attempt to query if such user exists in terms of authorization and if they get a response do perform an LDAP BIND operation but still both steps are independent and to LDAP server itself look completely unrelated.
That's why I said that LDAP server has no way to tell whether LDAP BIND operation wants or not 2FA to be done, unless there is a specific hint in the request.
For OpenVPN I would actually suggest you to use PAM integration with SSSD instead of using direct LDAP check. You'd configure OpenVPN to do PAM check, configure HBAC rules for openvpn service to grant access to users you want, via specified group, and configure SSSD to accept 2FA value as part of the password field because OpenVPN has no way to ask multiple prompts for PAM conversation. Please follow this instruction from one of OpenVPN developers: https://sourceforge.net/p/openvpn/mailman/message/35969399/.
@abbra First I want to thank you for your patience in describing the distinction between authentication vs authorization. It reshaped my understanding of how LDAP bind requests work. It helped a lot!
Second, logging into OpenVPN by appending the password with an OTP token using PAM authentication sounds like exactly what I need. So I adjusted OpenVPN to use PAM. However while PAM authentication works with password use only, it will not allow me to login with password + OTP token.
Summary of my testing: LDAP Authentication -- password only: works as expected (user-auth-type Is set to password and otp) LDAP Authentication -- password + OTP token: works as expected (user-auth-type Is set to password and otp) PAM Authentication -- password only: works as expected (as long as my user-auth-type Is set to password only) PAM Authentication -- password + OTP token: does not work (user-auth-type Is set to password and otp)
For implementing PAM authentication I followed the steps outlined in the https://sourceforge.net/p/openvpn/mailman/message/35969399/ link you shared with me. I first successfully authenticated into OpenVPN using only my password. At that time my user-auth-type was set to password only.
I then set my user-auth-type to otp in addition to the password value already set. At that point I expected to at least authenticate with password. But I can cannot authenticate with password only or password+otp token. In both scenarios the ipa log shows invalid credentials. I also tried setting the auth-ind to otp on the host record but that had no effect.
I'm trying to figure out where to troubleshoot. From what I described can you advise if this would be an OpenVPN issue, PAM configuration issue or FreeIPA issue?
The way we distinguish access to different applications in a bind request is with group membership. This is not what I am talking about. The content of your filter is irrelevant for the LDAP bind request itself because bind request itself has no filter supplied. In addition, you are mixing up authentication and authorization steps. The way how it works is that an application for authentication step: - opens an LDAP connection - sends LDAP BIND request for its own configured bind DN - sends LDAP SEARCH request with a filter that captures what it wants to query - waits for the LDAP SEARCH response - analyzes the received response and generates user DN - sends LDAP BIND request as a user DN - waits until the request succeeds The authentication step might skip LDAP search step if an application has a prior knowledge of how a user DN would look like. For example, some applications allow to specify base DN and user DN templates so that instead of searching a user by a certain attribute set it would simply do construct a DN like uid=foobar,cn=users,cn=accounts,dc=ipa,dc=mydomain,dc=biz and attempt to do LDAP BIND as that DN right away. Next step is authorization where an application: opens an LDAP connection sends LDAP BIND request for its own configured bind DN sends LDAP SEARCH request with a filter that captures what it wants to query waits for the LDAP SEARCH response analyzes the received response for the authorization purposes When LDAP server receives the BIND request with user DN, it does not have any idea who sendt that BIND request. There is no relation between the LDAP connection and user bind DN in terms of enforcing a particular behavior to require or not 2FA authentication -- unless the application itself would add a special LDAP control that asks for 2FA authentication, as @cheimes explained. The filter examples you are showing are part of authorization step which is applied after the BIND as that user already succeeded. Sure, some applications reverse the steps and first attempt to query if such user exists in terms of authorization and if they get a response do perform an LDAP BIND operation but still both steps are independent and to LDAP server itself look completely unrelated. That's why I said that LDAP server has no way to tell whether LDAP BIND operation wants or not 2FA to be done, unless there is a specific hint in the request. For OpenVPN I would actually suggest you to use PAM integration with SSSD instead of using direct LDAP check. You'd configure OpenVPN to do PAM check, configure HBAC rules for openvpn service to grant access to users you want, via specified group, and configure SSSD to accept 2FA value as part of the password field because OpenVPN has no way to ask multiple prompts for PAM conversation. Please follow this instruction from one of OpenVPN developers: https://sourceforge.net/p/openvpn/mailman/message/35969399/.
This is not what I am talking about. The content of your filter is irrelevant for the LDAP bind request itself because bind request itself has no filter supplied. In addition, you are mixing up authentication and authorization steps. The way how it works is that an application for authentication step: - opens an LDAP connection - sends LDAP BIND request for its own configured bind DN - sends LDAP SEARCH request with a filter that captures what it wants to query - waits for the LDAP SEARCH response - analyzes the received response and generates user DN - sends LDAP BIND request as a user DN - waits until the request succeeds The authentication step might skip LDAP search step if an application has a prior knowledge of how a user DN would look like. For example, some applications allow to specify base DN and user DN templates so that instead of searching a user by a certain attribute set it would simply do construct a DN like uid=foobar,cn=users,cn=accounts,dc=ipa,dc=mydomain,dc=biz and attempt to do LDAP BIND as that DN right away. Next step is authorization where an application:
opens an LDAP connection sends LDAP BIND request for its own configured bind DN sends LDAP SEARCH request with a filter that captures what it wants to query waits for the LDAP SEARCH response analyzes the received response for the authorization purposes
When LDAP server receives the BIND request with user DN, it does not have any idea who sendt that BIND request. There is no relation between the LDAP connection and user bind DN in terms of enforcing a particular behavior to require or not 2FA authentication -- unless the application itself would add a special LDAP control that asks for 2FA authentication, as @cheimes explained. The filter examples you are showing are part of authorization step which is applied after the BIND as that user already succeeded. Sure, some applications reverse the steps and first attempt to query if such user exists in terms of authorization and if they get a response do perform an LDAP BIND operation but still both steps are independent and to LDAP server itself look completely unrelated. That's why I said that LDAP server has no way to tell whether LDAP BIND operation wants or not 2FA to be done, unless there is a specific hint in the request. For OpenVPN I would actually suggest you to use PAM integration with SSSD instead of using direct LDAP check. You'd configure OpenVPN to do PAM check, configure HBAC rules for openvpn service to grant access to users you want, via specified group, and configure SSSD to accept 2FA value as part of the password field because OpenVPN has no way to ask multiple prompts for PAM conversation. Please follow this instruction from one of OpenVPN developers: https://sourceforge.net/p/openvpn/mailman/message/35969399/.
@abbra When advising switching to PAM authentication for OpenVPN, you mentioned configuring SSSD to accept 2FA value as part of the password field because OpenVPN has no way to ask multiple prompts for PAM conversation. To date I can not make password + 2FA value work with the OpenVPN plugin -- IPA logs how invalid credentials. But password only works fine.
Would this be an issue I need to pursue with OpenVPN regarding their plugin? Or would there be any additional configuration I could try within FreeIPA?
In recent SSSD versions there is support for specifying per-service single prompting for 2FA, as explained in the sssd.conf(5) man page. A design page is here: https://sssd.io/docs/design_pages/prompting_configuration.html
sssd.conf(5)
For possible setup see the last example in the design page (before "How to debug" section).
At least, I see this in Fedora 32.
Hmmm . . . Our server is running on Centos 7.8 with sssd version 1.16.4. My sssd.conf does not show a [prompting/2fa/my_service] section.
It appears the latest release of sssd is 2.3.0. So I have to look into upgrading it. But at least you steered me toward a solution.
-----Original Message----- From: Alexander Bokovoy pagure@pagure.io Sent: Wednesday, July 1, 2020 11:54 AM To: bcalder@clarityinnovates.com Subject: [freeipa] Issue #8380: Request for enhancement to selectiveley enforce 2FA authentication
abbra added a new comment to an issue you are following: At least, I see this in Fedora 32.
Since you have reported a successful test at https://stackoverflow.com/questions/62648745/how-do-i-configure-pam-authentication-to-combine-password-otp-token/62746727#62746727, I am closing this issue.
Metadata Update from @abbra: - Issue close_status updated to: worksforme - Issue status updated to: Closed (was: Open)
@abbra I was going to post my findings to this issue this morning but I saw you noted my Stack post.
As I mentioned everything works for the most part. The one other thing I wanted to mention is the HBAC rule described in an earlier link seems not to have any impact. The test I described in the Stack post were done with the rule disabled.
That said, the one other thing I'd like to be able to do is control access by FreeIPA group to VPN login. I tried adding to my pam.d file:
account sufficient pam_succeed_if.so user ingroup vpn
But that didn't work. Do you know if what I want to do is doable?
Otherwise . . Thanks for all your assistance in resolving!
This is exactly what you should be doing via HBAC rules. Create a rule that applies to the HBAC service named as your pam file (e.g. openvpn), add required POSIX groups to the rule, add the host of VPN server where the rule should be applying, enable the rule.
openvpn
@abbra That is how I had my HBAC rule configured but with it enabled it was allowing anybody to connect even if they were not a member of the vpn POSIX group. But then I remembered the allow_all HBAC rule was enabled for all hosts. I disabled that rule and added another rule to allow all hosts except the openvpn host.
Everything is functioning now exactly how I need - Thanks!