Skip to content
Integration test Vault code locally!
Go
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci
pkg/vaulttest
.gitignore
LICENSE
README.md
go.mod
go.sum

README.md

vaulttest

Circle CI

Library for spinning up test instances of Hashicorp Vault for use in integration tests locally and in CI systems.

Hashicorp Vault is an awesome tool, but if your job is managing it, you need more than pointing and clicking in a UI, or running vault commands against the server.

A much better way is to write some code that instruments your Vault in a predictable manner, but how does one test said code?

What's really needed is a test Vault or better yet a fleet of them to test changes in parallel.

Unfortunately Hashicorp Vault's source code is not organized/ exported in a way to make it's internal api easily adapted to a fully code defined, in memory Vault dev server.

What we can do, however, is have this package spin one up- provided the vault binary is on the system somewhere.

The vaulttest package will find a free port, spin up vault in dev mode on that port, allow you to do your tests against it, and shut it down politely once you're done.

Prerequisites

Usage

Include the following in your test code:

var testServer *vaulttest.VaultDevServer
var testClient *api.Client

func TestMain(m *testing.M) {
    setUp()

    code := m.Run()

    tearDown()

    os.Exit(code)
}

func setUp() {
    port, err := freeport.GetFreePort()
    if err != nil {
        log.Fatalf("Failed to get a free port on which to run the test vault server: %s", err)
    }

    testAddress := fmt.Sprintf("127.0.0.1:%d", port)

    testServer = vaulttest.NewVaultDevServer(testAddress)

    if !testServer.Running {
        testServer.ServerStart()
        client := testServer.VaultTestClient()

        // set up some secret engines
        for _, endpoint := range []string{
            "prod",
            "stage",
            "dev",
        } {
            data := map[string]interface{}{
                "type":        "kv-v2",
                "description": "Production Secrets",
            }
            _, err := client.Logical().Write(fmt.Sprintf("sys/mounts/%s", endpoint), data)
            if err != nil {
                log.Fatalf("Unable to create secret engine %q: %s", endpoint, err)
            }
        }

        // setup a PKI backend
        data := map[string]interface{}{
            "type":        "pki",
            "description": "PKI backend",
        }
        
        _, err := client.Logical().Write("sys/mounts/pki", data)
        if err != nil {
            log.Fatalf("Failed to create pki secrets engine: %s", err)
        }

        data = map[string]interface{}{
            "common_name": "test-ca",
            "ttl":         "43800h",
        }
        
        _, err = client.Logical().Write("pki/root/generate/internal", data)
        if err != nil {
            log.Fatalf("Failed to create root cert: %s", err)
        }

        data = map[string]interface{}{
            "max_ttl":         "24h",
            "ttl":             "24h",
            "allow_ip_sans":   true,
            "allow_localhost": true,
            "allow_any_name":  true,
        }
        
        _, err = client.Logical().Write("pki/roles/foo", data)
        if err != nil {
            log.Fatalf("Failed to create cert issuing role: %s", err)
        }

        data = map[string]interface{}{
            "type":        "cert",
            "description": "TLS Cert Auth endpoint",
        }

        _, err = client.Logical().Write("sys/auth/cert", data)
        if err != nil {
            log.Fatalf("Failed to enable TLS cert auth: %s", err)
        }
        
        ... Do other setup stuff ...
        
        testClient = client
    }
}

func tearDown() {
    if _, err := os.Stat(tmpDir); !os.IsNotExist(err) {
        os.Remove(tmpDir)
    }

    testServer.ServerShutDown()
}

func TestNewNamespace(t *testing.T) {
    path := "dev/foo/bar"
    secret, err := testClient.Logical().Read(path)
    if err != nil {
        log.Printf("Unable to read %q: %s\n", path, err)
        t.Fail()
    }
    
    if secret == nil {
        log.Print("Nil Secret")
        t.fail() 
    }
    
    assert.True(t, secret.Data["foo"].(string) == "bar", "Successfully returned secret")
}
You can’t perform that action at this time.