2015-04-05 01:07:53 +00:00
|
|
|
package file
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2015-04-27 19:40:32 +00:00
|
|
|
"path/filepath"
|
2015-04-27 21:28:02 +00:00
|
|
|
"strconv"
|
2015-04-05 01:07:53 +00:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/hashicorp/vault/audit"
|
|
|
|
"github.com/hashicorp/vault/logical"
|
2015-04-27 21:28:02 +00:00
|
|
|
"github.com/mitchellh/copystructure"
|
2015-04-05 01:07:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func Factory(conf map[string]string) (audit.Backend, error) {
|
|
|
|
path, ok := conf["path"]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("path is required")
|
|
|
|
}
|
|
|
|
|
2015-04-27 21:28:02 +00:00
|
|
|
// Check if raw logging is enabled
|
|
|
|
logRaw := false
|
|
|
|
if raw, ok := conf["log_raw"]; ok {
|
|
|
|
b, err := strconv.ParseBool(raw)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
logRaw = b
|
|
|
|
}
|
|
|
|
|
|
|
|
b := &Backend{
|
|
|
|
Path: path,
|
|
|
|
LogRaw: logRaw,
|
|
|
|
}
|
|
|
|
return b, nil
|
2015-04-05 01:07:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Backend is the audit backend for the file-based audit store.
|
|
|
|
//
|
|
|
|
// NOTE: This audit backend is currently very simple: it appends to a file.
|
|
|
|
// It doesn't do anything more at the moment to assist with rotation
|
|
|
|
// or reset the write cursor, this should be done in the future.
|
|
|
|
type Backend struct {
|
2015-04-27 21:28:02 +00:00
|
|
|
Path string
|
|
|
|
LogRaw bool
|
2015-04-05 01:07:53 +00:00
|
|
|
|
|
|
|
once sync.Once
|
|
|
|
f *os.File
|
|
|
|
}
|
|
|
|
|
2015-06-19 01:30:18 +00:00
|
|
|
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
|
2015-04-05 01:07:53 +00:00
|
|
|
if err := b.open(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-27 21:28:02 +00:00
|
|
|
if !b.LogRaw {
|
2015-06-30 00:16:17 +00:00
|
|
|
// Before we copy the structure we must nil out some data
|
|
|
|
// otherwise we will cause reflection to panic and die
|
|
|
|
if req.Connection != nil && req.Connection.ConnState != nil {
|
|
|
|
origState := req.Connection.ConnState
|
|
|
|
req.Connection.ConnState = nil
|
|
|
|
defer func() {
|
|
|
|
req.Connection.ConnState = origState
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2015-04-27 21:28:02 +00:00
|
|
|
// Copy the structures
|
|
|
|
cp, err := copystructure.Copy(auth)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
auth = cp.(*logical.Auth)
|
|
|
|
|
|
|
|
cp, err = copystructure.Copy(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
req = cp.(*logical.Request)
|
|
|
|
|
|
|
|
// Hash any sensitive information
|
|
|
|
if err := audit.Hash(auth); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := audit.Hash(req); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2015-04-05 01:07:53 +00:00
|
|
|
|
2015-04-13 21:12:14 +00:00
|
|
|
var format audit.FormatJSON
|
2015-06-19 01:30:18 +00:00
|
|
|
return format.FormatRequest(b.f, auth, req, outerErr)
|
2015-04-05 01:07:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Backend) LogResponse(
|
|
|
|
auth *logical.Auth,
|
|
|
|
req *logical.Request,
|
|
|
|
resp *logical.Response,
|
|
|
|
err error) error {
|
|
|
|
if err := b.open(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-27 21:28:02 +00:00
|
|
|
if !b.LogRaw {
|
2015-06-30 00:16:17 +00:00
|
|
|
// Before we copy the structure we must nil out some data
|
|
|
|
// otherwise we will cause reflection to panic and die
|
|
|
|
if req.Connection != nil && req.Connection.ConnState != nil {
|
|
|
|
origState := req.Connection.ConnState
|
|
|
|
req.Connection.ConnState = nil
|
|
|
|
defer func() {
|
|
|
|
req.Connection.ConnState = origState
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2015-04-27 21:28:02 +00:00
|
|
|
// Copy the structure
|
|
|
|
cp, err := copystructure.Copy(auth)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
auth = cp.(*logical.Auth)
|
|
|
|
|
|
|
|
cp, err = copystructure.Copy(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
req = cp.(*logical.Request)
|
|
|
|
|
|
|
|
cp, err = copystructure.Copy(resp)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
resp = cp.(*logical.Response)
|
|
|
|
|
|
|
|
// Hash any sensitive information
|
|
|
|
if err := audit.Hash(auth); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := audit.Hash(req); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := audit.Hash(resp); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2015-04-05 01:07:53 +00:00
|
|
|
|
2015-04-13 21:12:14 +00:00
|
|
|
var format audit.FormatJSON
|
|
|
|
return format.FormatResponse(b.f, auth, req, resp, err)
|
2015-04-05 01:07:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Backend) open() error {
|
|
|
|
if b.f != nil {
|
|
|
|
return nil
|
|
|
|
}
|
2015-04-27 19:40:32 +00:00
|
|
|
if err := os.MkdirAll(filepath.Dir(b.Path), 0600); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-05 01:07:53 +00:00
|
|
|
|
|
|
|
var err error
|
2015-05-06 18:33:06 +00:00
|
|
|
b.f, err = os.OpenFile(b.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
2015-04-05 01:07:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|