Fluentd
Search…
Linux Capability
This article shows configuration and dependent gem installation instructions for enabling Linux capabilities on Fluentd core.
Linux capabilities grant privileges to processes and executables that are otherwise reserved for the root user (UID 0). You can use these in conjunction with Fluentd plugins to enable the underlying Ruby executable read access to input sources.

Prerequisites

  • gcc and make etc. for building C extension sources
  • libcap-ng package and its development package
    • libcap-ng-dev on Debian GNU/Linux and Ubuntu
    • libcap-ng-devel on CentOS 7/8, Fedora 33, AmazonLinux 2
  • pkg-config package for linking libcap-ng library
  • Ruby and its development packages
    • ruby-dev on Debian GNU/Linux and Ubuntu
    • ruby-devel on CentOS 7/8, Fedora 33, AmazonLinux 2
  • Fluentd v1.12 or later

Install capability handling gem

Fluentd uses the capng_c gem to handle Linux capabilities.
Add this line to your Fluentd' or td-agent's Gemfile:
1
gem 'capng_c'
Copied!
And then execute:
1
$ bundle
Copied!
Or install it yourself as for Fluentd:
1
$ fluent-gem install capng_c
Copied!
Or install it yourself as for td-agent:
1
$ td-agent-gem install capng_c
Copied!
Note: capng_c uses pkg-config to link the libcap-ng library. If you couldn't handle Linux capability with capng_c installation, please confirm pgk-config package is installed on your box.

Capability handling on in_tail

The Fluentd core plugin in_tail handles the following Linux capabilities:
  • CAP_DAC_READ_SEARCH (:dac_read_search on in_tail code)
  • CAP_DAC_OVERRIDE (:dac_override on in_tail code)
Set up cap_dac_read_search or cap_dac_override to use the Ruby executable:
1
$ sudo fluent-cap-ctl --add dac_read_search [-f /path/to/bin/ruby]
2
Updating dac_read_search done.
3
Adding dac_read_search done.
Copied!

Using CAP_DAC_OVERRIDE

1
$ sudo fluent-cap-ctl --add dac_override [-f /path/to/bin/ruby]
2
Updating dac_override done.
3
Adding dac_override done.
Copied!

Example setting up capability for rbenv-ed Ruby

1
$ sudo fluent-cap-ctl --add "dac_override,cap_dac_read_search" -f $(rbenv prefix)/bin/ruby
2
Updating dac_read_search,dac_override done.
3
Adding dac_read_search,dac_override done.
4
$ fluent-cap-ctl --get -f $(rbenv prefix)/bin/ruby
5
Capabilities in '/home/fluentd/.rbenv/versions/2.6.3/bin/ruby',
6
Effective: dac_override, dac_read_search
7
Inheritable: dac_override, dac_read_search
8
Permitted: dac_override, dac_read_search
Copied!

Actual Example for Linux capability handling in in_tail

When adding cap_dac_override (partial privileges for rw file) and cap_dac_read_search (partial privileges for read only), Fluentd/td-agent can handle to read 640 permission files such as /var/log/syslog:
1
$ ls -lh /var/log/syslog
2
-rw-r----- 1 syslog adm 29K Nov 5 14:35 /var/log/syslog
Copied!
This file cannot be read by ordinary users:
1
$ cat /var/log/syslog
2
cat: /var/log/syslog: Permission denied
Copied!
Attach dac_read_search for using Ruby executable binary:
1
$ sudo fluent-cap-ctl --add dac_read_search [-f /path/to/bin/ruby]
2
Updating dac_read_search done.
3
Adding dac_read_search done.
4
$ fluent-cap-ctl --get [-f /path/to/bin/ruby]
5
Capabilities in '/path/to/bin/ruby',
6
Effective: dac_read_search
7
Inheritable: dac_read_search
8
Permitted: dac_read_search
Copied!
And prepare the following configuration:
1
<source>
2
@type tail
3
path /var/log/syslog
4
pos_file /var/run/fluentd/log/syslog_test_with_capability.pos
5
tag test
6
rotate_wait 5
7
read_from_head true
8
refresh_interval 60
9
<parse>
10
@type syslog
11
</parse>
12
</source>
13
14
<match test>
15
@type stdout
16
</match>
Copied!
Make and change ownership directory:
1
$ sudo mkdir /var/run/fluentd
2
$ sudo chown `whoami` /var/run/fluentd
Copied!
Then, run as an ordinary user with cap_dac_read_search capability attached Ruby:
1
$ bundle exec fluentd -c in_tail_camouflage_permission.conf
2
2020-11-05 14:47:57 +0900 [info]: parsing config file is succeeded path="example/in_tail.conf"
3
2020-11-05 14:47:57 +0900 [info]: gem 'fluentd' version '1.12.0'
4
2020-11-05 14:47:57 +0900 [info]: gem 'fluent-plugin-systemd' version '1.0.2'
5
2020-11-05 14:47:57 +0900 [info]: using configuration file: <ROOT>
6
<source>
7
@type tail
8
path "/var/log/syslog"
9
pos_file "/var/run/fluentd/log/syslog_test_with_capability.pos"
10
tag "test"
11
rotate_wait 5
12
read_from_head true
13
refresh_interval 60
14
<parse>
15
@type "syslog"
16
unmatched_lines
17
</parse>
18
</source>
19
<match test>
20
@type stdout
21
</match>
22
</ROOT>
23
2020-11-05 14:47:57 +0900 [info]: starting fluentd-1.12.0 pid=12109 ruby="2.6.3"
24
2020-11-05 14:47:57 +0900 [info]: spawn command to main: cmdline=["/home/fluentd/.rbenv/versions/2.6.3/bin/ruby", "-rbundler/setup", "-Eascii-8bit:ascii-8bit", "/home/fluentd/work/fluentd/vendor/bundle/ruby/2.6.0/bin/fluentd", "-c", "example/in_tail.conf", "--under-supervisor"]
25
2020-11-05 14:47:58 +0900 [info]: adding match pattern="test" type="stdout"
26
2020-11-05 14:47:58 +0900 [info]: adding source type="tail"
27
2020-11-05 14:47:58 +0900 [info]: #0 starting fluentd worker pid=12143 ppid=12109 worker=0
28
2020-11-05 14:47:58 +0900 [info]: #0 following tail of /var/log/syslog
29
2020-11-05 09:53:11.000000000 +0900 test: {"host":"fluentd-testing","ident":"anacron","pid":"22613","message":"Job `cron.daily' terminated"}
30
2020-11-05 09:53:11.000000000 +0900 test: {"host":"fluentd-testing","ident":"anacron","pid":"22613","message":"Normal exit (1 job run)"}
31
2020-11-05 09:55:01.000000000 +0900 test: {"host":"fluentd-testing","ident":"CRON","pid":"24610","message":"(root) CMD (command -v debian-sa1 > /dev/null && debian-sa1 1 1)"}
Copied!
Fluentd, which is running by a non-root user, does not complain with Permission denied. Users can retrieve root files' contents on a non-root process, yay!
If this article is incorrect or outdated, or omits critical information, please let us know. Fluentd is an open-source project under Cloud Native Computing Foundation (CNCF). All components are available under the Apache 2 License.
Last modified 3mo ago