There are situations in which you want to use your own Artifactory server for resolving Maven dependencies. Maybe you have private artifacts or are not yet in the process of migrating from Artifactory to GitHub Packages.

What is the goal of this blog post?

This blog shows you how you can grant your GitHub Actions CI/CD pipeline access to your private Maven repository hosted with Artifactory. My requirements have been the following:

  • In our GitHub Actions build process, download dependent libraries from our internal Artifactory server.
  • Only allow access to a single Maven repository in our Artifactory instance but not all of them.
  • Don’t create any additional CI/CD users in Artifactory or downstream user directories.

After reading through Artifactory’s documentation, I realized that I could use a transient user in Artifactory. This concept is explicitly designed for CI/CD processes.

Restrict access by creating a group in Artifactory

For security reasons, I only wanted to give access to one of our Maven repository in our Artifactory instance but not all. Transient users are not visible in Artifactory. So I had to create a specific group which can be used for permission mapping.

Create the new group at Admin > Security > Groups > New. You can use any name you want, but you need to note it. The group name (${ARTIFACTORY_GROUP_NAME}) is required in the next step.

Add a new group in Artifactory

After that I had to assign the proper permission to the newly created group. Navigate to Admin > Security > Permissions > New and select the proper repository on the Resources tab. On the Group tab, you have to select the recently created group and check the Read checkbox in the Repository Actions panel.

Grant read permissions for repository in Artifactory

Generate an access token in Artifactory

As already mentioned, the access token is used by GitHub Actions to gain access to the Artifactory server.

The Artifactory documentation does not explicitly mention it but you have to generate the access token with help of an API request. There is (seemingly?) no way to generate a normal access token through the web user interface. As written in the Artifactory REST API documentation, you need to call the Create Token endpoint.

On the command line, request a new token by calling

curl -u "${USERNAME}:${PASSWORD}" -XPOST "https://${ARTIFACTORY_HOST}/artifactory/api/security/token" \
  -d "username=github-actions" \
  -d scope="member-of-groups:${ARTIFACTORY_GROUP_NAME}" \
  -d expires_in=0

Replace the ${…} variables with the appropriate values.

  • The username variable only exists for convenience reasons. There is no need that the user itself exists. It is just important that member-of-groups points to our previosuly created group.
  • With expires_in you can set the expiration of the access token in seconds. A zero means no expiration is set.

Artifactory will respond with a body like this:

200
{
   "access_token":   "xajajaajajajaja...",
   "expires_in":    0,
   "scope":         "api:* member-of-groups:ci-cd",
   "token_type":    "Bearer"
}

Note the content of the access_token field (${ARTIFACTORY_ACCESS_TOKEN}). This is needed in your GitHub Action and pom.xml.

Configure your Maven project

Your Maven configuration has to be changed so GitHub Actions uses your Artifactory server.

Update your pom.xml

To make external dependencies more obvious, I decided to put the private repository in our pom.xml. You can alternatively skip it and use the settings.xml. But I’d recommend it this way: new developers will see during the checkout that this repository must be configured just by looking at the POM.

Just add the URL of your Artifactory’s repository URL to the pom.xml:

...
	</dependencies>
	<repositories>
		<repository>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
			<id>artifactory</id>
			<name>my-repo</name>
			<url>https://${ARTIFACTORY_HOST}/artifactory/my-repo</url>
		</repository>
	</repositories>
...

Note the name of the artifactory server id (<id>${MAVEN_SERVER_ID}</id>).

Test the access token by putting it in your local settings.xml

In your settings.xml (e.g. ~/.m2/settings.xml), you have to add a new server:

    <servers>
            <server>
                    <id>${MAVEN_SERVER_ID}</id>
                    <username>github-actions</username>
                    <password>xajajaajajajaja...</password>
            </server>
    </servers>
  • Replace ${MAVEN_SERVER_ID} with the id you have previously used in your pom.xml
  • Update the content of the password element with the ${ARTIFACTORY_ACCESS_TOKEN} value.

When you run mvn package, your Artifactory server should be used to download the private dependencies.

Configure GitHub Actions

Add secrets for the workflow

In your GitHub project, navigate to Settings > Secrets and add two new secrets:

  • ARTIFACTORY_TOKEN with the content of your ${ARTIFACTORY_ACCESS_TOKEN}
  • ARTIFACTORY_USERNAME with any content (see transient user above); for convenience reasons I suggest you are using the same username you have already used in the curl command.

After adding both environment variables, your Secrets page should look like the following:

Secrets in the GitHub project

Configure the GitHub Actions workflow

The action/setup-java action already contains the required workflow modifications. The action allows us to add a custom repository to the settings.xml. Customize your GitHub Actions workflow like this:

name: Build Dreitier

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8

    - name: Set up our custom Artifactory instance
      uses: actions/setup-java@v1
      with: # running setup-java again overwrites the settings.xml
        java-version: 1.8
        server-id: artifactory # value of repository/id field of the pom.xml
        server-username: ARTIFACTORY_USERNAME_REF  # env variable name for username of Artifactory server; value can be anything as it is a transient user
        server-password: ARTIFACTORY_TOKEN_REF # env variable name for Artifactory access token
        # after running this action, the <username> tag contains ${env.ARTIFACTORY_USERNAME_REF} and <password> contains ${env.ARTIFACTORY_TOKEN_REF}

    - name: Build with Maven
      run: mvn -B package
      env:
        # assign the environment variable env.ARTIFACTORY_TOKEN_REF with the previously configured ARTIFACTORY_TOKEN
        ARTIFACTORY_TOKEN_REF: ${{ secrets.ARTIFACTORY_TOKEN }}
        # assign the environment variable env.ARTIFACTORY_USERNAME_REF with the previously configured ARTIFACTORY_USERNAME
        ARTIFACTORY_USERNAME_REF: ${{ secrets.ARTIFACTORY_USERNAME }}

When running the build process, you will see that our custom Artifactory instance is used:

GitHub Actions workflow with custom Artifactory repository

I am asking you for a donation.

You liked the content or this article has helped and reduced the amount of time you have struggled with this issue? Please donate a few bucks so I can keep going with solving challenges.

Categories: CI/CD