DEV Community

Managing Secret For Your Golang Apps With The GCP Secret Manager

Photo by Aneta Pawlik on Unsplash

While developing a serverless application and having a secret key in JSON format, I always looked at how we store that file securely. We can’t save the JSON file in our public repository, right? ☠️

Since I plan to deploy the application using Google Cloud Run, I’ve found that Google Cloud has a Secret Manager service!

Store API keys, passwords, certificates, and sensitive data

Secret Manager is a secure and convenient storage system for API keys, passwords, certificates, and other sensitive data

  • Google Cloud

With Secret Manager, we can store the credentials to the Secret Manager and integrate our application to “take” the credentials from the Secret Manager.

There are two ways to store the secret, we can use the console or CLI, for this time I will use the CLI.

For example, I have a simple Golang app that has a file called secret-key.json for authentication to database services. I want to deploy the application using Cloud Run and using the secret key that is provided so the service can communicated to the database.

I already downloaded the key and am ready to put it on Secret Manager. First of all, make sure your devices are already authenticated with your Google Cloud account.

You can log in to your account by using this command

gcloud auth login
Enter fullscreen mode Exit fullscreen mode

After that, set to using your project

gcloud config set project <PROJECT_ID>
Enter fullscreen mode Exit fullscreen mode

The next step is we should enable the API of the Secret Manager service. You can use this command to enable it.

gcloud services enable secretmanager.googleapis.com
Enter fullscreen mode Exit fullscreen mode

If the message returns “Operation …….. finished successfully” now we’re ready to go 🚀

Now, we’re heading to the directory where we store the secret key, or you can use any directory and set it the path on the command, here is the command that we will use

gcloud secrets create <SECRET_NAME> --data-file=<SECRET_FILE_PATH>
Enter fullscreen mode Exit fullscreen mode

The image below shows the results if we already created the secret in Secret Manager.

captionless image

Or you can check it from the Google Cloud Console and go to the Secret Manager page.

captionless image

Now this is the Go code looks alike, since we just need to read the data, the process on this code is just to retrieve the secret. You should fill out the GOOGLE_CLOUD_PROJECT_NUMBER you can hardcode it or use OS Env.

package main
import (
 "context"
 "log"
 secretsmanager "cloud.google.com/go/secretmanager/apiv1"
 "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
)
func main() {
 projectNumber := os.Getenv("GOOGLE_CLOUD_PROJECT_NUMBER")
 secretName := os.Getenv("SECRET_NAME")
 ctx := context.Background()
 client, err := secretsmanager.NewClient(ctx)
 if err != nil {
  log.Fatalf("failed to setup client: %v", err)
 }
 defer client.Close()
 accessRequest := &secretmanagerpb.AccessSecretVersionRequest{
  Name: "projects/" + projectNumber + "/secrets/" + secretName + "/versions/latest",
 }
 result, err := client.AccessSecretVersion(ctx, accessRequest)
 if err != nil {
  log.Fatalf("failed to access secret version: %v", err)
 }
 secret := string(result.Payload.Data)
 log.Printf("secret: %s", secret)
} 
Enter fullscreen mode Exit fullscreen mode

While running it locally, don’t forget to authenticate the program with the Google Cloud Project by using this command. For more reference, you can check this out.

gcloud auth application-default login
Enter fullscreen mode Exit fullscreen mode

Then, you can run the program using go run main.go and here we go, this is the secret that we stored it before!

captionless image

If you want to deploy it to Cloud Run, you can try this code

package main
import (
 "context"
 "fmt"
 "log"
 "net/http"
 "os"
 secretsmanager "cloud.google.com/go/secretmanager/apiv1"
 "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
)
func main() {
 projectNumber := os.Getenv("GOOGLE_CLOUD_PROJECT_NUMBER")
 secretName := os.Getenv("SECRET_NAME")
 ctx := context.Background()
 client, err := secretsmanager.NewClient(ctx)
 if err != nil {
  log.Fatalf("failed to setup client: %v", err)
 }
 defer client.Close()
 accessRequest := &secretmanagerpb.AccessSecretVersionRequest{
  Name: "projects/" + projectNumber + "/secrets/" + secretName + "/versions/latest",
 }
 result, err := client.AccessSecretVersion(ctx, accessRequest)
 if err != nil {
  log.Fatalf("failed to access secret version: %v", err)
 }
 secret := string(result.Payload.Data)
 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Your secret is: %s", secret)
 })
 log.Fatal(http.ListenAndServe(":8080", nil))
}
Enter fullscreen mode Exit fullscreen mode

GitHub logo razanfawwaz / go-gcp-secret

Go Apps using Secret Manager

go-gcp-secret






Don’t forget to put the Env Variables while setting up the Cloud Run deployment.

If the deployment succeeds, you can try to call the “/” endpoint, and it will return the secret key that we need.

captionless image

Additionally, if the Cloud Run needs access to the Secret Manager, you can go to the Secret Manager and give access to your Cloud Run Service Account by clicking Add Principal.

captionless image

That’s all! 🚀 Thanks for reading!

Top comments (0)