fluent-plugin-syslog-tls 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 194b7c338bc48c3b97b41d51f5258157f0bf4fd1
4
- data.tar.gz: 340359e27afeac0a38eb705cfac9cdf5c123cd1e
3
+ metadata.gz: 3d451a9db525bf51ce92a8fb6ba314e07ef4fde7
4
+ data.tar.gz: 578fa7e673a40b1a469bb7eb70681f0cfe102878
5
5
  SHA512:
6
- metadata.gz: 66915ee3952bcc0eacd004e7b56bb3d7521bb2748c7921b0321dbac1ab09c8fcf356355e3b600287e13251cd545209cacd95edb6f579bfe382cba0309b88d14b
7
- data.tar.gz: 8b2e05659598a9dc390350841455c9d003afa520e984de48f30d32974ea014c4b36e21c583edf60e3932cc9a4d0830f66cb32935f9d57d79ee5bb90e7533f847
6
+ metadata.gz: e8f97eb7e0028c5a41735c8c474128b0ec6181aaac527e5772c984a22ee9ba4e5e424cd1aceae806bebe5f42b4768e3647d8d3d07a44e4c0db14b630e7660a55
7
+ data.tar.gz: d8121c0078122038002ccb99c7888a125656e3728d2a75588408ccbd55e23563d5d5ce1ac6a7945ee68c8933c78549e401af02e2b76d7791360d0bd263123ee9
@@ -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 from the original:
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
@@ -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
- ### cert
34
+ ### client_cert
23
35
 
24
36
  Optionally path to client certificate for TLS connection. Example: `/path/to/crt/file.crt`
25
37
 
26
- ### key
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, sending only the log text:
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
- cert /path/to/cert/file.crt
103
- key /path/to/key/file.key
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.0.0'
33
+ s.required_ruby_version = '>= 2.3.0'
34
34
 
35
- s.add_runtime_dependency 'fluentd', '~> 0.12'
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 :token, :string, :default => nil
33
- config_param :cert, :string, :default => nil
34
- config_param :key, :string, :default => nil
35
- config_param :hostname, :string, :default => nil
36
- config_param :facility, :string, :default => 'LOCAL0'
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, :default => nil
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, cert: cert, key: key, max_retries: 3)
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, :cert, :key, :ssl_version
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, cert: nil, key: nil, ssl_version: :TLSv1_2, max_retries: 1)
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
- @cert = cert
31
- @key = key
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
- @socket.connect
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 = TCPSocket.new(host, port)
94
+ tcp = get_tcp_connection
44
95
 
45
96
  ctx = OpenSSL::SSL::SSLContext.new
46
- ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
97
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
47
98
  ctx.ssl_version = ssl_version
48
99
 
49
- ctx.cert = OpenSSL::X509::Certificate.new(File.open(cert)) if cert
50
- ctx.key = OpenSSL::PKey::RSA.new(File.open(key)) if key
51
- OpenSSL::SSL::SSLSocket.new(tcp, ctx)
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
- @socket.send(:write, s)
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)
@@ -14,5 +14,5 @@
14
14
  # limitations under the License.
15
15
 
16
16
  module SyslogTls
17
- VERSION = '1.0.0'
17
+ VERSION = '1.1.0'
18
18
  end
@@ -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
- cert
56
- key
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.cert
64
- assert_equal '', instance.key
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
- cert
73
- key
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
- cert
95
- key
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
- cert
122
- key
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
- cert
146
- key
145
+ client_cert
146
+ client_key
147
147
  token 1234567890
148
148
  format out_file
149
- utc true
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
- cert
182
- key
181
+ client_cert
182
+ client_key
183
183
  token 1234567890
184
184
  hostname_key hostname
185
185
  procid_key procid
@@ -37,10 +37,10 @@ class SSLTransportTest < Test::Unit::TestCase
37
37
 
38
38
  def test_retry
39
39
  client = Object.new
40
- def client.connect
40
+ def client.connect_nonblock
41
41
  true
42
42
  end
43
- def client.write(s)
43
+ def client.write_nonblock(s)
44
44
  raise "Test"
45
45
  end
46
46
 
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.0.0
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-04 00:00:00.000000000 Z
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: '0.12'
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: '0.12'
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.0.0
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.1
176
+ rubygems_version: 2.5.2
176
177
  signing_key:
177
178
  specification_version: 4
178
179
  summary: Fluent Syslog TLS output plugin