diff --git a/builtin/audit/file/backend.go b/builtin/audit/file/backend.go index afdc8e019d..0318052a4b 100644 --- a/builtin/audit/file/backend.go +++ b/builtin/audit/file/backend.go @@ -54,8 +54,19 @@ func Factory(conf *audit.BackendConfig) (audit.Backend, error) { logRaw = b } + // Check if mode is provided + mode := os.FileMode(0600) + if modeRaw, ok := conf.Config["mode"]; ok { + m, err := strconv.ParseUint(modeRaw, 8, 32) + if err != nil { + return nil, err + } + mode = os.FileMode(m) + } + b := &Backend{ path: path, + mode: mode, formatConfig: audit.FormatterConfig{ Raw: logRaw, Salt: conf.Salt, @@ -93,6 +104,7 @@ type Backend struct { fileLock sync.RWMutex f *os.File + mode os.FileMode } func (b *Backend) GetHash(data string) string { @@ -131,12 +143,18 @@ func (b *Backend) open() error { if b.f != nil { return nil } - if err := os.MkdirAll(filepath.Dir(b.path), 0600); err != nil { + if err := os.MkdirAll(filepath.Dir(b.path), b.mode); err != nil { return err } var err error - b.f, err = os.OpenFile(b.path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + b.f, err = os.OpenFile(b.path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, b.mode) + if err != nil { + return err + } + + // Change the file mode in case the log file already existed + err = os.Chmod(b.path, b.mode) if err != nil { return err } diff --git a/builtin/audit/file/backend_test.go b/builtin/audit/file/backend_test.go new file mode 100644 index 0000000000..0a1a8c7751 --- /dev/null +++ b/builtin/audit/file/backend_test.go @@ -0,0 +1,85 @@ +package file + +import ( + "io/ioutil" + "os" + "path/filepath" + "strconv" + "testing" + + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/salt" +) + +func TestAuditFile_fileModeNew(t *testing.T) { + salter, _ := salt.NewSalt(nil, nil) + + modeStr := "0777" + mode, err := strconv.ParseUint(modeStr, 8, 32) + + path, err := ioutil.TempDir("", "vault-test_audit_file-file_mode_new") + defer os.RemoveAll(path) + + file := filepath.Join(path, "auditTest.txt") + + config := map[string]string{ + "path": file, + "mode": modeStr, + } + + _, err = Factory(&audit.BackendConfig{ + Salt: salter, + Config: config, + }) + if err != nil { + t.Fatal(err) + } + + info, err := os.Stat(file) + if err != nil { + t.Fatalf("Cannot retrieve file mode from `Stat`") + } + if info.Mode() != os.FileMode(mode) { + t.Fatalf("File mode does not match.") + } +} + +func TestAuditFile_fileModeExisting(t *testing.T) { + salter, _ := salt.NewSalt(nil, nil) + + f, err := ioutil.TempFile("", "test") + if err != nil { + t.Fatalf("Failure to create test file.") + } + defer os.Remove(f.Name()) + + err = os.Chmod(f.Name(), 0777) + if err != nil { + t.Fatalf("Failure to chmod temp file for testing.") + } + + err = f.Close() + if err != nil { + t.Fatalf("Failure to close temp file for test.") + } + + config := map[string]string{ + "path": f.Name(), + } + + _, err = Factory(&audit.BackendConfig{ + Salt: salter, + Config: config, + }) + if err != nil { + t.Fatal(err) + } + + info, err := os.Stat(f.Name()) + if err != nil { + t.Fatalf("cannot retrieve file mode from `Stat`") + } + if info.Mode() != os.FileMode(0600) { + t.Fatalf("File mode does not match.") + } +} diff --git a/website/source/docs/audit/file.html.md b/website/source/docs/audit/file.html.md index 8cf9a0d704..159197a246 100644 --- a/website/source/docs/audit/file.html.md +++ b/website/source/docs/audit/file.html.md @@ -69,6 +69,13 @@ Following are the configuration options available for the backend. optional A boolean, if set, enables the hashing of token accessor. Defaults to `true`. This option is useful only when `log_raw` is `false`. + +
  • + mode + optional + A string containing an octal number representing the bit pattern + for the file mode, similar to `chmod`. This option defaults to + `0600`.
  • format