<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roger Martinez</title>
    <description>The latest articles on DEV Community by Roger Martinez (@rogerthatdev).</description>
    <link>https://dev.to/rogerthatdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F341875%2F2efb2655-5d64-4c3c-b007-094c7a4e735e.png</url>
      <title>DEV Community: Roger Martinez</title>
      <link>https://dev.to/rogerthatdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rogerthatdev"/>
    <language>en</language>
    <item>
      <title>Quick dip: Use Google Cloud Vertex AI SDK with the Vercel AI SDK</title>
      <dc:creator>Roger Martinez</dc:creator>
      <pubDate>Fri, 12 Apr 2024 20:00:49 +0000</pubDate>
      <link>https://dev.to/rogerthatdev/quick-dip-use-the-vertex-ai-sdk-with-the-vercel-ai-sdk-5fme</link>
      <guid>https://dev.to/rogerthatdev/quick-dip-use-the-vertex-ai-sdk-with-the-vercel-ai-sdk-5fme</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🏊‍♀️ This post is a quick dip. The opposite of a deep dive.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://sdk.vercel.ai/docs/guides/providers/google" rel="noopener noreferrer"&gt;Vercel AI SDK documentation&lt;/a&gt; includes code samples for hooking up the SDK to different providers like &lt;a href="https://sdk.vercel.ai/docs/guides/providers/anthropic" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt;, &lt;a href="https://sdk.vercel.ai/docs/guides/providers/openai" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;, and others.  This list includes &lt;a href="https://sdk.vercel.ai/docs/guides/providers/google" rel="noopener noreferrer"&gt;Google&lt;/a&gt;, but only shows you how to use the &lt;a href="https://www.npmjs.com/package/@google/generative-ai" rel="noopener noreferrer"&gt;Google AI JavaScript SDK&lt;/a&gt;. Here's some sample code of how to hook it up to the &lt;a href="https://www.npmjs.com/package/@google-cloud/vertexai" rel="noopener noreferrer"&gt;Vertex AI SDK&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/chat/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;VertexAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google-cloud/vertexai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAIStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StreamingTextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLOUD_PROJECT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-central1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vertexAI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VertexAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Google GenAI API can use the edge runtime. This will not work with Vertex AI&lt;/span&gt;
&lt;span class="c1"&gt;// export const runtime = 'edge';&lt;/span&gt;

&lt;span class="c1"&gt;// Instantiate Gemini models&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generativeModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vertexAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGenerativeModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-pro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildGoogleGenAIPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;model&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;})),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Extract the `prompt` from the body of the request&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geminiStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;generativeModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContentStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;buildGoogleGenAIPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Convert the response into a friendly text-stream&lt;/span&gt;
  &lt;span class="c1"&gt;// GoogleGenerativeAIStream class decodes/extracts the text tokens in the&lt;/span&gt;
  &lt;span class="c1"&gt;// response and then re-encodes them properly for simple consumption.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenerativeAIStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geminiStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Respond with the stream&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StreamingTextResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the above code, follow the instructions for the &lt;a href="https://sdk.vercel.ai/docs/getting-started" rel="noopener noreferrer"&gt;Getting Started tutorial&lt;/a&gt; and use it for the &lt;code&gt;app/api/chat/route.ts&lt;/code&gt; file. (Skip the API key step).&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;Some differences between this Vertex AI SDK example and the one for the Google AI JavaScript SDK:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We don't indicate the runtime as &lt;code&gt;'edge'&lt;/code&gt; because it is not compatible with the Vertex AI SDK. &lt;a href="https://nextjs.org/docs/messages/node-module-in-edge-runtime" rel="noopener noreferrer"&gt;Click here for more information on the Edge Runtime and Node.js modules&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Instead of API keys, Vertex uses a project ID indicated via the &lt;code&gt;GOOGLE_CLOUD_PROJECT&lt;/code&gt; environment variable and application default credentials indicated via the &lt;code&gt;GOOGLE_APPLICATION_CREDENTIALS&lt;/code&gt; environment variable. &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>genai</category>
      <category>vercel</category>
      <category>googlecloud</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Push code with GitHub Actions to Google Cloud’s Artifact Registry</title>
      <dc:creator>Roger Martinez</dc:creator>
      <pubDate>Wed, 10 Apr 2024 17:17:29 +0000</pubDate>
      <link>https://dev.to/rogerthatdev/push-code-with-github-actions-to-google-clouds-artifact-registry-5c30</link>
      <guid>https://dev.to/rogerthatdev/push-code-with-github-actions-to-google-clouds-artifact-registry-5c30</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I originally published this post on &lt;a href="https://roger-that-dev.medium.com/push-code-with-github-actions-to-google-clouds-artifact-registry-60d256f8072f" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;, March 20, 2024&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’ve got some application code sitting in GitHub and need to push it to a Docker registry, there are a lot of options. This article is going to cover just one: &lt;strong&gt;pushing to Google Cloud Artifact Registry using GitHub Actions&lt;/strong&gt;. And we’re going to make it happen &lt;strong&gt;without using service account keys&lt;/strong&gt; by leveraging &lt;a href="https://cloud.google.com/iam/docs/workload-identity-federation" rel="noopener noreferrer"&gt;Google Cloud Workload Identity Federation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to begin
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Some things we need first
&lt;/h3&gt;

&lt;p&gt;To follow along with what I’m going to demonstrate, you’ll need a couple of things:&lt;/p&gt;

&lt;p&gt;☑️ &lt;strong&gt;A Google Cloud project:&lt;/strong&gt; this will be the project where we’ll be creating our resources, which includes an Artifact Registry repository and some IAM resources. Enable the &lt;a href="https://console.cloud.google.com/apis/api/iamcredentials.googleapis.com" rel="noopener noreferrer"&gt;IAM Service Account Credentials&lt;/a&gt; and &lt;a href="https://console.cloud.google.com/apis/api/artifactregistry.googleapis.com" rel="noopener noreferrer"&gt;Artifact Registry&lt;/a&gt; APIs on this project.&lt;/p&gt;

&lt;p&gt;☑️ &lt;strong&gt;Google Cloud CLI:&lt;/strong&gt; we’ll be using the &lt;code&gt;gcloud&lt;/code&gt; CLI to interact with Google Cloud. If you don’t want to install it on your local machine, you can use the &lt;a href="https://shell.cloud.google.com/" rel="noopener noreferrer"&gt;Cloud Shell&lt;/a&gt; in the Google Cloud console which has &lt;code&gt;gcloud&lt;/code&gt; built-in.&lt;/p&gt;

&lt;p&gt;☑️ &lt;strong&gt;A GitHub repository:&lt;/strong&gt; you’ll need a GitHub repository with a &lt;code&gt;Dockerfile&lt;/code&gt; so that you can build and push your container image to the Artifact Registry.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions workflow file
&lt;/h3&gt;

&lt;p&gt;GitHub Action workflows are typically stored as &lt;code&gt;yaml&lt;/code&gt; files in the &lt;code&gt;.github/workflows/&lt;/code&gt; directory of your repo. Here’s the GitHub Action workflow file we’re working with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push to Artifact Registry&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;AR_REPO_LOCATION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;AR_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; 
  &lt;span class="na"&gt;WORKLOAD_IDENTITY_PROVIDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push_to_ar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;read'&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;write'&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Google Auth&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auth&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;google-github-actions/auth@v2'&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;token_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;access_token'&lt;/span&gt;
          &lt;span class="na"&gt;project_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.PROJECT_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;service_account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.SERVICE_ACCOUNT }}&lt;/span&gt;
          &lt;span class="na"&gt;workload_identity_provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.WORKLOAD_IDENTITY_PROVIDER }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Docker Auth&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-auth&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;docker/login-action@v1'&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;oauth2accesstoken'&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;steps.auth.outputs.access_token&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.AR_REPO_LOCATION&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}-docker.pkg.dev'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Push Container&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
          &lt;span class="s"&gt;docker build -t "${{ env.AR_URL }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" ./&lt;/span&gt;
          &lt;span class="s"&gt;docker push "${{ env.AR_URL }}/${{ env.IMAGE_NAME }}:${{ github.sha }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow will authenticate with Google Cloud using the &lt;a href="https://github.com/google-github-actions/auth" rel="noopener noreferrer"&gt;Google Cloud auth GitHub Action&lt;/a&gt; and use Docker to authenticate and push to the registry. To make this workflow work (or flow?) we need to set up some Google Cloud resources and add in those values for our environment variables. Make sure to add in the value for &lt;code&gt;PROJECT_ID&lt;/code&gt; where you have permission to create resources. The value for &lt;code&gt;IMAGE_NAME&lt;/code&gt; can be anything — it’ll be created the first time this workflow runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-app-image'&lt;/span&gt;
  &lt;span class="na"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-project-id'&lt;/span&gt;
  &lt;span class="na"&gt;AR_REPO_LOCATION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;AR_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; 
  &lt;span class="na"&gt;WORKLOAD_IDENTITY_PROVIDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Good start! Next we’ll need an Artifact Registry repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifact Registry repository
&lt;/h2&gt;

&lt;p&gt;Artifact Registry is Google Cloud's build artifact management solution. It supports several types of repositories like apt, Maven, and Python. For our purposes, we want a &lt;strong&gt;Docker&lt;/strong&gt; repository. You can use an existing one, or create a new one with this &lt;code&gt;gcloud&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud artifacts repositories create my-ar-repo &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--repository-format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;docker &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Example Docker repository"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Docker repository called &lt;code&gt;my-ar-repo&lt;/code&gt; in the &lt;code&gt;us-central1&lt;/code&gt; region. You can see it in the console on the &lt;a href="https://console.cloud.google.com/artifacts" rel="noopener noreferrer"&gt;Artifact Registry repositories page&lt;/a&gt;. For our workflow &lt;code&gt;YAML&lt;/code&gt; file, we need the &lt;strong&gt;Artifact Registry URL&lt;/strong&gt;. Let's retrieve that with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud artifacts repositories describe my-ar-repo &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Encryption: Google-managed key
Registry URL: us-central1-docker.pkg.dev/my-project-id/my-ar-repo
Repository Size: 5026.459MB
createTime: '2024-03-13T23:19:57.701232Z'
description: Example Docker repository
format: DOCKER
mode: STANDARD_REPOSITORY
name: projects/my-project-id/locations/us-central1/repositories/my-ar-repo
updateTime: '2024-03-18T17:08:49.658081Z'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s take that value for the &lt;code&gt;Registry URL&lt;/code&gt; and throw it into our GitHub Actions workflow file, along with the repo location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
env:
  IMAGE_NAME: 'my-app-image'
  PROJECT_ID: 'my-project-id'
  AR_REPO_LOCATION: 'us-central1'
  AR_URL: 'us-central1-docker.pkg.dev/my-project-id/my-ar-repo'
  SERVICE_ACCOUNT: '' 
  WORKLOAD_IDENTITY_PROVIDER: ''
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Service account
&lt;/h2&gt;

&lt;p&gt;Next, we need a service account to serve as the identity that’s going to be doing the pushing to the Artifact Registry repository. Create a service account with &lt;code&gt;gcloud&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam service-accounts create github-actions-service-account &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"A service account for use in a GitHub Actions workflow"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--display-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"GitHub Actions service account."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have a service account (see it &lt;a href="http://console.cloud.google.com/iam-admin/serviceaccounts" rel="noopener noreferrer"&gt;in the console under IAM&lt;/a&gt;), let’s add the service account email to our &lt;code&gt;YAML&lt;/code&gt; file. The format is &lt;code&gt;SERVICE_ACCT_NAME@PROJECT_ID.iam.gserviceaccount.com&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-app-image'&lt;/span&gt;
  &lt;span class="na"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-project-id'&lt;/span&gt;
  &lt;span class="na"&gt;AR_REPO_LOCATION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-central1'&lt;/span&gt;
  &lt;span class="na"&gt;AR_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-central1-docker.pkg.dev/my-project-id/my-ar-repo'&lt;/span&gt;
  &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;github-actions-service-account@my-project-id.iam.gserviceaccount.com'&lt;/span&gt; 
  &lt;span class="na"&gt;WORKLOAD_IDENTITY_PROVIDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the service account has no permissions on any resources on the project. We only need it to be able to push builds to our Artifact Registry repo. Let’s make it so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud artifacts repositories add-iam-policy-binding my-ar-repo &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;roles/artifactregistry.createOnPushWriter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;serviceAccount:github-actions-service-account@my-project-id.iam.gserviceaccount.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above grants the &lt;em&gt;&lt;strong&gt;Artifact Registry Create-on-Push Writer&lt;/strong&gt;&lt;/em&gt; IAM role to our service account, but only for our particular Artifact Registry repository. We could grant it on the entire project by adding the IAM binding to the &lt;em&gt;project IAM policy&lt;/em&gt;, but since Artifact Registry repos have their own IAM policies, we can practice some least privilege and narrow the scope to just the one we’re working with.&lt;/p&gt;

&lt;p&gt;With that, our service account is able to push builds to our Artifact Registry. Well not really — now we need a way to tell it to do that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: If the application image already existed in our repository, then &lt;strong&gt;roles/artifactregistry.writer&lt;/strong&gt; would suffice. We’re using &lt;strong&gt;roles/artifactregistry.createOnPushWriter&lt;/strong&gt; instead because on the first push, it needs to be able to create the initial image for our application.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Workload Identity Federation
&lt;/h2&gt;

&lt;p&gt;Historically, one way to programmatically access resources with a service account has been to use JSON keys to authenticate with their credentials. That’s still possible, but it is highly discouraged due to the security risk associated with managing them. You’ll see caution signs about that throughout Google Cloud console and documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscw6xaxk3bfohrnjsoiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscw6xaxk3bfohrnjsoiu.png" alt="TLDR: service account keys bad" width="800" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Workload Identity Federation&lt;/em&gt;&lt;/strong&gt; offers an alternative. It lets us grant external identities the ability to impersonate a service account without the burden of service account keys. Our goal is to create a &lt;strong&gt;&lt;em&gt;workload identity pool provider&lt;/em&gt;&lt;/strong&gt; for our GitHub repository so that we can impersonate our service account from a GitHub Actions workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a workload identity pool
&lt;/h3&gt;

&lt;p&gt;Before we can create a provider, we need to create a &lt;strong&gt;&lt;em&gt;workload identity pool&lt;/em&gt;&lt;/strong&gt;. A workload identity pool is a Google Cloud resource that is used to manage external identities. Google Cloud suggests creating a new pool for each non-Google Cloud environment that needs to access resources in our project. For our case, let’s create a workload identity pool for our app’s development environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam workload-identity-pools create &lt;span class="s2"&gt;"my-app-dev-pool"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PROJECT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;global &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--display-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Identity pool for my test app"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a workload identity pool on your project. See it &lt;a href="https://console.cloud.google.com/iam-admin/workload-identity-pools" rel="noopener noreferrer"&gt;in the console under IAM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4oee9b25fcuppbaj0q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4oee9b25fcuppbaj0q0.png" alt="Workload identity pool in Cloud console" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a workload identity pool provider
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;&lt;em&gt;workload identity pool provider&lt;/em&gt;&lt;/strong&gt; describes the relationship between Google Cloud and an identity provider (IdP) that supports OpenID Connect (OIDC). It must be created within a workload identity pool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam workload-identity-pools providers create-oidc &lt;span class="s2"&gt;"github-actions-provider"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"global"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--workload-identity-pool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-app-dev-pool"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--display-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Provider for GitHub Actions"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--issuer-uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://token.actions.githubusercontent.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--attribute-mapping&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;create-oidc&lt;/code&gt; sub-command indicates that we want to create an &lt;em&gt;&lt;strong&gt;OpenID Connect (OIDC)&lt;/strong&gt;&lt;/em&gt; provider in our pool. GitHub uses OIDC to authenticate with different cloud providers (see &lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers" rel="noopener noreferrer"&gt;GitHub documentation on it here&lt;/a&gt;). The &lt;code&gt;issuer-uri&lt;/code&gt; parameter specifies the provider URL, as indicated by &lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws" rel="noopener noreferrer"&gt;GitHub’s OIDC documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;--attribute-mapping&lt;/code&gt;&lt;/strong&gt; parameter lists our &lt;em&gt;&lt;strong&gt;attribute mapping&lt;/strong&gt;&lt;/em&gt;. Attribute mapping defines how values are derived from an external token and mapped to the Google Security Token Service (STS) token attributes. The value for this parameter is a comma-separated list of mappings in the form of &lt;strong&gt;&lt;code&gt;TARGET_ATTRIBUTE=SOURCE_EXPRESSION&lt;/code&gt;&lt;/strong&gt;. These attributes will be referenced later when we set up permissions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Learn more about attribute mapping from &lt;a href="https://cloud.google.com/iam/docs/workload-identity-federation#mapping" rel="noopener noreferrer"&gt;Google Cloud’s documentation on workload identity federation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With a workload identity pool provider in place we can add the value to our workflow &lt;code&gt;YAML&lt;/code&gt; file. First, retrieve the full name of the provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam workload-identity-pools providers describe github-actions-provider &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;global &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workload-identity-pool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-app-dev-pool"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will include the name which will be in the format &lt;code&gt;projects/PROJECT_NUMBER/locations/POOL_LOCATION/workloadIdentityPools/POOL_NAME/providers/PROVIDER_NAME&lt;/code&gt;. That’s what we need for the &lt;code&gt;WORKLOAD_IDENTITY_PROVIDER&lt;/code&gt; environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-app-image'&lt;/span&gt;
  &lt;span class="na"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-project-id'&lt;/span&gt;
  &lt;span class="na"&gt;AR_REPO_LOCATION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-central1'&lt;/span&gt;
  &lt;span class="na"&gt;AR_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-central1-docker.pkg.dev/my-project-id/my-ar-repo'&lt;/span&gt;
  &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;github-actions-service-account@my-project-id.iam.gserviceaccount.com'&lt;/span&gt; 
  &lt;span class="na"&gt;WORKLOAD_IDENTITY_PROVIDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;projects/123456789/locations/global/workloadIdentityPools/my-app-dev-pool/providers/github-actions-provider'&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting permissions
&lt;/h2&gt;

&lt;p&gt;The only permissions we’ve granted so far have been to our service account to push to the Artifact Registry repository. Now that we have a workload identity provider, we need to grant it permission to act as the service account.&lt;/p&gt;

&lt;p&gt;If we wanted to grant service account impersonation permissions to a user account or service account principal, we would grant the &lt;strong&gt;&lt;em&gt;Service Account Token Creator&lt;/em&gt;&lt;/strong&gt; role on the service account’s IAM policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam service-accounts add-iam-policy-binding &lt;span class="se"&gt;\&lt;/span&gt;
  github-actions-service-account@my-project-id.iam.gserviceaccount.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;roles/iam.serviceAccountTokenCreator &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;user:roger@myemail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command would allow my user account to act as the service account and access whatever the service account can access. With Workload Identity Federation, it’s the same concept with 2 differences: the IAM role and the principal (or the &lt;code&gt;member&lt;/code&gt; parameter in the command above).&lt;/p&gt;

&lt;p&gt;Instead of granting the &lt;strong&gt;&lt;em&gt;Service Account Token Creator&lt;/em&gt;&lt;/strong&gt; role (&lt;code&gt;roles/iam.serviceAccountTokenCreator&lt;/code&gt;) to our workload identity pool principal, we need to grant the &lt;em&gt;&lt;strong&gt;Workload Identity User&lt;/strong&gt;&lt;/em&gt; role (&lt;code&gt;roles/iam.workloadIdentityUser&lt;/code&gt;) instead. This role allows the principal to impersonate service accounts from federated workloads.&lt;/p&gt;

&lt;p&gt;As for the principal, the prefixes &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;serviceAccount&lt;/code&gt; are used for user accounts and service accounts, respectively, followed by an email address:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;user:roger@myemail.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;serviceAccount:my-service-account@my-project-id.iam.gserviceaccount.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Workload Identity Federation however uses &lt;code&gt;principalSet&lt;/code&gt; as a prefix, followed by a &lt;em&gt;member identifier&lt;/em&gt; that includes the identity pool and an attribute from the provider’s attribute mapping:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;principalSet://iam.googleapis.com/WORKLOAD_IDENTITY_POOL_NAME/attribute.ATTRIBUTE_NAME/ATTRIBUTE_VALUE&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example, the following principal can be used to grant access to external identities coming from any GitHub repository that your organization owns:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;principalSet://iam.googleapis.com/WORKLOAD_IDENTITY_POOL_NAME/attribute.owner/your-github-organization&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can use any of the attributes that we mapped on our workload identity federation OIDC provider earlier. The principal that we’ll be using, however, will narrow access down to external identities corresponding with one particular GitHub repository using &lt;code&gt;attribute.repository&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;principalSet://iam.googleapis.com/WORKLOAD_IDENTITY_POOL_NAME/attribute.repository/github-repo-owner/github-repo-name&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: Besides attributes, you can grant permissions to external identities by &lt;strong&gt;subject&lt;/strong&gt; and by &lt;strong&gt;group&lt;/strong&gt;. Learn more about that &lt;a href="https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#allow_the_external_workload_to_impersonate_the_service_account" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we’ve got a IAM role and a principal to grant it to. Let’s add an IAM binding to our service account’s IAM policy. First, retrieve the workload identity pool name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam workload-identity-pools describe &lt;span class="s2"&gt;"my-app-dev-pool"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;global
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value will be in the format &lt;code&gt;projects/PROJECT_NUMBER/locations/POOL_LOCATION/workloadIdentityPools/POOL_NAME&lt;/code&gt;&lt;br&gt;
It’s a long string, so let’s throw this into an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;WIP_POOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;projects/123456789/locations/global/workloadIdentityPools/my-app-dev-pool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, let’s add the binding to the service account’s IAM policy. Be sure to update the values for &lt;code&gt;GITHUB_REPO_OWNER&lt;/code&gt; and &lt;code&gt;GITHUB_REPO_NAME&lt;/code&gt; with values for the GitHub repo that you plan on the running the workflow from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam service-accounts add-iam-policy-binding &lt;span class="se"&gt;\&lt;/span&gt;
  github-actions-service-account@my-project-id.iam.gserviceaccount.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;roles/iam.workloadIdentityUser &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;principalSet://iam.googleapis.com/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;WIP_POOL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/attribute.repository/GITHUB_REPO_OWNER/GITHUB_REPO_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this binding in place, GitHub Actions is able to use Workload Identity Federation to authenticate as your service account and push builds to your Artifact Registry. There’s one more thing we can do to further narrow the scope of access: specify an &lt;em&gt;&lt;strong&gt;attribute condition&lt;/strong&gt;&lt;/em&gt; on the identity pool provider.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;&lt;em&gt;attribute condition&lt;/em&gt;&lt;/strong&gt; is an expression that checks an attribute and must evaluate to true for a given credential in order for it to be accepted. For example, we can define an attribute condition that checks whether the attribute &lt;code&gt;repository_owner&lt;/code&gt; matches a GitHub organization or GitHub user that owns a repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud iam workload-identity-pools providers update-oidc &lt;span class="se"&gt;\&lt;/span&gt;
  github-actions-provider &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PROJECT_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;global &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workload-identity-pool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-app-dev-pool &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attribute-condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"assertion.repository_owner == 'GITHUB_REPO_OWNER'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the restriction added by this attribute condition is redundant, since the IAM policy binding is already limited to a particular repo owner. However, if for whatever reason the IAM policy ever changes to be more broad, this will still restrict access to the specified GitHub repo owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's test drive
&lt;/h2&gt;

&lt;p&gt;Before we can test this out, you’ll need a repository with a valid &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the final &lt;code&gt;YAML&lt;/code&gt; file for our workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Push to Artifact Registry&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-app-image'&lt;/span&gt;
  &lt;span class="na"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-project-id'&lt;/span&gt;
  &lt;span class="na"&gt;AR_REPO_LOCATION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-central1'&lt;/span&gt;
  &lt;span class="na"&gt;AR_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-central1-docker.pkg.dev/my-project-id/my-ar-repo'&lt;/span&gt;
  &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;github-actions-service-account@my-project-id.iam.gserviceaccount.com'&lt;/span&gt; 
  &lt;span class="na"&gt;WORKLOAD_IDENTITY_PROVIDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;projects/123456789/locations/global/workloadIdentityPools/my-app-dev-pool/providers/github-actions-provider'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push_to_ar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;read'&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;write'&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Google Auth&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auth&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;google-github-actions/auth@v2'&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;token_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;access_token'&lt;/span&gt;
          &lt;span class="na"&gt;project_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.PROJECT_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;service_account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.SERVICE_ACCOUNT }}&lt;/span&gt;
          &lt;span class="na"&gt;workload_identity_provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.WORKLOAD_IDENTITY_PROVIDER }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Docker Auth&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-auth&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;docker/login-action@v1'&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;oauth2accesstoken'&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;steps.auth.outputs.access_token&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
          &lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.AR_REPO_LOCATION&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}-docker.pkg.dev'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Push Container&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
          &lt;span class="s"&gt;docker build -t "${{ env.AR_URL }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" ./&lt;/span&gt;
          &lt;span class="s"&gt;docker push "${{ env.AR_URL }}/${{ env.IMAGE_NAME }}:${{ github.sha }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll place this configuration in our GitHub repository in &lt;code&gt;.github/workflows/push-to-ar.yml&lt;/code&gt;. As soon as you merge this file into your main branch, it’ll kick off the workflow and if all permissions and resources are in place, you’ll have a build of your application sitting in your Artifact Registry. Verify by visiting the &lt;a href="https://console.cloud.google.com/artifacts" rel="noopener noreferrer"&gt;Artifact Registry page in the Google Cloud Console.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;Arguably, the star of the show is the &lt;a href="https://cloud.google.com/blog/products/identity-security/enabling-keyless-authentication-from-github-actions" rel="noopener noreferrer"&gt;Google Auth GitHub Action&lt;/a&gt; - that’s what’s using the Workload Identity Provider and service account to access your Google Cloud project. If you plan on doing other things with this authentication, just be sure to use a service account that has the right access those things. For example, if you’re using the &lt;a href="https://github.com/google-github-actions/get-secretmanager-secrets" rel="noopener noreferrer"&gt;Secret Manager GitHub Action&lt;/a&gt; to access secrets from Secret Manager, make sure the service account has the &lt;em&gt;&lt;strong&gt;Secret Manager Secret Accessor&lt;/strong&gt;&lt;/em&gt; IAM role on the project or secret. To take a look at all of the available actions, check out the repos available in the &lt;a href="https://github.com/orgs/google-github-actions/repositories" rel="noopener noreferrer"&gt;Google GitHub Actions GitHub organization&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
