Securing Passwords in settings.xml (MNG-553)

Goal

Provide a way for securing passwords in settings.xml, instead of just storing it in plain text.

Design

  1. Password Obfuscation
    1. Provide a plugin which a user can use to obfuscate their passwords and use this generated secured password in their settings.xml file.
    2. Implement reading of obfuscated passwords in Maven (plexus? or maven-core?)
      • add a flag/parameter to enable the use of obfuscated passwords in Maven during the build. Add an <obfuscation> parameter in the settings.xml, as suggested by Benjamin (see comment below). In this case, Maven would check first the value of this parameter and perform un-obfuscation to the password if specified.
      • or, use a keyword prepended to the password to tell Maven that the password is obfuscated (like what Jetty does). For example, <password>OBF:securedPassword</password> with 'OBF:' as the keyword.
    3. Prompt for a password if none is found in the settings.xml. Use a parameter like the --non-interactive flag of the maven-release-plugin in order to disable this. (Already handled by Wagon as pointed out by Brett)
  2. Password Encryption
    This can be implemented in two ways:
    1. Using a keystore for the server passwords
      1. Interactive:
        • Use plexus-password-store (http://svn.codehaus.org/plexus/archive/plexus-sandbox/trunk/plexus-components/plexus-password-store) to create the key store where the server credentials would be stored. Maven can also use this component for accessing the keystore as specified in the next point.
        • In Maven:
          • Add a parameter to tell Maven the location of the keystore. (Ex. -DkeystoreLocation=/path/to/keystore)
          • If the keystore location parameter is specified, Maven would disregard the <password> set in the settings.xml file (if there is any) and prompt for the master password of the keystore. The server credentials will be retrieved from the keystore if the entered master password is correct. Use the retrieved credentials to access the secured server.
          • Otherwise, use the <password> (if there is any) set in the settings.xml file. (Take into account password obfuscation here if it will be implemented.)
      2. Non-interactive:
        • Same implementation as 'Interactive', except that the master password for the keystore can be set via a command-line parameter instead of Maven prompting for it. The drawback here is that the master password would be in plain text.
    2. Using password-based encryption on the password in <settings.xml> (see Oleg's comment below)

Limitation(s)

Password Encryption:

  1. <password> in settings.xml would be disregarded if the server credentials would be retrieved from the key store.

References

Securing Passwords in Jetty

  • No labels

25 Comments

  1. Regarding the flag/parameter to enable obfuscation: How about just extending the settings model such that the user can control the obfuscation method per server, proxy etc:

     <server>
       <username/>
       <password/>
       <obfuscation/> <!-- possible value: "none" (default) and whatever other methods you can think up -->
       <privateKey/>
       <passphrase/>
       <filePermissions/>
       <directoryPermissions/>
       <configuration/>
       <id/>
     </server>
    

    The addition would require an update to Maven anyway so one could also update the settings parser.

  2. Would it be better to have a plugin instead of a utility JAR? That might be helpful to the Jetty folks too, so it'd be good to check in with them.

    I agree with either using OBF:* or the <obfuscatedPassword /> suggestion of Benjamin.

    I believe prompting is already handled by Wagon so isn't needed at this stage. This also means the implementation is probably all within the settings reader.

  3. I agree, adding an <obfuscation> parameter and using a plugin instead of a utility jar sounds reasonable. I've added these in the design doc above. I've also commented that the password prompting is already handled by Wagon. Thanks for your comments and suggestions..

  4. If it's not able pass the authentication, then assume that the password set in settings.xml is in plain text and try again

    Is that really necessary? I mean, once you have a dedicated parameter like <obfuscation> along the password string, why not trust its value? If it's not working, it's a misconfiguration by the user and he/she should fix it. So I believe a single attempt to authentificate is always sufficient. For the approach with "OBF:securedPassword", one wouldn't do this second trial either in case the first one failed, would one?

  5. Yes, it shouldn't. Sorry, I just forgot to remove that part in the design doc. I was originally thinking when I written the first draft that the parameter/flag that will be used is a command-line flag that would tell maven to un-obfuscate the password(s) in the settings.xml. I was considering the scenario of "what if not all the passwords were obfuscated" that's why I had that part in the doc. Anyway, what you suggested about adding an <obfuscation> parameter made much more sense..

  6. Note: The above proposal does not yet take into account what Oleg already implemented in plexus-cipher. Maybe he can shed some light where the plexus-cipher would fit in? (smile)

  7. What I did was:

    • implemented an encryption/decryption plexus component. It takes a string, encrypts/decrypt it using Bouncy Castle provider, and then encodes/decodes to/from Base64 string. I had to use BC because there was not reliable provider across multiple versions of Sun and IBM JVMs
    • extended settings reader and writer, so that when they meet encrypted password, in the file - trey decrypt it in memory. And when data was writted to settings.xml - it was intercepted and encrypted. This also required some modifications in maven-embedder, maven-core and maven-project
    • wrote a maven plugin that allows one to set/reset passwords in settings.xml, using plugin parameters.

    The encrypted password looks like this:

    <server>
      <username>oleg</username>
      <password>reset by maven-core on 2007-10-16 20:21:46 {CE3t8uA8j681QMI=}</password>
      <id>repo6</id>
    </server>
    

    It may take me a day or two to restore all these, all the pieces are here and there. As I was not a Maven comitter at the time - I could not put then all into Maven (sad)

  8. Ok, thanks Oleg (smile) I guess we can move the components into one location once you've located them and start from there?

  9. Maria, I found the maven plugin, and plexus-cipher. Those are the two big ones, we can change the rest really easy.

  10. I added maven-crypto-plugin to Sonatype.org SVN under plugins/trunk.

    My previous implementation details: I kept master password encrypted in the settings.xml. When thre was a need to use it, I first searched settings.xml for a dummy server id="dummy.master.server" and used that password as a master. Otherwise I asked user for it and stored it in settings before proceeding.

    I will check with my schedule if I can be available this week for this project. If I do - I will try to recreate my old code.

  11. Sorry Oleg, I'm a bit confused by your last statement... does this rewrite settings.xml with a password in plaintext?

    In some ways I like the simplified encryption handling proposed here - though the keystore has advantages too (for example, the ability to use the OS X keystore as someone pointed out in the issue, and not needing to deal with encrypted passwords at all). Without going overboard, being able to make the "provider" replaceable would also be important for consumers of the embedder, so the IDE integration can store passwords somewhere else, etc.

    Deng, what about the simpler obfuscated passwords as a simple first step - is that still being considered?

    BTW, Given the availability of the Maven 2.1.x branch now it'd be great to have this put into the core settings handling rather than having to configure a plugin, IMO.

  12. Unknown User (ddimitrov)

    Hello,

    I am not sure whether the current proposal addresses the following use cases, so I'm listing them here:

    1. Allow multiple encrypted passwords using assymetric key. This way, we can store the passwords for the whole team in the same file. Select the one to decrypt based on the logged in username. (requires changes to settings.xml)
    2. Allow passwords to be encrypted using master-password. Useful for official builds - the build environment is public, but only the people knowing the master-key can deploy to the release repo.
    3. Allow master password to be passed on the command line, read with no echo (e.g. using JLine) or read from stdin (e.g. CI redirecting a Solaris stream)
    4. In case the password decryption fails, transparently ask the user to input it (with no echo) unless a -Dnon-interactive has been specified on the command line. The prompt should come up only once per password per build.
    5. Allow password override from a command line (i.e. -Dservers.XXX.overridePass=<PROMPT> or -Dservers.XXX.overridePass=foobar)

    Probably #3, #4 and #5 can be somehow handled by the same VM options.

  13. Brett:

    does this rewrite settings.xml with a password in plaintext?

    The I propose to do it - no, it always keeps encrypted passwords in settings.xml and if there is a request for a password -it's intercepted, and, if password exists but is not encrypted, it gets encrypted. If it does not exist - user is prompted for one.

    Brett:

    BTW, Given the availability of the Maven 2.1.x branch now it'd be great to have this put into the core settings handling rather than having to configure a plugin, IMO.

    Plugin is necessary as it allows user manipulate those passwords - add/change them

    Brett:

    what about the simpler obfuscated passwords as a simple first step - is that still being considered?

    It's exactly the same amount of work because because encryption itself has already been implemented (same as the entire described encryption schema, by the way )

  14. The I propose to do it - no, it always keeps encrypted passwords in settings.xml and if there is a request for a password -it's intercepted, and, if password exists but is not encrypted, it gets encrypted. If it does not exist - user is prompted for one.

    Right... sorry if I'm being dense, but the two bits I don't get there are:
    1. "if password exists but is not encrypted, it gets encrypted" - that means it is in the settings.xml unencrypted, and gets encrypted and settings.xml gets written again?
    2. where does the master password get stored? It seems to be in plain text in a dummy server from the description (or prompted). This is the big question for me - how do we avoid having to type this too much, but still avoid opening it all up?

    Plugin is necessary as it allows user manipulate those passwords - add/change them

    Totally agree - I was thinking more of the "intercept" bit on loading/using the settings being built in

    Thanks!

  15. Dimitar - great questions.

    1. Allow multiple encrypted passwords using assymetric key. This way, we can store the passwords for the whole team in the same file. Select the one to decrypt based on the logged in username. (requires changes to settings.xml)

    settings.xml is by definition a single user's config. storage. I think more general approach would be a team server approach - minimum information is stored per user, the rest comes from an outside source, so that you don't have maintain 30 copies of any other configurations in the settings and yet preserve one settings.xml per user, but here it only stores passwords for this single user.

    2. Allow passwords to be encrypted using master-password. Useful for official builds - the build environment is public, but only the people knowing the master-key can deploy to the release repo.

    With the above approach env. does not have to be public, users have their individual passwords.

    3. Allow master password to be passed on the command line, read with no echo (e.g. using JLine) or read from stdin (e.g. CI redirecting a Solaris stream)

    I tried it - it's not portable across platforms, especially windows. Better option is standardize on, say, PGP and pass a master key ID from keyring

    4. In case the password decryption fails, transparently ask the user to input it (with no echo) unless a -Dnon-interactive has been specified on the command line. The prompt should come up only once per password per build.

    Agree, see my previous comment - answers to Brett

    5. Allow password override from a command line (i.e. -Dservers.XXX.overridePass=<PROMPT> or -Dservers.XXX.overridePass=foobar)

    Command line issue again - not portable. Better use PGP.

    Overall, again - great questions, those are the use cases I would like to address!

  16. Brett:

    1. "if password exists but is not encrypted, it gets encrypted" - that means it is in the settings.xml unencrypted, and gets encrypted and settings.xml gets written again?

    Yes, it does

    Brett:

    2. where does the master password get stored? It seems to be in plain text in a dummy server from the description (or prompted). This is the big question for me - how do we avoid having to type this too much, but still avoid opening it all up?

    In settings.xml - see one of my comments above - search by "master password encrypted". Each user has their own settings.xml and master password.

  17. Unknown User (ddimitrov)

    Hi Oleg, thanks for the answers.

    Just to clear it up:

    Dimitar: >> 2. Allow passwords to be encrypted using master-password. Useful for official builds - the build environment is public, but only the people knowing the master-key can deploy to the release repo.

    Oleg: With the above approach env. does not have to be public, users have their individual passwords.

    A company I worked in had a policy that all release build has to be made from specific account on specific machine. Everybody had access to the account, but only the release manager knew the password for the deployment connection. In such case, if we store the private key in the account's PGP keyring and the passphrase in the user's settings.xml file, then everybody would be able to upload/change the builds on the staging server.

    Does it make sense or is it an isolated case?

  18. Dimitar,

    In the setup you just described,

    1. I'd rather store key ID in the settings.xml and ask user for the key password on build invocation.
    2. Or - as you also described - have multiple instances of the master key, encrypted by individual user's asymmetric key (smile)

    The first one seems cleaner to me.

  19. Unknown User (ddimitrov)

    Oleg, I agree that #1 looks better to me as well.

  20. But all that nice group stuff is only possible if we standardize on something like PGP or Java sec - we need a standard security storage.

    PGP as OpenPGP is much more broadly used so to me it seem the only valid choice. GPG implements it, Bouncy Castle has it, I think it's a winner (smile)

  21. Hi Oleg, thanks for adding the maven-crypto-plugin (smile) I just have some questions about some of the things mentioned above:

    The I propose to do it - no, it always keeps encrypted passwords in settings.xml and if there is a request for a password -it's intercepted, and, if password exists but is not encrypted, it gets encrypted. If it does not exist - user is prompted for one.

    And if the password is encrypted, then ask for or get the master password to decrypt it and use the decrypted password to access the server?

    I kept master password encrypted in the settings.xml. When thre was a need to use it, I first searched settings.xml for a dummy server id="dummy.master.server" and used that password as a master. Otherwise I asked user for it and stored it in settings before proceeding.

    Sorry, I think I misunderstood this part.. I originally thought that the master password for decrypting the <server> password will always be prompted when Maven executes. In the above implementation, you mean the master password will be set as an encrypted password of another <server> entry in the settings.xml?

  22. If encrypted master password is in settings.xml, and secret material used to encrypt it is in the code - it's obfuscation, if we have external source for it (ask user, get from external keystore) - it's real encryption.

    Big problem with it - users run Maven tens and hundreds times a day, there is no way they will tolerate typing the password that many times, so - really - the only way to address this, is an OS session piggy back.

    As we also need be portable across platforms, solution seem obvious: either java keyring or adapter to existing keyring solution. Here - GPG's OpenPGP seem very attractive.

    Personally - I don't like JNI because of maintenance costs, so I am wide open to suggestions: how to store secret material in OS user session. Once we find solution - it's downhill from there.

  23. I've been looking for other alternatives on how or where we can store the master password and so far I have found none (sad) I have also been looking at the gpg-agent which is the one that caches the GPG passphrase.

  24. I am adding a solution to the above described problem to 2.1.x.

    I already implemented the encryption (AES 128, with SHA256-based PBE) as well as an IT for MNG-553. I will try to commit it today.

    Solution is the one I described at the beginning of this thread and implemented for 2.0.7 code base back in 2007. I now modified my code to account for the use cases described here and get rid of BouncyCastle provider, that was adding 1.6M to the footprint

  25. I updated MNG-553 with a short documentation of the solution