<?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: tim dowd</title>
    <description>The latest articles on DEV Community by tim dowd (@timdowd19).</description>
    <link>https://dev.to/timdowd19</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%2F1058264%2F468b5b15-c4f9-4631-839d-a812cb3444f2.jpg</url>
      <title>DEV Community: tim dowd</title>
      <link>https://dev.to/timdowd19</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/timdowd19"/>
    <language>en</language>
    <item>
      <title>How to Point Your Domain to Google Cloud Run with CloudFlare in 2024</title>
      <dc:creator>tim dowd</dc:creator>
      <pubDate>Fri, 08 Nov 2024 12:45:34 +0000</pubDate>
      <link>https://dev.to/timdowd19/how-to-point-your-domain-to-google-cloud-run-with-cloudflare-in-2024-1c3g</link>
      <guid>https://dev.to/timdowd19/how-to-point-your-domain-to-google-cloud-run-with-cloudflare-in-2024-1c3g</guid>
      <description>&lt;p&gt;(See bottom of post for video explanation)&lt;/p&gt;

&lt;p&gt;Connecting Google Cloud Run to Cloud Flare with a Proxy caused me HTTPS redirect issues.  Luckily there is a way round this.&lt;/p&gt;

&lt;p&gt;This guide details the necessary steps for establishing your domain connection and ensuring it operates securely with SSL/TLS certification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Accessing Google Cloud Run for Domain Mapping
&lt;/h3&gt;

&lt;p&gt;Begin by navigating to the Cloud Run console. Locate the &lt;strong&gt;Manage Custom Domains&lt;/strong&gt; section. Here, you must verify your domain's ownership.&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%2Fmf9pgnbad1otgdhnpuqt.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%2Fmf9pgnbad1otgdhnpuqt.png" alt="Image description" width="579" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mapping Your Domain
&lt;/h3&gt;

&lt;p&gt;Link your domain to the Google Cloud Run service. The console provides on-screen prompts to simplify this task. Upon mapping, you'll receive DNS records needed for the subsequent steps. The type of DNS record needed here is typically an "A" record, although these steps are the same for CNAME records etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Configuring DNS with Cloudflare
&lt;/h2&gt;

&lt;p&gt;If you're leveraging Cloudflare, you must manage your DNS settings there to ensure the domain points to your Cloud Run service accurately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a New DNS Record
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Login to Cloudflare&lt;/strong&gt;: Select the domain you want to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access the DNS section&lt;/strong&gt;: Create a new DNS record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record Type&lt;/strong&gt;: Choose "A" record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hostname&lt;/strong&gt;: Use root ("@"). (root is for no subdomain, if you want to map a subdomain then enter it here rather than "@")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP Address&lt;/strong&gt;: Input the IP address from the Cloud Run mapping step.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Understanding Proxy Status
&lt;/h3&gt;

&lt;p&gt;This step is important for Cloudflare to work with Cloud Run. Cloudflare's proxy provides caching and DDOS protection as well as some other security benefits, but needs to be disabled temporarily for now.  Disable the proxy and set to DNS only for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Setting TTL and Await SSL/TLS Certification
&lt;/h2&gt;

&lt;p&gt;Post-mapping your DNS record, it's useful to manage your TTL setting, which dictates how quickly DNS updates propagate. A temporary TTL of &lt;strong&gt;1 minute&lt;/strong&gt; here should be set.&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%2Fpg4cyq4rk6j8lzrgsab6.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%2Fpg4cyq4rk6j8lzrgsab6.png" alt="Image description" width="800" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Adjusting SSL/TLS Settings in Cloudflare
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set SSL to Off (Not Secure)&lt;/strong&gt; temporarily in Cloudflare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust Edge Certificate settings&lt;/strong&gt;: Disable automatic HTTPS rewrites for initial setup to ensure certification.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once DNS settings are in place, certificate provisioning activates. This might seem slow and likely you will see a small grey loader next to your mapping in Cloud Run.&lt;/p&gt;

&lt;p&gt;If settings are correct, provisioning should complete within &lt;strong&gt;10 to 20 minutes&lt;/strong&gt;. Delays aren't unusual, so allow sufficient time before further interventions or troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Verifying DNS Propagation and Updates
&lt;/h2&gt;

&lt;p&gt;To check things are moving along you can confirm DNS propagation using terminal commands or online visual tools. For terminal users, &lt;code&gt;watch dig yourdomain.com&lt;/code&gt; shows real-time DNS updates worldwide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring DNS Records
&lt;/h3&gt;

&lt;p&gt;Compare global IP propagation against your hosting service-provided IP (example: &lt;code&gt;216.x.x.x&lt;/code&gt;). Propagation times vary, so allow multiple checks to ensure accuracy.&lt;/p&gt;

&lt;p&gt;Alternatively you can just wait for the green tick to appear next to your domain mapping in the Google Cloud Run domain mapping console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;So far we have covered initial steps such as pointing a domain name to Cloudflare with DNS-only settings and securing a https certificate.  Now we will update these configurations to turn on the proxy and take advantage of DDOS protection and cached content delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 Configuring CNAME and Adjusting Proxy Settings
&lt;/h2&gt;

&lt;p&gt;In Cloudflare choose your domain and click on DNS, then Records, then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Delete Existing DNS Record&lt;/strong&gt;: This step we delete our old A record which allows us to prepare for the new setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add New Records&lt;/strong&gt;: - &lt;strong&gt;Create a CNAME Record&lt;/strong&gt;: Direct this to your root domain:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Record Type&lt;/strong&gt;: CNAME&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: @&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Target&lt;/strong&gt;: &lt;code&gt;ghs.googlehosted.com&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enable Proxy Status&lt;/strong&gt;: Turn this "on".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 6 Re-Adjusting SSL/TLS Settings
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SSL/TLS Configuration&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change from "Off" to "Full".&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save Changes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Finalizing DNS Configuration and Leveraging Cloudflare's Full Suite
&lt;/h2&gt;

&lt;p&gt;Following completion of CNAME and SSL configurations, a brief waiting period for DNS propagation will be needed. Once completed, you should expect to be able to visit your domain successfully with no HTTPS redirect issues, and you should now have full access to cache and DDOS protection controls in your Cloudflare console.&lt;/p&gt;

&lt;p&gt;Shoutout to Adnan Hodzic for coming up with the original solution.  You can checkout his videos here detailing the process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=b0iBHDHOb3Y&amp;amp;list=PL83G0TLSeXREwjHDZPsV_34azAmniL81V&amp;amp;index=9&amp;amp;t=1s" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=b0iBHDHOb3Y&amp;amp;list=PL83G0TLSeXREwjHDZPsV_34azAmniL81V&amp;amp;index=9&amp;amp;t=1s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=CLOCCFT8rRo&amp;amp;list=PL83G0TLSeXREwjHDZPsV_34azAmniL81V" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=CLOCCFT8rRo&amp;amp;list=PL83G0TLSeXREwjHDZPsV_34azAmniL81V&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Scheduled Cloud Functions and Secrets - A Step By Step Tutorial - Google Cloud Platform 🤠</title>
      <dc:creator>tim dowd</dc:creator>
      <pubDate>Tue, 11 Apr 2023 19:31:12 +0000</pubDate>
      <link>https://dev.to/timdowd19/scheduled-cloud-functions-and-secrets-a-step-by-step-tutorial-google-cloud-platform-4dfi</link>
      <guid>https://dev.to/timdowd19/scheduled-cloud-functions-and-secrets-a-step-by-step-tutorial-google-cloud-platform-4dfi</guid>
      <description>&lt;p&gt;In this post I will be taking you through how to access secrets in google cloud - allowing you to make use of sensitive information such as api keys, while minimizing the risk of such data falling into the wrong hands. By following this tutorial, you will not only learn how to access secrets, but also learn how to setup and deploy a scheduled cloud function that will be triggered via cloud scheduler.&lt;/p&gt;

&lt;p&gt;Whilst most things can be done via the command line in google cloud, for starting out it's best to use the UI as things make much more sense when you are trying to wrap your head around the ins and outs of this platform and join the dots (at least for me anyway).  For that reason I will be performing and detailing this process using the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;To allow us to implement the features that we are learning about in this tutorial, we need to setup a Firebase 'Cloud Firestore' database. This database will be used to demonstrate that our cloud function has gained access to our secret in Secret Manager. To get started, the first step is to log in to Firebase or sign up if you haven't already, and then create a new project. Once the project is created, we will need to initialize the 'Cloud Firestore' database and create a new collection called 'myCollection.' You can find details on how to set this up &lt;a href="https://firebase.google.com/docs/firestore/quickstart" rel="noopener noreferrer"&gt;here&lt;/a&gt;, which covers steps 1 to 5: &lt;/p&gt;

&lt;p&gt;After you have set up the Firebase 'Cloud Firestore' database and created the necessary collection, the next step is to obtain your Firebase access key or credentials. You can do this by navigating to your project settings and then to the service accounts section, where you can generate a private key. It is important to save this key in a secure location as you will need to transfer it to Google Secret Manager in the next step of the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secret Manager
&lt;/h2&gt;

&lt;p&gt;Assuming you already have a Google Cloud Platform account setup, go into your project - you need to create a project if you have not already. Locate the secret manager by doing a quick search and click 'Create Secret'.   If you cannot access this service then you will need to enable it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fd18y8yv18qrny44b8mxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fd18y8yv18qrny44b8mxh.png" alt="secret manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your secret a name of 'FIRESTORE_SECRET' and for the secret value copy the access key we gained in our previous step and paste directly as JSON into the value field.  You will see there are a number of options for encryption and rotation etc - I will leave these all blank as I am happy with the default settings here, although it is recommended to look into these settings for a production setup.  For the purpose of simplicity in this tutorial  we go with default. Click done and your secret is created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Function
&lt;/h2&gt;

&lt;p&gt;Now are secret is created we are ready for the next step which is creating the cloud function. In the cloud console, do a search for 'Cloud Functions' and hit 'Create Function'.  For the purpose of this tutorial we are going to create a 1st generation cloud function with a pub/sub trigger:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F3nxidn7q1178sdc41v87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F3nxidn7q1178sdc41v87.png" alt="cloud function"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose 1st generation for the environment and give the function a suitable name, then select a region where your function will be hosted.  For the type of trigger choose cloud Pub/Sub then click create a topic from select a topic dropdown.&lt;/p&gt;

&lt;p&gt;Give the topic a suitable topic id.  For the purpose of the tutorial leave 'use schema' and 'enable message retention' unchecked, and leave 'google managed encryption key' checked. Hit create.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fxpuza62h3uw21bw3qo6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxpuza62h3uw21bw3qo6b.png" alt="topic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Continuing with the google function configuration click save and move onto the runtime section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ff0cf61lugipogtr51cig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ff0cf61lugipogtr51cig.png" alt="runtime"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In some cases your function may need run for some time, so its important to set a timeout that suits your function.  Here we can be happy with the default of 60 seconds.  Similarly with memory allocation - you need to ensure that your function has enough memory to handle itself.  For our case the default is fine.&lt;/p&gt;

&lt;p&gt;In the Runtime service account section we want to create a new identity for our cloud function. This identity will be given permissions to access secrets later on, which will in turn give our cloud function associated with the service account, access to those secrets. Click create new service account in the Runtime service account dropdown and give the service account an appropriate name.  Click Create Service Account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fyibl5nh6dst8ksuaxo24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fyibl5nh6dst8ksuaxo24.png" alt="service account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our function configuration is now setup and we are ready to move on to writing some code.  Click next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The js file we're about to use in this tutorial incorporates the firebase-admin npm module. This package allows us to execute firebase functionality on the server rather than via a front end, where it's commonly used. Additionally, we make use of the SecretManagerServiceClient from Google Cloud Secret Manager. This client will enable us to access secrets during runtime without needing to store them as environment variables at compile time, increasing the security of our secrets.&lt;/p&gt;

&lt;p&gt;If you're here, I'm assuming you have a good understanding of JavaScript, so I won't go into too much detail about how the code works. However, it's worth noting that in the code, the cloud function entry point name should be inserted as the first argument in your cloudEvent function to avoid errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fn8esc1aa76dmvux64yfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fn8esc1aa76dmvux64yfi.png" alt="entry point"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also need to ensure that the correct secret name is given when we use accessSecretVersion.  The name of your secret can be retrieved from google secret manager.  Usually it looks something 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;projects/&amp;lt;projectNumber&amp;gt;/secrets/&amp;lt;secretName&amp;gt;/versions/latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google-cloud/functions-framework&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin/app&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFirestore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin/firestore&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;SecretManagerServiceClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google-cloud/secret-manager&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;client&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;SecretManagerServiceClient&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;getSecretValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secretName&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;version&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessSecretVersion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;secretName&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;secretValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secretValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secretValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloudEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helloPubSub&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;cloudEvent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// remember to change the name of your cloud function to the entry point&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSecretValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;projects/&amp;lt;projectNumber&amp;gt;/secrets/FIRESTORE_SECRET/versions/latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no firestore config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getFirestore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;project_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;private_key_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;private_key_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;private_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;private_key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;client_email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client_email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;auth_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;token_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token_uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;auth_provider_x509_cert_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth_provider_x509_cert_url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;client_x509_cert_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firestoreConfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client_x509_cert_url&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="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;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFirestore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myCollection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And of course the package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sample-pubsub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@google-cloud/secret-manager"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.2.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"firebase-admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^11.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@google-cloud/functions-framework"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.1.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To complete the deployment process, simply copy and paste the above code, ensuring that you have made any necessary amendments for the secret name and cloud function entry point. Once you're satisfied that everything is in order, hit the deploy button and your cloud function will be deployed.&lt;/p&gt;

&lt;p&gt;If any issues arise, be sure to check the logs for any error messages. &lt;/p&gt;

&lt;h2&gt;
  
  
  Granting Permissions
&lt;/h2&gt;

&lt;p&gt;Next up we need to give your cloud function service account you made earlier permission to access your firebase secret..&lt;br&gt;
Go to the secret manager, click on the secret you made earlier, then click on the permission tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Freym34zxcqtgug7z9bwm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Freym34zxcqtgug7z9bwm.png" alt="permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click grant access and in the new principals input type the service account that you made earlier for the cloud function identity.  If you cant remember it you can find it in the service account section.&lt;/p&gt;

&lt;p&gt;Once you have added the principal in the role dropdown, search for secret manager secret accessor. Select it, then hit save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhft1h8jabvi5hmerfq49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhft1h8jabvi5hmerfq49.png" alt="granting roles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your cloud function is now setup to have access to the secrets you specified.&lt;/p&gt;

&lt;p&gt;Now we need to be able to fire our cloud function...  To do this we will setup a chron job in cloud scheduler that will fire our topic at a certain time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Scheduler
&lt;/h2&gt;

&lt;p&gt;To create a new job in Cloud Scheduler, first navigate to the Cloud Scheduler section by using the search bar and click on the "Create job" button. Give your job a descriptive and suitable name. Ensure that you select the same region as you used earlier for your cloud function to avoid any unexpected errors.&lt;/p&gt;

&lt;p&gt;Now, in the "Frequency" input field, you can enter a chron time that determines the schedule of your job. It's important to note that the frequency setting can have a significant impact on your costs. For example, a very frequent schedule could result in a larger bill from Google. I recommend using a sensible and suitable frequency, for example, "0 10 * * *", which will trigger the job at 10 AM every day. Remember that you can always adjust the frequency later if needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fz4kno9gthn9j4dis5d6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fz4kno9gthn9j4dis5d6j.png" alt="scheduler"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the time zone, hit continue to proceed with the schedule configuration. Choose the target type of pub/sub and select the topic you created earlier. The system will then request a message body, which is not relevant in this case. However, it is important to fill out this field with any suitable message to proceed. Once done, click on create to finish the configuration process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbemsrgu3ejme4y5oav86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbemsrgu3ejme4y5oav86.png" alt="schedule setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, click on the ellipses for the job you just created and click force run:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fq4lub1txqvdko3ijr0w1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fq4lub1txqvdko3ijr0w1.png" alt="trigger scheduled job"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Completion
&lt;/h2&gt;

&lt;p&gt;Your entry should now appear in Firestore and an entry will be made every day at 10 am via the schedule, which you will see via the timestamp in your Firestore entry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F0yl4tjspd4719ooni7j5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0yl4tjspd4719ooni7j5.png" alt="firestore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If for any reason the record isn't made in Firestore, remember to check your logs in the Cloud Function section of the console for errors.&lt;/p&gt;

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