Unverified Commit 385b8e83 authored by Rémi Lapeyre's avatar Rémi Lapeyre Committed by GitHub
Browse files

Add remote_port in the audit logs when it is available (#12790)

* Add remote_port in the audit logs when it is available

The `request.remote_port` field is now present in the audit log when it
is available:

```
{
  "time": "2021-10-10T13:53:51.760039Z",
  "type": "response",
  "auth": {
    "client_token": "hmac-sha256:1304aab0ac65747684e1b58248cc16715fa8f558f8d27e90fcbcb213220c0edf",
    "accessor": "hmac-sha256:f8cf0601dadd19aac84f205ded44c62898e3746a42108a51105a92ccc39baa43",
    "display_name": "root",
    "policies": [
      "root"
    ],
    "token_policies": [
      "root"
    ],
    "token_type": "service",
    "token_issue_time": "2021-10-10T15:53:44+02:00"
  },
  "request": {
    "id": "829c04a1-0352-2d9d-9bc9-00b928d33df5",
    "operation": "update",
    "mount_type": "system",
    "client_token": "hmac-sha256:1304aab0ac65747684e1b58248cc16715fa8f558f8d27e90fcbcb213220c0edf",
    "client_token_accessor": "hmac-sha256:f8cf0601dadd19aac84f205ded44c62898e3746a42108a511...
parent b204fdd4
Showing with 269 additions and 141 deletions
+269 -141
......@@ -123,6 +123,7 @@ func (f *AuditFormatter) FormatRequest(ctx context.Context, w io.Writer, config
Data: req.Data,
PolicyOverride: req.PolicyOverride,
RemoteAddr: getRemoteAddr(req),
RemotePort: getRemotePort(req),
ReplicationCluster: req.ReplicationCluster,
Headers: req.Headers,
ClientCertificateSerialNumber: getClientCertificateSerialNumber(connState),
......@@ -285,6 +286,7 @@ func (f *AuditFormatter) FormatResponse(ctx context.Context, w io.Writer, config
Data: req.Data,
PolicyOverride: req.PolicyOverride,
RemoteAddr: getRemoteAddr(req),
RemotePort: getRemotePort(req),
ClientCertificateSerialNumber: getClientCertificateSerialNumber(connState),
ReplicationCluster: req.ReplicationCluster,
Headers: req.Headers,
......@@ -348,6 +350,7 @@ type AuditRequest struct {
Data map[string]interface{} `json:"data,omitempty"`
PolicyOverride bool `json:"policy_override,omitempty"`
RemoteAddr string `json:"remote_address,omitempty"`
RemotePort int `json:"remote_port,omitempty"`
WrapTTL int `json:"wrap_ttl,omitempty"`
Headers map[string][]string `json:"headers,omitempty"`
ClientCertificateSerialNumber string `json:"client_certificate_serial_number,omitempty"`
......@@ -408,6 +411,14 @@ func getRemoteAddr(req *logical.Request) string {
return ""
}
// getRemotePort safely gets the remote port avoiding a nil pointer
func getRemotePort(req *logical.Request) int {
if req != nil && req.Connection != nil {
return req.Connection.RemotePort
}
return 0
}
func getClientCertificateSerialNumber(connState *tls.ConnectionState) string {
if connState == nil || len(connState.VerifiedChains) == 0 || len(connState.VerifiedChains[0]) == 0 {
return ""
......
```release-note:improvement
audit: The audit logs now contain the port used by the client
```
......@@ -530,14 +530,21 @@ WRITE_RESPONSE:
// attaching to a logical request
func getConnection(r *http.Request) (connection *logical.Connection) {
var remoteAddr string
var remotePort int
remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr)
remoteAddr, port, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
remoteAddr = ""
} else {
remotePort, err = strconv.Atoi(port)
if err != nil {
remotePort = 0
}
}
connection = &logical.Connection{
RemoteAddr: remoteAddr,
RemotePort: remotePort,
ConnState: r.TLS,
}
return
......
......@@ -14,6 +14,9 @@ import (
"testing"
"time"
kv "github.com/hashicorp/vault-plugin-secrets-kv"
"github.com/hashicorp/vault/api"
auditFile "github.com/hashicorp/vault/builtin/audit/file"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/logging"
......@@ -500,3 +503,90 @@ func TestLogical_ShouldParseForm(t *testing.T) {
}
}
}
func TestLogical_AuditPort(t *testing.T) {
coreConfig := &vault.CoreConfig{
LogicalBackends: map[string]logical.Factory{
"kv": kv.VersionedKVFactory,
},
AuditBackends: map[string]audit.Factory{
"file": auditFile.Factory,
},
}
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
HandlerFunc: Handler,
})
cluster.Start()
defer cluster.Cleanup()
cores := cluster.Cores
core := cores[0].Core
c := cluster.Cores[0].Client
vault.TestWaitActive(t, core)
if err := c.Sys().Mount("kv/", &api.MountInput{
Type: "kv-v2",
}); err != nil {
t.Fatalf("kv-v2 mount attempt failed - err: %#v\n", err)
}
auditLogFile, err := ioutil.TempFile("", "auditport")
if err != nil {
t.Fatal(err)
}
err = c.Sys().EnableAuditWithOptions("file", &api.EnableAuditOptions{
Type: "file",
Options: map[string]string{
"file_path": auditLogFile.Name(),
},
})
if err != nil {
t.Fatalf("failed to enable audit file, err: %#v\n", err)
}
writeData := map[string]interface{}{
"data": map[string]interface{}{
"bar": "a",
},
}
resp, err := c.Logical().Write("kv/data/foo", writeData)
if err != nil {
t.Fatalf("write request failed, err: %#v, resp: %#v\n", err, resp)
}
decoder := json.NewDecoder(auditLogFile)
var auditRecord map[string]interface{}
count := 0
for decoder.Decode(&auditRecord) == nil {
count += 1
// Skip the first line
if count == 1 {
continue
}
auditRequest := map[string]interface{}{}
if req, ok := auditRecord["request"]; ok {
auditRequest = req.(map[string]interface{})
}
if _, ok := auditRequest["remote_address"].(string); !ok {
t.Fatalf("remote_port should be a number, not %T", auditRequest["remote_address"])
}
if _, ok := auditRequest["remote_port"].(float64); !ok {
t.Fatalf("remote_port should be a number, not %T", auditRequest["remote_port"])
}
}
if count != 4 {
t.Fatalf("wrong number of audit entries: %d", count)
}
}
......@@ -10,6 +10,9 @@ type Connection struct {
// RemoteAddr is the network address that sent the request.
RemoteAddr string `json:"remote_addr"`
// RemotePort is the network port that sent the request.
RemotePort int `json:"remote_port"`
// ConnState is the TLS connection state if applicable.
ConnState *tls.ConnectionState `sentinel:""`
}
This diff is collapsed.
......@@ -242,7 +242,7 @@ message TokenEntry {
message LeaseOptions {
int64 TTL = 1;
bool renewable = 2;
int64 increment = 3;
......@@ -388,7 +388,7 @@ message HandleExistenceCheckReply {
// SetupArgs is the args for Setup method.
message SetupArgs {
uint32 broker_id = 1;
uint32 broker_id = 1;
map<string, string> Config = 2;
string backendUUID = 3;
}
......@@ -624,6 +624,9 @@ message Connection {
// RemoteAddr is the network address that sent the request.
string remote_addr = 1;
// RemotePort is the network port that sent the request.
int32 remote_port = 3;
// ConnectionState is the marshalled tls.ConnectionState from the original
// request
ConnectionState connection_state = 2;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment