mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	Merge pull request #36 from hashicorp/f-syslog
Adding syslog audit provider
This commit is contained in:
		@@ -22,6 +22,9 @@ func Hash(raw interface{}) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch s := raw.(type) {
 | 
						switch s := raw.(type) {
 | 
				
			||||||
	case *logical.Auth:
 | 
						case *logical.Auth:
 | 
				
			||||||
 | 
							if s == nil {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if s.ClientToken != "" {
 | 
							if s.ClientToken != "" {
 | 
				
			||||||
			token, err := fn(s.ClientToken)
 | 
								token, err := fn(s.ClientToken)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@@ -31,6 +34,9 @@ func Hash(raw interface{}) error {
 | 
				
			|||||||
			s.ClientToken = token
 | 
								s.ClientToken = token
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case *logical.Request:
 | 
						case *logical.Request:
 | 
				
			||||||
 | 
							if s == nil {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if s.Auth != nil {
 | 
							if s.Auth != nil {
 | 
				
			||||||
			if err := Hash(s.Auth); err != nil {
 | 
								if err := Hash(s.Auth); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
@@ -44,6 +50,9 @@ func Hash(raw interface{}) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		s.Data = data.(map[string]interface{})
 | 
							s.Data = data.(map[string]interface{})
 | 
				
			||||||
	case *logical.Response:
 | 
						case *logical.Response:
 | 
				
			||||||
 | 
							if s == nil {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if s.Auth != nil {
 | 
							if s.Auth != nil {
 | 
				
			||||||
			if err := Hash(s.Auth); err != nil {
 | 
								if err := Hash(s.Auth); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,12 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/hashicorp/vault/audit"
 | 
						"github.com/hashicorp/vault/audit"
 | 
				
			||||||
	"github.com/hashicorp/vault/logical"
 | 
						"github.com/hashicorp/vault/logical"
 | 
				
			||||||
 | 
						"github.com/mitchellh/copystructure"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Factory(conf map[string]string) (audit.Backend, error) {
 | 
					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 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.
 | 
					// 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
 | 
					// 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.
 | 
					// or reset the write cursor, this should be done in the future.
 | 
				
			||||||
type Backend struct {
 | 
					type Backend struct {
 | 
				
			||||||
	Path string
 | 
						Path   string
 | 
				
			||||||
 | 
						LogRaw bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	once sync.Once
 | 
						once sync.Once
 | 
				
			||||||
	f    *os.File
 | 
						f    *os.File
 | 
				
			||||||
@@ -35,6 +52,28 @@ func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
 | 
				
			|||||||
	if err := b.open(); err != nil {
 | 
						if err := b.open(); err != nil {
 | 
				
			||||||
		return err
 | 
							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
 | 
						var format audit.FormatJSON
 | 
				
			||||||
	return format.FormatRequest(b.f, auth, req)
 | 
						return format.FormatRequest(b.f, auth, req)
 | 
				
			||||||
@@ -48,6 +87,37 @@ func (b *Backend) LogResponse(
 | 
				
			|||||||
	if err := b.open(); err != nil {
 | 
						if err := b.open(); err != nil {
 | 
				
			||||||
		return err
 | 
							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
 | 
						var format audit.FormatJSON
 | 
				
			||||||
	return format.FormatResponse(b.f, auth, req, resp, err)
 | 
						return format.FormatResponse(b.f, auth, req, resp, err)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										135
									
								
								builtin/audit/syslog/backend.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								builtin/audit/syslog/backend.go
									
									
									
									
									
										Normal 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auditFile "github.com/hashicorp/vault/builtin/audit/file"
 | 
						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"
 | 
						credAppId "github.com/hashicorp/vault/builtin/credential/app-id"
 | 
				
			||||||
	credCert "github.com/hashicorp/vault/builtin/credential/cert"
 | 
						credCert "github.com/hashicorp/vault/builtin/credential/cert"
 | 
				
			||||||
@@ -49,7 +50,8 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
 | 
				
			|||||||
			return &command.ServerCommand{
 | 
								return &command.ServerCommand{
 | 
				
			||||||
				Meta: meta,
 | 
									Meta: meta,
 | 
				
			||||||
				AuditBackends: map[string]audit.Factory{
 | 
									AuditBackends: map[string]audit.Factory{
 | 
				
			||||||
					"file": auditFile.Factory,
 | 
										"file":   auditFile.Factory,
 | 
				
			||||||
 | 
										"syslog": auditSyslog.Factory,
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				CredentialBackends: map[string]logical.Factory{
 | 
									CredentialBackends: map[string]logical.Factory{
 | 
				
			||||||
					"cert":     credCert.Factory,
 | 
										"cert":     credCert.Factory,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
					  * `path` (required) - The path to where the file will be written. If
 | 
				
			||||||
      this path exists, the audit backend will append to it.
 | 
					      this path exists, the audit backend will append to it.
 | 
				
			||||||
 | 
					  * `log_raw` (optional) Should security sensitive information be logged raw. Defaults to "false".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Format
 | 
					## 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.
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								website/source/docs/audit/syslog.html.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								website/source/docs/audit/syslog.html.md
									
									
									
									
									
										Normal 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,6 +154,10 @@
 | 
				
			|||||||
					<ul class="nav">
 | 
										<ul class="nav">
 | 
				
			||||||
						<li<%= sidebar_current("docs-audit-file") %>>
 | 
											<li<%= sidebar_current("docs-audit-file") %>>
 | 
				
			||||||
							<a href="/docs/audit/file.html">File</a>
 | 
												<a href="/docs/audit/file.html">File</a>
 | 
				
			||||||
 | 
					                        </li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											<li<%= sidebar_current("docs-audit-syslog") %>>
 | 
				
			||||||
 | 
												<a href="/docs/audit/syslog.html">Syslog</a>
 | 
				
			||||||
						</li>
 | 
											</li>
 | 
				
			||||||
					</ul>
 | 
										</ul>
 | 
				
			||||||
				</li>
 | 
									</li>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user