Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add azure_subscription(s) resources #307

Merged
merged 1 commit into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ The static resources derived from the generic resources prepended with `azure_`
- [azure_storage_account_blob_containers](docs/resources/azure_storage_account_blob_containers.md)
- [azure_subnet](docs/resources/azure_subnet.md)
- [azure_subnets](docs/resources/azure_subnets.md)
- [azure_subscription](docs/resources/azure_subscription.md)
- [azure_subscriptions](docs/resources/azure_subscriptions.md)
- [azure_virtual_machine](docs/resources/azure_virtual_machine.md)
- [azure_virtual_machines](docs/resources/azure_virtual_machines.md)
- [azure_virtual_network](docs/resources/azure_virtual_network.md)
Expand Down
106 changes: 106 additions & 0 deletions docs/resources/azure_subscription.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: About the azure_subscription Resource
platform: azure
---

# azure_subscription

Use the `azure_subscription` InSpec audit resource to test properties of the current subscription.

## Azure REST API version, endpoint and http client parameters

This resource interacts with api versions supported by the resource provider.
The `api_version` can be defined as a resource parameter.
If not provided, the latest version will be used.
For more information, refer to [`azure_generic_resource`](azure_generic_resource.md).

Unless defined, `azure_cloud` global endpoint, and default values for the http client will be used.
For more information, refer to the resource pack [README](../../README.md).

## Availability

### Installation

This resource is available in the [InSpec Azure resource pack](https://github.com/inspec/inspec-azure).
For an example `inspec.yml` file and how to set up your Azure credentials, refer to resource pack [README](../../README.md#Service-Principal).

## Syntax

This resource will retrieve the current subscription id that InSpec uses unless it is provided via `id` or `resource_id` parameters.
```ruby
describe azure_subscription do
it { should exist }
end
```
or
```ruby
describe azure_subscription(id: '2e0b423p-aaaa-bbbb-1111-ee558463aabbd') do
it { should exist }
end
```
or
```ruby
describe azure_subscription(resource_id: '/subscriptions/2e0b423p-aaaa-bbbb-1111-ee558463aabbd') do
it { should exist }
end
```
## Parameters

| Name | Description |
|---------------------------------------|-------------|
| id | The ID of the target subscription. `2e0b423p-aaaa-bbbb-1111-ee558463aabbd` |
| resource_id | The fully qualified ID for the subscription. `/subscriptions/2e0b423p-aaaa-bbbb-1111-ee558463aabbd` |
| locations_api_version | The endpoint api version for the `locations` property. Optional. The latest version will be used unless provided. |

## Properties

| Property | Description |
|---------------------------|-------------|
| name | The subscription display name. |
| id | The subscription ID. `2e0b423p-aaaa-bbbb-1111-ee558463aabbd` |
| locations | The list of all available geo-locations. |
| managedByTenants | An array containing the [tenants](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/get#managedbytenant) managing the subscription. |

For properties applicable to all resources, such as `type`, `properties`, refer to [`azure_generic_resource`](azure_generic_resource.md#properties).

Also, refer to [Azure documentation](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/get#subscription) for other properties available.
Any attribute in the response may be accessed with the key names separated by dots (`.`), eg. `properties.<attribute>`.

## Examples

### Test Your Subscription`s Display Name
```ruby
describe azure_subscription do
its('name') { should cmp 'Demo Resources' }
end
```
### Test Your Subscription`s Authorization Source
```ruby
describe azure_subscription do
its('authorizationSource') { should cmp 'RoleBased' }
end
```
### Test Your Subscription`s Locations
```ruby
describe azure_subscription do
its('locations') { should include('eastus') }
end
```
## Matchers

This InSpec audit resource has the following special matchers. For a full list of available matchers, please visit our [Universal Matchers page](https://www.inspec.io/docs/reference/matchers/).

### exists
```ruby
# If we expect a resource to always exist
describe azure_subscription do
it { should exist }
end
# If we expect a resource to never exist
describe azure_subscription(id: 'fake_id') do
it { should_not exist }
end
```
## Azure Permissions

Your [Service Principal](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal) must be setup with a `contributor` role on the subscription you wish to test.
72 changes: 72 additions & 0 deletions docs/resources/azure_subscriptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: About the azure_subscriptions Resource
platform: azure
---

# azure_subscriptions

Use the `azure_subscriptions` InSpec audit resource to test properties and configuration of all Azure subscriptions for a tenant.

## Azure REST API version, endpoint and http client parameters

This resource interacts with api versions supported by the resource provider.
The `api_version` can be defined as a resource parameter.
If not provided, the latest version will be used.
For more information, refer to [`azure_generic_resource`](azure_generic_resource.md).

Unless defined, `azure_cloud` global endpoint, and default values for the http client will be used.
For more information, refer to the resource pack [README](../../README.md).

## Availability

### Installation

This resource is available in the [InSpec Azure resource pack](https://github.com/inspec/inspec-azure).
For an example `inspec.yml` file and how to set up your Azure credentials, refer to resource pack [README](../../README.md#Service-Principal).

## Syntax

An `azure_subscriptions` resource block returns all subscription for a tenant.
```ruby
describe azure_subscriptions do
it { should exist }
end
```
## Parameters

- This resource does not require any parameters.

## Properties

|Property | Description | Filter Criteria<superscript>*</superscript> |
|---------------|-------------------------------------------------------------|-----------------|
| ids | A list of the subscription ids. | `id` |
| names | A list of display names of all the subscriptions. | `name` |
| tags | A list of `tag:value` pairs defined on the subscriptions. | `tags` |
| tenant_ids | A list of tenant ids of all the subscriptions. | `tenant_id` |

<superscript>*</superscript> For information on how to use filter criteria on plural resources refer to [FilterTable usage](https://github.com/inspec/inspec/blob/master/dev-docs/filtertable-usage.md).

## Examples

### Check a Specific Subscription is Present
```ruby
describe azure_subscriptions do
its('names') { should include 'my-subscription' }
end
```
## Matchers

This InSpec audit resource has the following special matchers. For a full list of available matchers, please visit our [Universal Matchers page](https://www.inspec.io/docs/reference/matchers/).

### exists

The control will pass if the filter returns at least one result. Use `should_not` if you expect zero matches.
```ruby
describe azure_subscriptions do
it { should exist }
end
```
## Azure Permissions

Your [Service Principal](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal) must be setup with a `contributor` role on the subscription you wish to test.
2 changes: 2 additions & 0 deletions docs/resources/azurerm_subscription.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: About the azurerm_subscription Resource
platform: azure
---

> <b>WARNING</b> This resource will be deprecated in InSpec Azure Resource Pack version **2**. Please start using fully backward compatible [`azure_subscription`](azure_subscription.md) InSpec audit resource.

# azurerm\_subscription

Use the `azurerm_subscription` InSpec audit resource to test properties related to the current subscription
Expand Down
20 changes: 11 additions & 9 deletions libraries/azure_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -407,19 +407,21 @@ def get_next_link(next_link)
#
# @return [String] The resource type, 'Microsoft.Compute/virtualMachines'.
# @param resource_provider [String] The resource type, 'Microsoft.Compute/virtualMachines'.
# @param opts [Hash] Parameters to check if the ':resource_provider' key exists.
# If the resource type exists in the opts, this will raise an ArgumentError.
# The resource_provider parameter should not be provided by the user in static resources.
# Otherwise, static resource would not behave as expected if a different resource type is provided.
# @param opts [Hash] Parameters to validate.
#
# The resource_provider parameter should be the first parameter defined in a static resource by using this method.
# This will ensure that the end user won't be able pass blacklisted parameters
# which would cause the static resource behave differently than intended.
#
# All parameters will be validated again before talking to the Azure API.
#
def specific_resource_constraint(resource_provider, opts)
if opts.is_a?(Hash)
if opts.key?(:resource_provider)
raise ArgumentError, "#{@__resource_name__}: The `resource_provider` parameter is not allowed."\
" `#{resource_provider}` is predefined for this resource."
elsif opts.keys.any? { |key| %i(allowed_parameters required_parameters).include?(key) }
parameter_blacklist = %i(allowed_parameters required_parameters resource_uri resource_provider display_name
tag_name tag_value add_subscription_id resource_type)
if opts.keys.any? { |key| parameter_blacklist.include?(key) }
raise ArgumentError, "#{@__resource_name__}: The following parameters are not allowed: "\
'["allowed_parameters", "required_parameters"].'
"#{parameter_blacklist}"
end
else
raise ArgumentError, "#{@__resource_name__}: Parameters must be provided in an Hash object."
Expand Down
15 changes: 7 additions & 8 deletions libraries/azure_generic_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ def initialize(opts = {}, static_resource = false)
validate_generic_resource
return if failed_resource?
end
if @opts[:display_name].nil?
@display_name = @opts.slice(:resource_group, :resource_provider, :name, :tag_name, :tag_value, :resource_id,
@display_name = if @opts[:display_name].nil?
@opts.slice(:resource_group, :resource_provider, :name, :tag_name, :tag_value, :resource_id,
:resource_uri).values.join(' ')
else
@display_name = @opts[:display_name]
end
else
@opts[:display_name]
end

resource_fail('There is not enough input to create an Azure resource ID.') if @resource_id.empty?

Expand All @@ -44,9 +44,8 @@ def initialize(opts = {}, static_resource = false)

# resource_long_desc should be a Hash object
# &
# All resources must have a name:
# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/naming-and-tagging
unless @resource_long_desc.is_a?(Hash) && @resource_long_desc.key?(:name)
# All resources must have a id:
unless @resource_long_desc.is_a?(Hash) && @resource_long_desc.key?(:id)
resource_fail("Unable to get the detailed information for the resource_id: #{@resource_id}")
end

Expand Down
7 changes: 7 additions & 0 deletions libraries/azure_sql_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ class AzurermSqlServer < AzureSqlServer
EXAMPLE

def initialize(opts = {})
# Ensure backward compatibility unless these properties are provided by the users deliberately.
opts[:firewall_rules_api_version] ||= '2014-04-01'
opts[:auditing_settings_api_version] ||= '2017-03-01-preview'
opts[:threat_detection_settings_api_version] ||= '2017-03-01-preview'
opts[:administrators_api_version] ||= '2014-04-01'
opts[:encryption_protector_api_version] ||= '2015-05-01-preview'

Inspec::Log.warn Helpers.resource_deprecation_message(@__resource_name__, AzureSqlServer.name)
super
end
Expand Down
74 changes: 74 additions & 0 deletions libraries/azure_subscription.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require 'azure_generic_resource'

class AzureSubscription < AzureGenericResource
name 'azure_subscription'
desc 'Verifies settings for the current Azure Subscription'
example <<-EXAMPLE
describe azure_subscription do
its('name') { should eq 'subscription-name' }
its('locations') { should include 'eastus' }
end
EXAMPLE

attr_reader :locations

def initialize(opts = {})
# Options should be Hash type. Otherwise Ruby will raise an error when we try to access the keys.
raise ArgumentError, 'Parameters must be provided in an Hash object.' unless opts.is_a?(Hash)
raise ArgumentError, 'The `name` parameter is not allowed, use `id`, instead, in the format:'\
'`1e0b427a-aaaa-bbbb-1111-ee558463ebbf`' if opts.key?(:name)

opts[:resource_provider] = specific_resource_constraint('subscriptions', opts)
# This is an edge case resource where `id` becomes `name` from the backend perspective.
# Environment variable will be used unless `id` is provided.
opts[:name] = opts[:id] || ENV['AZURE_SUBSCRIPTION_ID']
opts[:resource_uri] = '/subscriptions/'
opts[:add_subscription_id] = false
opts[:allowed_parameters] = %i(locations_api_version id)

# static_resource parameter must be true for setting the resource_provider in the backend.
super(opts, true)

return if failed_resource?
@locations = collect_locations
# This is for backward compatibility.
define_singleton_method(:id) { subscriptionId }
end

def to_s
super(AzureSubscription)
end

def name
return unless exists?
displayName
end

private

def collect_locations
return unless exists?
api_version = @opts[:locations_api_version] || 'latest'
api_response = get_resource({ resource_uri: id + '/locations', api_version: api_version })
api_response[:value].map { |location| location[:name] }
end
end

# Provide the same functionality under the old resource name.
# This is for backward compatibility.
class AzurermSubscription < AzureSubscription
name 'azurerm_subscription'
desc 'Verifies settings for the current Azure Subscription'
example <<-EXAMPLE
describe azurerm_subscription do
its('name') { should eq 'subscription-name' }
its('locations') { should include 'eastus' }
end
EXAMPLE

def initialize(opts = {})
opts[:locations_api_version] ||= '2019-10-01'
Inspec::Log.warn Helpers.resource_deprecation_message(@__resource_name__, AzureSubscription.name)
super
end
end
Loading