Vault: LDAP auth method: support client certificate authentication

Created on 2 May 2019  路  18Comments  路  Source: hashicorp/vault

Is your feature request related to a problem? Please describe.
Using GSuite Secure LDAP as the LDAP server for the LDAP auth method is not currently possible directly due the use of client certificates for client authentication with the LDAP server. Use of the system pool for server certificate verification may also be an issue (I have not checked).

Describe the solution you'd like
The following additional fields in the /auth/ldap/config endpoint should be sufficient:

  • path to client certificate
  • path to client key
  • empty "certificate" field means "use the system pool" (unclear whether that's already the case)

Describe alternatives you've considered
It is possible to use stunnel to get around this restriction. This is the workaround included in the gsuite LDAP connection docs.

Explain any additional use-cases
Unsure about client certificate authentication for other LDAP server. I suspect this may be useful elsewhere.

Additional context
Username and password are not required but can still be provided.
Please see the linked gsuite docs for more details about client configuration.

GSuite secure LDAP is for enterprise GSuite accounts only. I am happy to provide an environment to help develop/test this.

autldap enhancement

Most helpful comment

Yes, you don't need to use stunnel.

All 18 comments

I've been trying to get this working for the last day using Gsuite LDAP and Vault. I have not yet succeeded.

Did you manage to get this to work?

What I tried:

  • Using stunnel I set the certificates and dropped ldaps at that point, run stunnel on 127.0.0.1. Vault config:
vault write auth/ldap/config \
  url="ldap://127.0.0.1:1636" \
  discoverdn=true \
  userdn="ou=Users,dc=ourcompanyname,dc=com"
  starttls=false \
  userattr="uid" \
  deny_null_bind=true

Stunnel conf:

debug = 7
output = /etc/stunnel/google-ldap.log
[ldap]
client = yes
accept = 127.0.0.1:1636
connect = ldap.google.com:636
cert = /etc/ssl/ldap-cert.crt
key = /etc/ssl/ldap-key.key

Outcome:

  • Vault makes an initial simple bindingRequest through LDAP (verified with Wireshark) but receives no results. Testing with ldapsearch yields the same results, an anonymous bind returns nothing.

There's a small bit of information on the Google docs for this:

ldapsearch returns status 0 (success) but no users are outputs

Specifying ldapsearch option -x (use SASL authentication) with client certificates will successfully authenticate but will not list users in the domain.

Recommendation: Remove the option -x and try again.

But in order to test with ldapsearch with the version I have on my system, I _must_ pass the -x parameter in order for ldapsearch to test due to the fact the certs Google provide you are self-signed. I will build ldapsearch locally with different compile flags enabled which could change how self-signed certs are handled.

I built vault v1.2.0 locally to insert some additional debugging and I can confirm it is attempting to use anonymous binds (go-ldap library in the vendor libs).

At a loss as to what to try next.

@AeroNotix did you get this to work?

Hi,

Kinda sorta.

I can get authentication working with vault and google groups:

  • Use stunnel
  • Use user principle binds
  • Disable verify TLS

This will authenticate users. (If the above doesn't work for you then I can get you my config to make it work). However, it will not allow groups to work. I've tried various configuration to get groups working but when accessing Google LDAP through Stunnel, it seems some operations don't work as expected? At least that what it seems like.

That's a shame the whole reason we paid for google cloud identity was to get vault ldap working with groups in there.

@stephenrjohnson I am not saying it is impossible - I am saying I couldn't figure out how to do it.

I managed to get this working including group belonging/mapping. These are the steps I have followed:

Setting up an LDAP application on Gsuite and giving it the following access

ldap-app

I created a set of LDAP access credentials (not sure if this is needed, but I had some issues that were fixed when doing this)

access-creds

Configured stunnel as per google documentation

Verify connectivity with ldapsearch command

This command should list you all the users on your organization:

ldapsearch -x -H ldap://127.0.0.1:1636 -D "cn=LDAPUSER-HERE" -b ou=Users,dc=example,dc=com -w LDAPPASSWORD-HERE

Note: dc=example,dc=com is for the domain example.com, replace accordingly.

Launch a local vault in dev mode:

export VAULT_DEV_ROOT_TOKEN_ID=myroot

export VAULT_LOG_LEVEL=debug

docker run --rm --name vault --net=host -d --cap-add=IPC_LOCK -e "VAULT_DEV_ROOT_TOKEN_ID=$VAULT_DEV_ROOT_TOKEN_ID" -e "VAULT_LOG_LEVEL=$VAULT_LOG_LEVEL" -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' "vault:1.2.2"

Note: LDAP logging error messages will be visible if you use docker logs command

Login and config local vault:

export VAULT_ADDR=http://0.0.0.0:8200
vault login --method token (user myroot here)

Configure ldap auth-backend

vault auth enable ldap

vault write auth/ldap/config url="ldap://127.0.0.1:1636" binddn="cn=LDAPUSER-HERE" bindpass="LDAPPASSWORD-HERE" userdn="ou=Users,dc=example,dc=com" userattr="uid" groupdn="ou=Groups,dc=example,dc=com" groupattr="cn" starttls=false

Note: dc=example,dc=com is for the domain example.com, replace accordingly.

Configure an LDAP group mapping

vault write auth/ldap/groups/group2 policies=default,group2

Note: This command assumes you have a group named "group2" in Gsuite

Authenticate with a user that belongs to "group2" in Gsuite

vault login -method=ldap username=<GSUITE_USER_WITHOUT @example.com> password=<GSUITE_PASSWORD>

token
Note: This output assumes you have a policy named "group2" in vault

@omar-nahhas does that work with users which aren't used for the binddn though? We recently finished a large portion of work to get this to _actually_ work properly, which is now in master.

I suggest to you look deeper into your setup to ensure it works as expected. It looks like it will only work for the single user you set up in the ldap configuration.

The user used on binddn is the access credentials you set up in GSuite when you set up the LDAP application, is not a user on your Gsuite account. Is worth to mention that the creds used for ldap auth were not used on any configuration step. Also, the "token_meta_username" field (after authenticating) shows the Gsuite user name not the binddn user.

I have carried out the following tests:

  • Tried vault login with a wrong user/password for the Gsuite user. This time it could not log-in.
  • Removed (In Gsuite) the user from the group for which I have created the mapping in vault, and try to authenticate again, this time the users did only have the default policy.

I hope this makes things a bit clearer

Interesting, thanks for information. Now it looks like there are multiple ways that GSuite LDAP can be used with vault. The additional pieces myself and @Gisson added, in order for it to work with unauthenticated binds and the client certificates - and apparently, your method here.

This is an extract from the debug logs (redacted) if that helps

2020-03-31T11:40:36.746Z [DEBUG] auth.ldap.auth_ldap_e72aXXXb: discovering user: userdn=ou=Users,dc=example,dc=net filter=(uid=gsuite_user)
2020-03-31T11:40:37.366Z [DEBUG] auth.ldap.auth_ldap_e72aXXXb: user binddn fetched: username=gsuite_user binddn=uid=gsuite_user,ou=Users,dc=example,dc=net
2020-03-31T11:40:38.544Z [DEBUG] auth.ldap.auth_ldap_e72aXXXb: re-bound to original binddn
2020-03-31T11:40:38.544Z [DEBUG] auth.ldap.auth_ldap_e72aXXXb: compiling group filter: group_filter=(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))
2020-03-31T11:40:38.544Z [DEBUG] auth.ldap.auth_ldap_e72aXXXb: searching: groupdn=ou=Groups,dc=example,dc=net rendered_query=(|(memberUid=gsuite_user)(member=uid=gsuite_user,ou=Users,dc=example,dc=net)(uniqueMember=uid=gsuite_user,ou=Users,dc=example,dc=net))
2020-03-31T11:40:39.515Z [DEBUG] auth.ldap.auth_ldap_e72aXXXb: groups fetched from server: num_server_groups=3 server_groups=[ou=Groups,dc=example,dc=net, group2, group1]
2020-03-31T11:40:39.515Z [DEBUG] identity: refreshing external group memberships: entity_id=XXXXXXX-a92f-2247-9ee3-XXXXXXXXX group_aliases=["mount_accessor:"auth_ldap_e72aXXXb" name:"ou=Groups,dc=example,dc=net" ", "mount_accessor:"auth_ldap_e72aXXXb" name:"group2" ", "mount_accessor:"auth_ldap_e72aXXXb" name:"group1" "]

Yes, I believe you that it works :)

The piece I was originally missing is that I wasn't aware you needed to use some extra credentials in order to access GSuite LDAP. It's not documented at all (unless you can point me to it?)

Therefore I added flags/features to vault in order for it to work as the GSuite documentation suggests, by using client certificates, unauthenticated binds. That work is in master, now.

You are right, that is not documented, I just happened to try both ways, thank you guys for the work on master, does it allow us to avoid using stunnel?

I have found this on Google docs, I think this is where I got the hint.

Yes, you don't need to use stunnel.

Is there a way to replicate the same on an OpenLDAP server and use client certificates to authenticate?

Any eta when this will be released?

Is there a way to replicate the same on an OpenLDAP server and use client certificates to authenticate?

I'm able to have vault work successfully with OpenLDAP by setting the LDAP_TLS_VERIFY_CLIENT=try environment variable using the osixia/docker-openldap docker image.

Is there a way to replicate the same on an OpenLDAP server and use client certificates to authenticate?

I'm able to have vault work successfully with OpenLDAP by setting the LDAP_TLS_VERIFY_CLIENT=try environment variable using the osixia/docker-openldap docker image.
@mister2d
I enabled the environment variable LDAP_TLS_VERIFY_CLIENT=try with the following output on the osixia/docker-openldap :

root@ldap:/# ldapsearch  -ZZ -Y EXTERNAL -b dc=example,dc=org
SASL/EXTERNAL authentication started
SASL username: cn=admin
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=org> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 3
result: 32 No such object

I have set my hostname to ldap.example.org while running the image.

This is what I get when i do the authentication with username and password (which I should get when using the certificate as well) :

root@ldap:/# ldapsearch -x -H ldaps://localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=org> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# example.org
dn: dc=example,dc=org
objectClass: top
objectClass: dcObject
objectClass: organization
o: Example Inc.
dc: example

# admin, example.org
dn: cn=admin,dc=example,dc=org
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9K0tqZ1hZV2NKZ2ptZnZSQ1kyMnI1SXRRREt6bWtyeTg=

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2

Is the certificate I have generated wrong? It looks like this :

Certificate:
Data:
Version: 3 (0x2)
Serial Number:
c5:86:23:9d:17:87:08:d7:4d:6c:0d:c1:ca:57:2d:b4
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=Root CA
Validity
Not Before: Jul 11 16:39:01 2020 GMT
Not After : Oct 14 16:39:01 2022 GMT
Subject: CN=admin
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
//Modulus
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Key Identifier:
D2:08:40:2F:0C:E9:D2:A9:30:AA:8E:D8:FA:D1:12:DF:F1:4A:D5:E2
X509v3 Authority Key Identifier:
keyid:01:CF:48:3D:BD:15:AA:81:D1:AF:5E:72:DF:34:2D:4C:7A:A8:1C:82
DirName:/CN=Root CA
serial:91:42:E6:57:2A:93:47:A7

        X509v3 Extended Key Usage:
            TLS Web Client Authentication
        X509v3 Key Usage:
            Digital Signature
Signature Algorithm: sha256WithRSAEncryption
    //Key

Am i missing something here?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tamalsaha picture tamalsaha  路  34Comments

SoMuchToGrok picture SoMuchToGrok  路  66Comments

TopherGopher picture TopherGopher  路  36Comments

ekristen picture ekristen  路  60Comments

mwitkow picture mwitkow  路  142Comments