Storing Secrets Securely for Go Cloud Applications 🔑
Tags: go, cloud, programming, devops
Published: 2023-10-26 09:54:12

## ✨ Let's learn how to secure a Go app

🤔 Wouldn't it be nice to store secret values like API keys, database passwords, and private keys, directly in the source code?

Of course, we can’t do that, it's horrifyingly insecure!
(Unfortunately, it's also [very common](https://www.ndss-symposium.org/ndss-paper/how-bad-can-it-git-characterizing-secret-leakage-in-public-github-repositories/).)

[Encore](https://encore.dev)'s secrets manager makes it simple to store secrets securely, and lets you use them in your program like regular variables.

In this guide, we'll show you how!🔑

## 💽 Install Encore

Install the Encore CLI to run your local environment:
- **macOS:** `brew install encoredev/tap/encore`
- **Linux:** `curl -L https://encore.dev/install.sh | bash`
- **Windows:** `iwr https://encore.dev/install.ps1 | iex`

## 🛠 Create an app

A common use case for storing secrets is when using a third-party API.

As an example, [ElevenLabs](https://elevenlabs.io/) offers a cool API for generating voices using AI.

To use it, let's create a new Encore application with this command and select the `Empty app` template:

```bash
encore app create
```

## 💾 Download the ElevenLabs package

1. Download the `elevenlabs` package from `https://github.com/encoredev/examples/tree/main/bits/elevenlabs` ([link](https://github.com/encoredev/examples/tree/main/bits/elevenlabs)) and add it to the app directory you just created.
2. Sync your project dependencies by running `go mod tidy`. (Note: This requires that you have Go 1.21, or later, [installed](https://go.dev/doc/install).)

Notice how the program uses `ElevenLabsAPIKey` as a regular variable, that's because Encore takes of supplying the secret from Encore's secret manager. But first, we need to store an API key.

## 🔑 Get your API Key and store it in Encore's secrets manager

Get your [API key from ElevenLabs](https://docs.elevenlabs.io/api-reference/quick-start/authentication) by signing up for a free account at <https://elevenlabs.io>.

Once you have the API key, save it as a secret using Encore's secret manager with the name `ElevenLabsAPIKey`, by running:

```bash
encore secret set --type dev,prod,local,pr ElevenLabsAPIKey
```

## 🏁 Run your app locally
Start your application locally by running:

```bash
encore run
```

You can now open Encore's local development dashboard at <http://localhost:9400> to see your app's API documentation, call the API using the API explorer and view traces, and more.

![Encore local dev dash](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ctzenhiglqnuq3lm470f.png)

## 🕹 Try out the API

Now let's play around a bit with our shiny new API integration!

From the API Explorer in the local development dashboard, try calling the `elevenlabs.DownloadAudio` endpoint with the text input of your choice in the request body.

![API Explorer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qk6vzf9m4fdidozyd3h.png)

This will use the API to generate an MP3 audio file and download it to your app root folder: `speech.mp3`.

If you see the file, it means your API integration works and you securely used your API key. Congratulations!🎉


## 🤔 How it works: Using secrets in your Encore application

Ok, so we know that it works. But _how_ does it work? Let's take a deeper look!

When using a secret in your application, you define it directly in your code by creating an unexported struct named `secrets`, where all fields are of type `string`. For example:

```go
var secrets struct {
    SSHPrivateKey string    // ed25519 private key for SSH server
    GitHubAPIToken string   // personal access token for deployments
    // ...
}
```

When you've defined secrets in your program, the Encore compiler will check that they are set before running or deploying your application. If a secret is not set, you will get a compilation error notifying you that a secret value is missing.

Once you've provided values for all secrets, you can just use them in your application like a regular variable. For example:

```go
func callGitHub(ctx context.Context) {
    req, _ := http.NewRequestWithContext(ctx, "GET", "https:///api.github.com/user", nil)
    req.Header.Add("Authorization", "token " + secrets.GitHubAPIToken)
    resp, err := http.DefaultClient.Do(req)
    // ... handle err and resp
}
```

## 🤔 How it works: Saving secret values

### Using the Cloud Dashboard

The simplest way to set up secrets is with the Secrets Manager in the Encore Cloud Dashboard. Open your app in [app.encore.dev](https://app.encore.dev), go to **Settings** in the main navigation, and then click on **Secrets** in the settings menu.

From there you can create secrets, save secret values, and configure different values for different environments.

![Encore's secrets manager](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlkwtpy50yyhvqvz57d0.png)

### Using the CLI

If you prefer, you can also set up secrets from the CLI using: `encore secret set --type <types> <secret-name>`

`<types>` defines which environment types the secret value applies to. Use a comma-separated list of `production`, `development`, `preview`, and `local`. Shorthands: `prod`, `dev`, `pr`.

For example `encore secret set --type prod SSHPrivateKey` sets the secret value for production environments,<br/> and `encore secret set --type dev,preview,local GitHubAPIToken` sets the secret value for development, preview, and local environments.

In some cases it can be useful to define a secret for a specific environment instead of an environment type.
You can do so with `encore secret set --env <env-name> <secret-name>`. Secret values for specific environments
take precedence over values for environment types.

### Environment settings

Each secret can only have one secret value for each environment type. For example: If you have a secret value that's shared between `development`, `preview` and `local`, and you want to override the value for `local`, you must first edit the existing secret and remove `local` using the Secrets Manager in the [Cloud Dashboard](https://app.encore.dev). You can then add a new secret value for `local`. The end result should look something like the picture below.

![Overriding a secret](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqj2oe09bgkcqwrr3d07.png)

## 🤔 How it works: Where are secrets stored?

When you store a secret Encore stores it encrypted using Google Cloud Platform's [Key Management Service](https://cloud.google.com/security-key-management) (KMS).

- **Production / Your own cloud:** When you deploy to production using your own cloud account on GCP or AWS, Encore provisions a secrets manager in your account (using either KMS or AWS Secrets Manager) and replicates your secrets to it. The secrets are then injected into the container using secret environment variables.
- **Local:** For local secrets Encore automatically replicates them to developers' machines when running `encore run`.
- **Development / Encore Cloud:** Environments on Encore's development cloud (running on GCP under the hood) work the same as self-hosted GCP environments, using GCP Secrets Manager.
## 🚀 Bonus: Deploy to the cloud

If you want to deploy your app to a free cloud environment in Encore's development cloud, simply run:

```bash
git add -A .
git commit -m 'Initial commit'
git push encore
```

👉 Then head over to the [Cloud Dashboard](https://app.encore.dev) to monitor your deployment and find your production URL by going the overview page for the environment you just created. It will be something like: `https://staging-[APP-ID].encr.app`.

![Environment overview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69ay5wocab7mh54d98sd.png)

### 🎉 Great job - you're running in the cloud!

Great job! You now have an AI-powered app running in the cloud.

Keep building with Encore using these Open Source [App Templates](https://encore.dev/templates). 👈

If you have questions or want to share your work, join the developer hangout in [Encore's community Slack](https://encore.dev/slack). 👈

## Learn More

- [Encore Documentation](https://encore.dev/docs)
- [ElevenLabs Documentation](https://docs.elevenlabs.io/welcome/introduction)