fluent-plugin-syslog-tls 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +3 -5
- data/docs/configuration.md +18 -5
- data/fluent-plugin-syslog-tls.gemspec +2 -2
- data/lib/fluent/plugin/out_syslog_tls.rb +9 -7
- data/lib/syslog_tls/ssl_transport.rb +121 -11
- data/lib/syslog_tls/version.rb +1 -1
- data/test/fluent/test_out_syslog_tls.rb +15 -15
- data/test/syslog_tls/test_ssl_transport.rb +2 -2
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d451a9db525bf51ce92a8fb6ba314e07ef4fde7
|
4
|
+
data.tar.gz: 578fa7e673a40b1a469bb7eb70681f0cfe102878
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8f97eb7e0028c5a41735c8c474128b0ec6181aaac527e5772c984a22ee9ba4e5e424cd1aceae806bebe5f42b4768e3647d8d3d07a44e4c0db14b630e7660a55
|
7
|
+
data.tar.gz: d8121c0078122038002ccb99c7888a125656e3728d2a75588408ccbd55e23563d5d5ce1ac6a7945ee68c8933c78549e401af02e2b76d7791360d0bd263123ee9
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#### 1.1.0
|
2
|
+
|
3
|
+
* Renamed `cert` and `key` to `client_cert` and `client_key` respectively.
|
4
|
+
* Change to short timeouts on network calls so logging doesn't go dead for extended periods.
|
5
|
+
* Added `idle_timeout` to force upstream reconnection after a period of time with no traffic for a particular tag. Useful for low-traffic senders. Not recommended for high-traffic.
|
6
|
+
* Added `ca_cert` to validate the remote certificate. Defaults to 'system' which uses the system certificate store.
|
7
|
+
|
8
|
+
|
9
|
+
#### 1.0.0
|
10
|
+
|
11
|
+
* Standard fluent formatting plugins are supported. Json output remains the default.
|
12
|
+
* `token` (Structured Data in syslog terms) is now optional, for syslog hosts that don't require it.
|
13
|
+
* Message payload in the syslog packet no longer duplicates Time or includes Tag by default.
|
14
|
+
|
15
|
+
|
16
|
+
#### < 1.0.0
|
17
|
+
From [Fluent::Plugin::SumologicCloudSyslog](https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog)
|
data/README.md
CHANGED
@@ -17,6 +17,8 @@ or
|
|
17
17
|
$ td-agent-gem install fluent-plugin-syslog-tls
|
18
18
|
```
|
19
19
|
|
20
|
+
Note: `fluent-plugin-syslog-tls` is compatible with Fluent 0.14.
|
21
|
+
|
20
22
|
|
21
23
|
## Configuration
|
22
24
|
---
|
@@ -48,11 +50,7 @@ For more configuration options see [configuration docs](docs/configuration.md)
|
|
48
50
|
|
49
51
|
## Origin/History
|
50
52
|
|
51
|
-
This plugin is derived from [Fluent::Plugin::SumologicCloudSyslog](https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog). Changes
|
52
|
-
|
53
|
-
* Standard fluent formatting plugins are supported. Json output remains the default.
|
54
|
-
* `token` (Structured Data in syslog terms) is now optional, for syslog hosts that don't require it.
|
55
|
-
* Message payload in the syslog packet no longer duplicates Time or includes Tag by default.
|
53
|
+
This plugin is derived from [Fluent::Plugin::SumologicCloudSyslog](https://github.com/acquia/fluent-plugin-sumologic-cloud-syslog). Changes are in the [Changelog](CHANGELOG.md).
|
56
54
|
|
57
55
|
|
58
56
|
## License
|
data/docs/configuration.md
CHANGED
@@ -15,15 +15,27 @@ Host represents DNS name of endpoint where should be data sent. Example: `syslog
|
|
15
15
|
|
16
16
|
Example: `6514`
|
17
17
|
|
18
|
+
### idle_timeout
|
19
|
+
|
20
|
+
If a given tag has gone this many seconds between log messages, disconnect and reconnect before sending logs. Useful in low-traffic logging situations with remote hosts that disconnect after a period of time. Disabled by default. Example: `600`
|
21
|
+
|
22
|
+
### ca_cert
|
23
|
+
|
24
|
+
Whether and how to verify the server's TLS certificate. Examples:
|
25
|
+
* ca_cert system - Default; use the system CA certificate store (which must then be configured correctly)
|
26
|
+
* ca_cert false - Disable verification; not recommended
|
27
|
+
* ca_cert /path/to/file - A path+filename to a single CA file
|
28
|
+
* ca_cert /path/to/dir/ - A directory of CA files (in format that OpenSSL can parse); must end with /
|
29
|
+
|
18
30
|
### token
|
19
31
|
|
20
32
|
Some services require a token to identify the account. Example: `ABABABABABABA@99999`. Not required for Papertrail.
|
21
33
|
|
22
|
-
###
|
34
|
+
### client_cert
|
23
35
|
|
24
36
|
Optionally path to client certificate for TLS connection. Example: `/path/to/crt/file.crt`
|
25
37
|
|
26
|
-
###
|
38
|
+
### client_key
|
27
39
|
|
28
40
|
Optionally path to client private key for TLS connection. Example: `/path/to/key/file.key`
|
29
41
|
|
@@ -72,6 +84,7 @@ Optionally record key where to get msgid from the record. If not provided nil va
|
|
72
84
|
@type syslog_tls
|
73
85
|
host logs1.papertrailapp.com
|
74
86
|
port 12345
|
87
|
+
idle_timeout 720
|
75
88
|
|
76
89
|
hostname static-hostname
|
77
90
|
facility SYSLOG
|
@@ -87,7 +100,7 @@ Optionally record key where to get msgid from the record. If not provided nil va
|
|
87
100
|
msgid_key ...
|
88
101
|
|
89
102
|
# Fluent's standard formatting options are supported. Default is 'json'.
|
90
|
-
# Example: For Docker logs sent to Papertrail,
|
103
|
+
# Example: For Docker logs sent to Papertrail, send only the log text:
|
91
104
|
format single_value
|
92
105
|
message_key log
|
93
106
|
</match>
|
@@ -99,8 +112,8 @@ Optionally record key where to get msgid from the record. If not provided nil va
|
|
99
112
|
host syslog.collection.us1.sumologic.com
|
100
113
|
port 6514
|
101
114
|
token [token]@[iana-id]
|
102
|
-
|
103
|
-
|
115
|
+
client_cert /path/to/cert/file.crt
|
116
|
+
client_key /path/to/key/file.key
|
104
117
|
|
105
118
|
hostname static-hostname
|
106
119
|
facility SYSLOG
|
@@ -30,9 +30,9 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
31
31
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
32
32
|
s.require_paths = ['lib']
|
33
|
-
s.required_ruby_version = '>= 2.
|
33
|
+
s.required_ruby_version = '>= 2.3.0'
|
34
34
|
|
35
|
-
s.add_runtime_dependency 'fluentd', '~> 0.
|
35
|
+
s.add_runtime_dependency 'fluentd', '~> 0.14.0'
|
36
36
|
s.add_runtime_dependency 'fluent-mixin-config-placeholders', '~> 0.3'
|
37
37
|
|
38
38
|
s.add_development_dependency 'minitest', '~> 5.8'
|
@@ -29,11 +29,13 @@ module Fluent
|
|
29
29
|
|
30
30
|
config_param :host, :string
|
31
31
|
config_param :port, :integer
|
32
|
-
config_param :
|
33
|
-
config_param :
|
34
|
-
config_param :
|
35
|
-
config_param :
|
36
|
-
config_param :
|
32
|
+
config_param :idle_timeout, :integer, default: nil
|
33
|
+
config_param :ca_cert, :string, default: 'system'
|
34
|
+
config_param :token, :string, default: nil
|
35
|
+
config_param :client_cert, :string, default: nil
|
36
|
+
config_param :client_key, :string, default: nil
|
37
|
+
config_param :hostname, :string, default: nil
|
38
|
+
config_param :facility, :string, default: 'LOCAL0'
|
37
39
|
|
38
40
|
# Allow to map keys from record to syslog message headers
|
39
41
|
SYSLOG_HEADERS = [
|
@@ -41,7 +43,7 @@ module Fluent
|
|
41
43
|
]
|
42
44
|
|
43
45
|
SYSLOG_HEADERS.each do |key_name|
|
44
|
-
config_param "#{key_name}_key".to_sym, :string, :
|
46
|
+
config_param "#{key_name}_key".to_sym, :string, default: nil
|
45
47
|
end
|
46
48
|
|
47
49
|
config_section :format do
|
@@ -99,7 +101,7 @@ module Fluent
|
|
99
101
|
end
|
100
102
|
|
101
103
|
def new_logger(tag)
|
102
|
-
transport = ::SyslogTls::SSLTransport.new(host, port,
|
104
|
+
transport = ::SyslogTls::SSLTransport.new(host, port, idle_timeout: idle_timeout, ca_cert: ca_cert, client_cert: client_cert, client_key: client_key, max_retries: 3)
|
103
105
|
logger = ::SyslogTls::Logger.new(transport, token)
|
104
106
|
logger.facility(facility)
|
105
107
|
logger.hostname(hostname)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# Copyright 2016 Acquia, Inc.
|
2
|
+
# Copyright 2016 t.e.morgan.
|
2
3
|
#
|
3
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
5
|
# you may not use this file except in compliance with the License.
|
@@ -18,17 +19,23 @@ require 'openssl'
|
|
18
19
|
module SyslogTls
|
19
20
|
# Supports SSL connection to remote host
|
20
21
|
class SSLTransport
|
22
|
+
CONNECT_TIMEOUT = 10
|
23
|
+
# READ_TIMEOUT = 5
|
24
|
+
WRITE_TIMEOUT = 5
|
25
|
+
|
21
26
|
attr_accessor :socket
|
22
27
|
|
23
|
-
attr_reader :host, :port, :
|
28
|
+
attr_reader :host, :port, :idle_timeout, :ca_cert, :client_cert, :client_key, :ssl_version
|
24
29
|
|
25
30
|
attr_writer :retries
|
26
31
|
|
27
|
-
def initialize(host, port,
|
32
|
+
def initialize(host, port, idle_timeout: nil, ca_cert: 'system', client_cert: nil, client_key: nil, ssl_version: :TLSv1_2, max_retries: 1)
|
28
33
|
@host = host
|
29
34
|
@port = port
|
30
|
-
@
|
31
|
-
@
|
35
|
+
@idle_timeout = idle_timeout
|
36
|
+
@ca_cert = ca_cert
|
37
|
+
@client_cert = client_cert
|
38
|
+
@client_key = client_key
|
32
39
|
@ssl_version = ssl_version
|
33
40
|
@retries = max_retries
|
34
41
|
connect
|
@@ -36,28 +43,96 @@ module SyslogTls
|
|
36
43
|
|
37
44
|
def connect
|
38
45
|
@socket = get_ssl_connection
|
39
|
-
|
46
|
+
begin
|
47
|
+
begin
|
48
|
+
@socket.connect_nonblock
|
49
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
50
|
+
select_with_timeout(@socket, :connect_read) && retry
|
51
|
+
rescue IO::WaitWritable
|
52
|
+
select_with_timeout(@socket, :connect_write) && retry
|
53
|
+
end
|
54
|
+
rescue Errno::ETIMEDOUT
|
55
|
+
raise 'Socket timeout during connect'
|
56
|
+
end
|
57
|
+
@last_write = Time.now if idle_timeout
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_tcp_connection
|
61
|
+
tcp = nil
|
62
|
+
|
63
|
+
family = Socket::Constants::AF_UNSPEC
|
64
|
+
sock_type = Socket::Constants::SOCK_STREAM
|
65
|
+
addr_info = Socket.getaddrinfo(host, port, family, sock_type, nil, nil, false).first
|
66
|
+
_, port, _, address, family, sock_type = addr_info
|
67
|
+
|
68
|
+
begin
|
69
|
+
sock_addr = Socket.sockaddr_in(port, address)
|
70
|
+
tcp = Socket.new(family, sock_type, 0)
|
71
|
+
tcp.setsockopt(Socket::SOL_SOCKET, Socket::Constants::SO_REUSEADDR, true)
|
72
|
+
tcp.setsockopt(Socket::SOL_SOCKET, Socket::Constants::SO_REUSEPORT, true)
|
73
|
+
tcp.connect_nonblock(sock_addr)
|
74
|
+
rescue Errno::EINPROGRESS
|
75
|
+
select_with_timeout(tcp, :connect_write)
|
76
|
+
begin
|
77
|
+
tcp.connect_nonblock(sock_addr)
|
78
|
+
rescue Errno::EISCONN
|
79
|
+
# all good
|
80
|
+
rescue SystemCallError
|
81
|
+
tcp.close rescue nil
|
82
|
+
raise
|
83
|
+
end
|
84
|
+
rescue SystemCallError
|
85
|
+
tcp.close rescue nil
|
86
|
+
raise
|
87
|
+
end
|
88
|
+
|
89
|
+
tcp.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
90
|
+
tcp
|
40
91
|
end
|
41
92
|
|
42
93
|
def get_ssl_connection
|
43
|
-
tcp =
|
94
|
+
tcp = get_tcp_connection
|
44
95
|
|
45
96
|
ctx = OpenSSL::SSL::SSLContext.new
|
46
|
-
ctx.
|
97
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
47
98
|
ctx.ssl_version = ssl_version
|
48
99
|
|
49
|
-
|
50
|
-
|
51
|
-
|
100
|
+
case ca_cert
|
101
|
+
when true, 'true', 'system'
|
102
|
+
# use system certs, same as openssl cli
|
103
|
+
ctx.cert_store = OpenSSL::X509::Store.new
|
104
|
+
ctx.cert_store.set_default_paths
|
105
|
+
when false, 'false'
|
106
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
107
|
+
when %r{/$} # ends in /
|
108
|
+
ctx.ca_path = ca_cert
|
109
|
+
when String
|
110
|
+
ctx.ca_file = ca_cert
|
111
|
+
end
|
112
|
+
|
113
|
+
ctx.cert = OpenSSL::X509::Certificate.new(File.read(client_cert)) if client_cert
|
114
|
+
ctx.key = OpenSSL::PKey::read(File.read(client_key)) if client_key
|
115
|
+
socket = OpenSSL::SSL::SSLSocket.new(tcp, ctx)
|
116
|
+
socket.sync_close = true
|
117
|
+
socket
|
52
118
|
end
|
53
119
|
|
54
120
|
# Allow to retry on failed writes
|
55
121
|
def write(s)
|
122
|
+
if idle_timeout
|
123
|
+
if (t=Time.now) > @last_write + idle_timeout
|
124
|
+
@socket.close rescue nil
|
125
|
+
connect
|
126
|
+
else
|
127
|
+
@last_write = t
|
128
|
+
end
|
129
|
+
end
|
56
130
|
begin
|
57
131
|
retry_id ||= 0
|
58
|
-
|
132
|
+
do_write(s)
|
59
133
|
rescue => e
|
60
134
|
if (retry_id += 1) < @retries
|
135
|
+
@socket.close rescue nil
|
61
136
|
connect
|
62
137
|
retry
|
63
138
|
else
|
@@ -66,6 +141,41 @@ module SyslogTls
|
|
66
141
|
end
|
67
142
|
end
|
68
143
|
|
144
|
+
def do_write(data)
|
145
|
+
data.force_encoding('BINARY') # so we can break in the middle of multi-byte characters
|
146
|
+
loop do
|
147
|
+
sent = 0
|
148
|
+
begin
|
149
|
+
sent = @socket.write_nonblock(data)
|
150
|
+
rescue OpenSSL::SSL::SSLError, Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable => e
|
151
|
+
if e.is_a?(OpenSSL::SSL::SSLError) && e.message !~ /write would block/
|
152
|
+
raise e
|
153
|
+
else
|
154
|
+
select_with_timeout(@socket, :write) && retry
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
break if sent >= data.size
|
159
|
+
data = data[sent, data.size]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def select_with_timeout(tcp, type)
|
164
|
+
o = case type
|
165
|
+
when :connect_read
|
166
|
+
args = [[tcp], nil, nil, CONNECT_TIMEOUT]
|
167
|
+
when :connect_write
|
168
|
+
args = [nil, [tcp], nil, CONNECT_TIMEOUT]
|
169
|
+
# when :read
|
170
|
+
# args = [[tcp], nil, nil, READ_TIMEOUT]
|
171
|
+
when :write
|
172
|
+
args = [nil, [tcp], nil, WRITE_TIMEOUT]
|
173
|
+
else
|
174
|
+
raise "Unknown select type #{type}"
|
175
|
+
end
|
176
|
+
IO.select(*args) || raise("Socket timeout during #{type}")
|
177
|
+
end
|
178
|
+
|
69
179
|
# Forward any methods directly to SSLSocket
|
70
180
|
def method_missing(method_sym, *arguments, &block)
|
71
181
|
@socket.send(method_sym, *arguments, &block)
|
data/lib/syslog_tls/version.rb
CHANGED
@@ -52,16 +52,16 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
52
52
|
config = %{
|
53
53
|
host syslog.collection.us1.sumologic.com
|
54
54
|
port 6514
|
55
|
-
|
56
|
-
|
55
|
+
client_cert
|
56
|
+
client_key
|
57
57
|
token 1234567890
|
58
58
|
}
|
59
59
|
instance = driver('test', config).instance
|
60
60
|
|
61
61
|
assert_equal 'syslog.collection.us1.sumologic.com', instance.host
|
62
62
|
assert_equal '6514', instance.port
|
63
|
-
assert_equal '', instance.
|
64
|
-
assert_equal '', instance.
|
63
|
+
assert_equal '', instance.client_cert
|
64
|
+
assert_equal '', instance.client_key
|
65
65
|
assert_equal '1234567890', instance.token
|
66
66
|
end
|
67
67
|
|
@@ -69,8 +69,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
69
69
|
config = %{
|
70
70
|
host syslog.collection.us1.sumologic.com
|
71
71
|
port 6514
|
72
|
-
|
73
|
-
|
72
|
+
client_cert
|
73
|
+
client_key
|
74
74
|
}
|
75
75
|
instance = driver('test', config).instance
|
76
76
|
|
@@ -91,8 +91,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
91
91
|
config = %{
|
92
92
|
host syslog.collection.us1.sumologic.com
|
93
93
|
port 6514
|
94
|
-
|
95
|
-
|
94
|
+
client_cert
|
95
|
+
client_key
|
96
96
|
token 1234567890
|
97
97
|
hostname_key hostname
|
98
98
|
procid_key procid
|
@@ -118,8 +118,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
118
118
|
config = %{
|
119
119
|
host syslog.collection.us1.sumologic.com
|
120
120
|
port 6514
|
121
|
-
|
122
|
-
|
121
|
+
client_cert
|
122
|
+
client_key
|
123
123
|
token 1234567890
|
124
124
|
severity_key severity
|
125
125
|
}
|
@@ -142,11 +142,11 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
142
142
|
config = %{
|
143
143
|
host syslog.collection.us1.sumologic.com
|
144
144
|
port 6514
|
145
|
-
|
146
|
-
|
145
|
+
client_cert
|
146
|
+
client_key
|
147
147
|
token 1234567890
|
148
148
|
format out_file
|
149
|
-
|
149
|
+
localtime false
|
150
150
|
}
|
151
151
|
instance = driver('test', config).instance
|
152
152
|
|
@@ -178,8 +178,8 @@ class SyslogTlsOutputTest < Test::Unit::TestCase
|
|
178
178
|
config = %{
|
179
179
|
host localhost
|
180
180
|
port #{server.addr[1]}
|
181
|
-
|
182
|
-
|
181
|
+
client_cert
|
182
|
+
client_key
|
183
183
|
token 1234567890
|
184
184
|
hostname_key hostname
|
185
185
|
procid_key procid
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-syslog-tls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thomas morgan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.14.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.14.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fluent-mixin-config-placeholders
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- ".coveralls.yml"
|
133
133
|
- ".gitignore"
|
134
134
|
- ".travis.yml"
|
135
|
+
- CHANGELOG.md
|
135
136
|
- Gemfile
|
136
137
|
- LICENSE
|
137
138
|
- README.md
|
@@ -164,7 +165,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
165
|
requirements:
|
165
166
|
- - ">="
|
166
167
|
- !ruby/object:Gem::Version
|
167
|
-
version: 2.
|
168
|
+
version: 2.3.0
|
168
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
170
|
requirements:
|
170
171
|
- - ">="
|
@@ -172,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
173
|
version: '0'
|
173
174
|
requirements: []
|
174
175
|
rubyforge_project:
|
175
|
-
rubygems_version: 2.5.
|
176
|
+
rubygems_version: 2.5.2
|
176
177
|
signing_key:
|
177
178
|
specification_version: 4
|
178
179
|
summary: Fluent Syslog TLS output plugin
|