package vault import ( "log" "os" "strings" "time" "github.com/hashicorp/vault/api" ) func GenerateClient() *api.Client { config := &api.Config{ Address: "http://vault:8200", MaxRetries: 4, } client, err := api.NewClient(config) if err != nil { log.Fatal(err) } applyToken := func() { tokenBytes, err := os.ReadFile("/vault/token/token") if err != nil { return } token := strings.TrimSpace(string(tokenBytes)) client.SetToken(token) } applyToken() // initial go func() { for { time.Sleep(1 * time.Second) applyToken() } }() return client } func (v *Manager) Get(path string) (*Secret, error) { v.mu.RLock() sec, ok := v.secrets[path] v.mu.RUnlock() if ok && time.Until(sec.ExpiresAt) > 15*time.Second { return sec, nil } var ( s *api.Secret err error ) // fetch from Vault for { s, err = v.client.Logical().Read(path) if err == nil { break } // return nil, err if respErr, ok := err.(*api.ResponseError); !ok || respErr.StatusCode != 403 { return nil, err } // force token reload tokenBytes, readErr := os.ReadFile("/vault/token/token") if readErr != nil { time.Sleep(1 * time.Second) log.Println("/vault/token/token does not exists for the moment") continue } v.client.SetToken(strings.TrimSpace(string(tokenBytes))) time.Sleep(1 * time.Second) } newSec := &Secret{ Data: s.Data, LeaseID: s.LeaseID, ExpiresAt: time.Now().Add(time.Duration(s.LeaseDuration) * time.Second), } v.mu.Lock() v.secrets[path] = newSec v.mu.Unlock() return newSec, nil } func NewManager(client *api.Client) *Manager { return &Manager{ client: client, secrets: make(map[string]*Secret), } }