-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rewrite storage account to new generic resource way (WIP) (#324)
* rewrite storage account to new generic resource way Signed-off-by: srb3 <sbrown@chef.io> * remove duplicate to_s * adding first pass at storage account docs Signed-off-by: srb3 <sbrown@chef.io> * Updat azure storage account Signed-off-by: Omer Demirok <odemirok@chef.io> * Update azure storage account resource Signed-off-by: Omer Demirok <odemirok@chef.io> * Fix a typo Signed-off-by: Omer Demirok <odemirok@chef.io> Co-authored-by: Ross <rmoles@users.noreply.github.com> Co-authored-by: Omer Demirok <odemirok@chef.io>
- Loading branch information
1 parent
3df94da
commit 3dcabe4
Showing
12 changed files
with
470 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
--- | ||
title: About the azure_storage_account Resource | ||
platform: azure | ||
--- | ||
|
||
# azure_storage_account | ||
|
||
Use the `azure_storage_account` InSpec audit resource to test properties related to an Azure Storage Account. | ||
|
||
## 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_storage_account` resource block identifies an Azure storage account by `name` and `resource_group` or the `resource_id`. | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'sa') do | ||
it { should exist } | ||
end | ||
``` | ||
```ruby | ||
describe azure_storage_account(resource_id: '/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}') do | ||
it { should exist } | ||
end | ||
``` | ||
## Parameters | ||
|
||
| Name | Description | | ||
|--------------------------------|--------------------------------------------------------------------------------------| | ||
| resource_group | Azure resource group that the targeted resource resides in. `MyResourceGroup` | | ||
| name | The name of the storage account within the specified resource group. `accountName` | | ||
| resource_id | The unique resource ID. `/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}` | | ||
| activity_log_alert_api_version | The activity log alerts endpoint api version used in `have_recently_generated_access_key` matcher. The latest version will be used unless provided. | | ||
| storage_service_endpoint_api_version | The storage service endpoint api version. `2019-12-12` wil be used unless provided. | | ||
|
||
Either one of the parameter sets can be provided for a valid query: | ||
- `resource_id` | ||
- `resource_group` and `name` | ||
|
||
## Properties | ||
|
||
| Property | Description | | ||
|----------------------------------------------|-------------| | ||
| queues<superscript>*</superscript> | Lists all of the queues in a given storage account. See [here](https://docs.microsoft.com/en-us/rest/api/storageservices/list-queues1) for more. | ||
| queue_properties<superscript>*</superscript> | gets the properties of a storage account’s Queue service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. See [here](https://docs.microsoft.com/en-us/rest/api/storageservices/get-queue-service-properties) for more. | ||
|
||
<superscript>*</superscript>: Note that the Azure endpoints return data in XML format; however, they will be converted to Azure Resource Probe to make the properties accessible via dot notation. | ||
The property names will be in snake case, `propety_name`. Therefore, `<EnumerationResults ServiceEndpoint="https://myaccount.queue.core.windows.net/">` can be tested via `its('enumeration_results.service_endpoint)`. | ||
|
||
For properties applicable to all resources, such as `type`, `name`, `id`, `properties`, refer to [`azure_generic_resource`](azure_generic_resource.md#properties). | ||
|
||
Also, refer to [Azure documentation](https://docs.microsoft.com/en-us/rest/api/storagerp/storageaccounts/getproperties#storageaccount) for other properties available. | ||
Any attribute in the response may be accessed with the key names separated by dots (`.`). | ||
|
||
## Examples | ||
|
||
### Test the Primary Endpoints | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
its('properties.primaryEndpoints.blob') { should cmp 'https://mysa.blob.core.windows.net/' } | ||
its('properties.primaryEndpoints.queue') { should cmp 'https://mysa.queue.core.windows.net/' } | ||
its('properties.primaryEndpoints.table') { should cmp 'https://mysa.table.core.windows.net/' } | ||
its('properties.primaryEndpoints.file') { should cmp 'https://mysa.file.core.windows.net/' } | ||
end | ||
``` | ||
### Verify that Only HTTPs is Supported | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
its('properties.supportsHttpsTrafficOnly') { should be true } | ||
end | ||
``` | ||
### Test Queues Service Endpoint | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
its('queues.enumeration_results.service_endpoint') { should cmp 'https://mysa.queue.core.windows.net/' } | ||
end | ||
``` | ||
### Test Queue Properties Logging Version | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
its('queue_properties.logging.version') { should cmp '1.0' } | ||
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://docs.chef.io/inspec/matchers/). | ||
|
||
### have_encryption_enabled | ||
|
||
Test if encryption is enabled. | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
it { should have_encryption_enabled } | ||
end | ||
``` | ||
### have_recently_generated_access_key | ||
|
||
Test if an access key has been generated within the last **90** days. | ||
```ruby | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
it { should have_recently_generated_access_key } | ||
end | ||
``` | ||
### exists | ||
```ruby | ||
# If we expect the resource to always exist | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') do | ||
it { should exist } | ||
end | ||
|
||
# If we expect the resource to never exist | ||
describe azure_storage_account(resource_group: 'rg', name: 'mysa') 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
--- | ||
title: About the azure_storage_accounts Resource | ||
platform: azure | ||
--- | ||
|
||
# azure_storage_accounts | ||
|
||
Use the `azure_storage_accounts` InSpec audit resource to test properties and configuration of multiple Azure Storage Accounts. | ||
|
||
## 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_storage_accounts` resource block returns all Azure storape accounts, either within a Resource Group (if provided), or within an entire Subscription. | ||
```ruby | ||
describe azure_storage_accounts do | ||
#... | ||
end | ||
``` | ||
or | ||
```ruby | ||
describe azure_storage_accounts(resource_group: 'my-rg') do | ||
#... | ||
end | ||
``` | ||
## Parameters | ||
|
||
- `resource_group` (Optional) | ||
|
||
## Properties | ||
|
||
|Property | Description | Filter Criteria<superscript>*</superscript> | | ||
|---------------|--------------------------------------------------------------------------------------|-----------------| | ||
| ids | A list of the unique resource ids. | `id` | | ||
| locations | A list of locations for all the resources being interrogated. | `location` | | ||
| names | A list of names of all the resources being interrogated. | `name` | | ||
| type | A list of types of all the resources being interrogated. | `type` | | ||
| tags | A list of `tag:value` pairs defined on the resources being interrogated. | `tags` | | ||
|
||
<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 If a Specific Storage Account Exists | ||
```ruby | ||
describe azurerm_storage_accounts(resource_group: 'rg') do | ||
its('names') { should include('mysa') } | ||
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 | ||
# If we expect at least one account to exist in a resource group | ||
describe azure_storage_accounts(resource_group: 'rg') do | ||
it { should exist } | ||
end | ||
|
||
# If we expect no storage accounts to exist in a resource group | ||
describe azure_storage_accounts(resource_group: 'rg') 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
require 'azure_generic_resource' | ||
require 'active_support/core_ext/hash' | ||
|
||
class AzureStorageAccount < AzureGenericResource | ||
name 'azure_storage_account' | ||
desc 'Verifies settings for a Azure Storage Account' | ||
example <<-EXAMPLE | ||
describe azure_storage_account(resource_group: 'r-group', name: 'default') do | ||
it { should exist } | ||
end | ||
EXAMPLE | ||
|
||
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) | ||
|
||
opts[:resource_provider] = specific_resource_constraint('Microsoft.Storage/storageAccounts', opts) | ||
opts[:allowed_parameters] = %i(activity_log_alert_api_version storage_service_endpoint_api_version) | ||
# fall-back `api_version` is fixed for now. | ||
# TODO: Implement getting the latest Azure Storage services api version | ||
opts[:storage_service_endpoint_api_version] ||= '2019-12-12' | ||
opts[:activity_log_alert_api_version] ||= 'latest' | ||
|
||
# static_resource parameter must be true for setting the resource_provider in the backend. | ||
super(opts, true) | ||
end | ||
|
||
def to_s | ||
super(AzureKeyVault) | ||
end | ||
|
||
# Resource specific methods can be created. | ||
# `return unless exists?` is necessary to prevent any unforeseen Ruby error. | ||
# Following methods are created to provide the same functionality with the current resource pack >>>> | ||
# @see https://github.com/inspec/inspec-azure | ||
|
||
def has_recently_generated_access_key? | ||
return unless exists? | ||
now = Time.now | ||
ninety_days_ago = ((60*60)*(24*90)) | ||
upper_bound = to_utc(now) | ||
lower_bound = to_utc(now - ninety_days_ago) | ||
|
||
filter = "resourceId eq '#{id}' and "\ | ||
"eventTimestamp ge '#{lower_bound}' and "\ | ||
"eventTimestamp le '#{upper_bound}' and "\ | ||
"operations eq 'Microsoft.Storage/storageAccounts/regeneratekey/action'" | ||
activity_log_alert_filter(filter) unless respond_to?(:activity_log_alert_filtered) | ||
activity_log_alert_filtered.any? | ||
end | ||
|
||
def has_encryption_enabled? | ||
return unless exists? | ||
properties.encryption.services.blob.enabled || false | ||
end | ||
|
||
def queues | ||
return unless exists? | ||
url = "https://#{name}.queue#{@azure.storage_endpoint_suffix}" | ||
param = { comp: 'list' } | ||
# Calls to Azure Storage resources requires a special header `x-ms-version` | ||
# https://docs.microsoft.com/en-us/rest/api/storageservices/versioning-for-the-azure-storage-services | ||
headers = { 'x-ms-version' => @opts[:storage_service_endpoint_api_version] } | ||
body = @azure.rest_get_call(url, param, headers) | ||
return unless body | ||
body_hash = Hash.from_xml(body) | ||
hash_with_snakecase_keys = RecursiveMethodHelper.method_recursive(body_hash, :snakecase) | ||
if hash_with_snakecase_keys | ||
create_resource_methods({ queues: hash_with_snakecase_keys }) | ||
public_send(:queues) if respond_to?(:queues) | ||
end | ||
end | ||
|
||
def queue_properties | ||
return unless exists? | ||
url = "https://#{name}.queue#{@azure.storage_endpoint_suffix}" | ||
param = { restype: 'service', comp: 'properties' } | ||
# @see #queues for the header `x-ms-version` | ||
headers = { 'x-ms-version' => @opts[:storage_service_endpoint_api_version] } | ||
body = @azure.rest_get_call(url, param, headers) | ||
return unless body | ||
body_hash = Hash.from_xml(body) | ||
hash_with_snakecase_keys = RecursiveMethodHelper.method_recursive(body_hash, :snakecase) | ||
properties = hash_with_snakecase_keys['storage_service_properties'] | ||
if properties | ||
create_resource_methods({ queue_properties: properties }) | ||
public_send(:queue_properties) if respond_to?(:queue_properties) | ||
end | ||
end | ||
|
||
private | ||
|
||
# @see AzureKeyVault#diagnostic_settings for how to use #additional_resource_properties method. | ||
# | ||
def activity_log_alert_filter(filter) | ||
return unless exists? | ||
# `additional_resource_properties` method will create a singleton method with the `property_name` | ||
# and make api response available through this property. | ||
additional_resource_properties( | ||
{ | ||
property_name: 'activity_log_alert_filtered', | ||
property_endpoint: '/providers/microsoft.insights/eventtypes/management/values', | ||
add_subscription_id: true, | ||
api_version: @opts[:activity_log_alert_api_version], | ||
filter_free_text: filter, | ||
}, | ||
) | ||
end | ||
|
||
def to_utc(datetime) | ||
# API requires times in UTC ISO8601 format. | ||
datetime.to_time.utc.iso8601 | ||
end | ||
end | ||
|
||
# Provide the same functionality under the old resource name. | ||
# This is for backward compatibility. | ||
class AzurermStorageAccount < AzureStorageAccount | ||
name 'azurerm_storage_account' | ||
desc 'Verifies settings for a Azure Storage Account' | ||
example <<-EXAMPLE | ||
describe azurerm_storage_account(resource_group: resource_name, name: 'default') do | ||
it { should exist } | ||
end | ||
EXAMPLE | ||
|
||
def initialize(opts = {}) | ||
Inspec::Log.warn Helpers.resource_deprecation_message(@__resource_name__, AzureStorageAccount.name) | ||
super | ||
end | ||
end |
Oops, something went wrong.