diff --git a/docs/resources/google_organization.md b/docs/resources/google_organization.md new file mode 100644 index 000000000..6fbe4072e --- /dev/null +++ b/docs/resources/google_organization.md @@ -0,0 +1,59 @@ +--- +title: About the google_organization Resource +platform: gcp +--- + +# google\_organization + +Use the `google_organization` InSpec audit resource to test properties of a GCP organization. + +
+ +## Syntax + +Google organization have a name, display name (or domain) and lifecycle state. For more info, please see [here](https://cloud.google.com/resource-manager/docs/creating-managing-organization). + +A `google_organization` resource block declares the tests for a single GCP organization identified by `display_name` or `name`: + + describe google_organization(display_name: 'google.com') do + it { should exist } + its('name') { should eq 'organizations/1234' } + its('display_name') { should eq 'google.com' } + end + + describe google_organization(name: 'organizations/1234') do + it { should exist } + its('name') { should eq 'google.com' } + its('lifecycle_state') { should eq 'ACTIVE' } + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that a GCP organization has the expected name + + describe google_organization(name: 'organizations/1234') do + its('name') { should eq 'organizations/1234' } + end + +### Test that a GCP organization has the expected lifecycle state e.g. "ACTIVE" + + describe google_organization(display_name: 'google.com') do + its('lifecycle_state') { should eq "ACTIVE" } + end + +
+ +## Properties + +* `name`, `display_name`, `lifecycle_state` + +
+ + +## GCP Permissions + +Ensure the [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com/) is enabled for the project. \ No newline at end of file diff --git a/docs/resources/google_organizations.md b/docs/resources/google_organizations.md new file mode 100644 index 000000000..5b0c7b355 --- /dev/null +++ b/docs/resources/google_organizations.md @@ -0,0 +1,85 @@ +--- +title: About the google_organizations Resource +platform: gcp +--- + +# google\_organizations + +Use the `google_organizations` InSpec audit resource to test properties of all, or a filtered group of, GCP +organizations. + +
+ +## Syntax + +A `google_organizations` resource block collects GCP organizations then tests that group. + + describe google_organizations do + it { should exist } + end + +Use this InSpec resource to enumerate IDs then test in-depth using `google_organization`. + + google_organizations.names.each do |name| + describe google_organization(name: name) do + it { should exist } + its('lifecycle_state') { should eq "ACTIVE" } + end + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that there are no more than a specified number of organizations available + + describe google_organizations do + its('count') { should be <= 100} + end + +### Test that an expected organization name is available + + describe google_organizations do + its('names') { should include "organization/1234" } + end + +### Test that an expected organization display name is available + + describe google_organizations do + its('display_names') { should include "google.com" } + end + +### Test that all organizations are ACTIVE + + describe google_organizations do + its('lifecycle_state'){ should eq 'ACTIVE' } + end + +### Test that a particular subset of ACTIVE organizations with display name 'goog*' exist + + google_organizations.where(display_name: /^goog/, lifecycle_state: 'ACTIVE').names.each do |name| + describe google_organization(name: name) do + it { should exist } + end + end + +
+ +## Filter Criteria + +This resource supports the following filter criteria: `name`; `display_name` and `lifecycle_state`. Any of these may be used with `where`, as a block or as a method. + +## Properties + +* `names` - an array of google_organization identifier strings +* `display_names` - an array of google_organization display name strings +* `lifecycle_state`- an array of google_organization lifecycle state strings + +
+ + +## GCP Permissions + +Ensure the [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com/) is enabled for the project. \ No newline at end of file diff --git a/libraries/google_organization.rb b/libraries/google_organization.rb new file mode 100644 index 000000000..5bbcd5e34 --- /dev/null +++ b/libraries/google_organization.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleOrganization < GcpResourceBase + name 'google_organization' + desc 'Verifies settings for an organization' + + example " + describe google_organization(name: 'google.com') do + it { should exist } + its('name') { should eq 'organizations/1234' } + its('display_name') { should eq 'google.com' } + its('lifecycle_state') { should eq 'ACTIVE' } + end + " + def initialize(opts = {}) + super(opts) + @display_name = opts[:name] || opts[:display_name] + catch_gcp_errors do + @organization = @gcp.gcp_project_client.get_organization(opts[:name]) + create_resource_methods(@organization) + end + end + + def label_value_by_key(label_key) + return [] if !defined?(labels) || labels.nil? + labels.item[label_key] + end + + def exists? + !@organization.nil? + end + + def to_s + "Organization #{@display_name}" + end + end +end diff --git a/libraries/google_organizations.rb b/libraries/google_organizations.rb new file mode 100644 index 000000000..c31f3f614 --- /dev/null +++ b/libraries/google_organizations.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleComputeOrganizations < GcpResourceBase + name 'google_organizations' + desc 'Verifies settings for GCP organizations in bulk' + + example " + describe google_organizations do + it { should exist } + ... + end + " + + def initialize(opts = {}) + super(opts) + end + + filter_table_config = FilterTable.create + filter_table_config.add(:names, field: :name) + filter_table_config.add(:display_names, field: :display_name) + filter_table_config.add(:lifecycle_state, field: :lifecycle_state) + filter_table_config.connect(self, :fetch_data) + + def fetch_data + organizations_rows = [] + loop do + catch_gcp_errors do + @organizations = @gcp.gcp_project_client.search_organizations({}) + end + return [] if !@organizations || !@organizations.organizations + @organizations.organizations.map do |organization| + organizations_rows += [{ name: organization.name, + display_name: organization.display_name, + lifecycle_state: organization.lifecycle_state, + }] + end + next_page = @organizations.next_page_token + break unless next_page + end + @table = organizations_rows + end + end +end