Skip to content

Commit

Permalink
chore: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
batthebee committed Oct 17, 2022
0 parents commit d8bb708
Show file tree
Hide file tree
Showing 1,304 changed files with 456,127 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
32 changes: 32 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
GOARCH = amd64

UNAME = $(shell uname -s)

ifndef OS
ifeq ($(UNAME), Linux)
OS = linux
else ifeq ($(UNAME), Darwin)
OS = darwin
endif
endif

.DEFAULT_GOAL := all

all: fmt build start

build:
GOOS=$(OS) GOARCH="$(GOARCH)" go build -o vault/plugins/vault-plugin-secrets-nats cmd/vault-plugin-secrets-nats/main.go

start:
vault server -dev -dev-root-token-id=root -dev-plugin-dir=./vault/plugins

enable:
vault secrets enable -path=nats-secrets vault-plugin-secrets-nats

clean:
rm -f ./vault/plugins/vault-plugin-secrets-nats

fmt:
go fmt $$(go list ./...)

.PHONY: build clean fmt start enable
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Vault Plugin Secrets Nats

## Usage

## License
95 changes: 95 additions & 0 deletions backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package natssecretsengine

import (
"context"
"strings"
"sync"

"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)

func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
b := backend()
if err := b.Setup(ctx, conf); err != nil {
return nil, err
}
return b, nil
}

// natsBackend defines an object that
// extends the Vault backend and stores the
// target API's client.
type natsBackend struct {
*framework.Backend
lock sync.RWMutex
client *natsClient
}

// backend defines the target API backend
// for Vault. It must include each path
// and the secrets it will store.
func backend() *natsBackend {
var b = natsBackend{}

b.Backend = &framework.Backend{
Help: strings.TrimSpace(backendHelp),
PathsSpecial: &logical.Paths{
LocalStorage: []string{},
SealWrapStorage: []string{
"config",
"role/*",
},
},
Paths: framework.PathAppend(
pathOperator(&b),
[]*framework.Path{},
),
Secrets: []*framework.Secret{
// b.hashiCupsToken(),
},
BackendType: logical.TypeLogical,
Invalidate: b.invalidate,
}
return &b
}

// reset clears any client configuration for a new
// backend to be configured
func (b *natsBackend) reset() {
b.lock.Lock()
defer b.lock.Unlock()
b.client = nil
}

// invalidate clears an existing client configuration in
// the backend
func (b *natsBackend) invalidate(ctx context.Context, key string) {
if key == "config" {
b.reset()
}
}

// getClient locks the backend as it configures and creates a
// a new client for the target API
func (b *natsBackend) getClient(ctx context.Context, s logical.Storage) (*natsClient, error) {
b.lock.RLock()
unlockFunc := b.lock.RUnlock
defer func() { unlockFunc() }()

if b.client != nil {
return b.client, nil
}

b.lock.RUnlock()
b.lock.Lock()
unlockFunc = b.lock.Unlock
return b.client, nil
}

// backendHelp should contain help information for the backend
const backendHelp = `
The HashiCups secrets backend dynamically generates user tokens.
After mounting this backend, credentials to manage HashiCups user tokens
must be configured with the "config/" endpoints.
`
142 changes: 142 additions & 0 deletions backend_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package natssecretsengine

import (
"context"
"os"
"testing"

"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/sdk/logical"
"github.com/stretchr/testify/require"
)

const (
envVarRunAccTests = "VAULT_ACC"
envVarHashiCupsUsername = "TEST_HASHICUPS_USERNAME"
envVarHashiCupsPassword = "TEST_HASHICUPS_PASSWORD"
envVarHashiCupsURL = "TEST_HASHICUPS_URL"
)

// getTestBackend will help you construct a test backend object.
// Update this function with your target backend.
func getTestBackend(tb testing.TB) (*natsBackend, logical.Storage) {
tb.Helper()

config := logical.TestBackendConfig()
config.StorageView = new(logical.InmemStorage)
config.Logger = hclog.NewNullLogger()
config.System = logical.TestSystemView()

b, err := Factory(context.Background(), config)
if err != nil {
tb.Fatal(err)
}

return b.(*natsBackend), config.StorageView
}

// runAcceptanceTests will separate unit tests from
// acceptance tests, which will make active requests
// to your target API.
var runAcceptanceTests = os.Getenv(envVarRunAccTests) == "1"

// testEnv creates an object to store and track testing environment
// resources
type testEnv struct {
Username string
Password string
URL string

Backend logical.Backend
Context context.Context
Storage logical.Storage

// SecretToken tracks the API token, for checking rotations
SecretToken string

// Tokens tracks the generated tokens, to make sure we clean up
Tokens []string
}

// AddConfig adds the configuration to the test backend.
// Make sure data includes all of the configuration
// attributes you need and the `config` path!
func (e *testEnv) AddConfig(t *testing.T) {
req := &logical.Request{
Operation: logical.CreateOperation,
Path: "config",
Storage: e.Storage,
Data: map[string]interface{}{
"username": e.Username,
"password": e.Password,
"url": e.URL,
},
}
resp, err := e.Backend.HandleRequest(e.Context, req)
require.Nil(t, resp)
require.Nil(t, err)
}

// AddUserTokenRole adds a role for the HashiCups
// user token.
func (e *testEnv) AddUserTokenRole(t *testing.T) {
req := &logical.Request{
Operation: logical.UpdateOperation,
Path: "role/test-user-token",
Storage: e.Storage,
Data: map[string]interface{}{
"username": e.Username,
},
}
resp, err := e.Backend.HandleRequest(e.Context, req)
require.Nil(t, resp)
require.Nil(t, err)
}

// ReadUserToken retrieves the user token
// based on a Vault role.
func (e *testEnv) ReadUserToken(t *testing.T) {
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "creds/test-user-token",
Storage: e.Storage,
}
resp, err := e.Backend.HandleRequest(e.Context, req)
require.Nil(t, err)
require.NotNil(t, resp)

if t, ok := resp.Data["token"]; ok {
e.Tokens = append(e.Tokens, t.(string))
}
require.NotEmpty(t, resp.Data["token"])

if e.SecretToken != "" {
require.NotEqual(t, e.SecretToken, resp.Data["token"])
}

// collect secret IDs to revoke at end of test
require.NotNil(t, resp.Secret)
if t, ok := resp.Secret.InternalData["token"]; ok {
e.SecretToken = t.(string)
}
}

// CleanupUserTokens removes the tokens
// when the test completes.
func (e *testEnv) CleanupUserTokens(t *testing.T) {
if len(e.Tokens) == 0 {
t.Fatalf("expected 2 tokens, got: %d", len(e.Tokens))
}

// for _, token := range e.Tokens {
// b := e.Backend.(*natsBackend)
// client, err := b.getClient(e.Context, e.Storage)
// if err != nil {
// t.Fatal("fatal getting client")
// }
// // client.Client.Token = string(token)
// // if err := client.SignOut(); err != nil {
// // t.Fatalf("unexpected error deleting user token: %s", err)
// // }
// }
}
38 changes: 38 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package natssecretsengine

import (
nats "github.com/nats-io/nats.go"
)

// natsClient creates an object storing
// the client.
type natsClient struct {
*nats.Conn
}

// // newClient creates a new client to access HashiCups
// // and exposes it for any secrets or roles to use.
// func newClient(config *natsConfig) (*natsClient, error) {
// if config == nil {
// return nil, errors.New("client configuration was nil")
// }

// if config.Username == "" {
// return nil, errors.New("client username was not defined")
// }

// if config.Password == "" {
// return nil, errors.New("client password was not defined")
// }

// if config.URL == "" {
// return nil, errors.New("client URL was not defined")
// }

// // c, err := hashicups.NewClient(&config.URL, &config.Username, &config.Password)
// nc, err := nats.Connect(nats.DefaultURL)
// if err != nil {
// return nil, err
// }
// return &natsClient{nc}, nil
// }
30 changes: 30 additions & 0 deletions cmd/vault-plugin-secrets-nats/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"os"

nats "github.com/edgefarm/vault-plugin-secrets-nats"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/plugin"
)

func main() {
apiClientMeta := &api.PluginAPIClientMeta{}
flags := apiClientMeta.FlagSet()
flags.Parse(os.Args[1:])

tlsConfig := apiClientMeta.GetTLSConfig()
tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig)

err := plugin.Serve(&plugin.ServeOpts{
BackendFactoryFunc: nats.Factory,
TLSProviderFunc: tlsProviderFunc,
})
if err != nil {
logger := hclog.New(&hclog.LoggerOptions{})

logger.Error("plugin shutting down", "error", err)
os.Exit(1)
}
}
23 changes: 23 additions & 0 deletions dev/docker-compose/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: '3.7'
services:
nats:
image: nats:2.9.0-alpine
ports:
- "8222:8222"
command: "--http_port 8222 --config /server.conf"
networks: ["nats"]
volumes:
- $PWD/server.conf:/server.conf
networks:
nats:
name: nats


# db:
# image: "hashicorpdemoapp/product-api-db:v0.0.17"
# ports:
# - "15432:5432"
# environment:
# POSTGRES_DB: 'products'
# POSTGRES_USER: 'postgres'
# POSTGRES_PASSWORD: 'password'
Loading

0 comments on commit d8bb708

Please sign in to comment.