Skip to content

Commit

Permalink
Add azure_subscription(s) resources
Browse files Browse the repository at this point in the history
Signed-off-by: Omer Demirok <odemirok@chef.io>
  • Loading branch information
Omer Demirok authored and Stuart Paterson committed Sep 28, 2020
1 parent 6bd8953 commit 8bd8f61
Show file tree
Hide file tree
Showing 15 changed files with 385 additions and 58 deletions.
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

0 comments on commit 8bd8f61

Please sign in to comment.