Skip to content

Commit

Permalink
Merge pull request #8 from tparker00/reworkClientUse
Browse files Browse the repository at this point in the history
Rework client use
  • Loading branch information
tparker00 authored Aug 15, 2024
2 parents 0091f22 + 311e927 commit 4de61a8
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 88 deletions.
12 changes: 7 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
FROM golang:alpine AS builder

WORKDIR /app
RUN apk add --no-cache musl-dev gcc ca-certificates
RUN apk add --no-cache musl-dev gcc
COPY . .
RUN cd cmd/bws-cache && go build -ldflags='-s -w' -trimpath -o /dist/bws-cache

RUN cd cmd/bws-cache && go build -ldflags='-s -w' -trimpath -o /dist/bws-cache
RUN ldd /dist/bws-cache | tr -s [:blank:] '\n' | grep ^/ | xargs -I % install -D % /dist/%

FROM scratch

FROM alpine
COPY --from=builder /dist /
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
RUN apk add --no-cache ca-certificates

USER 65534

CMD ["/bws-cache", "start"]

44 changes: 20 additions & 24 deletions internal/pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func New(config *config.Config) http.Handler {
router.Use(middleware.Recoverer)
router.Use(middleware.Timeout(config.WebTTL))

// Enable profiler
router.Mount("/debug", middleware.Profiler())

slog.Debug("Router middleware setup finished")

slog.Debug("Creating new bitwarden client connection")
Expand All @@ -55,63 +58,56 @@ func New(config *config.Config) http.Handler {
}

func (api *API) getSecretByID(w http.ResponseWriter, r *http.Request) {
slog.Debug("Getting secret by ID")
ctx := r.Context()
slog.DebugContext(ctx, "Getting secret by ID")
token, err := getAuthToken(r)
slog.Debug("Got auth token")
slog.DebugContext(ctx, "Got auth token")
if err != nil {
slog.Error(fmt.Sprintf("%+v", err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
id := chi.URLParam(r, "secret_id")

slog.Debug("Connecting to bitwarden service")
api.Client.Connect(token)
defer api.Client.Close()
slog.Debug("Connected to bitwarden service")

slog.Debug(fmt.Sprintf("Getting secret by ID: %s", id))
res, err := api.Client.GetByID(id)
slog.DebugContext(ctx, fmt.Sprintf("Getting secret by ID: %s", id))
res, err := api.Client.GetByID(ctx, id, token)
if err != nil {
slog.Error(fmt.Sprintf("%+v", err))
slog.ErrorContext(ctx, fmt.Sprintf("%+v", err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
slog.Debug("Got secret")
slog.DebugContext(ctx, "Got secret")
fmt.Fprint(w, res)
}

func (api *API) getSecretByKey(w http.ResponseWriter, r *http.Request) {
slog.Debug("Getting secret by key")
ctx := r.Context()
slog.DebugContext(ctx, "Getting secret by key")
token, err := getAuthToken(r)
if err != nil {
slog.Error(fmt.Sprintf("%+v", err))
slog.ErrorContext(ctx, fmt.Sprintf("%+v", err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
key := chi.URLParam(r, "secret_key")

slog.Debug("Connecting to bitwarden service")
api.Client.Connect(token)
defer api.Client.Close()
slog.Debug("Connected to bitwarden service")

slog.Debug(fmt.Sprintf("Searching for key: %s", key))
res, err := api.Client.GetByKey(key, api.OrgID)
slog.DebugContext(ctx, fmt.Sprintf("Searching for key: %s", key))
res, err := api.Client.GetByKey(ctx, key, api.OrgID, token)
if err != nil {
slog.Error(fmt.Sprintf("%+v", err))
slog.ErrorContext(ctx, fmt.Sprintf("%+v", err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
slog.Debug("Got key")
slog.DebugContext(ctx, "Got key")
fmt.Fprint(w, res)
}

func (api *API) resetConnection(w http.ResponseWriter, r *http.Request) {
slog.Info("Resetting cache")
ctx := r.Context()
slog.InfoContext(ctx, "Resetting cache")

api.Client.Cache.Reset()
slog.Info("Cache reset")
slog.InfoContext(ctx, "Cache reset")
}

func getAuthToken(r *http.Request) (string, error) {
Expand Down
145 changes: 86 additions & 59 deletions internal/pkg/client/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"context"
"encoding/json"
"fmt"
"log/slog"
Expand All @@ -14,87 +15,65 @@ import (
)

type Bitwarden struct {
Client sdk.BitwardenClientInterface
Cache *cache.Cache
clientsInUse int
tokenPath string
mu sync.Mutex
Client sdk.BitwardenClientInterface
Cache *cache.Cache
tokenPath string
mu sync.Mutex
}

func New(ttl time.Duration) *Bitwarden {
bw := Bitwarden{}
slog.Debug("Setting up cache")
bw.Cache = cache.New(ttl)
bw.tokenPath = fmt.Sprintf("/tmp/%s", uuid.New())
return &bw
}

func (b *Bitwarden) Connect(token string) error {
b.mu.Lock()
var err error
if b.clientsInUse == 0 {
slog.Debug("Creating new bitwarden client connection")
b.Client, err = b.newClient(token)
if err != nil {
return err
}
} else {
slog.Debug("Client already open/created")
}
b.clientsInUse++
b.mu.Unlock()
return nil
func (b *Bitwarden) connect(token string) error {
slog.Debug("Creating new bitwarden client connection")
return b.newClient(token)
}

func (b *Bitwarden) newClient(token string) (sdk.BitwardenClientInterface, error) {
bitwardenClient, _ := sdk.NewBitwardenClient(nil, nil)
if b.tokenPath == "" {
b.tokenPath = fmt.Sprintf("/tmp/%s", uuid.New())
}
err := bitwardenClient.AccessTokenLogin(token, &b.tokenPath)
if err != nil {
return nil, err
}
return bitwardenClient, nil
func (b *Bitwarden) newClient(token string) error {
b.Client, _ = sdk.NewBitwardenClient(nil, nil)
return b.Client.AccessTokenLogin(token, &b.tokenPath)
}

func (b *Bitwarden) Close() {
b.mu.Lock()
b.clientsInUse--
if b.clientsInUse == 0 {
slog.Debug("Closing bitwarden client connection")
b.Client.Close()
b.mu.Unlock()
return
}
slog.Debug("Client still in use not closing")
b.mu.Unlock()
func (b *Bitwarden) close() {
slog.Debug("Closing bitwarden client connection")
b.Client.Close()
}

func (b *Bitwarden) GetByID(id string) (string, error) {
slog.Debug(fmt.Sprintf("Getting secret by ID: %s", id))
func (b *Bitwarden) GetByID(ctx context.Context, id string, clientToken string) (string, error) {
slog.DebugContext(ctx, fmt.Sprintf("Getting secret by ID: %s", id))
value := b.Cache.GetSecret(id)
if value != "" {
slog.Debug(fmt.Sprintf("%s ID found in cache", id))
return value, nil
}
secretIDs := make([]string, 1)
secretIDs[0] = id

slog.Debug(fmt.Sprintf("%s not found in cache, populating", id))
secret, err := b.Client.Secrets().GetByIDS(secretIDs)

secret, err := b.getSecretByIDs(ctx, id, clientToken)
if secret == nil {
return "", fmt.Errorf("unable to find secret: %s", id)
}
if err != nil {
return "", err
}

secretJson, _ := json.Marshal(secret)
b.Cache.SetSecret(id, string(secretJson))
return string(secretJson), err
return string(secretJson), nil
}

func (b *Bitwarden) GetByKey(key string, orgID string) (string, error) {
func (b *Bitwarden) GetByKey(ctx context.Context, key string, orgID string, clientToken string) (string, error) {
secret := ""
id := b.Cache.GetID(key)
if id == "" {
slog.Debug(fmt.Sprintf("%s not found in cache, populating", key))
keyList, err := b.Client.Secrets().List(orgID)
slog.DebugContext(ctx, fmt.Sprintf("%s not found in cache, populating", key))

keyList, err := b.getSecretList(ctx, orgID, clientToken)
if err != nil {
return "", err
}
Expand All @@ -108,12 +87,6 @@ func (b *Bitwarden) GetByKey(key string, orgID string) (string, error) {
// query, but it returns all of them with a single query anyway
if keyPair.Key == key {
found = true
BwsSecret, err := b.Client.Secrets().Get(keyPair.ID)
if err != nil {
return "", err
}
storedSecret, _ := json.Marshal(BwsSecret)
b.Cache.SetSecret(keyPair.ID, string(storedSecret))
}
}
if !found {
Expand All @@ -124,14 +97,68 @@ func (b *Bitwarden) GetByKey(key string, orgID string) (string, error) {
}
secret = b.Cache.GetSecret(id)
if secret == "" {
slog.Debug(fmt.Sprintf("%s not found in cache, populating", key))
BwsSecret, err := b.Client.Secrets().Get(id)
slog.DebugContext(ctx, fmt.Sprintf("%s not found in cache, populating", key))
bwsSecret, err := b.getSecret(ctx, id, clientToken)
if err != nil {
return "", err
}
storedSecret, _ := json.Marshal(BwsSecret)
storedSecret, _ := json.Marshal(bwsSecret)
b.Cache.SetSecret(id, string(storedSecret))
secret = string(storedSecret)
}
return secret, nil
}

func (b *Bitwarden) getSecretList(ctx context.Context, orgID string, clientToken string) (*sdk.SecretIdentifiersResponse, error) {
slog.DebugContext(ctx, "getSecretList: Locking client")
b.mu.Lock()

slog.DebugContext(ctx, "getSecretList: Opening client")
b.connect(clientToken)

res, err := b.Client.Secrets().List(orgID)
slog.DebugContext(ctx, "getSecretList: Closing client")
b.close()

slog.DebugContext(ctx, "getSecretList: Unlocking client")
b.mu.Unlock()

return res, err
}

func (b *Bitwarden) getSecret(ctx context.Context, id string, clientToken string) (*sdk.SecretResponse, error) {
slog.DebugContext(ctx, "getSecret: Locking client")
b.mu.Lock()

slog.DebugContext(ctx, "getSecret: Opening client")
b.connect(clientToken)

res, err := b.Client.Secrets().Get(id)
slog.DebugContext(ctx, "getSecret: Closing Client")
b.close()

slog.DebugContext(ctx, "getSecret: Unlocking client")
b.mu.Unlock()

return res, err
}

func (b *Bitwarden) getSecretByIDs(ctx context.Context, id string, clientToken string) (*sdk.SecretsResponse, error) {
slog.DebugContext(ctx, "getSecretByIDs: Locking client")
b.mu.Lock()

slog.DebugContext(ctx, "getSecretByIDs: Opening client")
b.connect(clientToken)

secretIDs := make([]string, 1)
secretIDs[0] = id
res, err := b.Client.Secrets().GetByIDS(secretIDs)

slog.DebugContext(ctx, "getSecretByIDs: Closing client")
b.close()

slog.DebugContext(ctx, "getSecretByIDs: Unlocking client")
b.mu.Unlock()

return res, err
}

0 comments on commit 4de61a8

Please sign in to comment.