norad_cli 0.1.12 → 0.1.13

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: 1fdbc2f98f7a10dba2deb40bfc554540a1b9c630
4
- data.tar.gz: 9e9fb1b781796471420babc6bd263d3e4ce971f0
3
+ metadata.gz: ca54e887d7d704e64bbc278a2b4cc8afbbd0674c
4
+ data.tar.gz: 1201b3922139b899cc42785f6def1c58f9ea1f71
5
5
  SHA512:
6
- metadata.gz: b831f86443219c3fd5ca7f68d8dab0d8ecdb86cb960763406725fad24f34ea782f03efed5e3fcc94ef0f1d9c89e3e4cf3ccaef790770e464f76323949cd6ca4a
7
- data.tar.gz: 330c0fd1a7e51ebda7791087043c7ed4797a620b6e54cdd042d339c7a78ccd00ed4936dfcb081ae1daa19864685843a763220dc16468c305818adefc9cf3efab
6
+ metadata.gz: e28eaea3ca41e1e69c2021c1a770fa692b4f4d50b9343a021475fbb77855325e700023ba02328486bb7629b9c1c65759720475a7ede4f9fbaa78eb827b7a91a8
7
+ data.tar.gz: fc56350a7b03f7b7a037a8d3b692c6c2fb80e10020e793786f1f30d0389bf9effa228fdced9beba35b4932a924d000d24f76c50104527bacb70b305ab5f24748
data/.gitignore CHANGED
@@ -7,3 +7,6 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ # Editor files
12
+ *.swp
data/.rubocop.yml CHANGED
@@ -13,12 +13,14 @@ Metrics/LineLength:
13
13
  Metrics/MethodLength:
14
14
  Exclude:
15
15
  - 'lib/norad_cli/support/api_security_container_seed_script.rb'
16
+ - 'lib/norad_cli/support/sectest_container.rb'
16
17
  - 'lib/norad_cli/cli/sectest.rb'
17
18
  Metrics/AbcSize:
18
19
  Exclude:
19
20
  - 'lib/norad_cli/support/api_security_container_seed_script.rb'
20
21
  - 'lib/norad_cli/cli/sectest.rb'
21
22
  - 'lib/norad_cli/support/manifest_spec.rb'
23
+ - 'lib/norad_cli/support/sectest_container.rb'
22
24
  Metrics/BlockLength:
23
25
  Exclude:
24
26
  - 'spec/**/*'
data/README.md CHANGED
@@ -15,7 +15,7 @@ The above site contains all the necessary information to install Docker on a Mac
15
15
  This utility can be installed simply by:
16
16
 
17
17
  ```
18
- $ gem install norad
18
+ $ gem install norad_cli
19
19
  ```
20
20
 
21
21
  Once installed, a norad executable should be available.
@@ -101,14 +101,66 @@ The sectest subcommand is where general security test tool development occurs.
101
101
  ```
102
102
  $ norad help sectest
103
103
  Commands:
104
- norad sectest build SECTESTNAME # Builds the docker image for the security test SECTESTNAME
105
- norad sectest build:all SECTESTNAME # Builds all images for security test SECTESTNAME
106
- norad sectest build:specs SECTESTNAME # Builds the spec images for the security test SECTESTNAME
107
- norad sectest execute SECTESTNAME ARGUMENTS # Executes the specified security test SECTESTNAME w/ ARGUMENTS
108
- norad sectest help [COMMAND] # Describe subcommands or one specific subcommand
109
- norad sectest scaffold TESTNAME # Create a new security test with standard files + testing
110
- norad sectest seed # Create the containers.rb seed to import into the api
111
- norad sectest spec SECTESTNAME # Run the rspec tests for security tool SECTESTNAME
104
+ norad sectest build # Build all sectest images and specs for the entire repository
105
+ norad sectest build:all SECTESTNAME # Build sectest images for SECTESTNAME and all testing images for SECTESTNAME
106
+ norad sectest build:image SECTESTNAME # Build the docker image for the security test SECTESTNAME
107
+ norad sectest build:specs SECTESTNAME # Build the spec images (test images) for the security test SECTESTNAME
108
+ norad sectest execute SECTESTNAME # Execute SECTESTNAME against an arbitrary target
109
+ norad sectest help [COMMAND] # Describe subcommands or one specific subcommand
110
+ norad sectest scaffold TESTNAME # Create a new security test with standard files + testing
111
+ norad sectest seed # Create the containers.rb seed to import into the api
112
+ norad sectest spec # Run all rspec tests for the entire repo (all sectests)
113
+ norad sectest spec:image SECTESTNAME # Run the rspec tests for SECTESTNAME
114
+ norad sectest validate # Validate all manifest.yml and readme.md
115
+ norad sectest validate:image SECTESTNAME # Validate SECTESTNAME manifest.yml and readme.md
116
+ ```
117
+
118
+ ### Sectest Execute Command
119
+
120
+ The execute command enables users to run any SECTESTNAME container against an arbitrary target. To see the available options for the subcommand, run:
121
+
122
+ ```
123
+ $ norad sectest -h execute
124
+ Usage:
125
+ norad execute SECTESTNAME
126
+
127
+ Options:
128
+ -d, [--debug], [--no-debug] # Turn on debugging messages (e.g. Docker build logs to stdout)
129
+ -f, [--format], [--no-format] # Print the JSON results formatted
130
+ -r, [--registry=REGISTRY] # The Docker registry for Docker images
131
+ # Default: norad-registry.cisco.com:5000
132
+ -v, [--version=VERSION] # The version of the sectest container to build
133
+ # Default: latest
134
+
135
+ Execute SECTESTNAME against an arbitrary target
136
+ ```
137
+
138
+ Since the execute command runs arbitrary SECTESTNAME containers, it must support dynamically setting options for those containers. Therefore, the command supports gathering and printing help with any SECTESTNAME container. To get the help for a container run:
139
+
140
+ ```
141
+ $ norad sectest execute SECTESTNAME -h
142
+ ```
143
+
144
+ The execute subcommand reads the SECTESTNAME's manifest.yml to determine all available options. An example of this behavior is:
145
+
146
+ ```
147
+ $ norad sectest execute sec-ops-sudo -h
148
+ Usage:
149
+ norad execute sec-ops-sudo
150
+
151
+ Options:
152
+ -d, [--debug], [--no-debug] # Turn on debugging messages (e.g. Docker build logs to stdout)
153
+ -f, [--format], [--no-format] # Print the JSON results formatted
154
+ -r, [--registry=REGISTRY] # The Docker registry for Docker images
155
+ # Default: norad-registry.cisco.com:5000
156
+ -v, [--version=VERSION] # The version of the sectest container to build
157
+ # Default: latest
158
+ -t, [--target=TARGET] # The IP or FQDN of the host to test
159
+ -u, [--ssh-user=SSH_USER] # If the sectest requires authentication, then the username for authentication
160
+ -p, [--port=PORT] # The port to use for testing
161
+ -k, [--ssh-key=SSH_KEY] # If the sectest requires authentication, then the path to the ssh key file
162
+
163
+ Execute sec-ops-sudo against an arbitrary target
112
164
  ```
113
165
 
114
166
  ## Development
data/WALKTHROUGH.md CHANGED
@@ -44,18 +44,18 @@ Now, for this example, we will be creating a security test using the ping utilit
44
44
  ```
45
45
  $ norad help sectest
46
46
  Commands:
47
- norad sectest build # Build all sectest images and specs for the entire repository
48
- norad sectest build:all SECTESTNAME # Build sectest images for SECTESTNAME and all testing images for SECTESTNAME
49
- norad sectest build:image SECTESTNAME # Build the docker image for the security test SECTESTNAME
50
- norad sectest build:specs SECTESTNAME # Build the spec images (test images) for the security test SECTESTNAME
51
- norad sectest execute SECTESTNAME ARGUMENTS # Executes the specified security test SECTESTNAME w/ ARGUMENTS
52
- norad sectest help [COMMAND] # Describe subcommands or one specific subcommand
53
- norad sectest scaffold TESTNAME # Create a new security test with standard files + testing
54
- norad sectest seed # Create the containers.rb seed to import into the api
55
- norad sectest spec # Run all rspec tests for the entire repo (all sectests)
56
- norad sectest spec:image SECTESTNAME # Run the rspec tests for SECTESTNAME
57
- norad sectest validate # Validate all manifest.yml and readme.md
58
- norad sectest validate:image SECTESTNAME # Validate SECTESTNAME manifest.yml and readme.md
47
+ norad sectest build # Build all sectest images and specs for the entire repository
48
+ norad sectest build:all SECTESTNAME # Build sectest images for SECTESTNAME and all testing images for SECTESTNAME
49
+ norad sectest build:image SECTESTNAME # Build the docker image for the security test SECTESTNAME
50
+ norad sectest build:specs SECTESTNAME # Build the spec images (test images) for the security test SECTESTNAME
51
+ norad sectest execute SECTESTNAME # Execute SECTESTNAME against an arbitrary target
52
+ norad sectest help [COMMAND] # Describe subcommands or one specific subcommand
53
+ norad sectest scaffold TESTNAME # Create a new security test with standard files + testing
54
+ norad sectest seed # Create the containers.rb seed to import into the api
55
+ norad sectest spec # Run all rspec tests for the entire repo (all sectests)
56
+ norad sectest spec:image SECTESTNAME # Run the rspec tests for SECTESTNAME
57
+ norad sectest validate # Validate all manifest.yml and readme.md
58
+ norad sectest validate:image SECTESTNAME # Validate SECTESTNAME manifest.yml and readme.md
59
59
  ```
60
60
 
61
61
  To start off, we use the scaffold command to create all of the required files to create a security test. The scaffold subcommand includes several options:
@@ -3,28 +3,74 @@ require 'thor'
3
3
  require 'git'
4
4
  require 'docker'
5
5
  require 'norad_cli/support/api_security_container_seed_script'
6
+ require 'norad_cli/support/sectest_container'
6
7
  require 'rspec'
8
+ require 'json'
9
+ require 'rainbow'
7
10
 
8
11
  class Sectest < Thor
9
12
  include Thor::Actions
10
13
 
14
+ @reserved_sectest_args = { target: ['-t', 'The IP or FQDN of the host to test'],
15
+ ssh_user: ['-u', 'If the sectest requires authentication, then the username for authentication'],
16
+ ssh_key: ['-k', 'If the sectest requires authentication, then the path to the ssh key file'],
17
+ port: ['-p', 'The port to use for testing'],
18
+ service_username: ['-e', 'FILL ME IN'],
19
+ service_password: ['-r', 'FILL ME IN'],
20
+ web_service_protocolweb_service_url_blacklist: ['-b', 'FILL ME IN'],
21
+ web_service_auth_type: ['-a', 'FILL ME IN'],
22
+ web_service_starting_page_path: ['-g', 'FILL ME IN'],
23
+ web_service_login_form_username_field_name: ['-l', 'FILL ME IN'],
24
+ web_service_login_form_password_field_name: ['-m', 'FILL ME IN'] }
25
+
11
26
  def self.source_root
12
27
  File.join(File.dirname(File.expand_path(__FILE__)), '../templates/')
13
28
  end
14
29
 
30
+ # Loads a manifest file depending on the command
31
+ # rubocop:disable Style/GuardClause
32
+ def self.load_manifest
33
+ @sectest_manifest = {}
34
+
35
+ # Set defaults just in case no manifest.yml to overwrite
36
+ @sectest_manifest['registry'] = 'norad-registry.cisco.com:5000'
37
+ @sectest_manifest['version'] = 'latest'
38
+
39
+ # Dynamically add options and description based on the needs of the sectest container
40
+ if %w(build build:all build:image build:specs execute).include?(ARGV[1]) && ARGV[2] && !ARGV[2].start_with?('-', '--')
41
+ # Read in the program arguments
42
+ if File.exist?("sectests/#{ARGV[2]}/manifest.yml")
43
+ @sectest_manifest = YAML.safe_load(File.read("sectests/#{ARGV[2]}/manifest.yml"))
44
+ else
45
+ puts Rainbow("Error: #{ARGV[2]} sectest does not exist or it is missing sectests/#{ARGV[2]}/manifest.yml").red
46
+ puts Rainbow('Exiting...').red
47
+ exit(1)
48
+ end
49
+ end
50
+ end
51
+ # rubocop:enable Style/GuardClause
52
+
53
+ def initialize(*args)
54
+ super
55
+
56
+ # Check if the command is being run from the repository root (all commands must be)
57
+ root_dir?
58
+ end
59
+
60
+ # Load the manifest file if necessary
61
+ # Correct set default registry and version
62
+ load_manifest
63
+
15
64
  desc 'scaffold TESTNAME', 'Create a new security test with standard files + testing'
16
65
  option :test_type, aliases: '-t', default: 'whole_host', desc: 'The security test type, Options: [authenticated|web_application|brute_force|ssl_crypto|ssh_crypto|whole_host]'
17
- option :registry, aliases: '-r', default: 'norad-registry.cisco.com:5000', desc: 'The Docker registry to store docker images'
18
- option :version, aliases: '-v', default: 'latest', desc: 'The version of the security test'
66
+ option :registry, aliases: '-r', default: @sectest_manifest['registry'], desc: 'The Docker registry to store docker images'
67
+ option :version, aliases: '-v', default: @sectest_manifest['version'], desc: 'The version of the security test'
19
68
  option :base_image, aliases: '-b', default: 'norad-registry.cisco.com:5000/norad:0.0.1', desc: 'Base Docker image to use (i.e. FROM field in the Dockerfile)'
20
69
  option :configurable, type: :boolean, aliases: '-c', desc: 'Is the security test configurable (e.g. Qualys username and password)'
21
70
  def scaffold(sectest_name)
22
71
  # Grab the current directory
23
72
  repo_dir = Dir.pwd
24
73
 
25
- # Check for the root_dir
26
- root_dir?
27
-
28
74
  # Check for valid test types
29
75
  if !%w(authenticated web_application brute_force ssl_crypto ssh_crypto whole_host).include?(options[:test_type])
30
76
  say("#{options[:test_type]} is not a supported test type", :red)
@@ -58,12 +104,10 @@ class Sectest < Thor
58
104
  end
59
105
 
60
106
  desc 'build', 'Build all sectest images and specs for the entire repository'
61
- option :registry, aliases: '-r', default: 'norad-registry.cisco.com:5000', desc: 'The Docker registry for Docker images'
62
- option :version, aliases: '-v', default: 'latest', desc: 'The version of the sectest container to build'
107
+ option :debug, aliases: '-d', type: :boolean, default: true, desc: 'Turn on debugging messages (e.g. Docker build logs to stdout)'
108
+ option :registry, aliases: '-r', default: @sectest_manifest['registry'], desc: 'The Docker registry for Docker images'
109
+ option :version, aliases: '-v', default: @sectest_manifest['version'], desc: 'The version of the sectest container to build'
63
110
  def build
64
- # Check for the root_dir
65
- root_dir?
66
-
67
111
  # Error check to ensure this is a plugin directory
68
112
  Dir.glob('sectests/*').select do |f|
69
113
  if File.directory? f
@@ -75,12 +119,10 @@ class Sectest < Thor
75
119
 
76
120
  # Define arguments and options
77
121
  desc 'build:image SECTESTNAME', 'Build the docker image for the security test SECTESTNAME'
78
- option :registry, aliases: '-r', default: 'norad-registry.cisco.com:5000', desc: 'The Docker registry for Docker images'
79
- option :version, aliases: '-v', default: 'latest', desc: 'The version of the sectest container to build'
122
+ option :debug, aliases: '-d', type: :boolean, default: true, desc: 'Turn on debugging messages (e.g. Docker build logs to stdout)'
123
+ option :registry, aliases: '-r', default: @sectest_manifest['registry'], desc: 'The Docker registry for Docker images'
124
+ option :version, aliases: '-v', default: @sectest_manifest['version'], desc: 'The version of the sectest container to build'
80
125
  define_method 'build:image' do |name|
81
- # Check for the root_dir
82
- root_dir?
83
-
84
126
  imgs_to_build = {}
85
127
  imgs_to_build["sectests/#{name}"] = "#{options[:registry]}/#{name}:#{options[:version]}"
86
128
 
@@ -102,19 +144,17 @@ class Sectest < Thor
102
144
  imgs_to_build.keys.reverse_each do |img_dir|
103
145
  say("Building image #{img_dir}...", :green)
104
146
  Docker::Image.build_from_dir(img_dir, t: imgs_to_build[img_dir]) do |v|
105
- $stdout.puts v
147
+ $stdout.puts v if options[:debug]
106
148
  end
107
149
  end
108
150
  end
109
151
 
110
152
  # Define arguments and options
111
153
  desc 'build:specs SECTESTNAME', 'Build the spec images (test images) for the security test SECTESTNAME'
112
- option :registry, aliases: '-r', default: 'norad-registry.cisco.com:5000', desc: 'The Docker registry for Docker images'
113
- option :version, aliases: '-v', default: 'latest', desc: 'The version of the sectest container to build'
154
+ option :debug, aliases: '-d', type: :boolean, default: true, desc: 'Turn on debugging messages (e.g. Docker build logs to stdout)'
155
+ option :registry, aliases: '-r', default: @sectest_manifest['registry'], desc: 'The Docker registry for Docker images'
156
+ option :version, aliases: '-v', default: @sectest_manifest['version'], desc: 'The version of the sectest container to build'
114
157
  define_method 'build:specs' do |name|
115
- # Check for the root_dir
116
- root_dir?
117
-
118
158
  imgs_to_build = {}
119
159
  imgs_to_build["#{File.expand_path(File.dirname(__FILE__))}/../templates/spec/support/Dockerfile.testserver"] = 'docker-images-test-results-server:latest'
120
160
  imgs_to_build["#{File.expand_path(File.dirname(__FILE__))}/../templates/spec/support/Dockerfile.ubuntu_ssh"] = 'docker-images-test-ubuntu-ssh-server:latest'
@@ -131,7 +171,7 @@ class Sectest < Thor
131
171
  say("Building image #{img_dir}...", :green)
132
172
  docker_file = img_dir.split('/')[-1]
133
173
  Docker::Image.build_from_dir(img_dir.gsub(docker_file, ''), dockerfile: docker_file, t: imgs_to_build[img_dir]) do |v|
134
- $stdout.puts v
174
+ $stdout.puts v if options[:debug]
135
175
  end
136
176
  end
137
177
 
@@ -141,12 +181,10 @@ class Sectest < Thor
141
181
 
142
182
  # Define arguments and options
143
183
  desc 'build:all SECTESTNAME', 'Build sectest images for SECTESTNAME and all testing images for SECTESTNAME'
144
- option :registry, aliases: '-r', default: 'norad-registry.cisco.com:5000', desc: 'The Docker registry for Docker images'
145
- option :version, aliases: '-v', default: 'latest', desc: 'The version of the sectest container to build'
184
+ option :debug, aliases: '-d', type: :boolean, default: true, desc: 'Turn on debugging messages (e.g. Docker build logs to stdout)'
185
+ option :registry, aliases: '-r', default: @sectest_manifest['registry'], desc: 'The Docker registry for Docker images'
186
+ option :version, aliases: '-v', default: @sectest_manifest['version'], desc: 'The version of the sectest container to build'
146
187
  define_method 'build:all' do |name|
147
- # Check for the root_dir
148
- root_dir?
149
-
150
188
  # Build the sectest image
151
189
  send('build:image', name)
152
190
 
@@ -154,13 +192,56 @@ class Sectest < Thor
154
192
  send('build:specs', name)
155
193
  end
156
194
 
195
+ # Dynamically add options and description based on the needs of the sectest container
196
+ if ARGV[1] == 'execute' && ARGV[2] && !ARGV[2].start_with?('-', '--')
197
+ desc "execute #{ARGV[2]}", "Execute #{ARGV[2]} against an arbitrary target"
198
+
199
+ # Dynamically create options
200
+ @sectest_manifest['prog_args'].scan(/{(.*?)}/).each do |ar|
201
+ if @reserved_sectest_args.key?(ar[0].to_sym)
202
+ option ar[0].to_sym, aliases: @reserved_sectest_args[ar[0].to_sym][0], desc: @reserved_sectest_args[ar[0].to_sym][1]
203
+ else
204
+ option ar[0].to_sym
205
+ end
206
+ end
207
+ else
208
+ desc 'execute SECTESTNAME', 'Execute SECTESTNAME against an arbitrary target'
209
+ end
210
+ option :debug, aliases: '-d', type: :boolean, default: false, desc: 'Turn on debugging messages (e.g. Docker build logs to stdout)'
211
+ option :format, aliases: '-f', type: :boolean, default: false, desc: 'Print the JSON results formatted'
212
+ option :registry, aliases: '-r', default: @sectest_manifest['registry'], desc: 'The Docker registry for Docker images'
213
+ option :version, aliases: '-v', default: @sectest_manifest['version'], desc: 'The version of the sectest container to build'
214
+ def execute(sectest_name)
215
+ # Ensure the results server is built by building the images specs (code reuse)
216
+ send('build:specs', sectest_name)
217
+
218
+ # Build the sectest image if necessary
219
+ send('build:image', sectest_name)
220
+
221
+ # Allocate an instance of the sectest
222
+ sectest_instance = NoradCli::SecTestContainer.new(ARGV[2], options)
223
+
224
+ # Start the test
225
+ sectest_instance.start
226
+
227
+ # Print any debugging
228
+ sectest_instance.output(options[:target]) if options[:debug]
229
+
230
+ # Get the results
231
+ results = sectest_instance.results
232
+
233
+ say('Results are:', :green)
234
+ formatted_results = options[:format] ? JSON.pretty_generate(JSON.parse(results)) : results
235
+ puts formatted_results
236
+
237
+ # Cleanup the sectest container
238
+ sectest_instance.shutdown
239
+ end
240
+
157
241
  desc 'spec:image SECTESTNAME', 'Run the rspec tests for SECTESTNAME'
158
242
  option :verbose, aliases: '-v', type: :boolean, desc: 'Turn on verbose logging'
159
243
  option :debug, aliases: '-d', type: :boolean, desc: 'Turn on debugging'
160
244
  define_method 'spec:image' do |name|
161
- # Check for the root_dir
162
- root_dir?
163
-
164
245
  # Set environment variables
165
246
  if options[:verbose]
166
247
  ENV['ENABLE_LOGS'] = 'true'
@@ -189,9 +270,6 @@ class Sectest < Thor
189
270
  option :verbose, aliases: '-v', type: :boolean, default: false, desc: 'Turn on verbose logging'
190
271
  option :debug, aliases: '-d', type: :boolean, desc: 'Turn on debugging'
191
272
  def spec
192
- # Check for the root_dir
193
- root_dir?
194
-
195
273
  # Error check to ensure this is a plugin directory
196
274
  Dir.glob('sectests/*').select do |f|
197
275
  if File.directory? f
@@ -205,18 +283,12 @@ class Sectest < Thor
205
283
  option :seedfile, aliases: '-s', type: :string, default: './containers.rb', desc: 'The name of the seed file to generate'
206
284
  option :docsite, aliases: '-d', type: :string, default: 'https://norad.gitlab.io/docs/', desc: 'Set the documentation site'
207
285
  def seed
208
- # Check for the root_dir
209
- root_dir?
210
-
211
286
  # Generate the seed file
212
287
  SeedGenerator.process_manifests(options[:seedfile], options[:docsite])
213
288
  end
214
289
 
215
290
  desc 'validate:image SECTESTNAME', 'Validate SECTESTNAME manifest.yml and readme.md'
216
291
  define_method 'validate:image' do |name|
217
- # Check for the root_dir
218
- root_dir?
219
-
220
292
  # Validate the readme file
221
293
  ENV['sectest_name'] = name
222
294
  RSpec.clear_examples
@@ -229,13 +301,10 @@ class Sectest < Thor
229
301
 
230
302
  desc 'validate', 'Validate all manifest.yml and readme.md'
231
303
  def validate
232
- # Check for the root_dir
233
- root_dir?
234
-
235
304
  # Error check to ensure this is a plugin directory
236
305
  Dir.glob('sectests/*').select do |f|
237
306
  if File.directory? f
238
- # Build all for the sectest
307
+ # Validate manifest and readme for the sectest
239
308
  send('validate:image', f.split('/')[-1])
240
309
  end
241
310
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module NoradCli
3
+ class ResultsServer
4
+ attr_accessor :container
5
+
6
+ def initialize(test_results_server_image)
7
+ @container = Docker::Container.create(
8
+ Image: test_results_server_image,
9
+ HostConfig: { PublishAllPorts: true }
10
+ )
11
+ end
12
+
13
+ def start
14
+ @container.start
15
+ sleep 5 # sleep rather than wait since we are daemonizing a containe
16
+ refresh
17
+ end
18
+
19
+ def refresh
20
+ @container.refresh! # get more details
21
+ end
22
+
23
+ def shutdown
24
+ @container.stop
25
+ @container.delete(force: true)
26
+ end
27
+
28
+ def host_port
29
+ @container.info['NetworkSettings']['Ports']['3000/tcp'].first['HostPort']
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+ require 'norad_cli/support/results_server.rb'
3
+ require 'net/http'
4
+ require 'securerandom'
5
+ require 'rainbow'
6
+
7
+ module NoradCli
8
+ class SecTestContainer
9
+ attr_accessor :container
10
+ attr_accessor :assessment_id
11
+ attr_accessor :sectest_image
12
+ attr_accessor :results_server
13
+
14
+ def initialize(sectest_name, options)
15
+ # Generate a random assessment id
16
+ @assessment_id = SecureRandom.hex(32)
17
+
18
+ @sectest_image = "#{options['registry']}/#{sectest_name}:#{options[:version]}"
19
+
20
+ # Create a results server
21
+ @results_server = NoradCli::ResultsServer.new('docker-images-test-results-server')
22
+
23
+ ENV['ENABLE_LOGS'] = 'true'
24
+ env = [
25
+ 'NORAD_ROOT=http://results:3000',
26
+ %(ASSESSMENT_PATHS=[{"id":"singletest", "assessment": "/results/#{@assessment_id}"}]),
27
+ 'NORAD_SECRET=1234'
28
+ ]
29
+
30
+ # Create the container
31
+ @container = Docker::Container.create(Image: @sectest_image,
32
+ Cmd: prog_args(sectest_name, options),
33
+ Env: env,
34
+ HostConfig: { Links: ["#{@results_server.container.id}:results"] })
35
+ end
36
+
37
+ # Format the prog_args appropriately for the container
38
+ def prog_args(sectest_name, options)
39
+ # Grab the program arguments (minus other function options)
40
+ # Options is a Thor::CoreExt::HashWithIndifferentAccess (except does not work)
41
+ prog_arg_hash = options.each_with_object({}) do |(k, v), hsh|
42
+ hsh[k.to_sym] = v unless k == 'debug' || k == 'registry' || k == 'version'
43
+ end
44
+
45
+ # Load the prog_arg format
46
+ sectest_options ||= YAML.safe_load(File.read("sectests/#{sectest_name}/manifest.yml"))
47
+
48
+ # Load an ssh key if necess
49
+ prog_arg_hash[:ssh_key] = load_ssh_key(prog_arg_hash[:ssh_key]) if prog_arg_hash.key?(:ssh_key)
50
+
51
+ # Fill out the prog_args and return
52
+ begin
53
+ format(sectest_options['prog_args'], prog_arg_hash).split(' ')
54
+ rescue KeyError
55
+ puts Rainbow('Error: The containers required arguments were not set.').red
56
+ puts Rainbow("Arguments in %{} should be set: #{sectest_options['prog_args']}").red
57
+ puts Rainbow("Arguments given: #{prog_arg_hash}").red
58
+ puts Rainbow("Run 'norad sectest execute #{sectest_name} -h' to see how to set arguments!").red
59
+ puts Rainbow('Exiting...').red
60
+ exit(1)
61
+ end
62
+ end
63
+
64
+ def start
65
+ # Start the results server container
66
+ @results_server.start
67
+
68
+ # Start the sectest container
69
+ @container.start
70
+ @container.wait(60 * 10)
71
+ end
72
+
73
+ def output(target)
74
+ # Output container logs for debugging
75
+ @container.stop
76
+ c_state = @container.json['State']
77
+
78
+ # Print the entire state regardless of error or not to aid in debugging
79
+ puts Rainbow("[DEBUG] Container #{@sectest_image}'s Final State").green
80
+ puts Rainbow('-------------------------').green
81
+ c_state.each do |key, value|
82
+ puts Rainbow("#{key}: #{value}").green
83
+ end
84
+
85
+ puts Rainbow("\n[DEBUG] Logs for target #{@sectest_image} run against #{target}:").green
86
+
87
+ # Print logs regardless of ExitCode
88
+ puts Rainbow(@container.logs(stdout: true, stderr: true)).green
89
+ end
90
+
91
+ def results
92
+ # Get the results
93
+ url = "http://localhost:#{@results_server.host_port}/results?assessment_id=#{@assessment_id}"
94
+ uri = URI.parse(url)
95
+ http = Net::HTTP.new(uri.host, uri.port)
96
+ request = Net::HTTP::Get.new(uri)
97
+ response = http.request(request)
98
+ if response.code == '200'
99
+ response.body
100
+ else
101
+ puts Rainbow('Error retrieving results\nExiting...').red
102
+ shutdown
103
+ exit(1)
104
+ end
105
+ end
106
+
107
+ def shutdown
108
+ # Stop the sectest image container and delete
109
+ @container.stop
110
+ @container.delete(force: true)
111
+
112
+ # Cleanup/Garbage collect the results server
113
+ @results_server.shutdown
114
+ end
115
+
116
+ private
117
+
118
+ # Replace ssh key file with encoded ssh key
119
+ def load_ssh_key(ssh_key_file)
120
+ if File.exist?(ssh_key_file)
121
+ Base64.strict_encode64(File.read(ssh_key_file))
122
+ else
123
+ puts Rainbow("Error: SSH Key file: #{ssh_key_file} does not exist!\nExiting..\n").red
124
+ exit(1)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module NoradCli
3
- VERSION = '0.1.12'
3
+ VERSION = '0.1.13'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: norad_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Hitchcock
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-03-16 00:00:00.000000000 Z
13
+ date: 2017-03-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: git
@@ -197,6 +197,8 @@ files:
197
197
  - lib/norad_cli/support/api_security_container_seed_script.rb
198
198
  - lib/norad_cli/support/manifest_spec.rb
199
199
  - lib/norad_cli/support/readme_spec.rb
200
+ - lib/norad_cli/support/results_server.rb
201
+ - lib/norad_cli/support/sectest_container.rb
200
202
  - lib/norad_cli/templates/.gitignore
201
203
  - lib/norad_cli/templates/.rspec
202
204
  - lib/norad_cli/templates/CONTRIBUTING.md
@@ -275,7 +277,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
275
277
  version: '0'
276
278
  requirements: []
277
279
  rubyforge_project:
278
- rubygems_version: 2.6.10
280
+ rubygems_version: 2.6.11
279
281
  signing_key:
280
282
  specification_version: 4
281
283
  summary: Command line interface for norad.