Skip to content
This repository has been archived by the owner on Jun 25, 2021. It is now read-only.

Latest commit

 

History

History
164 lines (96 loc) · 11.9 KB

DESIGN.md

File metadata and controls

164 lines (96 loc) · 11.9 KB

Design

This document attempts to explain the organization of the InSpec-Iggy code and how to extend it as necessary. Because Iggy is an InSpec plugin, it tries to follow InSpec closely with regards to versions, style, and tooling. Links to the source code are given because there may be additional documentation within the files.

Files

Tracks against InSpec's settings for code style, currently using Chefstyle 0.13.0.

Has the rough feature set by each release but also contains the BACKLOG for the project, ideas considered but not yet implemented.

The source of the gems and additional gemsets for use with Bundler (ie. test).

This is where metadata for the Gem goes. We have also pinned the version of InSpec to between 2.3 and less than 5 to prevent breaking changes.

This is the "entry point" for InSpec to load if it thinks the plugin is installed. The only thing this file should do is setup the load path, then load the plugin definition file.

Plugin Definition file. The purpose of this file is to declare to InSpec what plugin_types (capabilities) are included in this plugin, and provide hooks that will load them as needed. It is important that this file load successfully and quickly. The plugin's functionality may never be used on this InSpec run; so we keep things fast and light by only loading heavy things when they are needed.

The entry points for the cli_commands for :terraform and :cloudformation are here. If you were to add another format this is the place to declare that.

Helpers

Helper class that parses JSON input files and handles errors.

Constants and helper methods for working with InSpec.

Constants

  • TRANSLATED_RESOURCES: Resources that do not map cleanly are provided by the TRANSLATED_RESOURCES hash. There are very few mismatches because both tools use the SDKs provided by the same vendors.
  • ADDITIONAL_COMMON_PROPERTIES: Because InSpec properties are often dynamically generated, it is hard to determine their existence without instantiating them. Because of this, we maintain a manual list of properties to check for.

Helper Methods

  • available_resources: The list of currently available InSpec Resources.
  • load_resource_pack(resource_path): Adds a resource pack's Resources to the available_resources.
  • available_resource_qualifiers(platform): The available qualifers for the Describe block within the Controls generated for a particular resource.
  • available_resource_iterators(platform): The iterators available for resources, also provides the qualifiers for those iterators. Used for iterating over negative coverage.
  • translated_resource_property(platform, resource, property): Resource properties that do not map cleanly are looked up from the associated platform, returning the property whether or not it is translated. This is currently used for mapping properties like name to group_name for example.
  • tf_controls: provides the content for the controls file for Terraform subcommand.
  • cfn_controls: provides the AWS API calls to dynamically check the passed CloudFormation stack and provide the content for the controls file.

Helper class to render a full InSpec profile with a README.md, inspec.yml, and the generated controls/generated.rb populated from the parsed input file and the CLI options provided.

Tracks the version of InSpec-Iggy.

Platform Helpers

The platform helpers provide constants used by the inspec_helper.rb for translating and filtering resources and their iterators, qualifiers, and properties. They also provide methods used by the profile_helper.rb to render the platform-specific instructions for the generated InSpec profiles.

Terraform

The inspec terraform CLI command and options. Given this is a Thor CLI, the desc and subcommand_desc provide help at the CLI. The class_options hash is used to define documentation and settings for allowed subcommand options. Each method (generate and negative) is turned into further subcommands (ie. inspec terraform generate) and there are currently no differences in options between them.

Within the generate method the following block:

generated_controls = InspecPlugins::Iggy::Terraform::Generate.parse_generate(options[:tfstate], resource_path, platform)

calls into the Terraform generate_parse_generate which returns the InSpec controls found by mapping Terraform resources to InSpec resources given a platform and the path to its resources.

printable_controls = InspecPlugins::Iggy::InspecHelper.tf_controls(options[:title], generated_controls, platform)

calls into the inspec helper to produce the InSpec controls to include within the profile, filtering on the platform.

InspecPlugins::Iggy::ProfileHelper.render_profile(ui, options, options[:tfstate], printable_controls, platform)

calls into the profile renderer.

The inspec terraform negative command uses the same options as the generate command and follows the same pattern of parsing the controls, converting them to a printable format, and printing the output as an InSpec profile.

This class parses the passed Terraform .tfstate files. The parse_generate method is the standard interface for parsing, it calls into the private InspecPlugins::Iggy::FileHelper.parse_json method which reads the actual JSON.

The parse_resources method then parses the Terraform JSON, iterating over the modules array of resources which are then mapped to the appropriate InSpec Resources. The parse_resources method calls into the InSpecHelper to load_resource_pack to load the additional InSpec Resources provided by the respective platform's resource pack. The TRANSLATED_RESOURCES provide a mapping of Terraform resources that do not match the InSpec equivalent. The resources that map from Terraform to InSpec are returned.

The parsed resources are then passed to parse_controls which generates InSpec Controls and tests for the matched resources. The generated InSpec controls are returned.

The Negative class reuses the InspecPlugins::Iggy::FileHelper.parse_json and InspecPlugins::Iggy::Terraform::Generate.parse_resources to parse the JSON and find the matched resources respectively.

Negative controls are generated by finding the platform resources that are not represented by Terraform (parse_unmatched_resources) and those that are managed with Terraform (parse_matched_resources).

  • parse_unmatched_resources iterates over all of the of InspecPlugins::Iggy::InspecHelper.available_resource_iterators that are not present in the matched resources. It then creates Controls that test that they should_not exist since they are not managed by Terraform.
  • parse_matched_resources iterates over each matched resource and removes them from the entire set of that resource. If there are any remaining resources they are not managed by Terraform, so we test that they should_not exist. Because we are embedding iterators in our Control, we have to render this control by hand rather than use InSpec's Control object.

CloudFormation

The CFN cli_command.rb is similar to the terraform/cli_command.rb. It requires a :stack as an option, because it will dynamically generate the InSpec profile from the launched CloudFormation stack in conjunction with the template.

The CFN parser is very similar to the terraform/generate.rb, parsing a JSON template file and iterating over the 'Resources'.

Platform Support

Terraform

For InSpec-Iggy to work, you must have both Terraform and InSpec support for your platform. This is because it maps Terraform resources to InSpec resources. You will need to provide the path to the proper InSpec resource pack providing your platform's resources. If there's not an InSpec plugin for the platform, there won't be any resources generated.

If you have working InSpec and Terraform support, you will want to run with

inspec terraform generate -t terraform.tfstate --platform PLATFORM --resourcepath ~/ws/inspec-PLATFORM --name DEBUG --debug

and look through the debugging messages to see what is being SKIPPED, TRANSLATED or MATCHED. You may want to drop a pry debugging breakpoint within the Terraform generate parse_resources method to see what is in the JSON versus what InSpec resources.

If you are not getting MATCHED resource_type resources and all SKIPPED, they are most likely not in the InspecPlugins::Iggy::InspecHelper::RESOURCES. The TRANSLATED_RESOURCES within the inspec_helper.rb may need to be updated to map resource_types to what is in InSpec.

At this point there are not mappings for InSpec properties to Terraform attributes. If this is an issue you may need to update the hash of resources and the attribute mappings in the inspec_helper.rb.

New Platforms

AWS, Azure, and GCP are currently supported in the [lib/inspec-iggy/platforms/]. If you wish to add another platform start with those helpers and provide the same constants and methods, assuming you have Terraform and InSpec support.

Alternate Formats

If you want to add support for another format (ie. ARM templates or something similar), follow the examples of the Terraform and CloudFormation support. You will start by adding a new cli_command to the lib/inspec-iggy/plugin.rb. You will need a cli_command.rb and parser.rb implementing the appropriate classes and methods.