Securing Software Supply

1. Overview

Artifact Registry enables you to store different artifact types, create multiple repositories in a single project, and associate a specific region or multi-region with each repository. There are several repository modes. Each mode serves a different purpose. The following diagram shows one of many possible ways you can use repositories in different modes together. The diagram shows a workflow across two Google Cloud projects. In a development project, developers build a Java application. In a separate runtime project, another build creates a container image with the application for deployment to Google Kubernetes Engine.

5af5e4da3ccfdff3.png

In this lab, you learn how to perform the following tasks.

  • Use Standard Repositories for deploying your private packages
  • Use Remote Repositories to cache maven central packages
  • Use Virtual Repositories to combine multiple upstream repos in one config

Self-paced environment setup

  1. Sign-in to the Google Cloud Console and create a new project or reuse an existing one. If you don't already have a Gmail or Google Workspace account, you must create one.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • The Project name is the display name for this project's participants. It is a character string not used by Google APIs. You can update it at any time.
  • The Project ID is unique across all Google Cloud projects and is immutable (cannot be changed after it has been set). The Cloud Console auto-generates a unique string; usually you don't care what it is. In most codelabs, you'll need to reference the Project ID (it is typically identified as PROJECT_ID). If you don't like the generated ID, you may generate another random one. Alternatively, you can try your own and see if it's available. It cannot be changed after this step and will remain for the duration of the project.
  • For your information, there is a third value, a Project Number which some APIs use. Learn more about all three of these values in the documentation.
  1. Next, you'll need to enable billing in the Cloud Console to use Cloud resources/APIs. Running through this codelab shouldn't cost much, if anything at all. To shut down resources so you don't incur billing beyond this tutorial, you can delete the resources you created or delete the whole project. New users of Google Cloud are eligible for the $300 USD Free Trial program.

Workspace Setup

Set up gcloud

In Cloud Shell, set your project ID and project number. Save them as PROJECT_ID and PROJECT_NUMBER variables.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')

Enable APIs

gcloud services enable artifactregistry.googleapis.com

Clone the repo

git clone https://github.com/GoogleCloudPlatform/java-docs-samples
cd java-docs-samples/container-registry/container-analysis

2. Standard repositories

Standard Repositories provide a way to store your private packages and share them across your other applications

Create a standard maven repository

From Cloud Shell run the following command to create a repository for Java artifacts:

gcloud artifacts repositories create container-dev-java-repo \
    --repository-format=maven \
    --location=us-central1 \
    --description="Java package repository for Container Dev Workshop"

Click Authorize if the Cloud Shell authorization prompt appears

Go to Google Cloud Console - Artifact Registry - Repositories and notice your newly created Maven repository named container-dev-java-repo, if you click on it you can see that it's empty at the moment.

gcloud artifacts repositories describe container-dev-java-repo \
    --location=us-central1

Should return a response similar to the following

Encryption: Google-managed key
Repository Size: 0.000MB
createTime: '2023-03-21T19:01:45.461589Z'
description: Java package repository for Container Dev Workshop
format: MAVEN
mavenConfig: {}
mode: STANDARD_REPOSITORY
name: projects/qwiklabs-gcp-03-4304110dc461/locations/us-central1/repositories/container-dev-java-repo
updateTime: '2023-03-21T19:01:45.461589Z'

Configure Maven for Artifact Registry

Run the following command to print the repository configuration to add to your Java project:

gcloud artifacts print-settings mvn \
    --repository=container-dev-java-repo \
    --location=us-central1

The previous command returns xml to be added into your projects pom.xml.

  • The repositories section specifies where Maven may download remote artifacts for use by the current project.
  • The distributionManagement section specifies which remote repository the project will push to when it is deployed.
  • The extensions section adds in artifactregistry-maven-wagon which enables the Authentication and transport layer needed for connecting to Artifact Registry
  • Note: Extensions can exist in pom.xml or extensions.xml. In cases where the project depends on a parent project, those dependencies are accessed before the rest of the entries in the pom.xml are loaded. To ensure the parent has access to the extension, it can be placed in an extensions.xml file which is loaded before the pom.xml thus making it available for the parent dependencies.

Copy the three sections then open the pom.xml in Cloud Shell Editor and add the returned settings to the bottom of the file just inside the closing project tag.

Tip: In cloudshell, run the following command in the terminal to open the editor in the current directory.

cloudshell workspace .

Example: (your project names will be different in your URLs)

  ...

  <distributionManagement>
    <snapshotRepository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
    </snapshotRepository>
    <repository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
    </repository>
  </distributionManagement>

  <repositories>
    <repository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
  </repositories>

  <build>
    <extensions>
      <extension>
        <groupId>com.google.cloud.artifactregistry</groupId>
        <artifactId>artifactregistry-maven-wagon</artifactId>
        <version>2.2.0</version>
      </extension>
    </extensions>
  </build>

</project>

Upload your Java package to Artifact Registry

With Artifact Registry configured in Maven, you can now use Artifact Registry to store Java jars for use by other projects in your organization.

Run the following command to upload your Java package to Artifact Registry:

mvn deploy -DskipTests

If you want to run this command again, make sure to increase the version in the pom.xml.

Check the Java package in Artifact Registry

Go to Cloud Console - Artifact Registry - Repositories Click into container-dev-java-repo and check that the hello-world binary artifact is there:

147eac5168648db1.png

3. Remote repositories

Remote Repositories provide the ability to cache third party packages for increased reliability and security.

Create a remote repository

Note: For details on authentication and configuration, review the product documentation.

From Cloud Shell run the following command to create a remote repository for Maven Central artifacts:

gcloud artifacts repositories create maven-central-cache \
    --project=$PROJECT_ID \
    --repository-format=maven \
    --location=us-central1 \
    --description="Remote repository for Maven Central caching" \
    --mode=remote-repository \
    --remote-repo-config-desc="Maven Central" \
    --remote-mvn-repo=MAVEN-CENTRAL

Review the repo in the console

Go to Cloud Console - Artifact Registry - Repositories Click into maven-central-cache and notice it's been created and is currently empty

Review the repo in the terminal

gcloud artifacts repositories describe maven-central-cache \
    --location=us-central1

Integrate the repo into your project

Run the following command to print the repository configuration to add to your Java project:

gcloud artifacts print-settings mvn \
    --repository=maven-central-cache \
    --location=us-central1

Add the repository section into your pom.xml. Be sure not to copy the outer <repositories> tag from the output.

Change the ID of the newly added repository to "central" to ensure each repository entry has a unique ID.

Example: (your project names will be different in your URLs)

  ...

  <distributionManagement>
    <snapshotRepository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
    </snapshotRepository>
    <repository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
    </repository>
  </distributionManagement>

  <repositories>
    <repository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>

    <repository>
      <id>central</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/maven-central-cache</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>


  </repositories>

  <build>
    <extensions>
      <extension>
        <groupId>com.google.cloud.artifactregistry</groupId>
        <artifactId>artifactregistry-maven-wagon</artifactId>
        <version>2.2.0</version>
      </extension>
    </extensions>
  </build>

</project>

Run the following commands in your terminal to create an extensions.xml for your project, To use the core extensions mechanism ensuring Maven can resolve parent or plugin dependencies from Artifact Registry.

mkdir .mvn 
cat > .mvn/extensions.xml << EOF
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
  <extension>
    <groupId>com.google.cloud.artifactregistry</groupId>
    <artifactId>artifactregistry-maven-wagon</artifactId>
    <version>2.2.0</version>
  </extension>
</extensions>
EOF

Pull dependencies from the Remote Repository

Run the following command to compile your application using the Remote Repository:

rm -rf ~/.m2/repository 
mvn compile

Review the packages in the console

Go to Cloud Console - Artifact Registry - Repositories Click into maven-central-cache and check that the binary artifacts cached there:

9deea93caa5fefd7.png

4. Virtual repositories

Virtual Repositories act as an interface for multiple repositories to be accessed through a single configuration. This simplifies client configuration for consumers of your artifacts and increases security by mitigating dependency confusion attacks.

Create a policy file

cat > ./policy.json << EOF
[
  {
    "id": "private",
    "repository": "projects/${PROJECT_ID}/locations/us-central1/repositories/container-dev-java-repo",
    "priority": 100
  },
  {
    "id": "central",
    "repository": "projects/${PROJECT_ID}/locations/us-central1/repositories/maven-central-cache",
    "priority": 80
  }
]

EOF

Create the virtual repository

gcloud artifacts repositories create virtual-maven-repo \
    --project=${PROJECT_ID} \
    --repository-format=maven \
    --mode=virtual-repository \
    --location=us-central1 \
    --description="Virtual Maven Repo" \
    --upstream-policy-file=./policy.json

Integrate the repo into your project

Run the following command to print the repository configuration to add to your Java project:

gcloud artifacts print-settings mvn \
    --repository=virtual-maven-repo \
    --location=us-central1

Replace the entire repositories section in your pom with the one virtual repositories section from the output.

Example: (your project names will be different in your URLs)

  ...


  <distributionManagement>
    <snapshotRepository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
    </snapshotRepository>
    <repository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/container-dev-java-repo</url>
    </repository>
  </distributionManagement>

  <repositories>
    <repository>
      <id>artifact-registry</id>
      <url>artifactregistry://us-central1-maven.pkg.dev/qwiklabs-gcp-04-3c51830ea757/virtual-maven-repo</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
  </repositories>

  <build>
    <extensions>
      <extension>
        <groupId>com.google.cloud.artifactregistry</groupId>
        <artifactId>artifactregistry-maven-wagon</artifactId>
        <version>2.2.0</version>
      </extension>
    </extensions>
  </build>

</project>


Pull dependencies from the Virtual Repository

Since the Virtual repository is a pass through and won't store any actual packages, to clearly demonstrate the process you'll delete the maven-central-cache repo you created earlier and recreate it, to start again with an empty repository

Run the following commands to recreate the cache repository

gcloud artifacts repositories delete maven-central-cache \
    --project=$PROJECT_ID \
    --location=us-central1 \
    --quiet

gcloud artifacts repositories create maven-central-cache \
    --project=$PROJECT_ID \
    --repository-format=maven \
    --location=us-central1 \
    --description="Remote repository for Maven Central caching" \
    --mode=remote-repository \
    --remote-repo-config-desc="Maven Central" \
    --remote-mvn-repo=MAVEN-CENTRAL

You can review the empty repo in the console. Go to Cloud Console - Artifact Registry - Repositories

Now exercise the virtual repository by building your project with the following command

rm -rf ~/.m2/repository 
mvn compile

Review the packages in the console

Go to Cloud Console - Artifact Registry - Repositories Click into maven-central-cache and check that the binary artifacts were configured to pull from the virtual repo but were ultimately pulled from the maven-central-cache:

9deea93caa5fefd7.png

5. Congratulations!

Congratulations, you finished the codelab!

What you've covered

  • Used Standard Repositories for deploying your private packages
  • Used Remote Repositories to cache maven central packages
  • Used Virtual Repositories to combine multiple upstream repos in one config

Cleanup

Run the following command to delete the project

gcloud projects delete ${PROJECT_ID}

Last update: 3/22/23