Skip to content
This repository has been archived by the owner on Nov 14, 2024. It is now read-only.

Merge pull request #50 from modular-magician/codegen-pr-1103 #52

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e1058cd
Add connection switching to gcp_backend
slevenick Nov 15, 2018
21d5ebb
Only use compute readonly scope
slevenick Nov 15, 2018
40ca0a0
More descriptive flag
slevenick Nov 16, 2018
81dd7ee
PR feedback
slevenick Nov 19, 2018
62d8831
Merge branch 'alternate-train' of github.com:modular-magician/inspec-…
slevenick Nov 19, 2018
ca8907e
Merge pull request #30 from modular-magician/alternate-train
slevenick Nov 19, 2018
044fbb4
Inherit from base GcpResource, SSL policy generation
slevenick Nov 20, 2018
53ef169
Merge pull request #33 from modular-magician/codegen-pr-930
slevenick Nov 26, 2018
fb44adf
Inspec example refactor
slevenick Nov 28, 2018
2461a51
Rubocop fixes
slevenick Nov 28, 2018
120dfe2
Merge pull request #35 from slevenick/backend-rubocop
slevenick Nov 28, 2018
320fef4
Merge pull request #34 from modular-magician/codegen-pr-949
slevenick Nov 28, 2018
0c2f87a
Adding rubocop for generated inspec files
slevenick Nov 28, 2018
c85c587
Merge pull request #36 from modular-magician/codegen-pr-956
slevenick Nov 28, 2018
70e629b
Plural doc generation
slevenick Nov 30, 2018
f7e7b04
Merge pull request #37 from modular-magician/codegen-pr-967
slevenick Nov 30, 2018
6783c5f
Remove extra licenses
slevenick Dec 1, 2018
103b87d
Merge pull request #38 from modular-magician/codegen-pr-977
slevenick Dec 1, 2018
52e0eb2
Move vcr config, require relative to load from inspec profile
slevenick Dec 3, 2018
558c2c7
Add Magic Modules resource test script to Rakefile. Add generated fil…
slevenick Dec 3, 2018
50f6768
PR feedback
slevenick Dec 3, 2018
8430681
Merge pull request #40 from modular-magician/mm-test-rake-tasks
slevenick Dec 3, 2018
b21e62f
Merge pull request #39 from modular-magician/codegen-pr-983
slevenick Dec 3, 2018
dafc2d5
Delete duplicated vcr config
slevenick Dec 4, 2018
7c21d35
Merge pull request #41 from modular-magician/delete-duplicate-config
slevenick Dec 4, 2018
1bcd66a
Add support for application default credentials if GOOGLE_APPLICATION…
slevenick Dec 4, 2018
db742d9
Updating scopes, add parsing and merging of mm generated vars
slevenick Dec 7, 2018
4c994c6
Fix path to mm attributes
slevenick Dec 7, 2018
226ebe2
Delete old folders
slevenick Dec 7, 2018
1434494
Revert ::
slevenick Dec 8, 2018
35930e6
Merge pull request #43 from modular-magician/single-terraform-command
slevenick Dec 8, 2018
0a137d3
Refactor rakefile
slevenick Dec 8, 2018
d6c69c7
Ruby scope :: for Google auth
slevenick Dec 9, 2018
e063c6e
Test commit
slevenick Dec 9, 2018
7e03fba
Merge pull request #45 from modular-magician/codegen-pr-1015
slevenick Dec 10, 2018
b4208eb
Changing file extension
slevenick Dec 11, 2018
8af7edc
Remove VCR from InSpec
slevenick Dec 11, 2018
10fa4f2
Merge pull request #46 from modular-magician/codegen-pr-1029
slevenick Dec 11, 2018
11542aa
Inspec attribute changes
slevenick Dec 12, 2018
7d7c385
Remove old MM files
slevenick Dec 12, 2018
3ec6dc7
Merge pull request #47 from modular-magician/codegen-pr-1031
slevenick Dec 12, 2018
8d6ab2f
Remove verify-mm from rakefile
slevenick Dec 13, 2018
8bf26da
Move inspec controls from verify-mm dir to verify
slevenick Dec 13, 2018
84c0fb5
Merge pull request #49 from modular-magician/codegen-pr-1052
slevenick Dec 13, 2018
c74f6b4
Remove extra folder in test
slevenick Dec 13, 2018
590b560
Remove old service account from inspec integration test tf file
slevenick Dec 26, 2018
e056f19
Merge pull request #50 from modular-magician/codegen-pr-1103
slevenick Dec 26, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ local
*.idea*
*.env
*inspec-gcp.tfvars
*gcp-inspec-attributes.yaml
*gcp-inspec-attributes.yaml
inspec-cassettes
*terraform.tfvars
*inspec.json
18 changes: 8 additions & 10 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
source 'https://rubygems.org'

gem 'inifile'
gem 'bundle'
gem 'google-api-client'
gem 'googleauth'
gem 'google-cloud'
gem 'bundle'
gem 'googleauth'
gem 'inifile'
gem 'inspec', '~> 3.0', '>= 3.0.25'
gem 'rubocop'

group :development do
gem 'rake'
gem 'rubocop'
gem 'github_changelog_generator'
gem 'pry-coolline'
gem 'passgen'
end

group :inspec do
gem 'inspec', '~> 3.0', '>= 3.0.25'
gem 'pry-coolline'
gem 'rake'
gem 'webmock'
end
12 changes: 8 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ namespace :test do
sh(cmd)
end

task :generate_integration_test_variables do
puts "----> Generating terraform and inspec variable files"
#p GCPInspecConfig.config[:gcp_project_id]
GCPInspecConfig.store_json(variable_file_name)
GCPInspecConfig.store_yaml(profile_attributes)
end

task :plan_integration_tests do

# Determine the storage account name and the admin password
Expand All @@ -56,10 +63,7 @@ namespace :test do
# Use the first 4 characters of the storage account to create a suffix
# suffix = sa_name[0..3]

puts "----> Generating terraform and inspec variable files"
#p GCPInspecConfig.config[:gcp_project_id]
GCPInspecConfig.store_json(variable_file_name)
GCPInspecConfig.store_yaml(profile_attributes)
Rake::Task["test:generate_integration_test_variables"].execute

puts "----> Setup"
# Create the plan that can be applied to GCP
Expand Down
43 changes: 43 additions & 0 deletions docs/resources/google_compute_ssl_policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: About the SslPolicy resource
platform: gcp
---


## Syntax
A `google_compute_ssl_policies` is used to test a Google SslPolicy resource

## Examples
```
describe google_compute_ssl_policies({project: ''}) do
it { should exist }
its('names') { should include 'inspec-gcp-ssl-policy' }
its('profiles') { should include 'CUSTOM' }
its('count') { should eq 1 }
end

google_compute_ssl_policies({project: ''}).names.each do |policy_name|
describe google_compute_ssl_policy({project: '', name: policy_name}) do
its('min_tls_version') { should cmp 'TLS_1_2' }
end
end
```

## Properties
Properties that can be accessed from the `google_compute_ssl_policies` resource:

See [google_compute_ssl_policy.md](google_compute_ssl_policy.md) for more detailed information
* `creation_timestamps`: an array of `google_compute_ssl_policy` creation_timestamp
* `descriptions`: an array of `google_compute_ssl_policy` description
* `ids`: an array of `google_compute_ssl_policy` id
* `names`: an array of `google_compute_ssl_policy` name
* `profiles`: an array of `google_compute_ssl_policy` profile
* `min_tls_versions`: an array of `google_compute_ssl_policy` min_tls_version
* `enabled_features`: an array of `google_compute_ssl_policy` enabled_features
* `custom_features`: an array of `google_compute_ssl_policy` custom_features
* `fingerprints`: an array of `google_compute_ssl_policy` fingerprint
* `warnings`: an array of `google_compute_ssl_policy` warnings

## Filter Criteria
This resource supports all of the above properties as filter criteria, which can be used
with `where` as a block or a method.
46 changes: 46 additions & 0 deletions docs/resources/google_compute_ssl_policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: About the SslPolicy resource
platform: gcp
---


## Syntax
A `google_compute_ssl_policy` is used to test a Google SslPolicy resource

## Examples
```
describe google_compute_ssl_policy({project: '', name: 'inspec-gcp-ssl-policy'}) do
it { should exist }
its('min_tls_version') { should cmp 'TLS_1_2' }
its('profile') { should cmp 'CUSTOM' }
its('custom_features') { should include 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' }
its('custom_features') { should include 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' }
end
```

## Properties
Properties that can be accessed from the `google_compute_ssl_policy` resource:

* `creation_timestamp`: Creation timestamp in RFC3339 text format.

* `description`: An optional description of this resource.

* `id`: The unique identifier for the resource.

* `name`: Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.

* `profile`: Profile specifies the set of SSL features that can be used by the load balancer when negotiating SSL with clients. This can be one of `COMPATIBLE`, `MODERN`, `RESTRICTED`, or `CUSTOM`. If using `CUSTOM`, the set of SSL features to enable must be specified in the `customFeatures` field.

* `min_tls_version`: The minimum version of SSL protocol that can be used by the clients to establish a connection with the load balancer. This can be one of `TLS_1_0`, `TLS_1_1`, `TLS_1_2`.

* `enabled_features`: The list of features enabled in the SSL policy.

* `custom_features`: A list of features enabled when the selected profile is CUSTOM. The method returns the set of features that can be specified in this list. This field must be empty if the profile is not CUSTOM.

* `fingerprint`: Fingerprint of this resource. A hash of the contents stored in this object. This field is used in optimistic locking.

* `warnings`: If potential misconfigurations are detected for this SSL policy, this field will be populated with warning messages.

* `code`: A warning code, if applicable.

* `message`: A human-readable description of the warning code.
213 changes: 213 additions & 0 deletions libraries/gcp_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#

require 'json'
require 'net/http'
require 'googleauth'

# Base class for GCP resources - depends on train GCP transport for connection
#
Expand All @@ -17,6 +19,10 @@ def initialize(opts)
@opts = opts
# ensure we have a GCP connection, resources can choose which of the clients to instantiate
@gcp = inspec.backend

# Magic Modules generated resources use an alternate transport method
# In the future this will be moved into the train-gcp plugin itself
@connection = GcpApiConnection.new if opts[:use_http_transport]
end

def failed_resource?
Expand Down Expand Up @@ -178,3 +184,210 @@ def camel_case(data)
camel_case_data.gsub(/[gb]/, &:upcase)
end
end

class GcpApiConnection
def initialize
@service_account_file = ENV['GOOGLE_APPLICATION_CREDENTIALS']
end

def fetch_auth
unless @service_account_file.nil?
return Network::Authorization.new.for!(
['https://www.googleapis.com/auth/compute.readonly'],
).from_service_account_json!(
@service_account_file,
)
end
Network::Authorization.new.from_application_default!
end

def fetch(base_url, template, var_data)
get_request = Network::Base.new(
build_uri(base_url, template, var_data),
fetch_auth,
)
return_if_object get_request.send
end

def fetch_all(base_url, template, var_data)
next_page(build_uri(base_url, template, var_data))
end

def next_page(uri, token = nil)
next_hash = {}
next_hash['pageToken'] = token unless token.nil?
current_params = Hash[URI.decode_www_form(uri.query || '')].merge(next_hash)
uri.query = URI.encode_www_form(current_params)
get_request = Network::Base.new(
uri,
fetch_auth,
)
result = JSON.parse(get_request.send.body)
next_page_token = result['nextPageToken']
return [result] if next_page_token.nil?

[result] + next_page(uri, next_page_token)
end

def return_if_object(response)
raise "Bad response: #{response.body}" \
if response.is_a?(Net::HTTPBadRequest)
raise "Bad response: #{response}" \
unless response.is_a?(Net::HTTPResponse)
return if response.is_a?(Net::HTTPNotFound)
return if response.is_a?(Net::HTTPNoContent)
result = JSON.parse(response.body)
raise_if_errors result, %w{error errors}, 'message'
raise "Bad response: #{response}" unless response.is_a?(Net::HTTPOK)
result
end

def raise_if_errors(response, err_path, msg_field)
errors = self.class.navigate(response, err_path)
raise_error(errors, msg_field) unless errors.nil?
end

def raise_error(errors, msg_field)
raise IOError, ['Operation failed:',
errors.map { |e| e[msg_field] }.join(', ')].join(' ')
end

def build_uri(base_url, template, var_data)
URI.join(
base_url,
expand_variables(template, var_data),
)
end

# Allows fetching objects within a tree path.
def self.navigate(source, path, default = nil)
key = path.take(1)[0]
path = path.drop(1)
return default unless source.key?(key)
result = source.fetch(key)
return navigate(result, path, default) unless path.empty?
return result if path.empty?
end

def extract_variables(template)
template.scan(/{{[^}]*}}/).map { |v| v.gsub(/{{([^}]*)}}/, '\1') }
.map(&:to_sym)
end

def expand_variables(template, var_data)
extract_variables(template).each do |v|
unless var_data.key?(v)
raise "Missing variable :#{v} in #{var_data} on #{caller.join("\n")}}"
end
template.gsub!(/{{#{v}}}/, CGI.escape(var_data[v].to_s))
end
template
end
end

# A handler for authenticated network request
module Network
class Base
def initialize(link, cred)
@link = link
@cred = cred
end

def builder
Net::HTTP.const_get('Get')
end

def send
request = @cred.authorize(builder.new(@link))
request['User-Agent'] = generate_user_agent
response = transport(request).request(request)
unless ENV['GOOGLE_HTTP_VERBOSE'].nil?
puts ["network(#{request}: [#{response.code}]",
response.body.split("\n").map(&:strip).join(' ')].join(' ')
end
response
end

def transport(request)
uri = request.uri
puts "network(#{request}: #{uri})" \
unless ENV['GOOGLE_HTTP_VERBOSE'].nil?
transport = Net::HTTP.new(uri.host, uri.port)
transport.use_ssl = uri.is_a?(URI::HTTPS)
transport.verify_mode = OpenSSL::SSL::VERIFY_PEER
transport.set_debug_output $stderr \
unless ENV['GOOGLE_HTTP_DEBUG'].nil?
transport
end

private

def generate_user_agent
'inspec-google/1.0.0'
end
end

# A class to aquire credentials and authorize Google API calls.
class Authorization
def initialize
@authorization = nil
@scopes = []
end

def authorize(obj)
raise ArgumentError, 'A from_* method needs to be called before' \
unless @authorization

if obj.class <= URI::HTTPS || obj.class <= URI::HTTP
authorize_uri obj
elsif obj.class < Net::HTTPRequest
authorize_http obj
else
obj.authorization = @authorization
obj
end
end

def for!(*scopes)
@scopes = scopes
self
end

def from_service_account_json!(service_account_file)
raise 'Missing argument for scopes' if @scopes.empty?
@authorization = ::Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open(service_account_file),
scope: @scopes,
)
self
end

def from_application_default!
@authorization = ::Google::Auth.get_application_default
self
end

private

def authorize_uri(obj)
http = Net::HTTP.new(obj.host, obj.port)
http.use_ssl = obj.instance_of?(URI::HTTPS)
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
[http, authorize_http(Net::HTTP::Get.new(obj.request_uri))]
end

def authorize_http(req)
req.extend TokenProperty
auth = {}
@authorization.apply!(auth)
req['Authorization'] = auth[:authorization]
req.token = auth[:authorization].split(' ')[1]
req
end
end
# Extension methods to enable retrieving the authentication token.
module TokenProperty
attr_reader :token
attr_writer :token
end
end
Loading