23

I am trying to do a maven deploy via GitHub actions and i am getting the below error:-

gpg: directory '/home/runner/.gnupg' created
gpg: keybox '/home/runner/.gnupg/pubring.kbx' created
gpg: no default secret key: No secret key
gpg: signing failed: No secret key
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  13.272 s
[INFO] Finished at: 2020-04-06T12:18:44Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-gpg-plugin:1.5:sign (sign-artifacts) on project pretty-simple-jar: Exit code: 2 -> [Help 1]

I understand that I need to somehow import my gpg secret key in the virtual runner where the actions workflow is running, but i cannot figure out a way to import my secret key in the virtual runner via the GitHub actions workflow ?

Below is my workflow:-

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Maven Central Repository
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Display settings.xml
        run: |
          echo "<settings><servers><server><id>ossrh</id><username>${{ secrets.OSSRH_USERNAME }}</username><password>${{ secrets.OSSRH_TOKEN }}</password></server></servers><profiles><profile><id>ossrh</id><activation><activeByDefault>true</activeByDefault></activation><properties><gpg.keyname>${{ secrets.GPG_KEY_ID }}</gpg.keyname><gpg.passphrase>'${{ secrets.GPG_PASSPHRASE }}'</gpg.passphrase></properties></profile></profiles></settings>" > /home/runner/.m2/settings.xml
          cat /home/runner/.m2/settings.xml
      - name: Build Maven Project
        run: mvn clean install
      - name: Publish to Apache Maven Central
        run: mvn deploy
Rishab Prasad
  • 771
  • 1
  • 8
  • 21
  • Check out this [article](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) by GitHub on using secrets – Madhu Bhat Apr 19 '20 at 16:00

5 Answers5

32

As GitHub Actions is basically a container that runs commands, have you considered define your key as a secret on your project and then importing it in your Github Action definition?

Here are the steps I previously used on a project to publish the generated artifacts to Sonatype's staging repository:

  • Open a terminal window.
  • If you don't know your key ID, search it by e-mail: gpg --list-secret-keys user@example.com
  • Export your key as Base64: gpg --export-secret-keys YOUR_ID_HERE | base64 > private.key
  • In your Github project, create a new Secret named GPG_SIGNING_KEY and paste the Base64 content of your key.
  • In your yml workflow file, include a step to import the key from your just defined secret.
- name: Configure GPG Key
  run: |
    echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
  env:
    GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}

So far, it works very well although there are a few limitations I couldn't solve:

  • Your GPG Key should not be protected by a password. I couldn't figure out a way to import the protected keys without being asked for their secret.
  • I couldn't find a way to use my GitHub GPG Key for this process.

Just in case, here is a working example of a project using this approach to publish Maven artifacts. The only difference from the steps above, though, is that the commands were externalized into a bash script file.

user672009
  • 4,379
  • 8
  • 44
  • 77
Miere
  • 1,495
  • 2
  • 19
  • 24
  • Just try "gpg --batch --import ~/.gnupg/private.key" for password-protected keys. I assume you don't need the password to import it, just to use it later on. – André May 20 '20 at 22:44
  • Thanks for your reply, worked well for me. To add the password, I've just used this reply instead of your 3rd run line: echo your_password | gpg --batch --yes --passphrase-fd 0 your_file.gpg https://unix.stackexchange.com/questions/60213/gpg-asks-for-password-even-with-passphrase – eduardohl Jan 02 '21 at 23:20
19

Thank You everyone for your response. I now use this GitHub actions which makes the process much more simpler:

Step 1: Extract the secret key

gpg --list-secret-keys --keyid-format LONG
gpg --export-secret-keys --armor {your_keyId}

Step 2: Store the extracted GPG key and passphrase as secrets

step 3: Include this step in your workflow

- name: Import GPG Key
  uses: crazy-max/ghaction-import-gpg@v1
  env:
     GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
     PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
cokeman19
  • 2,405
  • 1
  • 25
  • 40
Rishab Prasad
  • 771
  • 1
  • 8
  • 21
  • How could you use `--export-secret-keys` without a passphrase. I am unable to find a way to export the private key in workflow. it stuck at passphrase. – vgdub Jan 20 '23 at 06:31
  • Storing them will create the `.kbx` file in runner VM but if you have a passphrase you won't be able to use it ? – vgdub Jan 20 '23 at 06:32
  • You need this passphrase to export it. You defined the passphrase during creation of the key and without it, you won't be able to perform deployment. – Piotr Wittchen Mar 10 '23 at 11:19
18

Adding a new answer, since this question is about using the GPG key in maven deployments in particular.

No manual import is required when using Maven

In the meantime, the setup-java action supports everything out of the box. There is an example in the docs:

    - name: Set up Apache Maven Central
      uses: actions/setup-java@v3
      with: # running setup-java again overwrites the settings.xml
        java-version: 8
        distribution: 'temurin'
        cache: 'maven'
        server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml
        server-username: OSSRH_USERNAME # env variable for username in deploy
        server-password: OSSRH_TOKEN # env variable for token in deploy
        gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
        gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase

    - name: Publish to Apache Maven Central
      run: mvn deploy
      env:
        OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
        OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
        MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

Note that the setup-java action configures Maven's settings.xml file for you automatically and imports the GPG key from the given stored secret.

Be aware, that during setup-java you only configure the names of the environment variables. I.e. you need to provide the (secret) values for these env variables in later steps, where you want to use them.

Sebastian S
  • 4,420
  • 4
  • 34
  • 63
  • Tip: If your environment name is not the default, its important to set the property environment in the script or you will get the error of "No secret key" without any aparent error on the process. – Dubas Feb 23 '22 at 16:25
  • 1
    @Dubas I have that problem. What do you mean by default environment name? How and where I should set the property environment? – Piotr Olaszewski Jul 14 '22 at 22:17
  • @Piotr Olaszewski At your project Settings > Environment. The default environment is called "main" if you create an environment with other name you need to specify it in the script – Dubas Aug 10 '22 at 07:48
2

You can also use another plugin https://www.simplify4u.org/sign-maven-plugin/ for signing artifacts.

sign-maven-plugin simply takes signing key and rest configuration items from environment variables without special configuration.

Another advantage of sign-maven-plugin is that you need not use profiles for activate or deactivate plugin, because when signing key is not preset for plugin, plugin skip execution without error.

Slawomir Jaranowski
  • 7,381
  • 3
  • 25
  • 33
0

I came up with the following solution (see here)

steps:
  - name: Import GPG key
    run: echo $GPG_KEY | base64 --decode | gpg --batch --import
    env:
      GPG_KEY: ${{ secrets.GPG_KEY }}

  - name: Add the custom gpg siging program that passes the passphrase to the gpg CLI
    run: |
      rm -rf /tmp/gpg.sh
      echo '#!/bin/bash' >> /tmp/gpg.sh
      echo 'gpg --batch --pinentry-mode=loopback --passphrase $GPG_KEY_PASSPHRASE $@' >> /tmp/gpg.sh
      chmod +x /tmp/gpg.sh

  - name: Setup git
    run: |
      git config commit.gpgsign true
      git config user.signingkey $GPG_KEY_ID
      git config gpg.program /tmp/gpg.sh
    env:
      GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
Newbie
  • 1
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 02 '23 at 00:46