fluent-plugin-aes-forward 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/README.md +25 -0
- data/Rakefile +10 -0
- data/fluent-plugin-aes-forward.gemspec +24 -0
- data/lib/fluent/plugin/in_aes_forward.rb +56 -0
- data/lib/fluent/plugin/out_aes_forward.rb +63 -0
- data/test/helper.rb +21 -0
- data/test/test_in_aes_forward.rb +133 -0
- data/test/test_out_aes_forward.rb +45 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2638e8e8e4b855dcf519924f0637a3f17c00ad8d
|
4
|
+
data.tar.gz: e0dff996a87812b92ff3b595214faac78b5f12aa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bf97f4d5981e9e231d209bddd225f48be6688da2b9a04e77211866780e1d01805e90d4281dcdb686e4f631c8a60a436feff29b51c2f0eee7d1aef72a464c14d6
|
7
|
+
data.tar.gz: a2e92c6cbe1d8b48e4420e15280d9a8ec170c0d3ae019812d7f263be36a053b68d31590e11a67176c9e12ad7418f378c96bdc512a236da1a1b7968cc7139a398
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Fluent AES forward plugin
|
2
|
+
|
3
|
+
- This plugin is encrypt data at AES while transfer data.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'fluent-plugin-aes-forward'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install fluent-plugin-aes-forward
|
18
|
+
|
19
|
+
# License
|
20
|
+
|
21
|
+
[Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
22
|
+
|
23
|
+
# Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2013 Aiming Inc.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "fluent-plugin-aes-forward"
|
7
|
+
spec.version = "0.0.1"
|
8
|
+
spec.authors = ["futoase"]
|
9
|
+
spec.email = ["futoase@gmail.com"]
|
10
|
+
spec.description = %q{fluent plugin aes forward}
|
11
|
+
spec.summary = %q{This plugin is encrypt data at AES while transfer data.}
|
12
|
+
spec.homepage = "https://github.com/aiming/fluent-plugin-aes-forward"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
|
23
|
+
spec.add_dependency "fluentd"
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "fluent/plugin/in_forward"
|
2
|
+
require "openssl"
|
3
|
+
require "base64"
|
4
|
+
|
5
|
+
module Fluent
|
6
|
+
class AESForwardInput < ForwardInput
|
7
|
+
Fluent::Plugin.register_input('aes_forward', self)
|
8
|
+
|
9
|
+
config_param :key, :string, default: ""
|
10
|
+
config_param :iv, :string, default: ""
|
11
|
+
|
12
|
+
def decrypt_data(record)
|
13
|
+
decipher = OpenSSL::Cipher::AES.new(256, :CBC).decrypt
|
14
|
+
decipher.key = @key
|
15
|
+
decipher.iv = @iv
|
16
|
+
decipher.update(Base64.decode64(record)) + decipher.final
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_message(msg)
|
20
|
+
if msg.nil?
|
21
|
+
# for future TCP heartbeat_request
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO format error
|
26
|
+
tag = msg[0].to_s
|
27
|
+
entries = decrypt_data(msg[1])
|
28
|
+
|
29
|
+
if entries.class == String
|
30
|
+
# PackedForward
|
31
|
+
es = MessagePackEventStream.new(entries, @cached_unpacker)
|
32
|
+
Engine.emit_stream(tag, es)
|
33
|
+
|
34
|
+
elsif entries.class == Array
|
35
|
+
# Forward
|
36
|
+
es = MultiEventStream.new
|
37
|
+
entries.each {|e|
|
38
|
+
record = e[1]
|
39
|
+
next if record.nil?
|
40
|
+
time = e[0].to_i
|
41
|
+
time = (now ||= Engine.now) if time == 0
|
42
|
+
es.add(time, record)
|
43
|
+
}
|
44
|
+
Engine.emit_stream(tag, es)
|
45
|
+
|
46
|
+
else
|
47
|
+
# Message
|
48
|
+
record = msg[2]
|
49
|
+
return if record.nil?
|
50
|
+
time = msg[1]
|
51
|
+
time = Engine.now if time == 0
|
52
|
+
Engine.emit(tag, time, record)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "fluent/plugin/out_forward"
|
2
|
+
require "fluent/plugin/buf_memory"
|
3
|
+
require "base64"
|
4
|
+
require "openssl"
|
5
|
+
|
6
|
+
module Fluent
|
7
|
+
|
8
|
+
MemoryBufferChunk.class_eval do
|
9
|
+
def encrypt!(key, iv)
|
10
|
+
cipher = OpenSSL::Cipher::AES.new(256, :CBC).encrypt
|
11
|
+
cipher.key = key
|
12
|
+
cipher.iv = iv
|
13
|
+
cipher.encrypt
|
14
|
+
@data = Base64.encode64(cipher.update(@data) + cipher.final)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class AESForwardOutput < ForwardOutput
|
19
|
+
Fluent::Plugin.register_output('aes_forward', self)
|
20
|
+
|
21
|
+
config_param :key, :string, default: ""
|
22
|
+
config_param :iv, :string, default: ""
|
23
|
+
|
24
|
+
def send_data(node, tag, chunk)
|
25
|
+
sock = connect(node)
|
26
|
+
begin
|
27
|
+
opt = [1, @send_timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
|
28
|
+
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt)
|
29
|
+
|
30
|
+
opt = [@send_timeout.to_i, 0].pack('L!L!') # struct timeval
|
31
|
+
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, opt)
|
32
|
+
|
33
|
+
# beginArray(2)
|
34
|
+
sock.write FORWARD_HEADER
|
35
|
+
|
36
|
+
# writeRaw(tag)
|
37
|
+
sock.write tag.to_msgpack # tag
|
38
|
+
|
39
|
+
chunk.encrypt!(@key, @iv)
|
40
|
+
|
41
|
+
# beginRaw(size)
|
42
|
+
sz = chunk.size
|
43
|
+
#if sz < 32
|
44
|
+
# # FixRaw
|
45
|
+
# sock.write [0xa0 | sz].pack('C')
|
46
|
+
#elsif sz < 65536
|
47
|
+
# # raw 16
|
48
|
+
# sock.write [0xda, sz].pack('Cn')
|
49
|
+
#else
|
50
|
+
# raw 32
|
51
|
+
sock.write [0xdb, sz].pack('CN')
|
52
|
+
#end
|
53
|
+
|
54
|
+
# writeRawBody(packed_es)
|
55
|
+
chunk.write_to(sock)
|
56
|
+
|
57
|
+
node.heartbeat(false)
|
58
|
+
ensure
|
59
|
+
sock.close
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
Bundler.setup(:default, :test)
|
4
|
+
Bundler.require(:default, :test)
|
5
|
+
|
6
|
+
require 'fluent/test'
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
$:.unshift(File.join(File.dirname(__FILE__), '../lib'))
|
10
|
+
$:.unshift(File.dirname(__FILE__))
|
11
|
+
|
12
|
+
def unused_port
|
13
|
+
s = TCPServer.open(0)
|
14
|
+
port = s.addr[1]
|
15
|
+
s.close
|
16
|
+
port
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'base64'
|
20
|
+
require 'fluent/plugin/in_aes_forward'
|
21
|
+
require 'fluent/plugin/out_aes_forward'
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class InAESForwardTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
PORT = unused_port
|
9
|
+
KEY = "hogehogehogehogehogehogehogehoge"
|
10
|
+
IV = "mogemogemogemogemogemogemogemoge"
|
11
|
+
CONFIG = %[
|
12
|
+
key #{KEY}
|
13
|
+
iv #{IV}
|
14
|
+
port #{PORT}
|
15
|
+
bind 127.0.0.1
|
16
|
+
]
|
17
|
+
|
18
|
+
def create_driver(conf=CONFIG)
|
19
|
+
Fluent::Test::InputTestDriver.new(Fluent::AESForwardInput).configure(conf)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_configure
|
23
|
+
d = create_driver
|
24
|
+
assert_equal PORT, d.instance.port
|
25
|
+
assert_equal '127.0.0.1', d.instance.bind
|
26
|
+
end
|
27
|
+
|
28
|
+
def connect
|
29
|
+
TCPSocket.new('127.0.0.1', PORT)
|
30
|
+
end
|
31
|
+
|
32
|
+
def encrypt_data(data)
|
33
|
+
cipher = OpenSSL::Cipher::AES.new(256, :CBC).encrypt
|
34
|
+
cipher.key = KEY
|
35
|
+
cipher.iv = IV
|
36
|
+
Base64.encode64(cipher.update(Marshal.dump(data)) + cipher.final)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_time
|
40
|
+
d = create_driver
|
41
|
+
|
42
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
43
|
+
Fluent::Engine.now = time
|
44
|
+
|
45
|
+
d.expect_emit "tag1", time, { "a" => 1 }
|
46
|
+
d.expect_emit "tag2", time, { "a" => 2 }
|
47
|
+
|
48
|
+
d.run do
|
49
|
+
d.expected_emits.each do |tag, time, record|
|
50
|
+
send_data [tag, 0, record].map { |x| encrypt_data(x) }.to_msgpack
|
51
|
+
end
|
52
|
+
sleep 0.5
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_message
|
57
|
+
d = create_driver
|
58
|
+
|
59
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
60
|
+
|
61
|
+
d.expect_emit "tag1", time, { "a" => 1 }
|
62
|
+
d.expect_emit "tag2", time, { "a" => 2 }
|
63
|
+
|
64
|
+
d.run do
|
65
|
+
d.expected_emits.each do |tag, time, record|
|
66
|
+
send_data [tag, time, record].map { |x| encrypt_data(x) }.to_msgpack
|
67
|
+
end
|
68
|
+
sleep 0.5
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_forward
|
73
|
+
d = create_driver
|
74
|
+
|
75
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
76
|
+
|
77
|
+
d.expect_emit "tag1", time, { "a" => 1 }
|
78
|
+
d.expect_emit "tag1", time, { "a" => 2 }
|
79
|
+
|
80
|
+
d.run do
|
81
|
+
entries = []
|
82
|
+
d.expected_emits.each do |tag, time, record|
|
83
|
+
entries << [time, record]
|
84
|
+
end
|
85
|
+
send_data ["tag1", entries].map { |x| encrypt_data(x) }.to_msgpack
|
86
|
+
sleep 0.5
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_packed_forward
|
91
|
+
d = create_driver
|
92
|
+
|
93
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
94
|
+
|
95
|
+
d.expect_emit "tag1", time, { "a" => 1 }
|
96
|
+
d.expect_emit "tag1", time, { "a" => 2 }
|
97
|
+
|
98
|
+
d.run do
|
99
|
+
entries = ''
|
100
|
+
d.expected_emits.each do |tag, time, record|
|
101
|
+
[time, record].to_msgpack(entries)
|
102
|
+
end
|
103
|
+
send_data ["tag1", entries].map { |x| encrypt_data(x) }.to_msgpack
|
104
|
+
sleep 0.5
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_message_json
|
109
|
+
d = create_driver
|
110
|
+
|
111
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
112
|
+
|
113
|
+
d.expect_emit "tag1", time, { "a" => 1 }
|
114
|
+
d.expect_emit "tag2", time, { "a" => 2 }
|
115
|
+
|
116
|
+
d.run do
|
117
|
+
d.expected_emits.each do |tag, time, record|
|
118
|
+
send_data [tag, time, record].map { |x| encrypt_data(x) }.to_json
|
119
|
+
end
|
120
|
+
sleep 0.5
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def send_data(data)
|
125
|
+
io = connect
|
126
|
+
begin
|
127
|
+
io.write data
|
128
|
+
ensure
|
129
|
+
io.close
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "openssl"
|
2
|
+
|
3
|
+
class AESForwardOutputTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
CONFIG = %[
|
9
|
+
send_timeout 51
|
10
|
+
key hogehogehogehogehogehogehogehoge
|
11
|
+
iv mogemogemogemogemogemogemogemoge
|
12
|
+
<server>
|
13
|
+
name test
|
14
|
+
host 127.0.0.1
|
15
|
+
port 13999
|
16
|
+
</server>
|
17
|
+
]
|
18
|
+
|
19
|
+
def create_driver(conf=CONFIG)
|
20
|
+
Fluent::Test::OutputTestDriver.new(Fluent::AESForwardOutput) do
|
21
|
+
def write(chunk)
|
22
|
+
chunk.read
|
23
|
+
end
|
24
|
+
end.configure(conf)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_configure
|
28
|
+
d = create_driver
|
29
|
+
nodes = d.instance.nodes
|
30
|
+
assert_equal 51, d.instance.send_timeout
|
31
|
+
assert_equal :udp, d.instance.heartbeat_type
|
32
|
+
assert_equal 1, nodes.length
|
33
|
+
node = nodes.first
|
34
|
+
assert_equal "test", node.name
|
35
|
+
assert_equal '127.0.0.1', node.host
|
36
|
+
assert_equal 13999, node.port
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_configure_tcp_heartbeat
|
40
|
+
d = create_driver(CONFIG + "\nheartbeat_type tcp")
|
41
|
+
assert_equal :tcp, d.instance.heartbeat_type
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-aes-forward
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- futoase
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fluentd
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: fluent plugin aes forward
|
56
|
+
email:
|
57
|
+
- futoase@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- Gemfile
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- fluent-plugin-aes-forward.gemspec
|
67
|
+
- lib/fluent/plugin/in_aes_forward.rb
|
68
|
+
- lib/fluent/plugin/out_aes_forward.rb
|
69
|
+
- test/helper.rb
|
70
|
+
- test/test_in_aes_forward.rb
|
71
|
+
- test/test_out_aes_forward.rb
|
72
|
+
homepage: https://github.com/aiming/fluent-plugin-aes-forward
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.0.3
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: This plugin is encrypt data at AES while transfer data.
|
96
|
+
test_files:
|
97
|
+
- test/helper.rb
|
98
|
+
- test/test_in_aes_forward.rb
|
99
|
+
- test/test_out_aes_forward.rb
|