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 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