Saturday, November 3, 2007

Informix user authentication: PAM for the rescue (part 1)

Traditionally IDS authentication relyied only on the base OS. This approach has a few advantages, like simplicity and security, but currently can be considered too limited.

In todays environment most customers prefer to have a centralized user management facility, normally an LDAP server or an Active Directory server.
By the time IBM launched 9.4 this was already evident, so IBM had to do something to bring other forms of authentication to IDS. It could have followed other vendors approach like explicitly including code to authenticate on an LDAP server or even integrate this authentication with other IBM products like Tivoli's Identity Manager. This would probably lock the customers to IBM products like other vendors have done for their products.
IBM choice was better, in my opinion, since it was decided that the best option would be to take on an independent authentication mechanism that already existed and that allows the user to choose where and how he wants to have his authentication facilities. This mechanism is PAM and it appeared in IDS 9.40.UC2. First it was limited only to a few platforms and to 32bit IDS versions. Currently it is supported in both 32 and 64 bits in all major platforms (AIX, HP-UX, Solaris and Linux - Windows allows AD authentication)

In this article I will try to show how simple it is to use it, and specially the power and flexibility you'll gain by implementing this. There are still a few annoyances but they should be fixed in a near future. I will also include a step by step tutorial on how to setup an IDS instance to use an AD or OpenLdap server as it's authentication infra-structure.

So, this is a long and eventually a bit complex article. I'd advise you to read it slowly and if you're interested by the subject try to mimic the tutorial so you can gain hands on knowledge on these areas.

Let's start by a brief introduction of PAM. The acronym stands for Plugin Authentication Module. It's no more than a framework that allows independence between the applications that need the authentication services (in our article, this will be IDS) and the infra-structures that provide them (OpenLDAP or Active Directory). The applications have a set of well known functions that request authentication, and the PAM framework allows communication between requesters and providers, using modules that implement them.
In practice the implementations are made in modules, where each one implements a set of the functions specified in the PAM framework. This modules must be specified in a configuration file by the administrator and you can combine the modules you need, so that you achieve the desired goal. A set of modules that you define as the needed set to achieve your purposes (for authentication of IDS users for example) must be identified by a unique service name.
This service name is then used to instruct the application which modules it will use. In some OS this service name will be a field in an unique, system wide, text configuration file, while in others it will be the name of a file located in a specific directory (usually /etc/pam.d). We'll see several examples further ahead...

This modules can be stacked, and each module will be used in sequence. Each module will validate in a specific authentication system. For example, there are modules that talk to LDAP servers, another validate if the user is or is not specified in a file, other checks the hour and decides if the user is able to authenticate at that time, other emulates the hosts.equiv/.rhosts mechanism and there are even several modules to check the users against different RDBMS (including Informix)
When we specify the sequence of modules in a configuration file we have to specify the following:

  1. The area of funcionality.
    Can be "authentication", "account", "session" or "password". This indicates the type of function that we'll request from the module:
    1. "authentication" deals with the operations that guarantee the user is who he says he is
    2. "account" defines if the user account is valid under the circumstances (the account can be blocked, refused at specific times etc.)
    3. "session" implements functionalities like logging etc
    4. "password" deals with credential management like password changing
  2. The module control flag. Can be "required", "sufficient", "optional" or "requisite". This defines the influence that this module will have on the stack of modules. In other words you can define one module as:
    1. "sufficient" for the authentication functionality
      a success on this module will imply a success on the authentication funcionality
    2. "optional"
      it's result won't influence the final functionality result
    3. "required"
      a failure in it will cause a failure in the functionality, but all other modules will be called
    4. "requisite"
      a failure in it will cause a failure in the functionality and the error will be reported immediately without calling the other modules in the stack
  3. The module name
    The modules are usually supplied in dynamic libraries. Some OS require the specification of the filename with extension (e.g.: pam_ldap.so) while others will require the name without extension (e.g.: pam_ldap)
  4. The module parameters
    These are optional and completely dependent on the module. The administrator will have to check in the module documentation in order to learn what parameters are available and what they mean
The whole purpose of using PAM is to gain flexibility and reduce management tasks. Let's see some things we can accomplish by using PAM authentication:

  • Avoid the usage of multiple user passwords and/or password synchronization between systems
  • Accomplish complex authentication requirements like "allow users from that server, but not from the other", "allow users only within normal business period", "allow these users for instance A, and that users for instance B, assuming A and B are running in the same database server
  • Authenticate users against data stored in a database table (possibly encrypted)
  • Avoid the usage of trusted relations between servers (more on this below)
  • Quickly stop a user from connecting without having DBA or system administrator privilege: Usually you can do this by revoking connect, or blocking the user account. For the first you must be DBA on the specific database and the second requires system administration privilege. If you're just DBSA (and not necessarily DBA in every database) you can setup PAM to refuse users that exist in a specific file (which you can own)
  • Create your own PAM module that reacts to whatever you want. You may be surprised by the simplicity of PAM API. Although there is a lot to consider (stability, performance, security) before you jump into writing your own modules, this is a real option. You can write modules that react to system load, that handle user priorities (only privilege users can connect if system is overloaded), that check for too many connections from the same user etc. I'd say that with PAM the limit is not the sky, but your needs. It's so flexible you can do whatever you want with it.


Let's move on to the tutorial. I think this is the best way to explain how this works. What I will show you is an implementation of IDS PAM authentication against an Active Directory structure. The steps are very similar (on IDS side) if you want to authenticate against an LDAP server. Both the AD server and the IDS server will run in a virtual machine environment. The concerns here were mainly functional. In a real situation you should be much more worried with security.

First, we'll need a MS Windows server with active directory running and also services for Unix running. For simplicity sake and given this is for test purposes I choose to run it in a virtual machine environment. You'll need a virtual machine software like VMware or Virtual PC. Since the Windows Server image I used has a license that prevents convert it from VHD format I've used MS Virtual PC. You can get a working environment for testing purposes (during 30 days) here: http://www.microsoft.com/downloads/details.aspx?familyid=77f24c9d-b4b8-4f73-99e3-c66f80e415b6&displaylang=en..

After downloading the two files run the exe to uncompress it to a folder. This will be your virtual server installation. Then, assuming you have Virtual PC installed you can configure a new VM and start it. I'll assume you know how to do this or will be able to get help elsewhere.
The first time you launch it, Windows will configure several components. First you should add a role (a wizard will appear). Follow the steps as shown below. This will add Active Directory support on your new Windows 2003 server with very loose configuration... The purpose here is just to create something that runs... Not something efficient or very secure. Most of the times the AD infra-structure will already be there on your company or your customer's companies:
Role WizardStart the Wizard...
Choose Server RoleChoose to add Domain Controller roles
Create a new domainChoose to create a new domain...
New domain in a new forest...in a new forest
DNS name for new domainChoose a DNS name for the domain...
Domain NetBIOS name... and a Windows (NetBIOS) name
Database and log filesJust accept the defaults
Shared System VolumeAgain, use the default
Possible DNS problemsIf the Wizard informs you of DNS problems choose to solve them ater
Permissions for allThis shouldn't make difference, but choose the most compatible option
A password for restore modeYou won't need to remember it
Final confirmationAll set...
Installation runningRunning...
Installation completeHopefully you'll see this
And the typical rebootThis is windows...

Important: Be sure to setup your network correctly between the host and the virtual Windows 2003 server. Because I was using Virtual PC I installed MS loopback adapter. If you're following this tutorial be sure to know or find someone who knows how to configure all this. This is beyond this article's scope, so I'll just assume you were able to setup it, or you have access to a working active directory infra-structure.

Next we'll need an add-on for AD, Services For Unix. It's available here: http://www.microsoft.com/downloads/details.aspx?familyid=896c9688-601b-44f1-81a4-02878ff11778&displaylang=en

It's an exe file that you should run to unzip it to a temporary installation folder.
Be sure that you download it withing your Windows VM or you make it accessible to it. Then just run setup.exe (in the VM Windows 2003) and follow the instructions below:


SFU installation: Step 1Choose standard installation
Security optionsSecurity Settings. Mark them both, although it should not make any difference
User name mappingChoose local user name mapping in local files
Choose local filesIf you want to migrate user information from an existing system, put the passwd and group file in the windows machine and give the full PATH here. If not, just leave them blank


The installation should complete without any issues and the traditional reboot will be required.
By now you are ready to create a user for IDS authentication and to make IDS configuration adjustments to provide PAM capability to one of the IDS instance DBSERVERALIAS.
But let's complete our tasks on the Windows side. We should create a group and a user. Don't forget to add the Unix Attributes (provided by SFU extension) or it won't work. First open "Active Directory Users and Computers" in the "Administrative Tools" option on the Start menu.
When the interface appears expand the domain name you created. On the tree click on "Users", and use right mouse button to select New -> Group. I choosed to call it "linux", but it's your choice of course. What you must do is activate it's UNIX Attributes:

Group propertiesCreate a group and fill it's UNIX attributes


Then create a user (right mouse button, New -> User):

User  creationCreate a user. Remember to uncheck the option to force password change on next login
User UNIX attributesFill it's UNIX attributes. pam_ldap will need this info



This should end our Windows side tasks. Remember to check the network settings. I had to turn off the Windows firewall.
Let's now see what must be changed in the IDS side. I've used IDS 11 on a Linux VM, but it should not make any difference if you try with one of the latest (UC5+) version 10 releases.
Follow this steps:

  1. Alter $INFORMIXDIR/etc/$ONCONFIG to add a PAM enabled DBSERVERALIAS:

    DBSERVERALIASES cheetah_pam,cheetah_drda # List of alternate dbservernames


  2. Alter $INFORMIXSQLHOSTS to configure the service:

    cheetah_pam onsoctcp pacman.onlinedomus.net 1531 s=4,pam_serv=(ids_pam_service),pamauth=(password)


    Please note the changes:
    1. s=4
      means you'll use PAM on this service.
    2. pam_serv
      specifies the name of the PAM service you'll use. We have to configure this in the PAM files (done below)
    3. pamauth
      chooses the kind of authentication you'll use. It can be password or challenge response. For now, let's use the usual user/password method.
This is enough for IDS side, but now comes the fun part: The configuration of the PAM system to answer requests from IDS.
My experience tells me that it's here that most of the issues will happen. Anybody trying to setup IDS to use PAM should try to really understand how PAM works. The fact is, most of the problems will be around this, but the error message returned by IDS will almost always be the same. So, if you don't have some knowledge about PAM, or don't have a collaborative system administrator (where are they when we need one?) you could end up loosing lots of time here. And sometimes it will be difficult for IBM Informix support to help, because some details will vary with the OS you're using and specially the PAM modules.

For our tutorial we'll be using pam_ldap module running on Linux. This module will allow authentication against a LDAP server (AD is a LDAP server). This version of Linux (Fedora) uses a file for each PAM service and this files are located in /etc/pam.d

Since we specified ids_pam_service in $INFORMIXSQLHOSTS, we must create a file called /etc/pam.d/ids_pam_service with the following lines:

auth required pam_ldap.so config=/etc/ids_ldap.conf
account required pam_permit.so


This means the authorization will be done by pam_ldap.so module, using a configuration file called /etc/ids_ldap.conf and that the account services will be handled by a very simple module called pam_permit.so. The use of this later module means we will not put any restrictions on the account validation.
So, as you probably expect, we have to create a file called /etc/ids_ldap.conf.
My has the following (adjust to your environment):

#Host name or IP address of the LDAP/AD server. MUST CHANGE!
host 192.168.131.2
#Base structure in the tree where the users are located. MUST CHANGE!
base CN=Users,dc=onlinedomus,dc=net
#Name of the user that connects to the LDAP/AD. MUST CHANGE!
binddn CN=Administrator,CN=Users,dc=onlinedomus,dc=net
#Password for LDAP connection (should obviously be encripted and connection should be done through secure communication)
#MUST CHANGE!
bindpw Evaluation1

#Some more parameters. DON'T NEED TO CHANGE
nss_initgroups_ignoreusers root,ldap
pam_login_attribute sAMAccountName
pam_filter objectclass=User
nss_base_passwd cn=Users,dc=onlinedomus,dc=net
nss_base_shadow cn=Users,dc=onlinedomus,dc=net
nss_base_group cn=Users,dc=onlinedomus,dc=net
nss_map_attribute uidNumber msSFU30UidNumber
nss_map_attribute gidNumber msSFU30GidNumber
nss_map_attribute cn sAMAccountName
nss_map_attribute loginShell msSFU30LoginShell
nss_map_objectclass posixAccount User
nss_map_objectclass shadowAccount User
nss_map_attribute uid msSFU30Name
nss_map_attribute userPassword msSFU30Password
nss_map_attribute homeDirectory msSFU30HomeDirectory
nss_map_attribute homeDirectory msSFUHomeDirectory
nss_map_objectclass posixGroup Group
pam_login_attribute msSFU30Name
pam_filter objectclass=User
pam_password crypt


We will need one final step, and this leads us to the biggest inconvenient of IDS PAM usage:
Currently, IDS requires the user to be known by the underlying OS.
This apparently contradicts the whole idea of using PAM, but there are reasons for this, and ways to reduce the inconvenient. First let's understand the reasons why this is still a requirement:
  • Contrary to other databases, when you interact with the OS as a consequence of running a procedure (SYSTEM command) or a function (Some external function written in C or Java for example), IDS will use the real user identity. If you're connected as pamuser and execute a stored procedure with a SYSTEM command in it, the command specified as SYSTEM argument must be run as user pamuser. So, in order to accomplish this, the user must exist in the OS context.
  • When you activate the SET EXPLAIN in a remote (from another host) connection, IDS will try to create the sqexplain.out file in your user's HOME directory. This is impossible if the user does not exist.
So, these are at least two reasons for this inconvenient behavior. Does this mean that the use of PAM is worthless? By no means in my opinion and this is why:

  • Although you may need to create the user in the OS, the user can be locked, or have an unknown password, of have /bin/false as it's SHELL ect. So, although it logically exists it won't be able to connect or do anything in the database server
  • Having an external authentication method (like AD) means you don't have to manage or synchronize different passwords.
  • Currently you can configure most of the operating systems to use external LDAP users. So, by creating the user in the LDAP server you can also make the OS know about it. It may avoid an extra step to create the user in multiple machines
  • With PAM you can combine several modules to gain incredible flexibility in user authentication. You may refuse connections at certain times, or you may refuse connections based on certain files, or allow one user in an instance, but not in another running on the same machine etc. You can't have this power with simple user authentication.

Besides all these reasons, IBM is working on a solution for this issue. In the future, you'll be able to use PAM and don't have the user recognized by the OS. IBM will make some changes to avoid or control the issues above. I cannot give you any time frame, but this will happen. IBM development and product management team understand that this is a caveat that shouldn't exist.

So, for now, we have to create a local user called pamuser. Let's lock it's account and give him the /bin/false SHELL:

useradd pamuser
usermod -L -s /bin/false pamuser


Now everything is ready. Let's start dbaccess to test it. Make sure you choose connect from the menu. We will need to provide a user and password after choosing the correct INFORMIXSERVER (cheetah_pam).
If everything works correctly you should see the list of databases. Any problem will raise an error:

1809: Server rejected the connection.

And this is the second problem that exist in IDS PAM authentication. The error message(s) is almost useless. To be honest, there isn't much IDS can do to help... If an error happens in the PAM stack it's hard for the application to get the error. It may depend on how the module was coded, what kind of authentication is being done etc.
Your best bet is to check if the module(s) you're using have any kind of debug you can use. There are even some modules that don't do nothing except log the state of the authentication at the time they're called. I'm repeating myself, but to use this technology you really must try to understand PAM itself. The possibilities are enormous, but this framework may be complex to use.

This ends the first part of this article. But there is still a lot to talk about:
  • What is challenge/response and why do you need to know about it (or how can I use "implicit" connections like in 4GL and ESQL/C with PAM)
  • How do we configure the instances for distributed queries (or how do I get rid of /etc/hosts.equiv and .rhosts)
  • What more IBM needs to improve (it's great, but not yet perfect...)
So, there will be at least one more article about this, but possible two.
Until then, if you're interested in this, try to replicate the above tutorial or set it up in your test environments. If you have any trouble of find any error in the steps above please, don't hesitate to contact me.

References:

No comments:

Post a Comment