Merge branch 'nbrownus-audit-logging'
This commit is contained in:
commit
c1ff26d186
|
@ -11,7 +11,7 @@ type Backend interface {
|
|||
// request is authorized but before the request is executed. The arguments
|
||||
// MUST not be modified in anyway. They should be deep copied if this is
|
||||
// a possibility.
|
||||
LogRequest(*logical.Auth, *logical.Request) error
|
||||
LogRequest(*logical.Auth, *logical.Request, error) error
|
||||
|
||||
// LogResponse is used to syncronously log a response. This is done after
|
||||
// the request is processed but before the response is sent. The arguments
|
||||
|
|
|
@ -5,24 +5,32 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// FormatJSON is a Formatter implementation that structuteres data into
|
||||
// FormatJSON is a Formatter implementation that structures data into
|
||||
// a JSON format.
|
||||
type FormatJSON struct{}
|
||||
|
||||
func (f *FormatJSON) FormatRequest(
|
||||
w io.Writer,
|
||||
auth *logical.Auth, req *logical.Request) error {
|
||||
auth *logical.Auth,
|
||||
req *logical.Request,
|
||||
err error) error {
|
||||
|
||||
// If auth is nil, make an empty one
|
||||
if auth == nil {
|
||||
auth = new(logical.Auth)
|
||||
}
|
||||
if err == nil {
|
||||
err = errors.New("")
|
||||
}
|
||||
|
||||
// Encode!
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(&JSONRequestEntry{
|
||||
Type: "request",
|
||||
Error: err.Error(),
|
||||
|
||||
Auth: JSONAuth{
|
||||
DisplayName: auth.DisplayName,
|
||||
|
@ -31,9 +39,10 @@ func (f *FormatJSON) FormatRequest(
|
|||
},
|
||||
|
||||
Request: JSONRequest{
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
RemoteAddr: req.Connection.RemoteAddr,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -51,10 +60,13 @@ func (f *FormatJSON) FormatResponse(
|
|||
if resp == nil {
|
||||
resp = new(logical.Response)
|
||||
}
|
||||
if err == nil {
|
||||
err = errors.New("")
|
||||
}
|
||||
|
||||
var respAuth JSONAuth
|
||||
var respAuth *JSONAuth
|
||||
if resp.Auth != nil {
|
||||
respAuth = JSONAuth{
|
||||
respAuth = &JSONAuth{
|
||||
ClientToken: resp.Auth.ClientToken,
|
||||
DisplayName: resp.Auth.DisplayName,
|
||||
Policies: resp.Auth.Policies,
|
||||
|
@ -62,9 +74,9 @@ func (f *FormatJSON) FormatResponse(
|
|||
}
|
||||
}
|
||||
|
||||
var respSecret JSONSecret
|
||||
var respSecret *JSONSecret
|
||||
if resp.Secret != nil {
|
||||
respSecret = JSONSecret{
|
||||
respSecret = &JSONSecret{
|
||||
LeaseID: resp.Secret.LeaseID,
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +85,7 @@ func (f *FormatJSON) FormatResponse(
|
|||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(&JSONResponseEntry{
|
||||
Type: "response",
|
||||
Error: err.Error(),
|
||||
|
||||
Auth: JSONAuth{
|
||||
Policies: auth.Policies,
|
||||
|
@ -80,9 +93,10 @@ func (f *FormatJSON) FormatResponse(
|
|||
},
|
||||
|
||||
Request: JSONRequest{
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: req.Data,
|
||||
RemoteAddr: req.Connection.RemoteAddr,
|
||||
},
|
||||
|
||||
Response: JSONResponse{
|
||||
|
@ -99,6 +113,7 @@ type JSONRequestEntry struct {
|
|||
Type string `json:"type"`
|
||||
Auth JSONAuth `json:"auth"`
|
||||
Request JSONRequest `json:"request"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// JSONResponseEntry is the structure of a response audit log entry in JSON.
|
||||
|
@ -111,14 +126,15 @@ type JSONResponseEntry struct {
|
|||
}
|
||||
|
||||
type JSONRequest struct {
|
||||
Operation logical.Operation `json:"operation"`
|
||||
Path string `json:"path"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Operation logical.Operation `json:"operation"`
|
||||
Path string `json:"path"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
RemoteAddr string `json:"remote_address"`
|
||||
}
|
||||
|
||||
type JSONResponse struct {
|
||||
Auth JSONAuth `json:"auth,omitempty"`
|
||||
Secret JSONSecret `json:"secret,emitempty"`
|
||||
Auth *JSONAuth `json:"auth,omitempty"`
|
||||
Secret *JSONSecret `json:"secret,emitempty"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Redirect string `json:"redirect"`
|
||||
}
|
||||
|
|
|
@ -5,12 +5,14 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func TestFormatJSON_formatRequest(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
Auth *logical.Auth
|
||||
Req *logical.Request
|
||||
Err error
|
||||
Result string
|
||||
}{
|
||||
"auth, request": {
|
||||
|
@ -18,7 +20,11 @@ func TestFormatJSON_formatRequest(t *testing.T) {
|
|||
&logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "/foo",
|
||||
Connection: &logical.Connection{
|
||||
RemoteAddr: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
errors.New("this is an error"),
|
||||
testFormatJSONReqBasicStr,
|
||||
},
|
||||
}
|
||||
|
@ -26,7 +32,7 @@ func TestFormatJSON_formatRequest(t *testing.T) {
|
|||
for name, tc := range cases {
|
||||
var buf bytes.Buffer
|
||||
var format FormatJSON
|
||||
if err := format.FormatRequest(&buf, tc.Auth, tc.Req); err != nil {
|
||||
if err := format.FormatRequest(&buf, tc.Auth, tc.Req, tc.Err); err != nil {
|
||||
t.Fatalf("bad: %s\nerr: %s", name, err)
|
||||
}
|
||||
|
||||
|
@ -38,5 +44,5 @@ func TestFormatJSON_formatRequest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
const testFormatJSONReqBasicStr = `{"type":"request","auth":{"display_name":"","policies":["root"],"metadata":null},"request":{"operation":"write","path":"/foo","data":null}}
|
||||
const testFormatJSONReqBasicStr = `{"type":"request","auth":{"display_name":"","policies":["root"],"metadata":null},"request":{"operation":"write","path":"/foo","data":null,"remote_address":"127.0.0.1"},"error":"this is an error"}
|
||||
`
|
||||
|
|
|
@ -12,6 +12,6 @@ import (
|
|||
//
|
||||
// It is recommended that you pass data through Hash prior to formatting it.
|
||||
type Formatter interface {
|
||||
FormatRequest(io.Writer, *logical.Auth, *logical.Request) error
|
||||
FormatRequest(io.Writer, *logical.Auth, *logical.Request, error) error
|
||||
FormatResponse(io.Writer, *logical.Auth, *logical.Request, *logical.Response, error) error
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ type Backend struct {
|
|||
f *os.File
|
||||
}
|
||||
|
||||
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
|
||||
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
|
||||
if err := b.open(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
|
|||
}
|
||||
|
||||
var format audit.FormatJSON
|
||||
return format.FormatRequest(b.f, auth, req)
|
||||
return format.FormatRequest(b.f, auth, req, outerErr)
|
||||
}
|
||||
|
||||
func (b *Backend) LogResponse(
|
||||
|
|
|
@ -52,7 +52,7 @@ type Backend struct {
|
|||
logRaw bool
|
||||
}
|
||||
|
||||
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
|
||||
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
|
||||
if !b.logRaw {
|
||||
// Copy the structures
|
||||
cp, err := copystructure.Copy(auth)
|
||||
|
@ -79,7 +79,7 @@ func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
|
|||
// Encode the entry as JSON
|
||||
var buf bytes.Buffer
|
||||
var format audit.FormatJSON
|
||||
if err := format.FormatRequest(&buf, auth, req); err != nil {
|
||||
if err := format.FormatRequest(&buf, auth, req, outerErr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,9 @@ func handleHelp(core *vault.Core, w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
resp, err := core.HandleRequest(requestAuth(req, &logical.Request{
|
||||
Operation: logical.HelpOperation,
|
||||
Path: path,
|
||||
Operation: logical.HelpOperation,
|
||||
Path: path,
|
||||
Connection: getConnection(req),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
|
|
@ -54,13 +54,6 @@ func handleLogical(core *vault.Core) http.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
// http.Server will set RemoteAddr to an "IP:port" string
|
||||
var remoteAddr string
|
||||
remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
remoteAddr = ""
|
||||
}
|
||||
|
||||
// Make the internal request. We attach the connection info
|
||||
// as well in case this is an authentication request that requires
|
||||
// it. Vault core handles stripping this if we need to.
|
||||
|
@ -68,10 +61,7 @@ func handleLogical(core *vault.Core) http.Handler {
|
|||
Operation: op,
|
||||
Path: path,
|
||||
Data: req,
|
||||
Connection: &logical.Connection{
|
||||
RemoteAddr: remoteAddr,
|
||||
ConnState: r.TLS,
|
||||
},
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if !ok {
|
||||
return
|
||||
|
@ -198,6 +188,22 @@ func respondRaw(w http.ResponseWriter, r *http.Request, path string, resp *logic
|
|||
w.Write(body)
|
||||
}
|
||||
|
||||
func getConnection(r *http.Request) (connection *logical.Connection) {
|
||||
var remoteAddr string
|
||||
|
||||
remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
remoteAddr = ""
|
||||
}
|
||||
|
||||
connection = &logical.Connection{
|
||||
RemoteAddr: remoteAddr,
|
||||
ConnState: r.TLS,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type LogicalResponse struct {
|
||||
LeaseID string `json:"lease_id"`
|
||||
Renewable bool `json:"renewable"`
|
||||
|
|
|
@ -16,8 +16,9 @@ func handleSysListAudit(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
resp, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/audit",
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/audit",
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if !ok {
|
||||
return
|
||||
|
@ -57,8 +58,9 @@ func handleSysDisableAudit(core *vault.Core, w http.ResponseWriter, r *http.Requ
|
|||
}
|
||||
|
||||
_, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/audit/" + path,
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/audit/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if !ok {
|
||||
return
|
||||
|
@ -74,6 +76,7 @@ func handleSysEnableAudit(core *vault.Core, w http.ResponseWriter, r *http.Reque
|
|||
respondError(w, http.StatusNotFound, nil)
|
||||
return
|
||||
}
|
||||
|
||||
path := r.URL.Path[len(prefix):]
|
||||
if path == "" {
|
||||
respondError(w, http.StatusNotFound, nil)
|
||||
|
@ -88,8 +91,9 @@ func handleSysEnableAudit(core *vault.Core, w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
_, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/audit/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/audit/" + path,
|
||||
Connection: getConnection(r),
|
||||
Data: map[string]interface{}{
|
||||
"type": req.Type,
|
||||
"description": req.Description,
|
||||
|
|
|
@ -30,8 +30,9 @@ func handleSysListAuth(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
resp, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/auth",
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/auth",
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
@ -78,8 +79,9 @@ func handleSysEnableAuth(
|
|||
}
|
||||
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/auth/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/auth/" + path,
|
||||
Connection: getConnection(r),
|
||||
Data: map[string]interface{}{
|
||||
"type": req.Type,
|
||||
"description": req.Description,
|
||||
|
@ -99,8 +101,9 @@ func handleSysDisableAuth(
|
|||
r *http.Request,
|
||||
path string) {
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/auth/" + path,
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/auth/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
|
|
@ -38,8 +38,9 @@ func handleSysRenew(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
resp, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/renew/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/renew/" + path,
|
||||
Connection: getConnection(r),
|
||||
Data: map[string]interface{}{
|
||||
"increment": req.Increment,
|
||||
},
|
||||
|
@ -72,8 +73,9 @@ func handleSysRevoke(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/revoke/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/revoke/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, err)
|
||||
|
@ -104,8 +106,9 @@ func handleSysRevokePrefix(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/revoke-prefix/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/revoke-prefix/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, err)
|
||||
|
|
|
@ -41,8 +41,9 @@ func handleSysRemount(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/remount",
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/remount",
|
||||
Connection: getConnection(r),
|
||||
Data: map[string]interface{}{
|
||||
"from": req.From,
|
||||
"to": req.To,
|
||||
|
@ -65,8 +66,9 @@ func handleSysListMounts(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
resp, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/mounts",
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/mounts",
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
@ -121,8 +123,9 @@ func handleSysMount(
|
|||
}
|
||||
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/mounts/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/mounts/" + path,
|
||||
Connection: getConnection(r),
|
||||
Data: map[string]interface{}{
|
||||
"type": req.Type,
|
||||
"description": req.Description,
|
||||
|
@ -142,8 +145,9 @@ func handleSysUnmount(
|
|||
r *http.Request,
|
||||
path string) {
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/mounts/" + path,
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/mounts/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
|
|
@ -16,8 +16,9 @@ func handleSysListPolicies(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
resp, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/policy",
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/policy",
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if !ok {
|
||||
return
|
||||
|
@ -65,8 +66,9 @@ func handleSysDeletePolicy(core *vault.Core, w http.ResponseWriter, r *http.Requ
|
|||
}
|
||||
|
||||
_, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/policy/" + path,
|
||||
Operation: logical.DeleteOperation,
|
||||
Path: "sys/policy/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if !ok {
|
||||
return
|
||||
|
@ -89,8 +91,9 @@ func handleSysReadPolicy(core *vault.Core, w http.ResponseWriter, r *http.Reques
|
|||
}
|
||||
|
||||
resp, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/policy/" + path,
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/policy/" + path,
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if !ok {
|
||||
return
|
||||
|
@ -124,8 +127,9 @@ func handleSysWritePolicy(core *vault.Core, w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
_, ok := request(core, w, r, requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/policy/" + path,
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/policy/" + path,
|
||||
Connection: getConnection(r),
|
||||
Data: map[string]interface{}{
|
||||
"rules": req.Rules,
|
||||
},
|
||||
|
|
|
@ -15,8 +15,9 @@ func handleSysKeyStatus(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
resp, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/key-status",
|
||||
Operation: logical.ReadOperation,
|
||||
Path: "sys/key-status",
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
@ -37,8 +38,9 @@ func handleSysRotate(core *vault.Core) http.Handler {
|
|||
}
|
||||
|
||||
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/rotate",
|
||||
Operation: logical.WriteOperation,
|
||||
Path: "sys/rotate",
|
||||
Connection: getConnection(r),
|
||||
}))
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, err)
|
||||
|
|
|
@ -261,7 +261,7 @@ func (a *AuditBroker) IsRegistered(name string) bool {
|
|||
|
||||
// LogRequest is used to ensure all the audit backends have an opportunity to
|
||||
// log the given request and that *at least one* succeeds.
|
||||
func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request) (reterr error) {
|
||||
func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) (reterr error) {
|
||||
defer metrics.MeasureSince([]string{"audit", "log_request"}, time.Now())
|
||||
a.l.RLock()
|
||||
defer a.l.RUnlock()
|
||||
|
@ -276,7 +276,7 @@ func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request) (rete
|
|||
anyLogged := false
|
||||
for name, be := range a.backends {
|
||||
start := time.Now()
|
||||
err := be.backend.LogRequest(auth, req)
|
||||
err := be.backend.LogRequest(auth, req, outerErr)
|
||||
metrics.MeasureSince([]string{"audit", name, "log_request"}, start)
|
||||
if err != nil {
|
||||
a.logger.Printf("[ERR] audit: backend '%s' failed to log request: %v", name, err)
|
||||
|
|
|
@ -10,12 +10,14 @@ import (
|
|||
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type NoopAudit struct {
|
||||
ReqErr error
|
||||
ReqAuth []*logical.Auth
|
||||
Req []*logical.Request
|
||||
ReqErrs []error
|
||||
|
||||
RespErr error
|
||||
RespAuth []*logical.Auth
|
||||
|
@ -24,9 +26,10 @@ type NoopAudit struct {
|
|||
RespErrs []error
|
||||
}
|
||||
|
||||
func (n *NoopAudit) LogRequest(a *logical.Auth, r *logical.Request) error {
|
||||
func (n *NoopAudit) LogRequest(a *logical.Auth, r *logical.Request, err error) error {
|
||||
n.ReqAuth = append(n.ReqAuth, a)
|
||||
n.Req = append(n.Req, r)
|
||||
n.ReqErrs = append(n.ReqErrs, err)
|
||||
return n.ReqErr
|
||||
}
|
||||
|
||||
|
@ -203,8 +206,9 @@ func TestAuditBroker_LogRequest(t *testing.T) {
|
|||
Operation: logical.ReadOperation,
|
||||
Path: "sys/mounts",
|
||||
}
|
||||
reqErrs := errors.New("errs")
|
||||
|
||||
err := b.LogRequest(auth, req)
|
||||
err := b.LogRequest(auth, req, reqErrs)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -216,17 +220,20 @@ func TestAuditBroker_LogRequest(t *testing.T) {
|
|||
if !reflect.DeepEqual(a.Req[0], req) {
|
||||
t.Fatalf("Bad: %#v", a.Req[0])
|
||||
}
|
||||
if !reflect.DeepEqual(a.ReqErrs[0], reqErrs) {
|
||||
t.Fatalf("Bad: %#v", a.ReqErrs[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Should still work with one failing backend
|
||||
a1.ReqErr = fmt.Errorf("failed")
|
||||
if err := b.LogRequest(auth, req); err != nil {
|
||||
if err := b.LogRequest(auth, req, nil); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Should FAIL work with both failing backends
|
||||
a2.ReqErr = fmt.Errorf("failed")
|
||||
if err := b.LogRequest(auth, req); err.Error() != "no audit backend succeeded in logging the request" {
|
||||
if err := b.LogRequest(auth, req, nil); err.Error() != "no audit backend succeeded in logging the request" {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,10 +354,12 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
|
|||
return nil, ErrStandby
|
||||
}
|
||||
|
||||
var auth *logical.Auth
|
||||
|
||||
if c.router.LoginPath(req.Path) {
|
||||
resp, err = c.handleLoginRequest(req)
|
||||
resp, auth, err = c.handleLoginRequest(req)
|
||||
} else {
|
||||
resp, err = c.handleRequest(req)
|
||||
resp, auth, err = c.handleRequest(req)
|
||||
}
|
||||
|
||||
// Ensure we don't leak internal data
|
||||
|
@ -369,11 +371,20 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
|
|||
resp.Auth.InternalData = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Create an audit trail of the response
|
||||
if err := c.auditBroker.LogResponse(auth, req, resp, err); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit response (request: %#v, response: %#v): %v",
|
||||
req, resp, err)
|
||||
return nil, ErrInternalError
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
||||
func (c *Core) handleRequest(req *logical.Request) (*logical.Response, *logical.Auth, error) {
|
||||
defer metrics.MeasureSince([]string{"core", "handle_request"}, time.Now())
|
||||
|
||||
// Validate the token
|
||||
auth, err := c.checkToken(req.Operation, req.Path, req.ClientToken)
|
||||
if err != nil {
|
||||
|
@ -387,17 +398,22 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
|||
errType = logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
return logical.ErrorResponse(err.Error()), errType
|
||||
if err := c.auditBroker.LogRequest(auth, req, err); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
|
||||
req, err)
|
||||
}
|
||||
|
||||
return logical.ErrorResponse(err.Error()), nil, errType
|
||||
}
|
||||
|
||||
// Attach the display name
|
||||
req.DisplayName = auth.DisplayName
|
||||
|
||||
// Create an audit trail of the request
|
||||
if err := c.auditBroker.LogRequest(auth, req); err != nil {
|
||||
if err := c.auditBroker.LogRequest(auth, req, errors.New("")); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
|
||||
req, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
|
||||
// Route the request
|
||||
|
@ -422,7 +438,7 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
|||
c.logger.Printf(
|
||||
"[ERR] core: failed to register lease "+
|
||||
"(request: %#v, response: %#v): %v", req, resp, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
resp.Secret.LeaseID = leaseID
|
||||
}
|
||||
|
@ -435,7 +451,7 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
|||
c.logger.Printf(
|
||||
"[ERR] core: unexpected Auth response for non-token backend "+
|
||||
"(request: %#v, response: %#v)", req, resp)
|
||||
return nil, ErrInternalError
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
|
||||
// Set the default lease if non-provided, root tokens are exempt
|
||||
|
@ -452,31 +468,24 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
|||
if err := c.expiration.RegisterAuth(req.Path, resp.Auth); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to register token lease "+
|
||||
"(request: %#v, response: %#v): %v", req, resp, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
}
|
||||
|
||||
// Create an audit trail of the response
|
||||
if err := c.auditBroker.LogResponse(auth, req, resp, err); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit response (request: %#v, response: %#v): %v",
|
||||
req, resp, err)
|
||||
return nil, ErrInternalError
|
||||
}
|
||||
|
||||
// Return the response and error
|
||||
return resp, err
|
||||
return resp, auth, err
|
||||
}
|
||||
|
||||
// handleLoginRequest is used to handle a login request, which is an
|
||||
// unauthenticated request to the backend.
|
||||
func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, error) {
|
||||
func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, *logical.Auth, error) {
|
||||
defer metrics.MeasureSince([]string{"core", "handle_login_request"}, time.Now())
|
||||
|
||||
// Create an audit trail of the request, auth is not available on login requests
|
||||
if err := c.auditBroker.LogRequest(nil, req); err != nil {
|
||||
if err := c.auditBroker.LogRequest(nil, req, errors.New("")); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
|
||||
req, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, nil, ErrInternalError
|
||||
}
|
||||
|
||||
// Route the request
|
||||
|
@ -486,7 +495,7 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, erro
|
|||
if resp != nil && resp.Secret != nil {
|
||||
c.logger.Printf("[ERR] core: unexpected Secret response for login path"+
|
||||
"(request: %#v, response: %#v)", req, resp)
|
||||
return nil, ErrInternalError
|
||||
return nil, nil, ErrInternalError
|
||||
}
|
||||
|
||||
// If the response generated an authentication, then generate the token
|
||||
|
@ -511,7 +520,7 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, erro
|
|||
}
|
||||
if err := c.tokenStore.Create(&te); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to create token: %v", err)
|
||||
return nil, ErrInternalError
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
|
||||
// Populate the client token
|
||||
|
@ -531,21 +540,14 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, erro
|
|||
if err := c.expiration.RegisterAuth(req.Path, auth); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to register token lease "+
|
||||
"(request: %#v, response: %#v): %v", req, resp, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
|
||||
// Attach the display name, might be used by audit backends
|
||||
req.DisplayName = auth.DisplayName
|
||||
}
|
||||
|
||||
// Create an audit trail of the response
|
||||
if err := c.auditBroker.LogResponse(auth, req, resp, err); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit response (request: %#v, response: %#v): %v",
|
||||
req, resp, err)
|
||||
return nil, ErrInternalError
|
||||
}
|
||||
|
||||
return resp, err
|
||||
return resp, auth, err
|
||||
}
|
||||
|
||||
func (c *Core) checkToken(
|
||||
|
|
|
@ -140,6 +140,7 @@ func (m *RollbackManager) attemptRollback(path string, rs *rollbackState) (err e
|
|||
req := &logical.Request{
|
||||
Operation: logical.RollbackOperation,
|
||||
Path: path,
|
||||
Connection: &logical.Connection{},
|
||||
}
|
||||
_, err = m.router.Route(req)
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ func TestKeyCopy(key []byte) []byte {
|
|||
|
||||
type noopAudit struct{}
|
||||
|
||||
func (n *noopAudit) LogRequest(a *logical.Auth, r *logical.Request) error {
|
||||
func (n *noopAudit) LogRequest(a *logical.Auth, r *logical.Request, e error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -656,13 +656,13 @@ func (ts *TokenStore) handleLookup(
|
|||
|
||||
// Lookup the token
|
||||
out, err := ts.Lookup(id)
|
||||
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
// Fast-path the not found case
|
||||
if out == nil {
|
||||
return nil, nil
|
||||
return logical.ErrorResponse("bad token"), logical.ErrPermissionDenied
|
||||
}
|
||||
|
||||
// Generate a response. We purposely omit the parent reference otherwise
|
||||
|
|
Loading…
Reference in New Issue