Signing Artifacts for Publishing to Maven Central Repository
Introduction
If you are the author or maintainer of an JVM-based Open Source software, chances are you publish it to the Maven Central repository so that automated build tools can download it. With the recent decommissioning of JCenter and Bintray, Maven Central is pretty much the only game in town.
Problem Statement
Artifacts to be published to Maven Central must meet certain requirements, one of which is accompanying PGP signatures. Users of your library might want to verify these artifacts’ PGP signatures against a public key server. Several plugins are available for popular build tools like Maven, Gradle and SBT that attempt to make the publishing process less painful, but as far as I am aware, they all leave the signing part up to the user. In this article, I will lay out the exact steps needed for generating a PGP key pair, and a Gradle example of using them to sign the artifacts. Having generated the keys, they can be used by any build tool.
A PGP signature can also be used for signing commits and tags on GitHub.
Requirements
The only thing you will need other than a computer and an internet connection is Docker engine installed. For Windows and Mac, you can install Docker Desktop.
Steps
- Run an Ubuntu container.
docker run --rm -it -v $(pwd)/.gnupg:/root/.gnupg -e GPG_TTY=/dev/console ubuntu bash
- Install GnuPG, which is an implementation of the Open PGP standard.
apt update && apt install -y gnupg
- Generate a GPG key pair. Because of the Docker volume mapping, the generated keys are stored in the
.gnupg
directory in your home directory.gpg --full-generate-key
- At the prompt, specify the kind of key you want, or press Enter to accept the default RSA and RSA.
- Enter the desired key size. I recommend at least 4096 bits.
- Enter the length of time the key should be valid. Press Enter to accept the default selection, indicating that the key does not expire.
- Confirm that the key does not expire by entering ‘y’.
- Enter your full name.
- Enter your email address.
- Enter a comment, or press Enter to skip.
- Verify that your selections are correct. Enter ‘O’ (Upper case O) to proceed.
- Type a secure passphrase. If you enter a weak passphrase, you will be asked to confirm it.
- Retype the passphrase.
- Use the following command to list GPG keys for which you have both a public and private key.
gpg --list-secret-keys --keyid-format SHORT
The last few lines will be similar to the following. The key id/fingerprint is the 40-character string on the second line of
sec
. The last 8 characters (shown on the first line afterrsa3072
,9D397642
in the example below) are sufficient to uniquely identify the key, and is referred to as the<key id>
in the following steps.sec rsa3072/9D397642 2021-04-04 [SC] C49D1269413357A989292F0BBED9F87D9D397642 uid [ultimate] John Doe <johndoe@nowhere.com> ssb rsa3072/AD77D767 2021-04-04 [E]
- Upload the public key to a key server; Maven central uses hkp://keyserver.ubuntu.com.
gpg --keyserver hkp://keyserver.ubuntu.com --send-keys <key id>
Optionally, convert the secret key to a Base64 encoded format with no line breaks. This is required because a lot of public CI servers will allow the secret key to be set as an environment variable, and the line breaks and special characters in the secret key are not compatible with an environment variable.
gpg --armor --export-secret-keys <key id> | base64 -w0
If you are using Gradle, you can use the Signing plugin along with the keys to sign the artifacts, as shown below (using Kotlin DSL):
fun base64Decode(prop: String): String? {
return project.findProperty(prop)?.let {
String(Base64.getDecoder().decode(it.toString())).trim()
}
}
signing {
useInMemoryPgpKeys(base64Decode("signingKey"), base64Decode("signingPassword"))
sign(*publishing.publications.toTypedArray())
}
signingKey
and signingPassword
are project properties that are set from the corresponding environment properties.
Conclusion
And there we have it, a complete recipe for generating a PGP key pair, and a Gradle example of using them to sign the artifacts.
Leave a comment