How to enable kubernetes auth method via Go API

As part of my test code I stand up a Vault instance (in a Docker container, using testcontainers-go). Using the Go API, I need to enable the kubernetes auth method in this instance but for the life of me I can’t figure out how to do it using the Go API. Go is my newest language so I’m sure this is just me not understanding the API.

I tried to find an example of this but either there isn’t one out there or my Google-fu isn’t good enough to find it. I also tried reading the Go sources for the “vault” command but again, my Go-fu isn’t strong enough to figure it out.

Can anyone please help me out?

Thanks,
Adam

P.S. I suppose I could do the equivalent of a “docker exec” into the Vault container and from there do “vault auth enable kubernetes” but I’m already doing lots of other stuff via the Go API and I’d hate to have to switch mechanisms for just this one operation.

1 Like

Hi @asm2hcv Thanks for your post. In general I would always reccomend using some kind of configuration management system or terraform to configure Vault but for edge cases, I have prepared two example code snippets to accomplish this.

This first example using the Vault Go SDK to enable and configure the Kubernetes auth method:

package main

import (
"fmt"
"os"
"io/ioutil"

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

func main() {

	// Setting up vault client with token and address
	var token = os.Getenv("TOKEN")
	var vaultaddr = os.Getenv("VAULT_ADDR")

	// Setting sane defaults incase the environment variables are not set
	if token == "" {
		token = "root"
	}

	if vaultaddr == "" {
		vaultaddr = "http://127.0.0.1:8200"
	}

	config := &api.Config{
		Address: vaultaddr,
	}

	client, err := api.NewClient(config)
	if err != nil {
		fmt.Println(err)
		return
	}

	client.SetToken(token)
	c := client.Logical()

	// Enabling Kubernetes auth method

	kauth, err := c.Write("sys/auth/kubernetes", map[string]interface{}{
		"type": "kubernetes",
		"description": "k8s backend for development environment",
	})

	if err != nil {
		fmt.Println(err)
		return
	}

	if kauth != nil {
		fmt.Println(kauth)
		return
	}

	// Configuring Kubernetes auth method

	pemFile, err := ioutil.ReadFile("test.pem")
	f := string(pemFile)

	kconfig, err := c.Write("/auth/kubernetes/config", map[string]interface{}{
		"kubernetes_host": "127.0.0.1:8080",
		"kubernetes_ca_cert": f,
	})

	if err != nil {
		fmt.Println(err)
		return
	}

	if kconfig != nil {
		fmt.Println(kconfig)
		return
	}

}

This assumes you have a CA cert file called test.pem

The second example uses the Vault API directly to achieve the same thing as the above code snippet. Again it assumes the pressence of the test.pem file.

package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

var token = os.Getenv("TOKEN")
var vaultaddr = os.Getenv("VAULT_ADDR")

func enable()  {
	// setting up token and address for API calls
	if token == "" {
		token = "root"
	}

	if vaultaddr == "" {
		vaultaddr = "http://127.0.0.1:8200/v1"
	}

	// Enabling Kubernetes auth method

	// create http client
	client := &http.Client{	}

	// Create request body
	postBody, _ := json.Marshal(map[string]string{
		"type": "kubernetes",
		"description": "k8s backend for development environment",
	})
	responseBody := bytes.NewBuffer(postBody)

	// Create and make POST api call to Vault
	endpoint := vaultaddr + "/sys/auth/kubernetes"

	req, err := http.NewRequest("POST", endpoint, responseBody)
	req.Header.Add("X-Vault-Token", token)
	resp, err := client.Do(req)

	// Error handling from api call
	if err != nil {
		log.Fatalln(err)
		return
	}

	defer resp.Body.Close()

	// Handle api response

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}
	sb := string(body)
	log.Printf(sb)

}

func configure()  {
	// setting up token and address for API calls
	if token == "" {
		token = "root"
	}

	if vaultaddr == "" {
		vaultaddr = "http://127.0.0.1:8200/v1"
	}
	// Read a local CA cert file to configure
	certFile, err := ioutil.ReadFile("test.pem")
	f := string(certFile)

	// create http client
	client := &http.Client{	}

	// Create request body
	postBody, _ := json.Marshal(map[string]string{
		"kubernetes_host": "http://127.0.0.1:8080",
		"kubernetes_ca_cert": f,
	})
	responseBody := bytes.NewBuffer(postBody)

	// Create and make POST api call to Vault
	endpoint := vaultaddr + "/auth/kubernetes/config"

	req, err := http.NewRequest("POST", endpoint, responseBody)
	req.Header.Add("X-Vault-Token", token)
	resp, err := client.Do(req)

	// Error handling from api call
	if err != nil {
		log.Fatalln(err)
		return
	}

	defer resp.Body.Close()

	// Handle api response

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}
	sb := string(body)
	log.Printf(sb)

}

func main()  {
	enable()
	configure()
}

There are some API docs that will help you understand how these API calls are being constructed which I will list below:

Authenticating with Vault API
Enabling auth methods
Configuring Kubernetes Auth method

I hope you find this useful. As always, please feel free to reply to this post if you need any further clarification.

Robert,

First, thanks a bunch for the code examples! I’ll give them a try later today.

As for your suggestion about Terraform, config. management, etc., this is an ephemeral Vault instance that I bring up as part of my automated integration tests then tear down when the tests are finished. Otherwise, yeah, config management systems are the only way to go.

Thanks again,
Adam

1 Like