Is there any way to use the idassert feature ONLY for anonymous connections, while allowing all other binddns to be directly proxied as themselves?
I ask because we have root LDAP servers that have ACL configurations that work for our purposes, and we don't want to change them. We also do not allow anonymous binds to our root servers. To be clear, we do not want to change anything whatsoever on our root servers.
however, some clients do need to be able to bind anonymously. We're ok with this, as long as anonymous is allowed against LDAP proxies only, and not on our root LDAP servers. This way, we can control what anonymous user sees.
I am trying to make the proxy behave in the following ways:
* authenticated non-admin Users may bind as themselves, they can see groups, etc., (anything non-confidential) but can only see their own account (we have this one working, but is an essential element of the larger picture) * anonymous users see all of the same non-sensitive material, but no user accounts whatsoever * there are proxybind users in our DIT, one for read-ops and one for write-ops. The writer-proxybind user typically is needed for changing a users' password, etc. The read user is the one that performs lookups for strictly read-only operations. He can see all users.
If I set the idassert-bind to the read-only user, then no one can do writes. If i set it to the write-user, then everyone (even those who shouldn't) can do writes (except anonymous, which is good). The understanding I have is that we should be setting the proxy user in slapd's proxy config to be the highest-privileged user that we're ok with being "asserted". For example, we're not asserting to the rootdn or anything, rather we assert to a bind user that is designed to read the very information that the proxy is designed to lookup.
Here is our running config, though its been hacked up so much you should understand its probably not perfect around the edges. Also ignore the comments as they haven't been updated with the rest of the real parameters.
PS - I tried to upload as anonymous to your ftp and got this:
local: j-gropefruit-100114.txt remote: j-gropefruit-100114.txt 229 Entering Extended Passive Mode (|||60518|) 553 j-gropefruit-100114.txt: Permission denied.
So you'll just have to read it here:
###################################
include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/misc.schema include /etc/ldap/schema/openldap.schema include /etc/ldap/schema/duaconf.schema include /etc/ldap/schema/dyngroup.schema include /etc/ldap/schema/ppolicy.schema include /etc/ldap/schema/sudo.schema include /etc/ldap/schema/dhcp.schema include /etc/ldap/schema/samba.schema include /usr/share/doc/libpam-ldap/ldapns.schema include /etc/ldap/schema/hdb.schema include /etc/ldap/schema/uber.schema
pidfile /var/run/slapd/slapd.pid argsfile /var/run/slapd/slapd.args
loglevel stats stats2 conns parse idletimeout 0
sizelimit unlimited timelimit unlimited
defaultsearchbase dc=fake,dc=example,dc=com
limits dn.regex="^uid=([^,]+).,cn=plain,*" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read
## Load modules here
modulepath /usr/lib/ldap moduleload back_relay moduleload back_ldap moduleload back_hdb moduleload pcache moduleload rwm.la
## SSL/TLS
TLSCertificateFile /etc/ldap/ssl/wildcard.fake.example.com.crt TLSCertificateKeyFile /etc/ldap/ssl/wildcard.fake.example.com.key TLSCACertificateFile /etc/ldap/ssl/wildcard.fake.example.com.pem
## This is for SASL/GSSAPI authentication
sasl-realm FAKE.EXAMPLE.COM sasl-host ds-fake-int.fake.example.com authz-regexp "uid=(.*),cn=FAKE.EXAMPLE.COM,cn=gssapi,cn=auth" "uid=$1,cn=plain,cn=auth,dc=real,dc=example,dc=com" authz-regexp "uid=(.*),cn=DEV.EXAMPLE.COM,cn=gssapi,cn=auth" "uid=$1,cn=plain,cn=auth,cn=dev,dc=real,dc=example,dc=com"
## Define the actual 'database', as referenced by the suffix.
database ldap uri ldaps://10.9.8.7:636/ suffix "dc=real,dc=example,dc=com" rootdn "uid=rootdn,cn=plain,cn=auth,dc=real,dc=example,dc=com" overlay rwm rwm-rewriteEngine on # all dataflow from server to client rwm-rewriteContext searchEntryDN rwm-rewriteRule "(.+,)?dc=real,dc=example,dc=com$" "$1dc=fake,dc=example,dc=com"
## When proxying information, configure what identity to assert.
#acl-bind # bindmethod="simple" # binddn="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" # credentials="pass" # starttls="no" # tls_reqcert="never"
idassert-bind bindmethod="simple" binddn="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" credentials="pass" starttls="no" tls_reqcert="never" mode="legacy" flags="override,non-prescriptive"
idassert-authzFrom "dn.subtree:cn=plain,cn=auth,dc=real,dc=example,dc=com" idassert-authzFrom "dn.subtree:cn=plain,cn=auth,dc=real,dc=example,dc=com" idassert-authzFrom "dn.exact:"
chase-referrals NO rebind-as-user NO
## Cache data for PERFORMANCE - this only works when the upstream proxy ## is online. There's no way to cache data in its entirety if the provider ## goes down (that's what actual replication is for).
overlay pcache proxycache hdb 2000 5 100 1800 directory "/var/lib/ldap/cache" dbconfig set_cachesize 0 4097152 0 dbconfig set_lg_regionmax 1048576 dbconfig set_lg_max 1048576 dbconfig set_lg_dir /var/lib/ldap/cache dbconfig set_tmp_dir /tmp index uid,cn,sn,givenName eq,sub index uidNumber,gidNumber eq index homeDirectory,loginShell,gecos,objectClass eq proxycachequeries 10000 proxyattrset 0 uid userPassword uidNumber gidNumber cn homeDirectory loginShell gecos description objectClass proxytemplate (&(objectclass=)(uidNumber=)) 0 1200 proxytemplate (&(objectclass=)(uid=)) 0 1200 proxyattrset 1 objectclass proxytemplate (objectclass=) 1 1200 proxyattrset 2 uid proxytemplate (uid=) 2 1200 proxyattrset 3 cn nisNetgroupTriple memberNisNetgroup proxytemplate (&(objectClass=)(cn=)) 3 1200 proxyattrset 4 gidNumber proxytemplate (&(objectClass=)(memberUid=)) 4 1200
## Set a global rule to allow everything to our service/proxy users, then forbid ## all others access, but BREAK the rule so it keeps processing the rest of the rules, ## which are all much less-permissive ...
access to dn.subtree="dc=real,dc=example,dc=com" by group/groupOfUniqueNames/uniqueMember="cn=ldapadmin,cn=ldap,cn=groups,dc=real,dc=example,dc=com" write by dn.regex="^uid=plain(modify|change),cn=plain,cn=auth,dc=real,dc=example,dc=com" write by dn.regex="^uid=plain(proxy|agent),cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
access to attrs=userPassword by self =w by * =x
## OMFGZZZZ the Solipsism rule - if you touch this I will kill you. ## This fixes the MUST-BIND-AS-SELF logic problem with Sun VDI
access to dn.regex="^uid=([^,]+),cn=plain,cn=auth,dc=real,dc=example,dc=com" by dn.base,expand="uid=$1,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
########## Relay Instance for the "fake" zone
database relay suffix dc=fake,dc=example,dc=com relay dc=real,dc=example,dc=com overlay rwm rwm-suffixmassage dc=real,dc=example,dc=com rwm-rewriteEngine on rwm-normalize-mapped-attrs yes rwm-rewriteContext searchAttrDN rwm-rewriteRule "(.+,)?dc=real,dc=example,dc=com$" "$1dc=fake,dc=example,dc=com"
access to dn.subtree="dc=fake,dc=example,dc=com" by group/groupOfUniqueNames/uniqueMember="cn=ldapadmin,cn=ldap,cn=groups,dc=real,dc=example,dc=com" write by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
access to dn.children="cn=plain,cn=auth,dc=fake,dc=example,dc=com" attrs=userPassword filter=(&(uid=*)(|(objectClass=posixAccount)(objectClass=simpleSecurityObject)(objectClass=shadowAccount)(objectClass=inetOrgPerson)(objectClass=account))) by self write by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" write by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" write by anonymous auth by * none break
access to dn.children="cn=plain,cn=auth,dc=fake,dc=example,dc=com" filter=(&(uid=*)(|(objectClass=posixAccount)(objectClass=simpleSecurityObject)(objectClass=shadowAccount)(objectClass=inetOrgPerson)(objectClass=account))) by self read by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
access to dn.subtree="cn=groups,dc=fake,dc=example,dc=com" filter=(|(objectClass=posixGroup)(objectClass=nisNetgroup)(objectClass=groupOfUniqueNames)(objectClass=groupOfNames)(objectClass=organizationalRole)) by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by anonymous read by * none break
access to dn.onelevel="cn=gssapi,cn=auth,dc=fake,dc=example,dc=com" by dn="uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth" read by * none break
access to dn.onelevel="cn=FAKE.EXAMPLE.COM,cn=gssapi,cn=auth,dc=fake,dc=example,dc=com" by dn="uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth" write by * none break
access to dn.subtree="cn=sys,dc=fake,dc=example,dc=com" by * read
access to dn.subtree="cn=tester,dc=fake,dc=example,dc=com" by * read
access to dn.subtree="cn=dev,dc=fake,dc=example,dc=com" by * none
access to dn.subtree="cn=elements,dc=fake,dc=example,dc=com" by * none ###################################
The man pages and examples on OpenLDAP.org have helped tremendously, but I need some living & breathing opinions. Thanks
J
Is there any way to use the idassert feature ONLY for anonymous connections, while allowing all other binddns to be directly proxied as themselves?
In short: no, although it might be an interesting feature. Currently, you can allow a subset of identities to use identity assertion (idassert-authzFrom), and you can either reject others, or let them pass thru anonymously. What you're asking for is a third option: allow identities matching another subset to pass thru as they are. I suggest you file an ITS for a feature request.
<disclaimer> Please note: this does not mean that either myself or others will quickly implement it </disclaimer>
In the meanwhile, given your specific needs, you could easily obtain the same behavior by pointing normal clients to a normal proxy, and clients that need to bind anonymously to a special proxy that does identity assertion.
Hope this helps.
p.
I ask because we have root LDAP servers that have ACL configurations that work for our purposes, and we don't want to change them. We also do not allow anonymous binds to our root servers. To be clear, we do not want to change anything whatsoever on our root servers.
however, some clients do need to be able to bind anonymously. We're ok with this, as long as anonymous is allowed against LDAP proxies only, and not on our root LDAP servers. This way, we can control what anonymous user sees.
I am trying to make the proxy behave in the following ways:
- authenticated non-admin Users may bind as themselves, they can see
groups, etc., (anything non-confidential) but can only see their own account (we have this one working, but is an essential element of the larger picture)
- anonymous users see all of the same non-sensitive material, but no
user accounts whatsoever
- there are proxybind users in our DIT, one for read-ops and one for
write-ops. The writer-proxybind user typically is needed for changing a users' password, etc. The read user is the one that performs lookups for strictly read-only operations. He can see all users.
If I set the idassert-bind to the read-only user, then no one can do writes. If i set it to the write-user, then everyone (even those who shouldn't) can do writes (except anonymous, which is good). The understanding I have is that we should be setting the proxy user in slapd's proxy config to be the highest-privileged user that we're ok with being "asserted". For example, we're not asserting to the rootdn or anything, rather we assert to a bind user that is designed to read the very information that the proxy is designed to lookup.
Here is our running config, though its been hacked up so much you should understand its probably not perfect around the edges. Also ignore the comments as they haven't been updated with the rest of the real parameters.
PS - I tried to upload as anonymous to your ftp and got this:
local: j-gropefruit-100114.txt remote: j-gropefruit-100114.txt 229 Entering Extended Passive Mode (|||60518|) 553 j-gropefruit-100114.txt: Permission denied.
So you'll just have to read it here:
###################################
include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/misc.schema include /etc/ldap/schema/openldap.schema include /etc/ldap/schema/duaconf.schema include /etc/ldap/schema/dyngroup.schema include /etc/ldap/schema/ppolicy.schema include /etc/ldap/schema/sudo.schema include /etc/ldap/schema/dhcp.schema include /etc/ldap/schema/samba.schema include /usr/share/doc/libpam-ldap/ldapns.schema include /etc/ldap/schema/hdb.schema include /etc/ldap/schema/uber.schema
pidfile /var/run/slapd/slapd.pid argsfile /var/run/slapd/slapd.args
loglevel stats stats2 conns parse idletimeout 0
sizelimit unlimited timelimit unlimited
defaultsearchbase dc=fake,dc=example,dc=com
limits dn.regex="^uid=([^,]+).,cn=plain,*" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read
## Load modules here
modulepath /usr/lib/ldap moduleload back_relay moduleload back_ldap moduleload back_hdb moduleload pcache moduleload rwm.la
## SSL/TLS
TLSCertificateFile /etc/ldap/ssl/wildcard.fake.example.com.crt TLSCertificateKeyFile /etc/ldap/ssl/wildcard.fake.example.com.key TLSCACertificateFile /etc/ldap/ssl/wildcard.fake.example.com.pem
## This is for SASL/GSSAPI authentication
sasl-realm FAKE.EXAMPLE.COM sasl-host ds-fake-int.fake.example.com authz-regexp "uid=(.*),cn=FAKE.EXAMPLE.COM,cn=gssapi,cn=auth" "uid=$1,cn=plain,cn=auth,dc=real,dc=example,dc=com" authz-regexp "uid=(.*),cn=DEV.EXAMPLE.COM,cn=gssapi,cn=auth" "uid=$1,cn=plain,cn=auth,cn=dev,dc=real,dc=example,dc=com"
## Define the actual 'database', as referenced by the suffix.
database ldap uri ldaps://10.9.8.7:636/ suffix "dc=real,dc=example,dc=com" rootdn "uid=rootdn,cn=plain,cn=auth,dc=real,dc=example,dc=com" overlay rwm rwm-rewriteEngine on # all dataflow from server to client rwm-rewriteContext searchEntryDN rwm-rewriteRule "(.+,)?dc=real,dc=example,dc=com$" "$1dc=fake,dc=example,dc=com"
## When proxying information, configure what identity to assert.
#acl-bind # bindmethod="simple" # binddn="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" # credentials="pass" # starttls="no" # tls_reqcert="never"
idassert-bind bindmethod="simple" binddn="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" credentials="pass" starttls="no" tls_reqcert="never" mode="legacy" flags="override,non-prescriptive"
idassert-authzFrom "dn.subtree:cn=plain,cn=auth,dc=real,dc=example,dc=com" idassert-authzFrom "dn.subtree:cn=plain,cn=auth,dc=real,dc=example,dc=com" idassert-authzFrom "dn.exact:"
chase-referrals NO rebind-as-user NO
## Cache data for PERFORMANCE - this only works when the upstream proxy ## is online. There's no way to cache data in its entirety if the provider ## goes down (that's what actual replication is for).
overlay pcache proxycache hdb 2000 5 100 1800 directory "/var/lib/ldap/cache" dbconfig set_cachesize 0 4097152 0 dbconfig set_lg_regionmax 1048576 dbconfig set_lg_max 1048576 dbconfig set_lg_dir /var/lib/ldap/cache dbconfig set_tmp_dir /tmp index uid,cn,sn,givenName eq,sub index uidNumber,gidNumber eq index homeDirectory,loginShell,gecos,objectClass eq proxycachequeries 10000 proxyattrset 0 uid userPassword uidNumber gidNumber cn homeDirectory loginShell gecos description objectClass proxytemplate (&(objectclass=)(uidNumber=)) 0 1200 proxytemplate (&(objectclass=)(uid=)) 0 1200 proxyattrset 1 objectclass proxytemplate (objectclass=) 1 1200 proxyattrset 2 uid proxytemplate (uid=) 2 1200 proxyattrset 3 cn nisNetgroupTriple memberNisNetgroup proxytemplate (&(objectClass=)(cn=)) 3 1200 proxyattrset 4 gidNumber proxytemplate (&(objectClass=)(memberUid=)) 4 1200
## Set a global rule to allow everything to our service/proxy users, then forbid ## all others access, but BREAK the rule so it keeps processing the rest of the rules, ## which are all much less-permissive ...
access to dn.subtree="dc=real,dc=example,dc=com" by group/groupOfUniqueNames/uniqueMember="cn=ldapadmin,cn=ldap,cn=groups,dc=real,dc=example,dc=com" write by dn.regex="^uid=plain(modify|change),cn=plain,cn=auth,dc=real,dc=example,dc=com" write by dn.regex="^uid=plain(proxy|agent),cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
access to attrs=userPassword by self =w by * =x
## OMFGZZZZ the Solipsism rule - if you touch this I will kill you. ## This fixes the MUST-BIND-AS-SELF logic problem with Sun VDI
access to dn.regex="^uid=([^,]+),cn=plain,cn=auth,dc=real,dc=example,dc=com" by dn.base,expand="uid=$1,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
########## Relay Instance for the "fake" zone
database relay suffix dc=fake,dc=example,dc=com relay dc=real,dc=example,dc=com overlay rwm rwm-suffixmassage dc=real,dc=example,dc=com rwm-rewriteEngine on rwm-normalize-mapped-attrs yes rwm-rewriteContext searchAttrDN rwm-rewriteRule "(.+,)?dc=real,dc=example,dc=com$" "$1dc=fake,dc=example,dc=com"
access to dn.subtree="dc=fake,dc=example,dc=com" by group/groupOfUniqueNames/uniqueMember="cn=ldapadmin,cn=ldap,cn=groups,dc=real,dc=example,dc=com" write by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
access to dn.children="cn=plain,cn=auth,dc=fake,dc=example,dc=com" attrs=userPassword filter=(&(uid=*)(|(objectClass=posixAccount)(objectClass=simpleSecurityObject)(objectClass=shadowAccount)(objectClass=inetOrgPerson)(objectClass=account))) by self write by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" write by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" write by anonymous auth by * none break
access to dn.children="cn=plain,cn=auth,dc=fake,dc=example,dc=com" filter=(&(uid=*)(|(objectClass=posixAccount)(objectClass=simpleSecurityObject)(objectClass=shadowAccount)(objectClass=inetOrgPerson)(objectClass=account))) by self read by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by * none break
access to dn.subtree="cn=groups,dc=fake,dc=example,dc=com" filter=(|(objectClass=posixGroup)(objectClass=nisNetgroup)(objectClass=groupOfUniqueNames)(objectClass=groupOfNames)(objectClass=organizationalRole)) by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read by anonymous read by * none break
access to dn.onelevel="cn=gssapi,cn=auth,dc=fake,dc=example,dc=com" by dn="uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth" read by * none break
access to dn.onelevel="cn=FAKE.EXAMPLE.COM,cn=gssapi,cn=auth,dc=fake,dc=example,dc=com" by dn="uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth" write by * none break
access to dn.subtree="cn=sys,dc=fake,dc=example,dc=com" by * read
access to dn.subtree="cn=tester,dc=fake,dc=example,dc=com" by * read
access to dn.subtree="cn=dev,dc=fake,dc=example,dc=com" by * none
access to dn.subtree="cn=elements,dc=fake,dc=example,dc=com" by * none ###################################
The man pages and examples on OpenLDAP.org have helped tremendously, but I need some living & breathing opinions. Thanks
J
openldap-software@openldap.org