inspec-cloudformation 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +18 -0
- data/README.md +1 -0
- data/inspec-cloudformation.gemspec +38 -0
- data/lib/inspec-cloudformation/input.rb +156 -0
- data/lib/inspec-cloudformation/plugin.rb +25 -0
- data/lib/inspec-cloudformation/version.rb +8 -0
- data/lib/inspec-cloudformation.rb +14 -0
- metadata +50 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0bac1eaa6b1118ac6bb8066a77210d81199502aa46c8c6d0a66280f098fd0fca
|
|
4
|
+
data.tar.gz: 93fb485ae89f6c423a3dc815b1acd5a892e8d9849487d5ba562526b0b421cad9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: af62285f8c803d4e32303a271469412ecd78f28d6534a1e198d721ab264bf13b8da5130755dd14e54440b9e47bbcc25211e9796930e2a120ddd568d00dc882c0
|
|
7
|
+
data.tar.gz: 2b3692f7fbd654e8de573e58a8708dbbaade5e43658aefad4aeea1bcb0bb5bbab30e6673e0f16c7c53f11e65c519cea3edebbb775a68ef86c764460ff712939b
|
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# inspec-cloudformation
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# As plugins are usually packaged and distributed as a RubyGem,
|
|
2
|
+
# we have to provide a .gemspec file, which controls the gembuild
|
|
3
|
+
# and publish process. This is a fairly generic gemspec.
|
|
4
|
+
|
|
5
|
+
# It is traditional in a gemspec to dynamically load the current version
|
|
6
|
+
# from a file in the source tree. The next three lines make that happen.
|
|
7
|
+
lib = File.expand_path("lib", __dir__)
|
|
8
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
9
|
+
require "inspec-cloudformation/version"
|
|
10
|
+
|
|
11
|
+
Gem::Specification.new do |spec|
|
|
12
|
+
# Importantly, all InSpec plugins must be prefixed with `inspec-` (most
|
|
13
|
+
# plugins) or `train-` (plugins which add new connectivity features).
|
|
14
|
+
spec.name = "inspec-cloudformation"
|
|
15
|
+
|
|
16
|
+
# It is polite to namespace your plugin under InspecPlugins::YourPluginInCamelCase
|
|
17
|
+
spec.version = InspecPlugins::Vault::VERSION
|
|
18
|
+
spec.authors = ["Andy Boutte"]
|
|
19
|
+
spec.email = ["andyboutte@gmail.com"]
|
|
20
|
+
spec.summary = "Use CloudFormation Outputs in your InSpec profiles"
|
|
21
|
+
spec.description = "This plugin allows InSpec 'inputs' to be provided by CloudFormation Outputs."
|
|
22
|
+
spec.homepage = "https://github.com/aboutte/inspec-cloudformation"
|
|
23
|
+
spec.license = "Apache-2.0"
|
|
24
|
+
|
|
25
|
+
# Though complicated-looking, this is pretty standard for a gemspec.
|
|
26
|
+
# It just filters what will actually be packaged in the gem (leaving
|
|
27
|
+
# out tests, etc)
|
|
28
|
+
spec.files = %w{
|
|
29
|
+
README.md inspec-cloudformation.gemspec Gemfile
|
|
30
|
+
} + Dir.glob(
|
|
31
|
+
"lib/**/*", File::FNM_DOTMATCH
|
|
32
|
+
).reject { |f| File.directory?(f) }
|
|
33
|
+
spec.require_paths = ["lib"]
|
|
34
|
+
|
|
35
|
+
# If you rely on any other gems, list them here with any constraints.
|
|
36
|
+
# This is how `inspec plugin install` is able to manage your dependencies.
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require 'aws-sdk-cloudformation'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# See https://github.com/inspec/inspec/blob/master/docs/dev/plugins.md#implementing-input-plugins
|
|
13
|
+
|
|
14
|
+
module InspecPlugins::Vault
|
|
15
|
+
class Input < Inspec.plugin(2, :input)
|
|
16
|
+
|
|
17
|
+
VALID_PATTERNS = [
|
|
18
|
+
Regexp.new("^databag://[^/]+/[^/]+/.+$"),
|
|
19
|
+
Regexp.new("^node://[^/]*/attributes/.+$"),
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
attr_reader :plugin_conf
|
|
23
|
+
# attr_reader :mount_point
|
|
24
|
+
# attr_reader :path_prefix
|
|
25
|
+
# attr_reader :vault
|
|
26
|
+
attr_reader :priority
|
|
27
|
+
attr_reader :input_name
|
|
28
|
+
attr_reader :logger
|
|
29
|
+
|
|
30
|
+
def initialize
|
|
31
|
+
@plugin_conf = Inspec::Config.cached.fetch_plugin_config("inspec-cloudformation")
|
|
32
|
+
|
|
33
|
+
@logger = Inspec::Log
|
|
34
|
+
logger.debug format("inspec-cloudformation plugin version %s", VERSION)
|
|
35
|
+
|
|
36
|
+
# @mount_point = fetch_plugin_setting("mount_point", "secret")
|
|
37
|
+
# @path_prefix = fetch_plugin_setting("path_prefix", "inspec")
|
|
38
|
+
|
|
39
|
+
# We need priority to be numeric; even though env vars or JSON may present it as string - hence the to_i
|
|
40
|
+
@priority = fetch_plugin_setting("priority", 60).to_i
|
|
41
|
+
|
|
42
|
+
# @vault = Vault::Client.new(
|
|
43
|
+
# address: fetch_vault_setting("vault_addr"),
|
|
44
|
+
# token: fetch_vault_setting("vault_token")
|
|
45
|
+
# )
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# What priority should an input value recieve from us?
|
|
49
|
+
# This plgin does not currently allow setting this on a per-input basis,
|
|
50
|
+
# so they all recieve the same "default" value.
|
|
51
|
+
# Implements https://github.com/inspec/inspec/blob/master/dev-docs/plugins.md#default_priority
|
|
52
|
+
def default_priority
|
|
53
|
+
priority
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# returns Array of input names as strings
|
|
57
|
+
# def list_inputs(profile_name)
|
|
58
|
+
# vault.with_retries(Vault::HTTPConnectionError) do
|
|
59
|
+
# path = logical_path_for_profile(profile_name)
|
|
60
|
+
# doc = vault.logical.read(path)
|
|
61
|
+
# return [] unless doc
|
|
62
|
+
|
|
63
|
+
# return doc.data[:data].keys.map(&:to_s)
|
|
64
|
+
# end
|
|
65
|
+
# end
|
|
66
|
+
|
|
67
|
+
# Fetch a value of a single input from Vault
|
|
68
|
+
|
|
69
|
+
def fetch(profile_name, input_name)
|
|
70
|
+
return nil if input_name.include?('_')
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
cf = Aws::CloudFormation::Client.new
|
|
74
|
+
|
|
75
|
+
# input format will be "cloudformation stack name / output name"
|
|
76
|
+
|
|
77
|
+
stack_name = input_name.split('/').first
|
|
78
|
+
output_name = input_name.split('/').last
|
|
79
|
+
|
|
80
|
+
logger.info format("The stack name is %s", stack_name)
|
|
81
|
+
logger.info format("The output name is %s", output_name)
|
|
82
|
+
|
|
83
|
+
name = { stack_name: stack_name }
|
|
84
|
+
resp = cf.describe_stacks(name)
|
|
85
|
+
return nil if resp.stacks.nil? || resp.stacks.empty?
|
|
86
|
+
stack = resp.stacks.first
|
|
87
|
+
stack.outputs.each do |output|
|
|
88
|
+
next unless output['output_key'] == output_name
|
|
89
|
+
return output['output_value']
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# stacks.each do |stack|
|
|
93
|
+
# next if input(stack).nil? # If HRA addon was skipped we expect the input to be skipped also
|
|
94
|
+
|
|
95
|
+
# end
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# @input_name = input_name
|
|
100
|
+
|
|
101
|
+
# path = logical_path_for_profile(profile_name)
|
|
102
|
+
# item = input_name
|
|
103
|
+
|
|
104
|
+
# if absolute_path?
|
|
105
|
+
# _empty, *path, item = input_name.split("/")
|
|
106
|
+
# path = logical_path path.join("/")
|
|
107
|
+
# end
|
|
108
|
+
|
|
109
|
+
# logger.info format("Reading Vault secret from %s", path)
|
|
110
|
+
# vault.with_retries(Vault::HTTPConnectionError) do
|
|
111
|
+
# doc = vault.logical.read(path)
|
|
112
|
+
# # Keys from vault are always symbolized
|
|
113
|
+
# return doc.data[:data][item.to_sym] if doc
|
|
114
|
+
# end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
# # Assumption for profile based lookups: inputs have been stored on documents named
|
|
120
|
+
# # for their profiles, and each input has a key-value pair in the document.
|
|
121
|
+
# def logical_path_for_profile(profile_name)
|
|
122
|
+
# logical_path(profile_name)
|
|
123
|
+
# end
|
|
124
|
+
|
|
125
|
+
# def logical_path(relative_path)
|
|
126
|
+
# # When you actually read a value, on the KV2 backend you must
|
|
127
|
+
# # read secret/data/path, not secret/path (as on the CLI)
|
|
128
|
+
# # https://www.vaultproject.io/api/secret/kv/kv-v2.html#read-secret-version
|
|
129
|
+
# # Is this true for all backends?
|
|
130
|
+
# "#{mount_point}/data/#{prefix}#{relative_path}"
|
|
131
|
+
# end
|
|
132
|
+
|
|
133
|
+
# def prefix
|
|
134
|
+
# return "#{path_prefix}/" unless absolute_path?
|
|
135
|
+
|
|
136
|
+
# ""
|
|
137
|
+
# end
|
|
138
|
+
|
|
139
|
+
# def absolute_path?
|
|
140
|
+
# input_name.start_with?("/")
|
|
141
|
+
# end
|
|
142
|
+
|
|
143
|
+
def valid_plugin_input?(input)
|
|
144
|
+
VALID_PATTERNS.any? { |regex| regex.match? input }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def fetch_plugin_setting(setting_name, default = nil)
|
|
148
|
+
env_var_name = "INSPEC_CLOUDFORMATION_#{setting_name.upcase}"
|
|
149
|
+
ENV[env_var_name] || plugin_conf[setting_name] || default
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# def fetch_vault_setting(setting_name)
|
|
153
|
+
# ENV[setting_name.upcase] || plugin_conf[setting_name]
|
|
154
|
+
# end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Plugin Definition file
|
|
2
|
+
# The purpose of this file is to declare to InSpec what plugin_types (capabilities)
|
|
3
|
+
# are included in this plugin, and provide hooks that will load them as needed.
|
|
4
|
+
|
|
5
|
+
# It is important that this file load successfully and *quickly*.
|
|
6
|
+
# Your plugin's functionality may never be used on this InSpec run; so we keep things
|
|
7
|
+
# fast and light by only loading heavy things when they are needed.
|
|
8
|
+
|
|
9
|
+
# Presumably this is light
|
|
10
|
+
require "inspec-cloudformation/version"
|
|
11
|
+
module InspecPlugins
|
|
12
|
+
module Vault
|
|
13
|
+
class Plugin < ::Inspec.plugin(2)
|
|
14
|
+
# Internal machine name of the plugin. InSpec will use this in errors, etc.
|
|
15
|
+
plugin_name :'inspec-cloudformation'
|
|
16
|
+
|
|
17
|
+
# Define an Input plugin type.
|
|
18
|
+
input :vault do
|
|
19
|
+
require_relative "input"
|
|
20
|
+
InspecPlugins::Vault::Input
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# This file is known as the "entry point."
|
|
2
|
+
# This is the file InSpec will try to load if it
|
|
3
|
+
# thinks your plugin is installed.
|
|
4
|
+
|
|
5
|
+
# The *only* thing this file should do is setup the
|
|
6
|
+
# load path, then load the plugin definition file.
|
|
7
|
+
|
|
8
|
+
# Next two lines simply add the path of the gem to the load path.
|
|
9
|
+
# This is not needed when being loaded as a gem; but when doing
|
|
10
|
+
# plugin development, you may need it. Either way, it's harmless.
|
|
11
|
+
libdir = File.dirname(__FILE__)
|
|
12
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
|
13
|
+
|
|
14
|
+
require "inspec-cloudformation/plugin"
|
metadata
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: inspec-cloudformation
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andy Boutte
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2022-07-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: This plugin allows InSpec 'inputs' to be provided by CloudFormation Outputs.
|
|
14
|
+
email:
|
|
15
|
+
- andyboutte@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- Gemfile
|
|
21
|
+
- README.md
|
|
22
|
+
- inspec-cloudformation.gemspec
|
|
23
|
+
- lib/inspec-cloudformation.rb
|
|
24
|
+
- lib/inspec-cloudformation/input.rb
|
|
25
|
+
- lib/inspec-cloudformation/plugin.rb
|
|
26
|
+
- lib/inspec-cloudformation/version.rb
|
|
27
|
+
homepage: https://github.com/aboutte/inspec-cloudformation
|
|
28
|
+
licenses:
|
|
29
|
+
- Apache-2.0
|
|
30
|
+
metadata: {}
|
|
31
|
+
post_install_message:
|
|
32
|
+
rdoc_options: []
|
|
33
|
+
require_paths:
|
|
34
|
+
- lib
|
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: '0'
|
|
45
|
+
requirements: []
|
|
46
|
+
rubygems_version: 3.1.6
|
|
47
|
+
signing_key:
|
|
48
|
+
specification_version: 4
|
|
49
|
+
summary: Use CloudFormation Outputs in your InSpec profiles
|
|
50
|
+
test_files: []
|