Open Source Kerberos Tooling
Overview
Source
KNC
Kharon
krb5_admin
krb5_keytab
k5ping
lnetd
prefork

Overview

Kharon is a simple and lightweight Perl RPC library that provides tight integration with KNC as well as UNIX domain sockets and forked programs. It provides an OO model which can be conceptualised as remotely calling an object. It is mainly intended at the moment for relatively small client/server applications written to automate basic procedures. It is used as the basis of the OSKT Kerberos administrative tools krb5_admin and krb5_keytab.

It provides:

  1. automatic failover,

  2. server side redirection,

  3. marshalling and unmarshalling of relatively complex Perl data structures containing an arbitrarily nested list of scalars, undef, array refs and hash refs, and

  4. exception propagation.

In this document, we shall construct a simple example of using Kharon with KNC to write a very simple Kerberised client/server application in just a few minutes.

A Simple Example

The Object

In order to start with Kharon programming, the first thing that one wants to do is construct an object which will perform the functionality that is expected to live on the server. For our example, let’s consider a simple service based on the canonical OO tutorial object, the incrementer. We will add a couple of methods “complicated” and “exception” to demonstrate slightly more complicated data structures and exception handling. The use of the object should be relatively self-explanatory.

package Example::Eg1;

use strict;
use warnings;

sub new {
        my $self;

        $self->{num} = 1;

        bless($self);
}

sub inc {
        my ($self) = @_;

        $self->{num}++;
        undef;
}

sub query {
        my ($self) = @_;

        return $self->{num};
}

sub complicated {

        return ("foo", ["bar", "baz", {a=>'b', c=>'d', wow=>undef} ]);
}

sub exception {

        die "alkjsnckjsanclkjac";
}

1;

The Program

We can now write a simple program that uses our object:

#!/usr/pkg/bin/perl

use Example::Eg1;

use strict;
use warnings;

my $obj = Example::Eg1->new();

my $ret = $obj->query();
print "$ret\n";

$obj->inc();
$obj->inc();
$obj->inc();

$ret = $obj->query();
print "$ret\n";

$obj->complicated();

$obj->exception();

This program will output:

1
4
alkjsnckjsanclkjac at Example/Eg1.pm line 34.

Making our object into a daemon

So, far, though, we have not yet made a client/server application. All we have is an object and a program that speaks to it. What we’ll need to do now is make the object into a server. Here’s how we do it:

#!/usr/pkg/bin/perl

use Example::Eg1;

use Kharon::Protocol::ArrayHash;
use Kharon::ProtocolEngineServer;

use strict;
use warnings;

#
# Instantiate our object:

my $obj = Example::Eg1->new();

#
# Setup Kharon:

my $ahr = Kharon::Protocol::ArrayHash->new(banner => { version => '2.0' } );
my $pes = Kharon::ProtocolEngineServer->new($ahr);
$pes->Connect();

#
# And now ``Run the Object'', exporting the methods inc, query, exception
# and complicated:

$pes->RunObj(object => $obj, cmds => [ qw/inc query exception complicated/ ]);

This is a program that will interact on stdin/stdout in the following way:

dowdeslx $ ./daemon
220 . {version=2.0}
query
250 . 1
inc
250 . !
inc
250 . !
inc
250 . !
query
250 . 4
complicated
250 - foo
250 . [bar,baz,{wow=!,c=d,a=b}]
quit
220 . bye

As you can see, the protocol looks roughly like SMTP.

Running the daemon via KNC

If you do not have a keytab, you’ll need to get one:

$ krb5_keytab

And now that you have a keytab, you are good to go. You can use KNC to run the daemon. For this example, let’s use port 2666.

$ KRB5_KTNAME=/var/spool/keytabs/elric knc -l 2666 ./daemon

Now, you have a daemon that speaks the protocol that we discussed in the previous section.

Connecting to the daemon remotely via knc (interactively)

You can further test your daemon by connecting to it remotely:

$ knc elric@stormbringer.imrryr.org 2666

This is a useful thing to remember, because it can be useful when debugging to connect directly to your server and issue commands to it and see how it responds.

Making a client module

Now, we need to write a client module, let’s call it Example/Client.pm:

package Example::Client;

use Kharon::Protocol::ArrayHash;
use Kharon::ProtocolEngineClientKnc;
use Kharon::utils qw/mk_array_methods mk_scalar_methods/;

use Example::Eg1;

use strict;
use warnings;

sub new {
        my ($isa, @servers) = @_;
        my $self;

        my $ahr = Kharon::Protocol::ArrayHash->new(banner => {version=>'2.0'});
        my $pec = Kharon::ProtocolEngineClientKnc->new($ahr);

        $pec->SetServerDefaults({KncService=>'service1', PeerPort=>2666});
        $pec->Connect(@servers);

        $self->{pec} = $pec;

        bless($self, $isa);
}

eval mk_scalar_methods('Example::Eg1', qw/inc query complicated exception/);

1;

Changing our original program to be a client

We now have two objects defined in modules. The first Example/Eg1.pm provides our functionality and is used by the server side. The second Example/Client.pm has almost exactly the same interface as Example/Eg1.pm but when its methods are called it will marshall up the arguments and send them over the wire to the server which will execute the method and return the results.

So, we can rewrite our original program just adding:

use Example::Client;

And then modifying the instantiation of $obj from using Example::Eg1 to Example::Client:

my $obj = Example::Client->new('dowdeslx');

And now we have a Kerberised, mutually authenticated, encrypted, integral client/server application.

Caveats: What wasn’t properly covered

  1. talk about the banner.

  2. talk about future extensions.

  3. talk more about Client.pm.

  4. talk about ACLs, etc.

  5. talk about “Kharon::Protocol::foo”