Merge pull request #36 from hashicorp/f-syslog

Adding syslog audit provider
This commit is contained in:
Armon Dadgar
2015-04-27 16:13:13 -07:00
7 changed files with 264 additions and 3 deletions

View File

@@ -22,6 +22,9 @@ func Hash(raw interface{}) error {
switch s := raw.(type) {
case *logical.Auth:
if s == nil {
return nil
}
if s.ClientToken != "" {
token, err := fn(s.ClientToken)
if err != nil {
@@ -31,6 +34,9 @@ func Hash(raw interface{}) error {
s.ClientToken = token
}
case *logical.Request:
if s == nil {
return nil
}
if s.Auth != nil {
if err := Hash(s.Auth); err != nil {
return err
@@ -44,6 +50,9 @@ func Hash(raw interface{}) error {
s.Data = data.(map[string]interface{})
case *logical.Response:
if s == nil {
return nil
}
if s.Auth != nil {
if err := Hash(s.Auth); err != nil {
return err

View File

@@ -4,10 +4,12 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"sync"
"github.com/hashicorp/vault/audit"
"github.com/hashicorp/vault/logical"
"github.com/mitchellh/copystructure"
)
func Factory(conf map[string]string) (audit.Backend, error) {
@@ -16,7 +18,21 @@ func Factory(conf map[string]string) (audit.Backend, error) {
return nil, fmt.Errorf("path is required")
}
return &Backend{Path: path}, nil
// 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
}
// Backend is the audit backend for the file-based audit store.
@@ -25,7 +41,8 @@ func Factory(conf map[string]string) (audit.Backend, error) {
// 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 {
Path string
Path string
LogRaw bool
once sync.Once
f *os.File
@@ -35,6 +52,28 @@ func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
if err := b.open(); err != nil {
return err
}
if !b.LogRaw {
// 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
}
}
var format audit.FormatJSON
return format.FormatRequest(b.f, auth, req)
@@ -48,6 +87,37 @@ func (b *Backend) LogResponse(
if err := b.open(); err != nil {
return err
}
if !b.LogRaw {
// 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
}
}
var format audit.FormatJSON
return format.FormatResponse(b.f, auth, req, resp, err)

View File

@@ -0,0 +1,135 @@
package file
import (
"bytes"
"strconv"
"github.com/hashicorp/go-syslog"
"github.com/hashicorp/vault/audit"
"github.com/hashicorp/vault/logical"
"github.com/mitchellh/copystructure"
)
func Factory(conf map[string]string) (audit.Backend, error) {
// Get facility or default to AUTH
facility, ok := conf["facility"]
if !ok {
facility = "AUTH"
}
// Get tag or default to 'vault'
tag, ok := conf["tag"]
if !ok {
tag = "vault"
}
// 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
}
// Get the logger
logger, err := gsyslog.NewLogger(gsyslog.LOG_INFO, facility, tag)
if err != nil {
return nil, err
}
b := &Backend{
logger: logger,
logRaw: logRaw,
}
return b, nil
}
// Backend is the audit backend for the syslog-based audit store.
type Backend struct {
logger gsyslog.Syslogger
logRaw bool
}
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
if !b.logRaw {
// 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
}
}
// Encode the entry as JSON
var buf bytes.Buffer
var format audit.FormatJSON
if err := format.FormatRequest(&buf, auth, req); err != nil {
return err
}
// Write out to syslog
_, err := b.logger.Write(buf.Bytes())
return err
}
func (b *Backend) LogResponse(auth *logical.Auth, req *logical.Request,
resp *logical.Response, err error) error {
if !b.logRaw {
// 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
}
}
// Encode the entry as JSON
var buf bytes.Buffer
var format audit.FormatJSON
if err := format.FormatResponse(&buf, auth, req, resp, err); err != nil {
return err
}
// Write otu to syslog
_, err = b.logger.Write(buf.Bytes())
return err
}

View File

@@ -4,6 +4,7 @@ import (
"os"
auditFile "github.com/hashicorp/vault/builtin/audit/file"
auditSyslog "github.com/hashicorp/vault/builtin/audit/syslog"
credAppId "github.com/hashicorp/vault/builtin/credential/app-id"
credCert "github.com/hashicorp/vault/builtin/credential/cert"
@@ -49,7 +50,8 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
return &command.ServerCommand{
Meta: meta,
AuditBackends: map[string]audit.Factory{
"file": auditFile.Factory,
"file": auditFile.Factory,
"syslog": auditSyslog.Factory,
},
CredentialBackends: map[string]logical.Factory{
"cert": credCert.Factory,

View File

@@ -21,6 +21,7 @@ When enabling this backend, the following options are accepted:
* `path` (required) - The path to where the file will be written. If
this path exists, the audit backend will append to it.
* `log_raw` (optional) Should security sensitive information be logged raw. Defaults to "false".
## Format
@@ -30,3 +31,6 @@ what type of object it is. Currently, only two types exist: "request" and
The line contains all of the information for any given request and response.
If `log_raw` if false, as is default, all sensitive information is first hashed
before logging. If explicitly enabled, all values are logged raw without hashing.

View File

@@ -0,0 +1,37 @@
---
layout: "docs"
page_title: "Audit Backend: Syslog"
sidebar_current: "docs-audit-syslog"
description: |-
The "syslog" audit backend writes audit logs to syslog.
---
# Audit Backend: Syslog
Name: `syslog`
The "syslog" audit backend writes audit logs to syslog.
It currently does not support a configurable syslog desination, and
always sends to the local agent. This backend is only supported on Unix systems,
and should not be enabled if any standby Vault instances do not support it.
## Options
When enabling this backend, the following options are accepted:
* `facility` (optional) - The syslog facility to use. Defaults to "AUTH".
* `tag` (optional) - The syslog tag to use. Defaults to "vault".
* `log_raw` (optional) Should security sensitive information be logged raw. Defaults to "false".
## Format
Each line in the audit log is a JSON object. The "type" field specifies
what type of object it is. Currently, only two types exist: "request" and
"response".
The line contains all of the information for any given request and response.
If `log_raw` if false, as is default, all sensitive information is first hashed
before logging. If explicitly enabled, all values are logged raw without hashing.

View File

@@ -154,6 +154,10 @@
<ul class="nav">
<li<%= sidebar_current("docs-audit-file") %>>
<a href="/docs/audit/file.html">File</a>
</li>
<li<%= sidebar_current("docs-audit-syslog") %>>
<a href="/docs/audit/syslog.html">Syslog</a>
</li>
</ul>
</li>