Skip to content

Commit

Permalink
Set default umask of 0027 for all Beats-created files (#14119)
Browse files Browse the repository at this point in the history
* Set umask of 027 (on non-windows systems) for all Beats-created files

* Fixing comment

* Update tests

* Updating docs for filebeat.registry.file_permissions

* Denoting octal

* Allow beats to override umask

* Removing accidentally-committed file

* Adding system test for default umask

* Make setUmask return error

* Defining ErrNotImplemented locally

* Defining not implemented error locally

* Fixing typo

* Skip umask test on Windows

* Adding missed imports

* Adding CHANGELOG entry
  • Loading branch information
ycombinator authored Oct 24, 2019
1 parent e9f3c57 commit 2bb87cf
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Disable Alibaba Cloud and Tencent Cloud metadata providers by default. {pull}13812[12812]
- Libbeat HTTP's Server can listen to a unix socket using the `unix:///tmp/hello.sock` syntax. {pull}13655[13655]
- Libbeat HTTP's Server can listen to a Windows named pipe using the `npipe:///hello` syntax. {pull}13655[13655]
- By default, all Beats-created files and folders will have a umask of 0027 (on POSIX systems). {pull}14119[14119]

*Auditbeat*

Expand Down
6 changes: 4 additions & 2 deletions filebeat/docs/filebeat-general-options.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ NOTE: The content stored in filebeat/data.json is compatible to the old registry

The permissions mask to apply on registry data file. The default value is 0600. The permissions option must be a valid Unix-style file permissions mask expressed in octal notation. In Go, numbers in octal notation must start with 0.

The most permissive mask allowed is 0640. If a higher permissions mask is
specified via this setting, it will be subject to a umask of 0027.

This option is not supported on Windows.

Examples:

0644: give read and write access to the file owner, and read access to all others.
0640: give read and write access to the file owner, and read access to members of the group associated with the file.
0600: give read and write access to the file owner, and no access to all others.
0664: give read and write access to the file owner and members of the group associated with the file, as well as read access to all other users.

[source,yaml]
-------------------------------------------------------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions filebeat/tests/system/test_registrar.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def test_registry_file_custom_permissions(self):
self.render_config_template(
path=os.path.abspath(self.working_dir) + "/log/*",
registry_home=registry_home,
registry_file_permissions=0644,
registry_file_permissions=0640,
)
os.mkdir(self.working_dir + "/log/")
testfile_path = self.working_dir + "/log/test.log"
Expand All @@ -223,7 +223,7 @@ def test_registry_file_custom_permissions(self):
max_timeout=1)
filebeat.check_kill_and_wait()

self.assertEqual(self.file_permissions(registry_file), "0644")
self.assertEqual(self.file_permissions(registry_file), "0640")

def test_registry_file_update_permissions(self):
"""
Expand Down Expand Up @@ -262,7 +262,7 @@ def test_registry_file_update_permissions(self):
self.render_config_template(
path=os.path.abspath(self.working_dir) + "/log/*",
registry_home="a/b/c/registry_x",
registry_file_permissions=0644
registry_file_permissions=0640
)

filebeat = self.start_beat()
Expand All @@ -280,7 +280,7 @@ def test_registry_file_update_permissions(self):

filebeat.check_kill_and_wait()

self.assertEqual(self.file_permissions(registry_file), "0644")
self.assertEqual(self.file_permissions(registry_file), "0640")

def test_rotating_file(self):
"""
Expand Down
12 changes: 12 additions & 0 deletions libbeat/cmd/instance/beat.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ func initRand() {
// instance.
// XXX Move this as a *Beat method?
func Run(settings Settings, bt beat.Creator) error {
err := setUmaskWithSettings(settings)
if err != nil && err != errNotImplemented {
return errw.Wrap(err, "could not set umask")
}

name := settings.Name
idxPrefix := settings.IndexPrefix
version := settings.Version
Expand Down Expand Up @@ -1046,3 +1051,10 @@ func initPaths(cfg *common.Config) error {
}
return nil
}

func setUmaskWithSettings(settings Settings) error {
if settings.Umask != nil {
return setUmask(*settings.Umask)
}
return setUmask(0027) // 0640 for files | 0750 for dirs
}
2 changes: 2 additions & 0 deletions libbeat/cmd/instance/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ type Settings struct {
ILM ilm.SupportFactory

Processing processing.SupportFactory

Umask *int
}
32 changes: 32 additions & 0 deletions libbeat/cmd/instance/umask_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

// +build !windows

package instance

import (
"errors"
"syscall"
)

var errNotImplemented = errors.New("not implemented on platform")

func setUmask(newmask int) error {
syscall.Umask(newmask)
return nil // the umask syscall always succeeds: http://man7.org/linux/man-pages/man2/umask.2.html#RETURN_VALUE
}
27 changes: 27 additions & 0 deletions libbeat/cmd/instance/umask_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package instance

import "errors"

var errNotImplemented = errors.New("not implemented on windows")

func setUmask(newmask int) error {
// No way to set umask on Windows
return errNotImplemented
}
3 changes: 3 additions & 0 deletions libbeat/tests/system/config/mockbeat.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ output:
path: {{ output_file_path|default(beat.working_dir + "/output") }}
filename: "{{ output_file_filename|default("mockbeat") }}"
rotate_every_kb: 1000
{% if output_file_permissions %}
permissions: {{ output_file_permissions }}
{% endif %}
#number_of_files: 7
{%- endif %}

Expand Down
36 changes: 36 additions & 0 deletions libbeat/tests/system/test_umask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from base import BaseTest

import os
import stat
import unittest
import sys

INTEGRATION_TESTS = os.environ.get('INTEGRATION_TESTS', False)


class TestUmask(BaseTest):
"""
Test default umask
"""

DEFAULT_UMASK = 0027

def setUp(self):
super(BaseTest, self).setUp()

self.output_file_permissions = 0666

self.render_config_template(output_file_permissions=self.output_file_permissions)
proc = self.start_beat()
self.wait_until(lambda: self.output_lines() > 0, max_timeout=2)
proc.check_kill_and_wait()

@unittest.skipIf(sys.platform.startswith("win"), "umask is not available on Windows")
def test_output_file_perms(self):
"""
Test that output file permissions respect default umask
"""
output_file_path = os.path.join(self.working_dir, "output", "mockbeat")
perms = stat.S_IMODE(os.lstat(output_file_path).st_mode)

self.assertEqual(perms, self.output_file_permissions & ~TestUmask.DEFAULT_UMASK)

0 comments on commit 2bb87cf

Please sign in to comment.