A walkthrough about using debian ldap , kerberos and bind packages with gnumed

Notes by Syan Tan (minor edits by Jim Busser).

Setting Up Bind

These notes refer to the debian packages bind9. Useful urls were http://www.unix.org.ua/orelly/networking/dnsbind/ch04_01.htm

1. install bind9, bind9-doc - bind8 did strange freeze errors.

2. the default installation: /etc/bind/named.conf named.conf shows the zone definitions that are default for the local machiine.

The questions that come up are:

a) how does it resolve local machine references ?

b) how does it use the internet to lookup non-local names ?

Answ a) the zones 'localhost' and "127.in-addr.arpa" . Answ b) the zone '.'

Note that a) is "type master" and b) is "type hint".

"type master" means that this machine's bind program is the authoratitive nameserver, and can resolve the addresses.

"type hint" means this machine will point the way to other machines' nameservers who may have the resolving information.

the line ' file ""; ' holds the details of the resolving information (a), or the forwarding internet addresses of other nameservers (b)

for zone "localhost" the file is "/etc/bind9/db.local" , and "127.in-addr.arpa" it is /etc/named/db.127

The 2 files db.local and db.127 are almost identical, except for the last line.

db.local 's last line is "@ IN A"

db.127 last line is "1.0.0 IN PTR localhost."

The @ is a token for the local zone name context, which is "localhost" for db.local

The IN stands for "internet" class , and it in effect, is redundant and historical.

The A is an Authoratative record mapping, or name-to-address mapping, so localhost is mapped to

The PTR is used in reverse mappings, or address-to-name mappings, and the this reverse maps to localhost.

The first part of the address is given in "127.in-addr.arpa" in the zone name , in /etc/bind9/named.conf.

The rest of the address is given in reverse order.

If an address or name is followed by a '.' , then that terminates the name or address, but if not, then the address is a prefix , so that monidesktop.monidomain maps to localhost.monidomain.monidomain so usually, specifying the name in full and terminating with a '.' is a good idea.

If the zone name had been "127.0.in-addr.arpa" then the record would have been "0.1 IN PTR localhost" instead of "1.0.0 IN PTR localhost"

To setup the local machine with a different name than localhost, these can be copied to a file and forward and reverse mappings created for the local network.

here's the configuration :

desktop runs the bind9. laptop is the only other network computer.

syan@monidesktop 192:~$ cat /etc/resolv.conf


upto 3 nameserver's can be pointed to , and will be tried in order.

syan@monidesktop 192:~$ cat /etc/hostname

this is the localhost name.

syan@monidesktop 192:~$ cat /etc/bind/named.conf

// This is the primary configuration file for the BIND DNS server named.
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
// If you are just adding zones, please do that in /etc/bind/named.conf.local

include "/etc/bind/named.conf.options";

// prime the server with knowledge of the root servers
zone "." {
        type hint;
        file "/etc/bind/db.root";

// be authoritative for the localhost forward and reverse zones, and for
// broadcast zones as per RFC 1912

zone "localhost" {
        type master;
        file "/etc/bind/db.local";

zone "127.in-addr.arpa" {
        type master;
        file "/etc/bind/db.127";

zone "0.in-addr.arpa" {
        type master;
        file "/etc/bind/db.0";

zone "255.in-addr.arpa" {
        type master;
        file "/etc/bind/db.255";

// zone "com" { type delegation-only; };
// zone "net" { type delegation-only; };

// From the release notes:
//  Because many of our users are uncomfortable receiving undelegated answers
//  from root or top level domains, other than a few for whom that behaviour
//  has been trusted and expected for quite some length of time, we have now
//  introduced the "root-delegations-only" feature which applies delegation-only
//  logic to all top level domains, and to the root domain.  An exception list
//  should be specified, including "MUSEUM" and "DE", and any other top level
//  domains from whom undelegated responses are expected and trusted.
// root-delegation-only exclude { "DE"; "MUSEUM"; };

include "/etc/bind/named.conf.local";

this is the default /etc/bind/named.conf, except that named.conf.local is included

// Do any local configuration here

// Consider adding the 1918 zones here, if they are not used in your
// organization
// include "/etc/bind/zones.rfc1918";

zone    "monidomain" in {
        type master;
        file "/etc/bind/db.local.moni";

zone    "168.192.in-addr.arpa" in {
        type master;
        file "/etc/bind/db.192.168";


this specifies 2 mutually paired zones, one for name-to-address mapping of the monidomain network, and one for reverse mapping of that network.

syan@monidesktop 192:~$ cat /etc/bind/db.local.moni
; BIND data file for local loopback interface
$TTL    604800
;domainname.    internet  start of authority, primary master, administrator email
@       IN      SOA     localhost. syan.localhost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
@       IN      NS      localhost.

monidesktop     IN      A
monilaptop      IN      A

this provides static addressing of the two machines on the network.

syan@monidesktop 192:~$ cat /etc/bind/db.192.168
; BIND data file for local loopback interface
$TTL    604800
;domainname.    internet  start of authority, primary master, administrator email
@       IN      SOA     monidesktop. syan.localhost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
@       IN      NS      monidesktop.monidomain.

5.1     IN      PTR     monidesktop.monidomain.
6.1     IN      PTR     monilaptop.monidomain.

this reverse maps , to monidesktop.monidomain.

Additional configuration is given in the reference, when there is a router in the local network(s) , and it has two interfaces, or machines are aliased.

Problems with bind and dhcp

I don't think they mix very well.

If dhcp is running, and the broadband/adsl router is the dhcp server , then it is likely that every time the computer is turned off and on again, changes will be made to /etc/resolv.conf by the dhcp client daemon, during the bootup process.

I think the solution then becomes uninstalling, or stopping the dhcp service, in which case , the local ip addresses will be statically allocated by bind.

But I haven't done it yet, I still save /etc/resolv.conf , and copy it back , after the machine has booted up.

TODO: how to make this all dynamic IP.

Other issues : what about the AVAHI , or using DHCP with DNS ?

Setting up krb5

after setting up bind for the network, krb5 can be setup . This example has the following allocations:

1. the master key server, and kadmin server runs on the same machine as the bind9 server.

2. postgresql 8.2 was used ( not necessary): ensure when making from source that at least ./configure --with-krb5 is run , ( also --with-openssl , for encrypted postgres sessions , without having to redirect through ssh).

After doing a plain debian install of krb5-admin-server and krb5-kdc, libkrb5-devel (if compiling postgresql) take the following steps:

1. configure /etc/krb5.conf

the concept is that a security domain name is a separate name, so that joe@mydomain , where mydomain is kerberos security domain, is different from joe@joehost.mydomain, the local network user, and joe@mydomain can login with any machine specified in krb5.conf , as part of a security domain ( mydomain)

syan@monidesktop 192:~$ cat /etc/krb5.conf
        default_realm = monidomain

# The following krb5.conf variables are only for MIT Kerberos.
        krb4_config = /etc/krb.conf
        krb4_realms = /etc/krb.realms
        kdc_timesync = 1
        ccache_type = 4
        forwardable = true
        proxiable = true

# The following encryption type specification will be used by MIT Kerberos
# if uncommented.  In general, the defaults in the MIT Kerberos code are
# correct and overriding these specifications only serves to disable new
# encryption types as they are added, creating interoperability problems.

#       default_tgs_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
#       default_tkt_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
#       permitted_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5

# The following libdefaults parameters are only for Heimdal Kerberos.
        v4_instance_resolve = false
        v4_name_convert = {
                host = {
                        rcmd = host
                        ftp = ftp
                plain = {
                        something = something-else
        fcc-mit-ticketflags = true

        monidomain = {
                kdc = kerberos.monidomain
                admin_server = kerberos.monidomain
        ATHENA.MIT.EDU = {
                kdc = kerberos.mit.edu:88
                kdc = kerberos-1.mit.edu:88
                kdc = kerberos-2.mit.edu:88
                admin_server = kerberos.mit.edu
                default_domain = mit.edu
        MEDIA-LAB.MIT.EDU = {
                kdc = kerberos.media.mit.edu
                admin_server = kerberos.media.mit.edu
        ZONE.MIT.EDU = {
                kdc = casio.mit.edu
                kdc = seiko.mit.edu
                admin_server = casio.mit.edu
        MOOF.MIT.EDU = {
                kdc = three-headed-dogcow.mit.edu:88
                kdc = three-headed-dogcow-1.mit.edu:88
                admin_server = three-headed-dogcow.mit.edu
        CSAIL.MIT.EDU = {
                kdc = kerberos-1.csail.mit.edu
                kdc = kerberos-2.csail.mit.edu
                admin_server = kerberos.csail.mit.edu
                default_domain = csail.mit.edu
                krb524_server = krb524.csail.mit.edu
        IHTFP.ORG = {
                kdc = kerberos.ihtfp.org
                admin_server = kerberos.ihtfp.org
        GNU.ORG = {
                kdc = kerberos.gnu.org
                kdc = kerberos-2.gnu.org
                kdc = kerberos-3.gnu.org
                admin_server = kerberos.gnu.org
        1TS.ORG = {
                kdc = kerberos.1ts.org
                admin_server = kerberos.1ts.org
        GRATUITOUS.ORG = {
                kdc = kerberos.gratuitous.org
                admin_server = kerberos.gratuitous.org
        DOOMCOM.ORG = {
                kdc = kerberos.doomcom.org
                admin_server = kerberos.doomcom.org
        ANDREW.CMU.EDU = {
                kdc = vice28.fs.andrew.cmu.edu
                kdc = vice2.fs.andrew.cmu.edu
                kdc = vice11.fs.andrew.cmu.edu
                kdc = vice12.fs.andrew.cmu.edu
                admin_server = vice28.fs.andrew.cmu.edu
                default_domain = andrew.cmu.edu
        CS.CMU.EDU = {
                kdc = kerberos.cs.cmu.edu
                kdc = kerberos-2.srv.cs.cmu.edu
                admin_server = kerberos.cs.cmu.edu
        DEMENTIA.ORG = {
                kdc = kerberos.dementia.org
                kdc = kerberos2.dementia.org
                admin_server = kerberos.dementia.org
        stanford.edu = {
                kdc = krb5auth1.stanford.edu
                kdc = krb5auth2.stanford.edu
                kdc = krb5auth3.stanford.edu
                admin_server = krb5-admin.stanford.edu
                default_domain = stanford.edu

        .monidomain = monidomain
        .mit.edu = ATHENA.MIT.EDU
        mit.edu = ATHENA.MIT.EDU
        .media.mit.edu = MEDIA-LAB.MIT.EDU
        media.mit.edu = MEDIA-LAB.MIT.EDU
        .csail.mit.edu = CSAIL.MIT.EDU
        csail.mit.edu = CSAIL.MIT.EDU
        .whoi.edu = ATHENA.MIT.EDU
        whoi.edu = ATHENA.MIT.EDU
        .stanford.edu = stanford.edu

        krb4_convert = true
        krb4_get_tickets = false


here kerberos.monidomain is the only machines running kerberos infrastructure - the minimum is a master key server , and a admin server, both which can run on one machine.

2.configure matching records in bind

syan@monidesktop 192:~$ cat /etc/bind/db.local.moni
; BIND data file for local loopback interface
$TTL    604800
;domainname.    internet  start of authority, primary master, administrator email
@       IN      SOA     localhost. syan.localhost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
@       IN      NS      localhost.

kerberos                CNAME   monidesktop
postgres                CNAME   monidesktop
_kerberos._udp          SRV     0 0 88 monidesktop
_kerberos-adm._tcp      SRV     0 0 750 monidesktop
_kerberos-master._udp   SRV     0 0 88 monidesktop

monidesktop     IN      A
monilaptop      IN      A

here the kerberos hostname is aliased to the monidesktop hostname. The other entries tell where specific server names map onto what port of what machine e.g. _kerberos._udp server name maps to monidesktop:88

3. Next is to create the master key database: this is taken from the krb5-doc admin html documentation
shell% /usr/local/sbin/kdb5_util create -r ATHENA.MIT.EDU -s
     Initializing database '/usr/local/var/krb5kdc/principal' for
     => realm 'ATHENA.MIT.EDU',
     master key name 'K/M@ATHENA.MIT.EDU'
     You will be prompted for the database Master Password.
     It is important that you NOT FORGET this password.
     Enter KDC database master key:  <= Type the master password.
     Re-enter KDC database master key to verify:  <= Type it again.

substitute after -r for the realm name e.g. monidomain , for the example.

4. Add administrators to the /etc/krb5kdc/kadm5.acl . The easiest is to add


where monidomain is substituted with the kerberos domain name that was decided on in krb5.conf.

monidesktop 192:/home/syan# cat /etc/krb5kdc/kadm5.acl
*/admin@monidomain *

This acl file is referred to in /etc/krb5kdc/kdc.conf , and so is the kadm5.keytab file . (no actions here)
monidesktop 192:/home/syan# cat /etc/krb5kdc/kdc.conf
    kdc_ports = 750,88

    monidomain = {
        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 = des3-hmac-sha1:normal des-cbc-crc:normal des:normal des:v4 des:norealm des:onlyrealm des:afs3
        default_principal_flags = -preauth

actually , I did turn off preauth from +preath to -preauth .

5. create admin users, as per guide.

     shell% /usr/local/sbin/kadmin.local
     kadmin.local: addprinc admin/admin@ATHENA.MIT.EDU
     NOTICE: no policy specified for "admin/admin@ATHENA.MIT.EDU";
     assigning "default".
     Enter password for principal admin/admin@ATHENA.MIT.EDU:  <= Enter a password.
     Re-enter password for principal admin/admin@ATHENA.MIT.EDU:  <= Type it again.
     Principal "admin/admin@ATHENA.MIT.EDU" created.

the kadmin.local tool is run as root, and doesn't need authentication.

The admin principal for the example domain would be admin/admin@monidomain.

6. export some special principals to the kadm5.keytab file, used for backward compatibility with older kerberos clients.

     shell% /usr/local/sbin/kadmin.local
     kadmin.local: ktadd -k /usr/local/var/krb5kdc/kadm5.keytab  kadmin/admin kadmin/changepw

ktadd is a command of kadmin.local that exports to a keytab file, the listed principals ( kadmin/admin, kadmin/changepw)

7. start the servers in debian , it's
/etc/init.d/krb5-admin-server start  

/etc/init.d/krb5-kdc start

8. install krb5-client package to the client computers, and copy krb5.conf to them at /etc/krb5.conf

9. test the installation. e.g. using kadmin.local , add_principal command, add a principal , say the user.

then exit kadmin.local,

then try e.g. kinit user@domain , where user was the newly created user, and domain is the krb5.conf kerberos domain (e.g. monidomain).

10. for some reason, getting postgesql to use kerberos can go wrong for name reasons.

pg_hba.conf needs to be changed so that krb5 is used.


# "local" is for Unix domain socket connections only
local   all         all                               trust
# IPv4 local connections:
#host    all         all          trust
host    all         all         krb5

11. also a keytab file is needed, which should be accessible to postgres user after it has been created by kadmin.local


addprinc  postgres/monidesktop.monidomain

ktadd -k /home/crypt2/postgresql/8.2/main/pg.keytab postgres/monidesktop.monidomain


chown postgres.postgres /home/crypt2/postgresql/8.2/main/pg.keytab

here, the principal postgres/monidesktop.monidomain is exported to pg.keytab , a file visible to postgres , and postgres is made owner of the file pg.keytab. ( This would suggest that verification of the key is not done via a service, but by a kerberos library call by postgres .)

The principal name has to match exactly , a configuration in postgresql.conf, the parameters krb5_srvname , and krb5_server_hostname .

krb5_srvname matches the first part (postgres), before the slash, krb5_server_hostname matches the second part after the slash, (monidesktop.monidomain).

# extracted from postgresql.conf
# Kerberos
krb_server_keyfile = './pg.keytab'              # (change requires restart)
krb_srvname = 'postgres'                # (change requires restart)
krb_server_hostname = 'monidesktop.monidomain'  # empty string matches any keytab entry

13. then test for errors ,

- restart the postgresql server. This should run without a problem.

- psql to this server running the kerberos-configured pg_hba.conf. It should say there are no credentials.

- kinit any principal, then psql to this server running the kerberos-configured pg_hba.conf. If it works first time, then yay , I commend you, clever bastard! (says he who wasted many hours).

- kdestroy , and try psql again to ensure psql only works after successful kinit.

If it didn't work, below is a litany of errors possible.

14. possible errors during setup

* If the postgres kerberos principal name doesn't match, then a no credentials found error will be reported when trying to login.

fix : check the postgres principal exported to pg.keytab is the same name as specified by the postgresql.conf paramaters krb5_srvname and krb5_server_hostname .

* if the pg.keytab file has the wrong permissions, than a permission denied error will be reported.

fix : chown postgres.postgres pg.keytab

* if a kerberos version 5 not supported is reported, it is either reported in the server and the client. Make sure that both client program (psql) and server program (pg_ctl) , are from packages with kerberos support.

If compiling from say the latest package of postgresql, make sure ./configure has been run with the parameters --with-krb5 , before doing make, and make install.

* if a no canonical hostname error occurs, then check the other log, the /var/log/kdc.log .

(below is from the postgresql log to standard output)
LOG:  Kerberos sname_to_principal("monidesktop.monidomain", "postgres") returned error -1765328168
postgres: Hostname cannot be canonicalized while getting server principal for server "monidesktop.monidomain" for service "postgres"
FATAL:  Kerberos 5 authentication failed for user "syan"

maybe the keytab is corrupted /? expired sometimes. a sign might be trying kinit postgres/monidesktop.monidomain@monidomain , and see if can login with the set password.

if not,


change_password postgres/monidesktop.monidomain

ktadd -k / postgres/monidesktop.monidomain

can often fix this.

* if there is an error , but there is not a "No canonical hostname" error, then there can be either an inability for the client to find a certain hostname, and there will be a message like "kdc for server hostname not found ", or that a lookup has been done with the hostname, and a key is present, but the key is not the key that matches a ticket granting service , in which case a "server name not found" error.

check that the local /etc/krb5.conf file has been updated in two places, one is obviously the definition of the kerberos security realm that is being used, but the other is the mapping of domain-to-realm in domain_realm. e.g.

if in the above /etc/krb5.conf file , the line " .monidomain =monidomain" is missing, then there will be no mapping between the domain and the realm, and a client will get "Server name not found" error, and looking at the master_key_server's log in /var/log/kdc.log will show that a best guess is made at the mapping by capitalizing the domain name; so if the domain name is monidomain, at there is a missing domain_realm mapping for .monidomain, then the client will try something like ( which in this case, is wrong):

(from /var/log/kdc.log)

Dec 16 19:52:32 monidesktop.monidomain krb5kdc[5713](info): TGS_REQ (7 etypes {18 17 16 23 1 3 2}) UNKNOWN_SERVER: authtime 1166259147,  syan@monidomain for krbtgt/MONIDOMAIN@monidomain, Server not found in Kerberos database

if on the other hand, it says,

Dec 16 18:28:17 monidesktop krb5kdc[3876](info): AS_REQ (7 etypes {18 17 16 23 1 3 2}) ISSUE: authtime 1166254097, etypes {rep=16 tkt=16 ses=16}, syan@monidomain for krbtgt/monidomain@monidomain

Dec 16 18:29:37 monidesktop krb5kdc[3876](info): TGS_REQ (7 etypes {18 17 16 23 1 3 2}) UNKNOWN_SERVER: authtime 1166254097,  syan@monidomain for krbtgt/LOCALDOMAIN@monidomain, Server not found in Kerberos database

Its not using the apparent domain name , monidomain, which the client is supposed to be part of: 1) check by doing '/usr/bin/hostname' , check /etc/hostnames , /etc/host and make sure the domain name isn't being overridden locally. Check /etc/krb5.conf , and see if there is a line like

        default_realm = localdomain   # should be monidomain

and change the default_realm to the realm name being used.

Finally, if everything is right, then you should see, something like

Dec 16 18:03:46 monidesktop krb5kdc[3876](info): AS_REQ (7 etypes {18 17 16 23 1 3 2}) ISSUE: authtime 1166252626, etypes {rep=16 tkt=16 ses=16}, syan@monidomain for krbtgt/monidomain@monidomain

Dec 16 18:09:29 monidesktop krb5kdc[3876](info): TGS_REQ (7 etypes {18 17 16 23 1 3 2}) ISSUE: authtime 1166252626, etypes {rep=16 tkt=16 ses=16}, syan@monidomain for postgres/monidesktop.monidomain@monidomain

For example, I had the desktop machine's name mapped to my late cat's name in the laptop in /etc/hostnames which was done many months ago, and that caused a lot of wasted time. Then after this, it still wasn't fixed because the default_realm of the lib_defaults section in krb5.conf was set to =LOCALDOMAIN , and this overrode a missing domain_realm mapping as above. After fixing this , the domain name was guessed to be MONIDOMAIN , which was also wrong, and was only fixed when the [domain_realm] mapping .monidomain = monidomain was added in krb5.conf

Looking at the /var/log/kdc.log is a good idea, as it also picks up configuration errors outside of kerberos. It also reinforces shows a little how kerberos works : basically , an AS (authorization service), grants a temporary authority with a ticket, that authenticates requests to a TGS ( ticket granting service ) that issues further temporary tickets associated with services. The postgresql configuration above shows that the application tickets are just tokens with a name identifying them; the application just makes kerberos library calls verifying the ticket with kerberos.

Kerberos users most correspond to postgres users in spelling

The users for gnumed must also be kerberos principals , and spelt the same way: e.g. kadmin.local , addprinc any-doc@mydomain . Preferrably, don't use a hyphenated password, it may not work. Thereafter, if wanting to use the gnumed client, kinit any-doc@mydomain, and enter the non-hyphenated password. After this, the login screen for gnumed doesn't need a password : it will only proceed if the kinit worked prior to running gnumed. It also means, that if one forgets to kdestroy after leaving the gnumed session, then someone could login for a limited time afterwards.


Most people are comfortable with ssh , ssl , https , where channels of communication are encrypted with a session key , sent briefly encrypted with a public key of a server. Once the channel is established, then a clear-text password can be sent over the channel .

Kerberos is probably attractive to windows users , as windows has always been marketed on ease-of-use, and non-technicality for users, so it often goes by the name Windoze, to unix masochists, especially.

Kerberos provides the ability for single sign-on , and use of applications as a single security principal, limited to a per user/principal basis. It probably is most useful if the windowing system login is also kerberized, so that if JoeDoctor? signs onto the desktop , he would just go ahead and use gnumed without a login password, because JoeDoctor? is a gnumed gm-doctors postges role member.



to setup gnumed for use in a kerberized debian based network.


MIT kerberos version 5, Bind 9 from ISC, OpenLDAP? , postgresql version 8.0, gnumed and dependencies


the initial setup is one machine running debian linux. This is to be specific about what flavour of linux, in order to match the directory tree.

e.g. in my instance of debian linux
  • /etc - this directory is where configuration information usually goes.
  • /etc/init.d - this is where the scripts to run services reside .
  • /var - this is the directory where runtime data usually goes.
  • /var/lib - where package persistent data goes. for example, postgresql's database data goes in /var/lib/postgresql
  • /var/log - this is where to find logs, useful debugging
  • /usr - this is where package static data goes, such as programs and libraries, fixed configuration and documentation.
  • /usr/bin , /usr/sbin - where programs are. System programs usually go in /usr/sbin e.g. this is where kerberos administration files go.
  • /usr/share/doc - this is the base directory to find documentation for packages.

Machine setup

It is assumed that gnumed has been setup , and one can run a client and login. This requires the successful installation of : - python (specifically 2.3) , wx-python (-2.3), pyPgSQL python package, egenix-datetime python library, postgresql

Network setup

initially there is one machine to install kerberos , ldap and bind . This will later be the server, and the aim is to get a client machine with the above gnumed basic installation to connect to the server.

Background information

About debian packaging system

- many people like the automatic dependency checking of the apt-get / dpkg system ( frontended with the console based aptitude program, or the graphical synaptic package ). - at the top most division, there are groups of packages called stable, unstable and testing. - a read of the /etc/apt/sources.list will usually tell what set of packages one is getting when updating the packages list.

About postgresql

- postgresql is a relational database system that implements ANSI-SQL to a level that makes its SQL language more powerful than mysql, but its scalability and network capabilities less than Oracle. - the administrators guide to postgresql is not difficult to read, and is available if installed under /usr/share/doc/postgresql--doc/html/index.html

About ldap

- ldap is internet standard based name directory system . It can be used to store address book information, and even store application directory data , like where particular instances of programs are running on a network, etc.... The proposed context for gnumed was a store for address book for referrals, and have authentication and encryption information stored as attributes for entities listed in the address book, for use in secure email standard such as SMIME.

About bind

- bind is the name of an Internet Systems Consortium software package ( Berkeley Internet Name Domain) , and it specifcally provides the DNS service that finds internet number addresses for names. It works by listing well-known heavily used bind instances , giving their concrete internet number address. If the local instance of bind cannot resolve a name into a number, it will go round robin and ask each of the well-known entities if they can resolve the name. These entities can recursively do the same until some bind program coughs up the number.

- in the context of this exercise, the basic organization of the bind configuration files is described, a bind zone file is examined , so an entry can be made for some constant local names used by kerberos. In this way, a kerberos configuration file, only has to specify on which machine in a network a kerberos instance is running, and the services names will be translated by the local network's bind instance(s) into hard network numbers and ports.

About kerberos

- kerberos is an academic , popular based network security system , originally used to try to secure large academic networks - 100s to 1000s of machines, so it is thought to be a well scaled system for that scale of network. It was designed so that there is a well described authentication mechanism, and applications could use the security concept of a well-known path to a stored credential file which associates with a unix user's uid when login occurs. applications can get the user's uid from their environment, and then examine the credential given for the unix user using the application. In the case of postgresql, it seems that the psql program and the pgsql client library are enabled for kerberos, so any program or package backended by the standard postgres client library should work. e.g. pyPgSQL , the python postgres client library package used by gnumed .

Further information of kerberos is at http://www.isi.edu/gost/brian/security/kerberos.html and http://www.ornl.gov/~jar/HowToKerb.html. I really don't understand it that well, but it goes something like:

- AS is an Authenticating Service . The authenticating service sends 2 things on a login request to another service, a challenge containing a session key, and a ticket containing a session key. The ticket is sent to a service, and the ticket can be decrypted by the services secret key, and the ticket also contains the session key. The user must break the challenge in order to get his copy of the session key. He can always send the ticket, but without breaking the challenge, he cannot use his end of the session key. In order to not have to login for each different service, a session key can be cached for a limited time.

This session key is to the Ticket Granting Service or TGS session key.

Once the TGS gets the session key, the channel to the tgs can be encrypted, so further session keys for other services can be passed. The ticket granting service has access to other services secret keys, and issues sessions tickets encrypted with the other services keys. applications that implement kerberos security use the kerberos library to access a service private key file, to decrypt tickets granted by the TGS. The private key file is exported while running the administration tool, kadmin, when adding keys to a principal. ( ktadd -k file principal) .

The private key file should not be readable in an operating system's filesystem except by a special operating system user for that service, as it is not encrypted i.e. it is "secure"

- Kerberos is supposed to be scalable because it works recursively like BIND, so that TGS can talk to a peer TGS in a different security realm, who can talk on behalf of another TGS to a third TGS , who can do the same, and return any tickets back to the originally requesting TGS.

Quick Preview Of Concrete Setup

  • su , synaptic,
  • install kerberos version 5 server and client and dependencies, optionally m install documentation.
  • install bind
  • configure kerberos
  • choose security domain name. A security domain is not an internet address, it specifies a set of principals. In a basic setup of a security domain, any user principal that is logged in , can use any service principal in the
security domain.

Choosing the security domain is usually done in the debian install, and it relies on the user later creating dns records to map standard names to concrete addresses.

The only extra configuration is really to alter /etc/krb5.conf and set the [logging] section.

 admin_server = SYSLOG:INFO:DAEMON

this is useful for debugging by doing
tail -n 20 /var/log/syslog

to read the last 20 lines of what some daemons did. reference http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.3/doc/krb5-admin/logging.html#logging

A sample configuration file: http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.3/doc/krb5-admin/Sample-krb5.conf-File.html#Sample%20krb5.conf%20File

debian installation will add under [realm] something like:

     kdc = kerberos.localdomain
     admin_server = kerberos.localdomain

* choose a name for the host machine and the local network. e.g. change localhost.localdomain to something else. Otherwise, start of with localhost.localdomain and try to move on from there.

* ensure well known static ip addresses for the kerberos machine ( and also other machines). this can be administered through bind. this involves
  1. configuring bind,
  2. setting the nameserver in /etc/resolv.conf, and
  3. possibly changing /etc/hosts.

* configure bind to resolve

This is done by copying /etc/bind/db.empty to say /etc/bind/db.kdc Say the actual host is named myhost1 and domain is mydomain1 .

First , define a local bind zone. A zone is any part of a internet name that can help bind lookup some specific information .
zone "mydomain1" { type master; file "/etc/bind/db.kdc" }

put this line in /etc/bind/named.conf.local ; this says that when a url ending in .mydomain1 is requested, the local bind program will lookup /etc/bind/db.kdc for some resolving information.

A zone file may contain entries like:-

$TTL a_number
this specifies a time period before giving up on this zone to resolve a name.

ORIGIN domain.
this specifies that all urls following will have "domain" appended to it.

The following have a format like :

url (IN) OPERATION url-or-address

for example:

_kerberos    TXT    "mydomain1" 
kerberos   CNAME   "myhost1"

_kerberos._udp        SRV 0 0 88  myhost1 
                      SRV 0 0 88  myhost2

_kerberos-master._udp SRV 0 0 88 myhost1
_kerberos-adm._tcp    SRV 0 0 749 myhost1
_kpasswd._udp         SRV 0 0 464

myhost1       IN     A
myhost2       IN     A

reference: http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.3/doc/krb5-admin/Hostnames-for-KDCs.html#Hostnames%20for%20KDCs

Now this is a total guess how it works:

line 2 specifies that the name kerberos maps to myhost1. This helps the realm definition to find a canonical name for kerberos. ; the above [realm] extract would map kerberos.localdomain to myhost1.localdomain. Sometimes there are extra hosts specified in the realm part of krb5.conf such as kerberos-1 and kerberos-2 to specify "slave" kdc servers. These also should have an entry in db.kdc

kerberos-1   CNAME  "myhost2"

where myhost2 is the specific name for a second machine on your network running krb5kdc.

Lines 3 to 7 specify SRV definitions, which specify a mapping of constant kerberos names . Note that line 4 has a second SRV definition for _kerboros._udp , which is another host for a kdc server.

udp port 88 is a standard key distribution server. tcp port 749 is used for the admin server. udp port 464 is used by the client kpasswd to change user passwords.

the last two lines are mappings of the host names to specific static ip addresses. Note these names are subject to the $ORIGIN statement as well, so they are actually myhost1.mydomain1 and myhost2.mydomain2

The complete /etc/bind/db.kdc of my setup is below. It is a copy of db.empty for the first part before $ORIGIN, except localhost was replaced with monihost.
is a zone attribute definition command.
stands for the current
name context, which would be the zone name in
zone "mydomain" { type master; file "/etc/bind/db.kdc"  } 
, as above.
stands for nameserver, which is specifying the nameserver host for the @ so it is monihost.mydomain
( actually it's monihost.monidomain , because that was the name I used for the zone reference ).

$TTL    86400
@       IN      SOA     monihost. root.monihost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                          86400 )       ; Negative Cache TTL
@       IN      NS      monihost.

$ORIGIN moni.net.
_kerberos               TXT     "MONI.NET"
kerberos                CNAME   MONIHOST
_kerberos._udp          SRV     0 0 88  monihost
_kerberos-adm._tcp      SRV     0 0 750 monihost
_kerberos-master._udp   SRV     0 0 88  monihost

monihost        IN      A
temple          IN      A
;monihost       IN      A

  • setting /etc/resolv.conf
if using dhclient , the default is something like
where would be the fixed ip address of dhcp server , usually the adsl box .

change this to


where would be the address of the machine running bind ( or named ).

  • possibly changing /etc/hosts.

This should be left out unless debugging doesn't obviously show the problem. Because myhost1 without the domain part may not be a url defined in a hard way, an easy way to do it would be in /etc/hosts with lines like   myhost1 host   myhost2 

The second "host" might be needed, because when looking up services, sometimes ethereal shows a kerberos request packet is sending something like "ldap/host.mydomain1@MYDOMAIN1" where host has been inserted into the principal name .This probably a misconfiguration somewhere related to ldap.

Running and debugging kerberos

to run kerberos , the scripts are in /etc/init.d krb5_admin_server , krb5kdc.

to debug, useful commands are:-
 ps -A 
as root , ( this lists all running processes : a misconfiguration will not run: after /etc/init.d/krb5_admin_server start check kadmin is running.

after /etc/init.d/krb5_kdc start check krb5kdc is running.

after /etc/init.d/slapd start check slapd is listed in ps -A.

after /etc/init.d/bind start check named is listed in ps -A.

if not, then it is likely the configuration file has an error. checking the /var/log/syslog might have clues, if errors in starting are not going to the console.

ps -A | grep k
this will only list the processes beginning with k.

Another way to check , is to (as root) do :-

netstat -l -p -n 

this will list all listening ( server ) sockets, (-l), with associated programs running as servers (-p), as well as the numeric addresses , including ports ( -n)

One particular bug is trying to run the kdc on , one a single computer with no ethernet plugged in. It doesn't work, as it looks on the unix socket family , family 17, and this isn't implemented. The error is detected by looking at /var/log/syslog using
tail /var/log/syslog

other useful logs might be /var/log/daemon.log

and the log files specified in /etc/krb5.conf [logging] section ( if not set to SYSLOG:INFO:DAEMON , which is syslog)

Another useful debugging tool is ethereal. Capturing on the local interface if using one machine (lo) : it can translate kerberos protocol packets as well, and is useful to work out when a "client principal not found ", "server principal not found", or "see etext" error occurs.

Common errors include: - not adding a principal - not setting a key for a principal and exporting it for a service ( for postgresql) - adding a principal, but not adding a fresh key ( for ldap) - not naming a service principal properly (e.g. ldap requires the principal to be named host/full-canonical-domain name, e.g. if mydomain.org.au then the principal must be myhost/mydomain.org.au ) - mistyping a principal's name when adding it , so that when logging in , it can't be found under the expected name.

  • using kadmin.local to create a kerberos principals and keys.

as root, do kadmin.local, this should work.

  • in kadmin.local, "listprincs", this should show a list of principals, which will be mainly the TGT , the admin server, the kdc.

  • "addprinc myuser1/myhost" then "cpw myuser1/myhost" , then listprincs, then "getprinc myuser1/myhost"

  • "addprinc -randkey ldap/myhost.myfulldomain" this sets up ldap.

  • "addprinc -randkey postgres/myhost.myfulldomain" , "ktadd -k /etc/postgresql/8.0/main/krb5.keytab",

setting up postgres server to user kerboros

  • then exit kadmin.local
  • do "chown postgres.postgres /etc/postgresql/8.0/main/krb5.keytab", followed by
  • editing /etc/postgresql/8.0/main/postgresql.conf, and set the parameter


  • editing etc/postgresql/8.0/main/pg_hba.conf , and for the non-local ip domain being used (i.e. not adding
host     all    all   krb5

to allow kerberized network access to gnumed_v2 , and all other databases in main cluster.

  • going back into kadmin.local , and add principals for all the database users needed,

e.g. gm-dbo, any-doc

  • the gnumed/client/gm-V2.conf file has a profile entry for the canonical name of the postgresql host that isn't
localhost.localdomain ( e.g. myhost1.mydomain1) that also matches the postgres/ principal, where should be the full url ( e.g. myhost1.mydomain1).

here's an example gm-v2.conf

logins = $logins$
profiles = $profiles$
GNUmed - v2 database on this machine
GNUmed - v2 database at publicdb.gnumed.de
GNUmed - v2 on monihost
client encoding = latin1

[profile GNUmed - v2 on monihost]
host = monihost.moni.net
port = 5432
database = gnumed_v2

[profile GNUmed - v2 database on this machine]
host =
port = 5432
database = gnumed_v2

[profile GNUmed - v2 database at publicdb.gnumed.de]
host = publicdb.gnumed.de
port = 5432
database = gnumed_v2

help desk = GNUmed Development List <Gnumed-devel@gnu.org>
name = Librarian Release (0.2)

All this setup , but once it is debugged to work, users only have to do something like:-

kinit -p any-doc/mydomain

and then they will both be able to:-
  1. login into gnumed without a password entered
  2. use ldapsearch and ldapadd and ldapmodify
  3. be kerberos ready for other kerberos enabled applications.

to clear user authentication, it suggested on logout to run kdestroy

Users can also do kpasswd to change a user password.

Setting up a ldap directory database

* /etc/slapd.conf should have a default top organization after debian configuration here is an example of an extra database definition.

In this example, the
access to * by users write
allows authenticated users write access.

database        bdb
suffix          "o=gnumed"
directory       "/var/lib/ldap/gnumed"

the above extract shows that a gnumed subdirectory is created in /var/lib/ldap where the berkeley database files are stored. This directory should be created before running, otherwise no file error may stop slapd running.

The Example

# This is the main slapd configuration file. See slapd.conf(5) for more
# info on the configuration options.

# Global Directives:

# Features to permit
#allow bind_v2

# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema

# Schema check allows for forcing entries to
# match schemas for their objectClasses's
schemacheck     on

# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile         /var/run/slapd/slapd.pid

# List of arguments that were passed to the server
argsfile        /var/run/slapd.args

# Read slapd.conf(5) for possible values
loglevel        0

# Where the dynamically loaded modules are stored
modulepath      /usr/lib/ldap
moduleload      back_bdb

# Specific Backend Directives for bdb:
# Backend specific directives apply to this backend until another
# 'backend' directive occurs
backend         bdb
checkpoint 512 30

# Specific Backend Directives for 'other':
# Backend specific directives apply to this backend until another
# 'backend' directive occurs
#backend                <other>

# Specific Directives for database #1, of type bdb:
# Database specific directives apply to this databasse until another
# 'database' directive occurs
database        bdb

# The base of your directory in database #1
suffix          "dc=moni,dc=net,dc=au"

# Where the database file are physically stored for database #1
directory       "/var/lib/ldap"

# Indexing options for database #1
index           objectClass eq

# Save the time that the entry gets modified, for database #1
lastmod         on

# Where to store the replica logs for database #1
# replogfile    /var/lib/ldap/replog

# The userPassword by default can be changed
# by the entry owning it if they are authenticated.
# Others should not be able to see it, except the
# admin entry below
# These access lines apply to database #1 only
access to attrs=userPassword
        by dn="cn=admin,dc=moni,dc=net,dc=au" write
        by anonymous auth
        by self write
        by * none

# Ensure read access to the base for things like
# supportedSASLMechanisms.  Without this you may
# have problems with SASL not knowing what
# mechanisms are available and the like.
# Note that this is covered by the 'access to *'
# ACL below too but if you change that as people
# are wont to do you'll still need this if you
# want SASL (and possible other things) to work
# happily.
access to dn.base="" by * read

# The admin dn has full write access, everyone else
# can read everything.
access to *
        by dn="cn=admin,dc=moni,dc=net" write
        by users write
        by * read

# For Netscape Roaming support, each user gets a roaming
# profile for which they have write access to
#access to dn=".*,ou=Roaming,o=morsnet"
#        by dn="cn=admin,dc=moni,dc=net" write
#        by dnattr=owner write

# Specific Directives for database #2, of type 'other' (can be bdb too):
# Database specific directives apply to this databasse until another
# 'database' directive occurs
#database        <other>

# The base of your directory for database #2
#suffix         "dc=debian,dc=org"

# The base of your directory for database #2
database        bdb
suffix          "o=gnumed"
directory       "/var/lib/ldap/gnumed"
index           objectClass eq
lastmod         on

#replogfile     "/var/lib/ldap/gnumed/replog"
access to dn.base=""
        by * read

access to *
        by users write
        by * read

  • there are commands available as root not available to ordinar users, such as slapadd and slapcat.
slapcat needs to have a -nN parameter, where N is the number of a database, if there is more than one database defined in slapd.conf.

On the other hand, ldapsearch can extract from any database defined in slapd.conf. 1. a hint to using ldapsearch is to use the -b parameter, to bind to the dn description of an organization. e.g. ldapsearch -b "o=gnumed" "(objectclass=*)" should pull back all objects under the organization gnumed.

*hint - when debugging ldapsearch, often the problem is getting the credentials right. Sometimes this requires fiddling with the keys, especially if the ldap service principal doesn't have the right keys.

An example ldif dump of a gnumed database
# extended LDIF
# LDAPv3
# base <o=gnumed> with scope sub
# filter: (objectclass=*)
# requesting: ALL

# gnumed
dn: o=gnumed
objectClass: top
objectClass: organization
o: gnumed
description: "gnumed organization"

# gnumedAdmin, gnumed
dn: cn=gnumedAdmin,o=gnumed
objectClass: top
objectClass: organizationalRole
cn: gnumedAdmin
description: gnumed LDAP administrator

# au developers, gnumed
dn: ou=au developers,o=gnumed
objectClass: top
objectClass: organizationalUnit
ou: au developers
description: au developers

# Herb Horst, au developers, gnumed
dn: cn=Herb Horst,ou=au developers,o=gnumed
objectClass: inetOrgPerson
sn: Horst
cn: Herb Horst

# Dr. Karsten Hilbert 2006020728, au developers, gnumed
dn: description=Dr. Karsten Hilbert 2006020728,ou=au developers,o=gnumed
cn:: RHIuIEthcnN0ZW4gSGlsYmVydCA=
title: doc , developer
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
o: gnumed
sn: Hilbert
givenName: Karsten
description: Dr. Karsten Hilbert 2006020728

For further reference: incomplete

  • /etc/postgresql/8.0 - this is the base of a version 8.0 postgresql installation ( thus ../8.1 can be for another
version of postgresql, and this can coexist with 8.0)
  • /etc/postgresql/8.0/main - postgresql allows multiple instances postgres to run, each having their own
template0 and template1 database from which to create databases from. The reason for this might be for applications with different user names in each set of applications, as users are global to each "instance" or cluster of databases. As a concrete example, suppose you have databases called gnumed_v1 and gnumed_v2 and each were created in the "main" cluster. If one changes the any-doc user's password for gnumed_v1, then it will be changed in gnumed_v2 as well. If you dump gnumed_v1 in pg_dump, the default is not to dump out the user data declaration statements, but if you do a pg_dumpall of the main cluster, then both databases and the user declarations will also be dumped.
Topic revision: 11 Feb 2011, SebastianHilbert
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback
Powered by Olark