Avisi Blog

JDBC datasource password encryption in JBoss AS7

Geschreven door Avisi | 10 June 2013

At Avisi we maintain an application platform where the platform (VM's, databases, LDAP, etc.) is maintained by a third party. Modernizing our deployment processes, we obtained ownership of the platform's configuration. This brought up a practical issue: we don't know the passwords used by the applications to connect to the services provided by the platform (database, LDAP). In fact, we aren't allowed to know these passwords since that would break the SLA with the platform provider.

 

Before, the platform provider would set the required credentials but since we're automating our build & deployment cycle (in fact, we're moving to Continuous Delivery) a manual step is something we want to avoid. Thus, the problem is quite interesting: Storing configuration which's actual values you don't know.

 

The solution is quite simple: symmetric encryption, where the key (or passphrase) is only present at the target machine. Since we don't have access to the target machines (we just deliver our deployment package), we're unable to read the encryption key. Encrypt once, decrypt often:

  1. The platform provider generates a key and stores it on the target machine. The actual key doesn't really matter much as long as:
    1. It's unknown by anyone except the platform provider.
    2. It's long enough.
    3. It can't be guessed (foobar isn't a very strong key).
  2. Ask the provider to encrypt the passwords and share them with you (please don't use e-mail).
  3. Configure your datasources using the encrypted passwords.
  4. Deploy your application, whenever a new connection is allocated the password will be decrypted.

 

Implementation

The full implementation would span a few pages, so to prevent you from getting RSI due to all that scrolling the basic outline is below.

 

if the underlying driver hasn't been created yet
     create the underlying driver
 
read the passphrase from the passphrase URL
decrypt the supplied password using the passphrase
delegate the properties and decrypted password to the underlying driver

 

You don't have to implement it yourself since we were so kind to provide you with both the source and packaged JAR (see 'Resources' section at the bottom of this post).

 

Deployment in JBoss AS7

Since this article is titled JDBC datasource password encryption in JBoss AS7, you'd expect us to tell you how to deploy it in JBoss AS7. Well, we will do so, in the snippet below. We're even so kind to provide you with a JBoss module which you can just extract and drop into your JBoss installation.

 

JBoss AS7 datasource configuration
< datasource jta = "false" jndi-name = "java:/jdbc/my-datasource" pool-name = "myDs" enabled = "true" use-java-context = "true" >
     < connection-url >jdbc:some-url</ connection-url >
     <!-- URL from which the passphrase/key will be read -->
     < connection-property name = "passphrase-url" >file:/path/to/encryption/key.txt</ connection-property >
      <!-- Underlying JDBC driver class -->
     < connection-property name = "driver-class" >com.mysql.jdbc.Driver</ connection-property >
     < driver >encrypted</ driver >
     < pool >
         < min-pool-size >1</ min-pool-size >
         < max-pool-size >5</ max-pool-size >
     </ pool >
     < security >
         < user-name >my-user</ user-name >
         <!-- This password is encrypted -->
         < password >my-encrypted-password</ password >
     </ security >
</ datasource >
...
< drivers >
     <!-- Here you define your custom JDBC driver -->
     < driver name = "encrypted" module = "nl.avisi.jdbc:main" >
         < xa-datasource-class >nl.avisi.jdbc.EncryptedPasswordDriver</ xa-datasource-class >
     </ driver >
     ...
</ drivers >

 

Limitations

Since this generic delegating JDBC driver doesn't know about its underlying driver until connect() is invoked, it won't be able to provide information regarding its version, JDBC compliance and supported JDBC URLs (which is required for using the DriverManager). Thus, a more refined version would implement driver-specific flavors which could delegate all invocations to its underlying driver, which might be required by your application of choice. That's up to you to implement.

 

Hints

  1. You can generate a passprase or key using the openssl tool:
    $ openssl rand -base64 50
  2. Don't forget to provide the actual JDBC driver (MySql in the example) to the application server along with your custom driver.
  3. This solution doesn't limit itself to JDBC drivers, of course. We use it for any credential which we aren't allowed to know.

 

Resources

  1. Download source code (Maven)
  2. Download JAR packaged JDBC driver