Consul is a tool for service discovery and configuration. It provides a way to discover services and manage configurations in a distributed system.

Vault is a service that help us to manage secrets and protect sensitive data. It provides a secure way to store and access secrets like API keys, passwords, certificates, etc.

Both are similar tools provided by HashiCorp Where we can access the services using the HTTP API.

Let’s see how we can connect to Consul and Vault using Golang.

Prerequisites

  • Consul & Vault server running

docker compose file to run

services:
  vault:
    image: hashicorp/vault
    container_name: vault
    ports:
      - 8200:8200 # Expose Vault's UI and API port
    environment:
      - VAULT_DEV_ROOT_TOKEN_ID=myroot
    cap_add:
      - IPC_LOCK # Required for Vault to lock memory
    volumes:
      - ./vault-data:/vault/file # Persist Vault data
  consul:
    image: hashicorp/consul
    container_name: consul
    ports:
      - 8500:8500 # Expose Consul's UI and API port

Create some values in Consul

docker exec -it consul_container consul kv put config/myapp '{"host": "http://localhost"}'

Create some secrets in Vault

docker exec -it -e VAULT_ADDR=http://127.0.0.1:8200 -e VAULT_TOKEN=myroot vault_container vault kv put secret/myapp username=admin password=admin123

Connecting to Consul and Vault using Golang

We need to install the client package to connect to Consul and Vault.

go get github.com/hashicorp/consul/api
go get github.com/hashicorp/vault/api

Here is an example code to connect to Vault using Golang.

package main

import (
	"context"
	"encoding/json"
	"log"

	consul "github.com/hashicorp/consul/api"
	vault "github.com/hashicorp/vault/api"
)

func vaultRead() {
	config := vault.DefaultConfig()

	config.Address = "http://127.0.0.1:8200"

	client, err := vault.NewClient(config)
	if err != nil {
		log.Fatalf("unable to initialize Vault client: %v", err)
	}

	// Authenticate
	client.SetToken("myroot")

	ctx := context.Background()

	// Read a secret
	secret, err := client.KVv2("secret").Get(ctx, "myapp")
	if err != nil {
		log.Fatalf("unable to read secret: %v", err)
	}

	value, ok := secret.Data["username"].(string)
	if !ok {
		log.Fatalf("unable to read username: %v", err)
	}

	log.Println("Username:", value)
    // Username: admin
}

type ConsulConfig struct {
	Host string `json:"host"`
}

func consulRead() {
    // Connect to Consul
	config := consul.DefaultConfig()

	config.Address = "http://127.0.0.1:8500"

    // Create a new client
	client, err := consul.NewClient(config)
	if err != nil {
		log.Fatalf("unable to initialize Vault client: %v", err)
	}

    // Read a value
	pair, _, err := client.KV().Get("config/myapp", nil)
	if err != nil {
		log.Fatalf("unable to read secret: %v", err)
	}

	log.Println("Host:", string(pair.Value))

	var consulConfig ConsulConfig
	if err := json.Unmarshal(pair.Value, &consulConfig); err != nil {
		log.Fatalf("unable to unmarshal Consul config: %v", err)
	}

	log.Println("Host:", consulConfig.Host)
    // Host: http://localhost
}

func main() {
	vaultRead()
	consulRead()
}

It’s pretty simple to connect to Consul and Vault using Golang. We can use the client packages provided by HashiCorp to connect to the services.

The http api by Consul and Vault is simple to use and we can easily connect to the services using Golang clients provided by HashiCorp.

That’s it. We have seen how to connect to Consul and Vault using Golang.