Hashicorp Vault: Part 2 GENERAL SECRET STORAGE IN GOLANG
GENERAL SECRET STORAGE IN GOLANG
In this blog I will explain how to save and use a password into Hashicorp Vault server using Go language.
So, why don’t we prepare a password database for our customer, encrypt it using our own encryption algorithm and present it to the customer in this way? Why is it more reliable to use Hashicorp Vault?
I can tell you the answer to this question as follows. Hashicorp is a reliable and widespread organization. Creating a system as reliable as Hashicorp would be difficult and non-cost friendly. So using a known service will be beneficial for users.
note: *WIL is the personal notes that I took as a result of my research and I want to share. For more detailed information, you should visit Hashicorp Vault’s own site.
I will explain and show some examples in three parts about Hashicorp Vault.
- General explanation about Hashicorp Vault
- General Secret Storage (with example code) (this blog)
- Short-term access to Google Cloud Secret Engine
I am attaching two videos explaining how to install the vault for linux and windows machine and how to create the configuration file. I will just show you how to store K-V type password in Go language.
Before we write the code, we must set up a Vault server.
vault server -dev
When the server starts in -dev
mod, the warning will appear below. We have to save the Root Token
aside so we can access the vault server.
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variables:
PowerShell:
$env:VAULT_ADDR="http://127.0.0.1:8200"
cmd.exe:
set VAULT_ADDR=http://127.0.0.1:8200
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: ZHU7Znx8ocIsG5HJ6dZtNxbHSt1qZezuxDoID61kMAE=
Root Token: hvs.dmpAuR3a0sXLC6HZwdjQDzrw
Development mode should NOT be used in production installations!
According the warning, the ip address must set to the environment variables from cmd. But I want to set environment variable from code.
Firstly, I use the api
package named vault
from the Vault Go library. It is create a new client for authentication with Vault root token. Then I add a password variable to store in vault.
package main
import (
"context"
"log"
"os"
vault "github.com/hashicorp/vault/api"
)
const password string = "PASSWORD1234"
The code first sets the VAULT_ADDR
and VAULT_TOKEN
environment variables to the address of the Vault server and an authentication token. Write the Root Token which you save before.
func Setenv() error {
if err := os.Setenv("VAULT_ADDR", "http://127.0.0.1:8200"); err != nil {
log.Printf("Cannot set VAULT_ADDR")
return err
}
if err := os.Setenv("VAULT_TOKEN", "hvs.dmpAuR3a0sXLC6HZwdjQDzrw"); err != nil {
log.Printf("Cannot set VAULT_TOKEN")
return err
}
return nil
}
Next, it creates a new Vault client using the vault
package's NewClient()
function and the VAULT_ADDR
environment variable as the address of the Vault server. It then sets the client's authentication token using the VAULT_TOKEN
environment variable.
config := vault.DefaultConfig()
config.Address = os.Getenv("VAULT_ADDR")
client, err := vault.NewClient(config)
if err != nil {
log.Fatalf("Unable to initialize a Vault client: %v", err)
}
client.SetToken(os.Getenv("VAULT_TOKEN"))
After that, the code creates a map containing a single key-value pair with the key “password” and the value password
. It then writes this map to the Vault server using the KVv2()
method and the Put()
function, under the key "my-secret-password" in the "secret" path. This stores the "password" value in Vault.
secretData := map[string]interface{}{
"password": password,
}
ctx := context.Background()
_, err = client.KVv2("secret").Put(ctx, "my-secret-password", secretData)
if err != nil {
log.Fatalf("Unable to write secret: %v to the vault", err)
}
log.Println("password written successfully to the vault.")
The password has been securely saved to the Vault Server!
Finally, the code reads the value back from the Vault server using the KVv2()
method and the Get()
function, and returned the value of the "password" key.
secret, err := client.KVv2("the_password").Get(ctx, "my-secret-password")
if err != nil {
log.Fatalf(
"Unable to read the password from the vault: %v",
err,
)
}
value, ok := secret.Data["password"].(string)
if !ok {
log.Fatalf(
"unable to add password: %T %#v",
secret.Data["password"],
secret.Data["password"],
)
}
log.Printf("password [%s] was returned.\n", value)
I am sharing the entire code as GithubGist below.
- WIL: what I learned