libvault/token.go

163 lines
3.6 KiB
Go

//////////////////////////////////////////////////////////////////////////
package libvault
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
import (
"errors"
log "github.com/sirupsen/logrus"
"os"
"strings"
"time"
)
//////////////////////////////////////////////////////////////////////////
type Token struct {
Token string
expires time.Time
}
//////////////////////////////////////////////////////////////////////////
// read and save token to a file
func NewTokenFromFile(filename string) (*Token, error) {
// default the filename if not passed as arg
if filename == "" {
filename = VAULT_TOKEN_FILE
}
// read the contents of the file
b, err := os.ReadFile(filename)
if err != nil {
log.WithFields(log.Fields{
"filename": filename,
"error": err,
}).Error("libvault: failed to read vault token from file")
return nil, err
}
// get first line and trim any whitespace
ts, _, _ := strings.Cut(string(b), "\n")
ts = strings.TrimSpace(ts)
if ts == "" {
log.WithFields(log.Fields{
"filename": filename,
"raw": string(b),
}).Error("libvault: failed to parse vault token from file")
return nil, errors.New("libvault: failed to parse vault token from file")
}
log.WithFields(log.Fields{
"filename": filename,
"token": ts,
}).Debug("libvault: successfully read vault token")
return &Token{Token: ts}, nil
}
func (t *Token) SaveToFile(filename string) error {
if filename == "" {
filename = VAULT_TOKEN_FILE
}
data := []byte(t.Token + "\n")
if err := os.WriteFile(filename, data, 0600); err != nil {
log.WithFields(log.Fields{
"filename": filename,
"error": err,
}).Error("libvault: failed to write token to file")
return err
}
log.WithFields(log.Fields{
"filename": filename,
}).Debug("libvault: successfully saved vault token")
return nil
}
//////////////////////////////////////////////////////////////////////////
// find token expiry date
func (t *Token) Expires() (time.Time, error) {
if t.expires.IsZero() {
// request and response json structures
req := &struct {
Token string `json:"token"`
}{Token: t.Token}
resp := &struct {
Data *struct {
ExpireTime time.Time `json:"expire_time"`
} `json:"data"`
}{}
if err := vault.POST(t, "/auth/token/lookup", req, resp); err != nil {
log.WithFields(log.Fields{
"token": t.Token,
}).Error("libvault: failed to determine token expiry date")
return t.expires, err
}
t.expires = resp.Data.ExpireTime
}
return t.expires, nil
}
//////////////////////////////////////////////////////////////////////////
// renew token
func (t *Token) Renew(increment time.Duration) error {
expiry, err := t.Expires()
if err != nil {
return err
}
// check if token should be renewed
ttl := expiry.Sub(time.Now())
if ttl.Seconds() > (VAULT_RENEW_PERIOD.Seconds()) {
log.WithFields(log.Fields{
"expiry": expiry.String(),
"ttl": ttl.String(),
}).Debug("Token renewal not required")
return nil
}
// renew token
if increment == 0 {
increment = VAULT_TTL
}
req := &struct {
Increment string `json:"increment"`
}{Increment: increment.String()}
if err := vault.POST(t, "/auth/token/renew-self", req, nil); err != nil {
log.WithFields(log.Fields{
"token": t.Token,
"expiry": expiry.String(),
"ttl": ttl.String(),
"increment": increment.String(),
}).Error("libvault: failed to renew token")
return err
}
// reset expiry
t.expires = time.Time{}
return nil
}
//////////////////////////////////////////////////////////////////////////
// end of file