docker-openldap icon indicating copy to clipboard operation
docker-openldap copied to clipboard

Integrated kerberos KDC configuration

Open beargiles opened this issue 6 years ago • 7 comments

I'm trying to integrate Kerberos KDC configuration and wanted to add an issue to track progress, ask help, and probably vent a bit. :-) I've checked the earlier kerberos issues.

Ideally this will be integrated into the one-time setup and controlled by an env var like 'USE_KDC=1'

Here's what I have so far... oddly the openldap container fails the first time I run docker-compose up but succeeds afterwards. I'll update this later unless I get so frustrated with Docker that I end up finishing this up with an ansible script.

Preparation

  1. Download the kerberos source (apt-get source krb5). /usr/share/doc/krb5-kdc-ldap is similar but doesn't include kerberos.openldap.ldif. That file strips out some things already present in a standard openldap configuation.

  2. Copy src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema to bootstrap/schema

  3. Copy src/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif to bootstrap/ldif

  4. Create krb5 directory

  5. Add krb5/kdc.conf

     [libdefaults]
         default_realm = EXAMPLE.COM
    
         kdc_timesync = 1
         ccache_type = 4
         forwardable = true
         proxiable = true
    
     [realms]
         EXAMPLE.COM = {
                 kdc = localhost
                 admin_server = localhost
                 default_domain = example.com
         }
    
     [domain_realm]
         .example.com = EXAMPLE.COM
         example.com = EXAMPLE.COM
    
  6. Add krb5/kdc.conf

     [kdcdefaults]
         kdc_ports = 750,88
    
     [realms]
         EXAMPLE.COM = {
             database_module = LDAP
             # database_name = /var/lib/krb5kdc/principal
             admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
             # acl_file = /etc/krb5kdc/kadm5.acl
             key_stash_file = /etc/krb5kdc/stash
             kdc_ports = 750,88
             max_life = 10h 0m 0s
             max_renewable_life = 7d 0h 0m 0s
             master_key_type = des3-hmac-sha1
             #supported_enctypes = aes256-cts:normal aes128-cts:normal
             default_principal_flags = +preauth
         }
    
     [dbmodules]
         LDAP = {
             db_library = kldap
             ldap_kerberos_container_dn = cn=krbContainer,dc=example,dc=com
             ldap_kdc_dn = cn=admin,dc=example,dc=com
             ldap_kadmind_dn = cn=admin,dc=example,dc=com
             ldap_service_password_file = /etc/krb5kdc/ldap.stash
             ldap_servers = ldapi:///
         }
    
  7. Add this to Dockerfile

     ADD krb5/krb5.conf /etc/krb5.conf
     ADD krb5/kdc.conf /etc/krb5kdc/kdc.conf
    

Configuration

This is still done manually. I don't know if there's already a hook, similar to bootstrap, that allows us to run an arbitrary script before or after the openldap server is up.

Note: best practices would probably include creating an LDAP entry specifically for the KDC and KADMIND admin roles instead of reusing cn=admin.

  1. Add ou=users. (And ou=systems ?)

  2. Stash ldap key. I don't know if you can specify the

     kdb5_ldap_util stashsrvpw cn=admin,dc=example,dc=com
    
  3. Initialize the KDC entries in LDAP

     kdb5_ldap_util -D cn=admin,dc=snapdevteam,dc=com create -subtrees ou=users,dc=example,dc=com -r EXAMPLE.COM -s
    
  4. Start service

     sudo service krb5-kdc start
    

Verify

  1. Start container

  2. Verify /etc/ldap/slapd.d/cn=config/cn=schema contains cn={5}kerberos.ldif.

  3. Run

    ldapsearch -L -x -D cn=admin,dc=example,dc=com -b dc=example,dc=com -W

You should see entries for

system:

cn=krbContainer
cn=EXAMPLE.COM,cn=krbContainer
krbPrincipalName=K/[email protected],cn=EXAMPLE.COM,...
krbPrincipalName=krbtgt/EXAMPLE.COM,cn=EXAMPLE.COM,...

people:

krbPrincipalName=kadmin/adminEXAMPLE.COM,cn=EXAMPLE.COM,...
krbPrincipalName=kadmin/[email protected],cn=EXAMPLE.COM,...
krbPrincipalName=kadmin/[email protected],cn=EXAMPLE.COM,...

servers:

krbPrincipalName=kadmin/[email protected],cn=EXAMPLE.COM,...
krbPrincipalName=kiprop/[email protected],cn=EXAMPLE.COM,...

Questions

  1. How do I turn on indexing by krbPrincipalName?

  2. How do I add the ACL file that restricts access to LDAP entries:

     access to dn.base=""
         by * read
    
     access to dn.base="cn=Subschema"
         by * read
    
     access to attrs=userPassword,userPKCS12
         by self write
         by * auth
    
     access to attrs=shadowLastChange
         by self write
         by * read
    
     # Providing access to realm container
     access to dn.subtree= "cn=EXAMPLE.COM,cn=krbcontainer,dc=example,dc=com"
         by dn.exact="cn=kdc-service,dc=example,dc=com" write
         by dn.exact="cn=adm-service,dc=example,dc=com" write
         by * none
    
     # Providing access to principals, if not underneath realm container
     access to dn.subtree= "ou=users,dc=example,dc=com"
         by dn.exact="cn=kdc-service,dc=example,dc=com" write
         by dn.exact="cn=adm-service,dc=example,dc=com" write
         by * none
    
     access to *
         by * read
    

Notes

  1. Some documentation also refers to misc.schema and misc.ldif.
  2. The cosine.schema at https://github.com/openldap/opendap seems to be a lot bigger than the cosine.schema bundled in the Debian package. Among other things the former one seems to contain some PKI (X.509 certificates) absent from the latter. That's important since we often want LDAP + Kerberos + public key.

beargiles avatar May 07 '19 18:05 beargiles

Progress update....

I decided it would be easier to create a fork and pull request than list a bunch of suggested changes. The way the code is shaking out is:

  1. Stuff that should always be added since there's minimal impact and it's a good start if people want to tweak the files later.
  • add kerberos.schema
  • assets/config/krb5/krb5.conf
  • assets/config/krb5/kdc.conf
  • new function in setup that creates /etc/krb5.conf and /etc/krb5kdc.conf with appropriate substitutions.
  • tweaked assets/config/bootstrap/ldif/05-index.ldif to add krbPrincipalName as an indexed value.
  • (pending) tweaked assets/config/bootstrap/ldif/02-security.ldif to add ACLs.

The krb5 and kdc files are the standard files with appropriate changes so that we can use substitution.

There are three new envvars.

  • KRB_REALM, default ${LDAP_DOMAIN^^}.
  • KDC_SERVER, default 'localhost'
  • KADMIN_SERVER, default ${KDC_SERVER}
  1. Stuff that's debatable and doesn't require a running LDAP server.
  • kdb_ldap_util stashsrvpw -- stores LDAP admin password (in plaintext?!) so KDC has without prompting user.

On the plus side startup.sh knows the LDAP admin password. On the minus side anyone who's not using KDC is not going to be happy to have the admin password stashed, esp. if it's in plaintext.

  1. Stuff that should be conditional AND requires the LDAP server to be running.
  • add ou=users and ou=services. We shouldn't create them by default and we can't assume that every organization wants to use those names or that they only want two.

I'm not deeply knowledgeable about LDAP schemas - I think we can have a mix of entries that do/don't list the objectClass krbPrincipal but I'm not sure. Unfortunately that class lists krbPrincipalName as a mandatory attribute so I can't add it to these ou's without making a pretty critical assumption.

  • create initial KDC entries: 'kdb5_ldap_util create -subtrees ou=users,${LDAP_BASE_DN}:ou=servers,${LDAP_BASE_DN} -sscope SUB -r ${KRB_REALM}'

Recommendation

Add #1 in startup.sh. It has minimal impact and is a good base if anyone wants to tweak the config later.

Add #2 and #3 with a post-startup script triggered by a 'USE_KRB' envvar. It should be in a place that's easily overridden, similar to assets/config/ldif/custom. An arbitrary number of scripts should be supported - the 'USE_KRB' should be tested in this script.

Open Questions

  1. How to handle calling the extra post-startup scripts. I'll probably submit a pull request with the script explicitly called and let you generalize it.

  2. krb5_ldap_util prompts the console for the admin password to stash and for the new master Kerberos password. I'm pretty sure that can be handled in the bash script - I've pinged my coworkers on this.

beargiles avatar May 08 '19 12:05 beargiles

Yay, figured out how to update the ldap admin password stash.

  coproc kdb5_ldap_util stashsrvpw cn=admin,${LDAP_BASE_DN}
  echo ${LDAP_ADMIN_PASSWORD} >&${COPROC[1]}
  echo ${LDAP_ADMIN_PASSWORD} >&${COPROC[1]}

I can do the same thing when creating the ldap entries but it needs to be executed when the ldap server is up.

The total changes to date to startup.sh are

  #
  # Kerberos
  #
  if [ -z "$KRB_REALM" ]; then
    KRB_REALM=${LDAP_DOMAIN^^}
  fi
    
  function create_krb5_config (){
    local FILE=$1
    log-helper debug "Processing file ${FILE}"
    sed -i "s|{{ LDAP_DOMAIN }}|${LDAP_DOMAIN}|g" $FILE
    sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" $FILE
    sed -i "s|{{ KRB_REALM }}|${KRB_REALM}|g" $FILE
    cp $FILE $2
  }
    
  #
  # Create configuration files
  #
  create_krb5_config ${CONTAINER_SERVICE_DIR}/slapd/assets/config/krb5/krb5.conf /etc/krb5.conf
  create_krb5_config ${CONTAINER_SERVICE_DIR}/slapd/assets/config/krb5/kdc.conf /etc/krb5kdc/kdc.conf
    
  # -- going beyond this point should be conditional
    
  #
  # Cache credentials
  # Create initial KDC entries (requires running LDAP server)
  #
  coproc kdb5_ldap_util stashsrvpw cn=admin,${LDAP_BASE_DN}
  echo ${LDAP_ADMIN_PASSWORD} >&${COPROC[1]}
  echo ${LDAP_ADMIN_PASSWORD} >&${COPROC[1]}
  
  #  kdb5_ldap_util -D cn=admin,${LDAP_BASE_DN} -w ${LDAP_ADMIN_PASSWORD} -H ldapi:// create \
  #       -subtrees ou=users,${LDAP_BASE_DN}:ou=servers,${LDAP_BASE_DN} -sscope SUB -r ${KRB_REALM}

beargiles avatar May 08 '19 14:05 beargiles

I've created a pull request with my changes. https://github.com/osixia/docker-openldap/pull/322

I've been successfully running kinit and kadmin (not just kadmin.local) on both the docker container and my desktop (with appropriate /etc/krb5.conf entries).

It's mostly automatic. There's only one manual step required since it can't be done until the LDAP server is up. It should only be run once and at first glance startup.sh is only run before the server comes up. The simple bash script is at /usr/local/bin/01-kdc.sh. It would be much better if it could be run automatically, conditional on something like ENABLE_KDC.

I also updated the documentation with some brief notes on both enabling a KDC and using Kerberos authentication when connecting to the LDAP server.

Source at https://github.com/beargiles/docker-openldap, 'kdc' branch.

beargiles avatar May 09 '19 00:05 beargiles

Hi @beargiles

I've been looking at your PR as we need to run kerberos for our hdfs cluster,

A couple of changes I made to get the container running without intervention:

kdc.conf - line 5 - you have your realm hard coded. I changed the value to {{ KRB_REALM }} to pick up the correct realm name

startup.sh - slapd comes up quickly for me so I run the 01-kdc.sh 10 seconds later with this command: sleep 10 && /usr/local/bin/01-kdc.sh & I'm planning on making it smarter (adding retries, polling to see if the service comes up etc) but for the moment it does the job for me.

whiskerch avatar May 23 '19 08:05 whiskerch

Commenting here to stay in the loop.

tsmethurst avatar Sep 27 '19 08:09 tsmethurst

I've created a pull request with my changes. #322

I've been successfully running kinit and kadmin (not just kadmin.local) on both the docker container and my desktop (with appropriate /etc/krb5.conf entries).

It's mostly automatic. There's only one manual step required since it can't be done until the LDAP server is up. It should only be run once and at first glance startup.sh is only run before the server comes up. The simple bash script is at /usr/local/bin/01-kdc.sh. It would be much better if it could be run automatically, conditional on something like ENABLE_KDC.

I also updated the documentation with some brief notes on both enabling a KDC and using Kerberos authentication when connecting to the LDAP server.

Source at https://github.com/beargiles/docker-openldap, 'kdc' branch.

@beargiles Thanks for your great work!

For manual running of 01-kdc.sh, do consider taking a look here.

I was doing a Keycloak demo with MIT Kerberos / OpenLDAP and managed to get something working based on your work. See here for the script to start KDC and Kadmin.

deskoh avatar Aug 23 '20 09:08 deskoh

@beargiles, thanks for your effort, it is exactly what I am looking for. But, is this effort still active? If not for merging here, is your fork ready?

ygalblum avatar Oct 06 '21 05:10 ygalblum