AWS Lambda and Golang logos

Using secrets in AWS Lambda Serverless (Golang)

Going serverless with AWS Lambda Functions provides many benefits for your cloud operation. However, it also comes with its own set of challenges. One of them is getting secrets into your functions. Because more often than not, serverless functions need some secrets to operate. With its native integration with AWS, SecretHub provides an easy method to get your secrets into your function at runtime.

This guide will take you step by step through the process of setting up your Golang Lambda Function that uses the SecretHub Golang SDK for fetching any secrets it needs.

Schematic overview of using SecretHub for an AWS Lambda Function

Before you begin

Before you start with using SecretHub for Lambda, make sure you have completed the following steps:

  1. Install the SecretHub CLI for your OS.
  2. Signup for a SecretHub account.
  3. Install the the AWS CLI.
  4. Configure the AWS CLI to connect to your AWS account.
  5. Download and install the Go distribution for your OS.

Step 1: Make a basic Lambda Function

Let’s first start with setting up the application we’re going to deploy to Lambda. For this we’ll use the following code throughout the guide, but you can follow the same steps for using SecretHub with your own code. Save it as main.go to a clean directory.

package main

import (
    "fmt"
    "context"
    "io/ioutil"
    "net/http"
    "os"
    "github.com/aws/aws-lambda-go/lambda"
)

var (
    username = os.Getenv("USERNAME")
    password = os.Getenv("PASSWORD")
)

func HandleRequest(ctx context.Context) (string, error) {
    url := fmt.Sprintf("https://%s:%s@demo.secrethub.io/api/v1/basic-auth", username, password)

    resp, err := http.Get(url)
    if err != nil {
        return "", fmt.Errorf("could not perform request: %v", err)
    }

    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", fmt.Errorf("could not read body: %v", err)
    }
    return string(body), nil
}

func main() {
        lambda.Start(HandleRequest)
}

The above code makes a request to the SecretHub demo API. The requested endpoint is “secured” with Basic Authentication so we need a username and password for it. For now they are both read from the environment, but throughout this guide we will switch to using SecretHub for retrieving these values.

The username and password for the demo API are stored in SecretHub under your-username/demo/username and your-username/demo/password. If you have not done so before, you can create this repository with secrethub demo init.


Step 2: Insert SecretHub into the Function

This is where the magic happens. The only thing we have to do, is call the SecretHub SDK in the init() function:

import (
    "github.com/secrethub/secrethub-go/pkg/secrethub"
)

func init() {
	client := secrethub.Must(secrethub.NewClient())
	var err error
	username, err = client.Secrets().ReadString("your-username/demo/username")
	if err != nil {
		panic(err)
	}
	password, err = client.Secrets().ReadString("your-username/demo/password")
	if err != nil {
		panic(err)
	}
}

Now the username and password will be loaded into the context of the Lambda function and our handler should be able to make its request to the API.


Step 3: Create a Lambda Execution Role

The first thing we need for the AWS Integration to work, is a Lambda Execution Role.

  1. Go to the Create role page on the AWS Console.
  2. Select AWS Service and then Lambda as trusted entity. Continue by clicking Next: Permissions.

First step in creating IAM Role

  1. Select any Policies your Lambda Function needs and then click Next: Tags. For using SecretHub no specific policy is needed.
  2. Add any tags you like and click Next: Review.
  3. Set a descriptive Role name and description and click Create role. For the example we will use SecretHubDemoLambdaExecutionRole as the name.

Step 4: Create a KMS key

Next, we have to setup a KMS Key to use for encryption and decryption.

  1. Go to the Create Customer Managed Key page on the AWS Console.
  2. Enter an alias and optionally a description for the key and click Next. For the example we will use SecretHub-Demo-Service-Key as an alias.
  3. Add any tags you like and click Next.
  4. Select any users or roles you would like as Key administrators and click Next. Make sure your own IAM user or a role you have access is selected or that you select it on the next page as a Key user.
  5. Select the role you previously created as a Key user and set any other preferred key users and then click Next. A role or user you have access to should either be a Key user or a Key Administrator.

Select the correct Key user for the KMS key

  1. Create the KMS key by clicking Finish.
  2. Take note of the id of the newly created key (e.g. 1234abcd-12ab-34cd-56ef-1234567890ab), you’ll need it in the next step.

Step 5: Setup SecretHub Service Account

Now that we have the required IAM role and KMS key, we can create a service account on SecretHub.

Just run the following command and enter the name of the role, the id of the KMS key and the region you created the KMS key in when asked.

secrethub service aws init your-username/demo --permission read

The --permission read automatically grants the newly created service account read access on the whole repository.


Step 6: Build and Package the Function

It is time to build the function so we can deploy it to AWS.

First create a Gomodule to let Go automatically download all dependencies:

go mod init secrethub-lambda-demo

Next, build the code and create a zip package:

GOOS=linux go build -o main .
zip function.zip main

Step 7: Deploy to AWS

The moment has come to actually deploy our code to AWS Lambda.

  1. Go to the Create function page on the Lambda dashboard on the AWS Console.
  2. Enter a name for the function. We will use secrethubLambdaDemo.
  3. Choose the Go 1.x runtime.
  4. Expand the Choose or create an execution role section. Select Use an existing role and select the Execution Role you created and then click Create Function.

Create the Lambda Function

  1. In the Function code section set Handler to main.
  2. Click Upload and select the function.zip file you created earlier.
  3. In the Environment Variables enter SECRETHUB_IDENTITY_PROVIDER as Key and aws as Value.
  4. Click Save in the upper right corner.

Congratulations, your Lambda Function is now live!


Verify it works

If you want to verify whether your function actually has access to the required secrets, you can trigger a Test Event. In the upper right corner expand Select a test event. Then click on Configure test event. Here you can setup Test Events.

For the demo code we supplied, you can just use the Hello World template, enter a name (e.g. TestEvent) and click Create.

After that you can click the Test button. Your function is now executed. Expand the Details section to see the result of the execution.


See also