2016-12-07 04:35:30 +00:00
|
|
|
package socket
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strconv"
|
2017-02-02 23:44:56 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2016-12-07 04:35:30 +00:00
|
|
|
|
2017-02-05 00:55:17 +00:00
|
|
|
multierror "github.com/hashicorp/go-multierror"
|
2016-12-07 04:35:30 +00:00
|
|
|
"github.com/hashicorp/vault/audit"
|
2017-02-02 23:44:56 +00:00
|
|
|
"github.com/hashicorp/vault/helper/duration"
|
2016-12-07 04:35:30 +00:00
|
|
|
"github.com/hashicorp/vault/logical"
|
|
|
|
)
|
|
|
|
|
|
|
|
func Factory(conf *audit.BackendConfig) (audit.Backend, error) {
|
|
|
|
if conf.Salt == nil {
|
|
|
|
return nil, fmt.Errorf("nil salt passed in")
|
|
|
|
}
|
|
|
|
|
|
|
|
address, ok := conf.Config["address"]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("address is required")
|
|
|
|
}
|
|
|
|
|
2017-02-02 23:44:56 +00:00
|
|
|
socketType, ok := conf.Config["socket_type"]
|
2016-12-07 04:35:30 +00:00
|
|
|
if !ok {
|
2017-02-02 23:44:56 +00:00
|
|
|
socketType = "tcp"
|
|
|
|
}
|
|
|
|
|
2017-02-05 00:55:17 +00:00
|
|
|
writeDeadline, ok := conf.Config["write_timeout"]
|
2017-02-02 23:44:56 +00:00
|
|
|
if !ok {
|
|
|
|
writeDeadline = "2s"
|
|
|
|
}
|
|
|
|
writeDuration, err := duration.ParseDurationSecond(writeDeadline)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-12-07 04:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
format, ok := conf.Config["format"]
|
|
|
|
if !ok {
|
|
|
|
format = "json"
|
|
|
|
}
|
|
|
|
switch format {
|
|
|
|
case "json", "jsonx":
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unknown format type %s", format)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if hashing of accessor is disabled
|
|
|
|
hmacAccessor := true
|
|
|
|
if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok {
|
|
|
|
value, err := strconv.ParseBool(hmacAccessorRaw)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
hmacAccessor = value
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if raw logging is enabled
|
|
|
|
logRaw := false
|
|
|
|
if raw, ok := conf.Config["log_raw"]; ok {
|
|
|
|
b, err := strconv.ParseBool(raw)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
logRaw = b
|
|
|
|
}
|
|
|
|
|
2017-02-02 23:44:56 +00:00
|
|
|
conn, err := net.Dial(socketType, address)
|
2016-12-07 04:35:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b := &Backend{
|
|
|
|
connection: conn,
|
|
|
|
formatConfig: audit.FormatterConfig{
|
|
|
|
Raw: logRaw,
|
|
|
|
Salt: conf.Salt,
|
|
|
|
HMACAccessor: hmacAccessor,
|
|
|
|
},
|
2017-02-02 23:44:56 +00:00
|
|
|
writeDuration: writeDuration,
|
|
|
|
address: address,
|
|
|
|
socketType: socketType,
|
2016-12-07 04:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch format {
|
|
|
|
case "json":
|
2017-02-11 00:56:28 +00:00
|
|
|
b.formatter.AuditFormatWriter = &audit.JSONFormatWriter{
|
|
|
|
Prefix: conf.Config["prefix"],
|
|
|
|
}
|
2016-12-07 04:35:30 +00:00
|
|
|
case "jsonx":
|
2017-02-11 00:56:28 +00:00
|
|
|
b.formatter.AuditFormatWriter = &audit.JSONxFormatWriter{
|
|
|
|
Prefix: conf.Config["prefix"],
|
|
|
|
}
|
2016-12-07 04:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Backend is the audit backend for the socket audit transport.
|
|
|
|
type Backend struct {
|
|
|
|
connection net.Conn
|
|
|
|
|
|
|
|
formatter audit.AuditFormatter
|
|
|
|
formatConfig audit.FormatterConfig
|
2017-02-02 23:44:56 +00:00
|
|
|
|
|
|
|
writeDuration time.Duration
|
|
|
|
address string
|
|
|
|
socketType string
|
|
|
|
|
|
|
|
sync.Mutex
|
2016-12-07 04:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Backend) GetHash(data string) string {
|
|
|
|
return audit.HashString(b.formatConfig.Salt, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
if err := b.formatter.FormatRequest(&buf, b.formatConfig, auth, req, outerErr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-02 23:44:56 +00:00
|
|
|
b.Lock()
|
2017-02-05 00:55:17 +00:00
|
|
|
defer b.Unlock()
|
2017-02-02 23:44:56 +00:00
|
|
|
|
2017-02-06 19:38:38 +00:00
|
|
|
err := b.write(buf.Bytes())
|
2017-02-02 23:44:56 +00:00
|
|
|
if err != nil {
|
2017-02-05 00:55:17 +00:00
|
|
|
rErr := b.reconnect()
|
|
|
|
if rErr != nil {
|
|
|
|
err = multierror.Append(err, rErr)
|
2017-02-06 19:38:38 +00:00
|
|
|
} else {
|
|
|
|
// Try once more after reconnecting
|
|
|
|
err = b.write(buf.Bytes())
|
2017-02-05 00:55:17 +00:00
|
|
|
}
|
2017-02-02 23:44:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
2016-12-07 04:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Backend) LogResponse(auth *logical.Auth, req *logical.Request,
|
2017-02-02 23:44:56 +00:00
|
|
|
resp *logical.Response, outerErr error) error {
|
2016-12-07 04:35:30 +00:00
|
|
|
var buf bytes.Buffer
|
2017-02-02 23:44:56 +00:00
|
|
|
if err := b.formatter.FormatResponse(&buf, b.formatConfig, auth, req, resp, outerErr); err != nil {
|
2016-12-07 04:35:30 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-02-02 23:44:56 +00:00
|
|
|
|
|
|
|
b.Lock()
|
2017-02-05 00:55:17 +00:00
|
|
|
defer b.Unlock()
|
2017-02-02 23:44:56 +00:00
|
|
|
|
2017-02-06 19:38:38 +00:00
|
|
|
err := b.write(buf.Bytes())
|
2017-02-02 23:44:56 +00:00
|
|
|
if err != nil {
|
2017-02-05 00:55:17 +00:00
|
|
|
rErr := b.reconnect()
|
|
|
|
if rErr != nil {
|
|
|
|
err = multierror.Append(err, rErr)
|
2017-02-06 19:38:38 +00:00
|
|
|
} else {
|
|
|
|
// Try once more after reconnecting
|
|
|
|
err = b.write(buf.Bytes())
|
2017-02-05 00:55:17 +00:00
|
|
|
}
|
2017-02-02 23:44:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
2016-12-07 04:35:30 +00:00
|
|
|
}
|
|
|
|
|
2017-02-06 19:38:38 +00:00
|
|
|
func (b *Backend) write(buf []byte) error {
|
|
|
|
err := b.connection.SetWriteDeadline(time.Now().Add(b.writeDuration))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = b.connection.Write(buf)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-05 00:55:17 +00:00
|
|
|
func (b *Backend) reconnect() error {
|
2017-02-02 23:44:56 +00:00
|
|
|
conn, err := net.Dial(b.socketType, b.address)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b.connection.Close()
|
|
|
|
b.connection = conn
|
|
|
|
|
2016-12-07 04:35:30 +00:00
|
|
|
return nil
|
|
|
|
}
|
2017-02-05 00:55:17 +00:00
|
|
|
|
|
|
|
func (b *Backend) Reload() error {
|
|
|
|
b.Lock()
|
|
|
|
defer b.Unlock()
|
|
|
|
|
|
|
|
err := b.reconnect()
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|