Friday, October 18, 2013

Signing maven releases with gpg while keeping your passphrase secure

On the road towards putting sample code into Maven Central I stumbled at GPG signatures of my artifacts. The problem was how to handle my passphrase.

The recommended solutions (one source of many) all had shortcomings:

  • Prompting for your passphrase is often unuseful and is broken when running maven in Cygwin.
  • Putting your passphrase on the command-line is visible to ps and is saved in history.
  • Putting your passphrase into {{settings.xml}} leaves it on disk.
  • Putting your passphrase on removable media and linking to it in {{settings.xml}} is awkward.
  • Using a gpg agent would be best, but I did get everything hooked up right; I should investigate further.
  • I will not even entertain removing the passphrase from my secrets just to satisfy maven.

A little think and some trial and error led me to:

  1. In pom.xml enable maven-pgp-plugin and configure maven-release-plugin:
    <plugin>
        <artifactId>maven-release-plugin</artifactId>
        <configuration>
            <arguments>-Dgpg.passphrase=${gpg.passphrase}</arguments>
        </configuration>
    </plugin>
  2. In settings.xml add a profile:
    <profile>
        <id>gpg-sign</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <gpg.passphrase>${env.GPG_PASSPHRASE}</gpg.passphrase>
        </properties>
    </profile>
  3. Write a small helper shell script:
    #!/usr/bin/bash
    
    read -er -p 'Passphrase: ' gpg_passphrase
    echo # Get back newline
    GPG_PASSPHRASE="$gpg_passphrase" exec "$@"

The key observation is that environment variables are private to the process, in memory and transient. I invoke thus:

$ ./rls mvn clean verify
Passphrase:
[INFO] Scanning for projects...

No comments: