nexpose_paloalto 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/{lib/bin/nexpose_paloalto.rb → bin/nexpose_paloalto} +3 -0
- data/lib/paloalto.rb +23 -15
- data/lib/paloalto/nexpose_helper.rb +3 -2
- data/lib/paloalto/nx_logger.rb +159 -20
- data/lib/paloalto/version.rb +3 -1
- metadata +10 -10
- data/nexpose_paloalto.gemspec +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4031017be8639d09edbb9fef2ffb3ec43b21330e
|
4
|
+
data.tar.gz: f75c2a16d0ce151d132a77eaf11c9e3b377b2cbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 410ba9dfbe608b1465fdc6bd5967f561537e1ef3b36799ff9454d9440de7a3d708f68a80ba82112b68f88ac7196a6c5941d9f9ed6c0fea48a36a88980b4a9034
|
7
|
+
data.tar.gz: 3495a3363873daa1faa9fc2956262907d37f6e7122e1ae269094c41c01cce8f12f5d910df0cda6dc579b076d271699de2252779dee83b7be5935525f79c9866c
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -59,5 +59,5 @@ For Windows systems, make sure they are on the Environment Variables section in
|
|
59
59
|
* (Optional) Review the log file under the logs folder in the Gem path.
|
60
60
|
|
61
61
|
|
62
|
-
For any support requests, please email
|
62
|
+
For any support requests, please email support@rapid7.com with a description of the issue and any logs
|
63
63
|
available.
|
@@ -1,3 +1,4 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
require 'paloalto'
|
2
3
|
|
3
4
|
# Obtain Nexpose settings from Environment Variables.
|
@@ -6,6 +7,8 @@ raise 'Must configure nexpose settings before starting' if ENV['NEXPOSE_URL'].ni
|
|
6
7
|
nexpose_settings[:nexpose_url] = ENV['NEXPOSE_URL']
|
7
8
|
nexpose_settings[:nexpose_username] = ENV['NEXPOSE_USERNAME']
|
8
9
|
nexpose_settings[:nexpose_password] = ENV['NEXPOSE_PASSWORD']
|
10
|
+
# User can change the port if Nexpose does not use port 3780
|
11
|
+
nexpose_settings[:nexpose_port] = 3780
|
9
12
|
|
10
13
|
# Obtain PAN's info.
|
11
14
|
pan_settings = Hash.new
|
data/lib/paloalto.rb
CHANGED
@@ -16,6 +16,7 @@ module Paloalto
|
|
16
16
|
nexpose_url = nexpose_settings[:nexpose_url]
|
17
17
|
nexpose_username = nexpose_settings[:nexpose_username]
|
18
18
|
nexpose_password = nexpose_settings[:nexpose_password]
|
19
|
+
nexpose_port = nexpose_settings[:nexpose_port]
|
19
20
|
|
20
21
|
pan_url = pan_settings[:pan_url]
|
21
22
|
pan_username = pan_settings[:pan_username]
|
@@ -24,7 +25,11 @@ module Paloalto
|
|
24
25
|
report_timeout = nexpose_settings[:timeout]
|
25
26
|
|
26
27
|
#Setup logging
|
27
|
-
@log = Paloalto::
|
28
|
+
@log = Paloalto::NxLogger.instance
|
29
|
+
@log.setup_statistics_collection(Paloalto::VENDOR,
|
30
|
+
Paloalto::PRODUCT,
|
31
|
+
Paloalto::VERSION)
|
32
|
+
@log.setup_logging(true, 'info')
|
28
33
|
|
29
34
|
#Nexpose sites and DAGs to import. Uses Site Id and DAG ID e.g. 'sites = [1,2,3,4]'. Leave as nil to run on all sites and DAGs the user has access to or
|
30
35
|
# set as an empty array e.g. 'dags=[]' to not run on any sites/dags.
|
@@ -34,9 +39,12 @@ module Paloalto
|
|
34
39
|
@log.log_message("Running with user configured site IDs <#{sites}> and dynamic asset group IDs #{dags}.")
|
35
40
|
|
36
41
|
# Log in to nexpose.
|
37
|
-
nsc = Paloalto::NexposeHelper.login(nexpose_url,
|
42
|
+
nsc = Paloalto::NexposeHelper.login(nexpose_url,
|
43
|
+
nexpose_username,
|
44
|
+
nexpose_password,
|
45
|
+
nexpose_port)
|
38
46
|
|
39
|
-
#Gather the sites
|
47
|
+
# Gather the sites
|
40
48
|
all_sites = nsc.sites
|
41
49
|
all_sites.delete_if {|site| !(sites.include? site.id)} unless sites.nil?
|
42
50
|
all_sites_names = []
|
@@ -53,53 +61,53 @@ module Paloalto
|
|
53
61
|
# Login to PAN.
|
54
62
|
pan_key = Paloalto::Ngfw.login(pan_url, pan_username, pan_password)
|
55
63
|
|
56
|
-
#Get the device config
|
64
|
+
# Get the device config
|
57
65
|
device_config_xml = Paloalto::Ngfw.retrieve_device_config(pan_url, pan_key)
|
58
66
|
|
59
|
-
#Get the device names
|
67
|
+
# Get the device names
|
60
68
|
device_name = Paloalto::Ngfw.parse_device_name(device_config_xml)
|
61
69
|
vsys_name = Paloalto::Ngfw.parse_vsys_name(device_config_xml)
|
62
70
|
|
63
71
|
@log.log_message("Found device configuration. Name <#{device_name}> and vsys <#{vsys_name}>.")
|
64
72
|
|
65
|
-
#Get this device's config
|
73
|
+
# Get this device's config
|
66
74
|
vsys_config = Paloalto::Ngfw.retrieve_device_config(pan_url, pan_key, device_name, vsys_name)
|
67
75
|
|
68
|
-
#Get the existing tags
|
76
|
+
# Get the existing tags
|
69
77
|
existing_tags = Paloalto::Ngfw.parse_existing_tags(vsys_config)
|
70
78
|
|
71
|
-
#Gather the tags we want to create
|
79
|
+
# Gather the tags we want to create
|
72
80
|
wanted_tags = []
|
73
81
|
all_sites_names.each {|site_name| wanted_tags << site_name.gsub(/[()]/, "")}
|
74
82
|
wanted_tags << 'Nexpose'
|
75
83
|
all_nexpose_dag_details.each {|details| wanted_tags << details[1].gsub(/[()']/, "")}
|
76
84
|
|
77
|
-
#
|
85
|
+
# Finds which new tags need to be created
|
78
86
|
tags_to_create = wanted_tags - existing_tags
|
79
87
|
|
80
88
|
@log.log_message("New tags to be created <#{tags_to_create}>.")
|
81
89
|
|
82
|
-
#Find the existing DAGs
|
90
|
+
# Find the existing DAGs
|
83
91
|
existing_dags = Paloalto::Ngfw.parse_existing_dags(vsys_config)
|
84
92
|
|
85
|
-
#Gather the dags we want to create
|
93
|
+
# Gather the dags we want to create
|
86
94
|
wanted_dags = []
|
87
95
|
all_sites_names.each {|site_name| wanted_dags << site_name.gsub(/[()]/, "")}
|
88
96
|
wanted_dags << 'Nexpose'
|
89
97
|
all_nexpose_dag_details.each {|details| wanted_dags << details[1].gsub(/[()']/, "")}
|
90
98
|
|
91
|
-
#Find which new dags need to be created
|
99
|
+
# Find which new dags need to be created
|
92
100
|
dags_to_create = wanted_dags - existing_dags
|
93
101
|
|
94
102
|
@log.log_message("New DAGs to be created <#{dags_to_create}>.")
|
95
103
|
|
96
|
-
#Create the new tags
|
104
|
+
# Create the new tags
|
97
105
|
@log.log_message("Creating tags...")
|
98
106
|
tags_element=''
|
99
107
|
tags_to_create.each {|tag_to_create| tags_element << Paloalto::Ngfw.generate_tag_xml(tag_to_create, 'color3', "Nexpose tag for asset grouping: #{tag_to_create}")}
|
100
108
|
response = Paloalto::Ngfw.create_tags(pan_url, pan_key, device_name, vsys_name, tags_element) unless tags_element.empty?
|
101
109
|
|
102
|
-
#Create the new dags
|
110
|
+
# Create the new dags
|
103
111
|
@log.log_message("Creating DAGs...")
|
104
112
|
dags_element=''
|
105
113
|
dags_to_create.each {|dag_to_create| dags_element << Paloalto::Ngfw.generate_dag_xml(dag_to_create, "'Nexpose' AND '#{dag_to_create}'", dag_to_create)}
|
@@ -107,7 +115,7 @@ module Paloalto
|
|
107
115
|
|
108
116
|
@log.log_message('Committing the changes...')
|
109
117
|
|
110
|
-
#Commit the changes
|
118
|
+
# Commit the changes
|
111
119
|
response = Paloalto::Ngfw.commit(pan_url, pan_key)
|
112
120
|
|
113
121
|
@log.log_message("Commit response <#{response}>")
|
@@ -5,10 +5,11 @@ module Paloalto
|
|
5
5
|
require 'paloalto/nx_logger'
|
6
6
|
|
7
7
|
# Logs in to Nexpose using the url, username and password.
|
8
|
-
def self.login(url=nil, username=nil, password=nil)
|
8
|
+
def self.login(url=nil, username=nil, password=nil, port=3780)
|
9
9
|
raise 'Nexpose connection must be set in environment variables.' if url.nil? || username.nil? || password.nil?
|
10
|
-
nsc = Nexpose::Connection.new(url, username, password)
|
10
|
+
nsc = Nexpose::Connection.new(url, username, password, port)
|
11
11
|
nsc.login
|
12
|
+
Paloalto::NxLogger.instance.on_connect(url, port, nsc.session_id, "{}")
|
12
13
|
nsc
|
13
14
|
end
|
14
15
|
|
data/lib/paloalto/nx_logger.rb
CHANGED
@@ -1,27 +1,166 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'singleton'
|
5
|
+
|
1
6
|
module Paloalto
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
class NxLogger
|
8
|
+
include Singleton
|
9
|
+
LOG_PATH = "./logs/rapid7_%s.log"
|
10
|
+
KEY_FORMAT = "external.integration.%s"
|
11
|
+
PRODUCT_FORMAT = "%s_%s"
|
12
|
+
|
13
|
+
DEFAULT_LOG = 'integration'
|
14
|
+
PRODUCT_RANGE = 4..30
|
15
|
+
KEY_RANGE = 3..15
|
16
|
+
|
17
|
+
ENDPOINT = '/data/external/statistic/'
|
18
|
+
|
19
|
+
def initialize()
|
20
|
+
create_calls
|
21
|
+
@logger_file = get_log_path @product
|
22
|
+
setup_logging(true, 'info')
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup_statistics_collection(vendor, product_name, gem_version)
|
26
|
+
begin
|
27
|
+
@statistic_key = get_statistic_key vendor
|
28
|
+
@product = get_product product_name, gem_version
|
29
|
+
rescue => e
|
30
|
+
#Continue
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_logging(enabled, log_level = 'info', stdout=false)
|
35
|
+
@stdout = stdout
|
36
|
+
|
37
|
+
log_message('Logging disabled.') unless enabled || @log.nil?
|
38
|
+
@enabled = enabled
|
39
|
+
return unless @enabled
|
40
|
+
|
41
|
+
@logger_file = get_log_path @product
|
42
|
+
|
43
|
+
require 'logger'
|
44
|
+
directory = File.dirname(@logger_file)
|
45
|
+
FileUtils.mkdir_p(directory) unless File.directory?(directory)
|
46
|
+
io = IO.for_fd(IO.sysopen(@logger_file, 'a'), 'a')
|
47
|
+
io.autoclose = false
|
48
|
+
io.sync = true
|
49
|
+
@log = Logger.new(io, 'weekly')
|
50
|
+
@log.level = if log_level.to_s.casecmp('info') == 0
|
51
|
+
Logger::INFO
|
52
|
+
else
|
53
|
+
Logger::DEBUG
|
54
|
+
end
|
55
|
+
log_message("Logging enabled at level <#{log_level}>")
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_calls
|
59
|
+
levels = [:info, :debug, :error, :warn]
|
60
|
+
levels.each do |level|
|
61
|
+
method_name =
|
62
|
+
define_singleton_method("log_#{level.to_s}_message") do |message|
|
63
|
+
puts message if @stdout
|
64
|
+
@log.send(level, message) unless !@enabled || @log.nil?
|
65
|
+
end
|
19
66
|
end
|
20
67
|
end
|
21
68
|
|
22
|
-
# Logs a message
|
23
69
|
def log_message(message)
|
24
|
-
|
70
|
+
log_info_message message
|
71
|
+
end
|
72
|
+
|
73
|
+
def log_stat_message(message)
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_log_path(product)
|
77
|
+
product.downcase! unless product.nil?
|
78
|
+
File.join(File.dirname(__FILE__), LOG_PATH % (product || DEFAULT_LOG))
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_statistic_key(vendor)
|
82
|
+
if vendor.nil? || vendor.length < KEY_RANGE.min
|
83
|
+
log_stat_message("Vendor length is below minimum of <#{KEY_RANGE}>")
|
84
|
+
return nil
|
85
|
+
end
|
86
|
+
|
87
|
+
vendor.gsub!('-', '_')
|
88
|
+
vendor.slice! vendor.rindex('_') until vendor.count('_') <= 1
|
89
|
+
|
90
|
+
vendor.delete! "^A-Za-z0-9\_"
|
91
|
+
|
92
|
+
KEY_FORMAT % vendor[0...KEY_RANGE.max].downcase
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_product(product, version)
|
96
|
+
return nil if ((product.nil? || product.empty?) ||
|
97
|
+
(version.nil? || version.empty?))
|
98
|
+
|
99
|
+
product.gsub!('-', '_')
|
100
|
+
product.slice! product.rindex('_') until product.count('_') <= 1
|
101
|
+
|
102
|
+
product.delete! "^A-Za-z0-9\_"
|
103
|
+
version.delete! "^A-Za-z0-9\.\-"
|
104
|
+
|
105
|
+
product = (PRODUCT_FORMAT % [product, version])[0...PRODUCT_RANGE.max]
|
106
|
+
|
107
|
+
product.slice! product.rindex(/[A-Z0-9]/i)+1..-1
|
108
|
+
|
109
|
+
if product.length < PRODUCT_RANGE.min
|
110
|
+
log_stat_message("Product length below minimum <#{PRODUCT_RANGE.min}>.")
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
product.downcase
|
114
|
+
end
|
115
|
+
|
116
|
+
def generate_payload(statistic_value='')
|
117
|
+
product_name, separator, version = @product.to_s.rpartition('_')
|
118
|
+
payload_value = {'version' => version}.to_json
|
119
|
+
|
120
|
+
payload = {'statistic-key' => @statistic_key.to_s,
|
121
|
+
'statistic-value' => payload_value,
|
122
|
+
'product' => product_name}
|
123
|
+
JSON.generate(payload)
|
25
124
|
end
|
125
|
+
|
126
|
+
def send(nexpose_address, nexpose_port, session_id, payload)
|
127
|
+
header = {'Content-Type' => 'application/json',
|
128
|
+
'nexposeCCSessionID' => session_id,
|
129
|
+
'Cookie' => "nexposeCCSessionID=#{session_id}"}
|
130
|
+
req = Net::HTTP::Put.new(ENDPOINT, header)
|
131
|
+
req.body = payload
|
132
|
+
http_instance = Net::HTTP.new(nexpose_address, nexpose_port)
|
133
|
+
http_instance.use_ssl = true
|
134
|
+
http_instance.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
135
|
+
response = http_instance.start { |http| http.request(req) }
|
136
|
+
log_stat_message "Received code #{response.code} from Nexpose console."
|
137
|
+
log_stat_message "Received message #{response.msg} from Nexpose console."
|
138
|
+
log_stat_message 'Finished sending statistics data to Nexpose.'
|
139
|
+
|
140
|
+
response.code
|
141
|
+
end
|
142
|
+
|
143
|
+
def on_connect(nexpose_address, nexpose_port, session_id, value)
|
144
|
+
log_stat_message 'Sending statistics data to Nexpose'
|
145
|
+
|
146
|
+
if @product.nil? || @statistic_key.nil?
|
147
|
+
log_stat_message('Invalid product name and/or statistics key.')
|
148
|
+
log_stat_message('Statistics collection not enabled.')
|
149
|
+
return
|
150
|
+
end
|
151
|
+
|
152
|
+
begin
|
153
|
+
payload = generate_payload value
|
154
|
+
send(nexpose_address, nexpose_port, session_id, payload)
|
155
|
+
rescue => e
|
156
|
+
#Let the program continue
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
#Used by net library for debugging
|
161
|
+
def <<(value)
|
162
|
+
log_debug_message(value)
|
163
|
+
end
|
164
|
+
|
26
165
|
end
|
27
|
-
end
|
166
|
+
end
|
data/lib/paloalto/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexpose_paloalto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damian Finol
|
8
8
|
- JJ Cassidy
|
9
9
|
autorequire:
|
10
|
-
bindir:
|
10
|
+
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-05-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -45,14 +45,14 @@ dependencies:
|
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '3.2'
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '3.2'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: curb
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,8 +84,9 @@ dependencies:
|
|
84
84
|
description: This Gem allows usage of Nexpose Dynamic Asset groups with Palo Alto
|
85
85
|
TAGs.
|
86
86
|
email:
|
87
|
-
-
|
88
|
-
executables:
|
87
|
+
- support@rapid7.com
|
88
|
+
executables:
|
89
|
+
- nexpose_paloalto
|
89
90
|
extensions: []
|
90
91
|
extra_rdoc_files: []
|
91
92
|
files:
|
@@ -94,13 +95,12 @@ files:
|
|
94
95
|
- LICENSE.txt
|
95
96
|
- README.md
|
96
97
|
- Rakefile
|
97
|
-
-
|
98
|
+
- bin/nexpose_paloalto
|
98
99
|
- lib/paloalto.rb
|
99
100
|
- lib/paloalto/nexpose_helper.rb
|
100
101
|
- lib/paloalto/ngfw.rb
|
101
102
|
- lib/paloalto/nx_logger.rb
|
102
103
|
- lib/paloalto/version.rb
|
103
|
-
- nexpose_paloalto.gemspec
|
104
104
|
homepage: http://www.rapid7.com
|
105
105
|
licenses:
|
106
106
|
- MIT
|
@@ -121,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
121
|
version: '0'
|
122
122
|
requirements: []
|
123
123
|
rubyforge_project:
|
124
|
-
rubygems_version: 2.
|
124
|
+
rubygems_version: 2.5.1
|
125
125
|
signing_key:
|
126
126
|
specification_version: 4
|
127
127
|
summary: Nexpose Palo Alto Gem Integration
|
data/nexpose_paloalto.gemspec
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'paloalto/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "nexpose_paloalto"
|
8
|
-
spec.version = Paloalto::VERSION
|
9
|
-
spec.authors = ['Damian Finol', 'JJ Cassidy']
|
10
|
-
spec.email = ['integrations_support@rapid7.com']
|
11
|
-
|
12
|
-
spec.summary = 'Nexpose Palo Alto Gem Integration'
|
13
|
-
spec.description = 'This Gem allows usage of Nexpose Dynamic Asset groups with Palo Alto TAGs.'
|
14
|
-
spec.homepage = "http://www.rapid7.com"
|
15
|
-
spec.license = "MIT"
|
16
|
-
|
17
|
-
spec.files = Dir['[A-Z]*'] + Dir['lib/**/*'] + Dir['bin/**']
|
18
|
-
spec.bindir = "exe"
|
19
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
-
spec.require_paths = ["lib"]
|
21
|
-
|
22
|
-
spec.add_development_dependency "bundler", "~> 1.8"
|
23
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
-
spec.add_runtime_dependency 'nexpose', "~> 0.9"
|
25
|
-
spec.add_runtime_dependency 'curb', "~> 0.8.7"
|
26
|
-
spec.add_runtime_dependency 'nokogiri', "~> 1.6"
|
27
|
-
spec.required_ruby_version = '~> 2.0'
|
28
|
-
end
|