- Project State: Maintained
For more information on project states and SLAs, see this documentation.
This InSpec resource pack uses the Azure REST API and provides the required resources to write tests for resources in Azure.
- Prerequisites
- Resource Documentation
- Examples
- Parameters Applicable To All Resources
- Connectors
- Development
- Ruby
- Bundler installed
- Azure Service Principal Account
- Azure Service Principal may read the Azure Active Directory
Your Azure Service Principal Account must have contributor role to any subscription that you'd like to use this resource pack against. You should have the following pieces of information:
- TENANT_ID
- CLIENT_ID
- CLIENT_SECRET
- SUBSCRIPTION_ID
To create your account Service Principal Account:
- Login to the Azure portal.
- Click on
Azure Active Directory. - Click on
APP registrations. - Click on
New application registration. - Fill in a name and select
Webfrom theApplication Typedrop down. Save your application. - Note your Application ID. This is your
client_idabove. - Click on
Certificates & secrets - Click on
New client secret - Create a new password. This value is your
client_secretabove. - Go to your subscription (click on
All Servicesthen subscriptions). Choose your subscription from that list. - Note your Subscription ID can be found here.
- Click
Access control (IAM) - Click Add
- Select the
contributorrole. - Select the application you just created and save.
These must be stored in a environment variables prefaced with AZURE_. If you use Dotenv then you may save these values in your own .envrc file.
Either source it or run direnv allow. If you don't use Dotenv then you may just create environment variables in the way that your prefer.
Since this is an InSpec resource pack, it only defines InSpec resources. To use these resources in your own controls you should create your own profile:
$ inspec init profile --platform azure my-profile
Example inspec.yml:
name: my-profile
title: My own Azure profile
version: 0.1.0
inspec_version: '>= 4.6.9'
depends:
- name: inspec-azure
url: https://github.com/inspec/inspec-azure/archive/x.tar.gz
supports:
- platform: azure(For available inspec-azure versions, see this list of inspec-azure versions.)
The following is a list of generic resources.
- azure_generic_resource
- azure_generic_resources
- azure_graph_generic_resource
- azure_graph_generic_resources
With the generic resources:
- Azure cloud resources that this resource pack does not include a static InSpec resource for can be tested.
- Azure resources from different resource providers and resource groups can be tested at the same time.
- Server side filtering can be used for more efficient tests.
The following is a list of static resources.
The static resources derived from the generic resources prepended with azure_ are fully backward compatible with their azurerm_ counterparts.
- azure_aks_cluster
- azure_aks_clusters
- azure_api_management
- azure_api_managements
- azure_application_gateway
- azure_application_gateways
- azure_cosmosdb_database_account
- azure_event_hub_authorization_rule
- azure_event_hub_event_hub
- azure_event_hub_namespace
- azure_hdinsight_cluster
- azure_iothub
- azure_iothub_event_hub_consumer_group
- azure_iothub_event_hub_consumer_groups
- azure_graph_user
- azure_graph_users
- azure_key_vault
- azure_key_vaults
- azure_load_balancer
- azure_load_balancers
- azure_lock
- azure_locks
- azure_management_group
- azure_management_groups
- azure_mariadb_server
- azure_mariadb_servers
- azure_monitor_activity_log_alert
- azure_monitor_activity_log_alerts
- azure_monitor_log_profile
- azure_monitor_log_profiles
- azure_mysql_database
- azure_mysql_databases
- azure_mysql_server
- azure_mysql_servers
- azure_network_interface
- azure_network_interfaces
- azure_network_security_group
- azure_network_security_groups
- azure_policy_definition
- azure_policy_definitions
- azure_postgresql_database
- azure_postgresql_databases
- azure_postgresql_server
- azure_postgresql_servers
- azure_public_ip
- azure_resource_group
- azure_resource_groups
- azure_role_definition
- azure_role_definitions
- azure_security_center_policies
- azure_security_center_policy
- azure_sql_database
- azure_sql_databases
- azure_sql_server
- azure_sql_servers
- azure_storage_account
- azure_storage_accounts
- azure_storage_account_blob_container
- azure_storage_account_blob_containers
- azure_subnet
- azure_subnets
- azure_subscription
- azure_subscriptions
- azure_virtual_machine
- azure_virtual_machines
- azure_virtual_machine_disk
- azure_virtual_machine_disks
- azure_virtual_network
- azure_virtual_networks
- azure_virtual_network_gateways
- azure_webapp
- azure_webapps
For more details and different use cases, please refer to the specific resource pages.
Interrogate All Resources that Have project_A in Their Names within Your Subscription Regardless of Their Type and Resource Group
azure_generic_resources(substring_of_name: 'project_A').ids.each do |id|
describe azure_generic_resource(resource_id: id) do
its('location') { should eq 'eastus' }
end
endazure_generic_resources(tag_name: 'project_A').ids.each do |id|
describe azure_generic_resource(resource_id: id) do
its('location') { should eq 'eastus' }
end
enddescribe azure_virtual_machine(resource_group: 'MyResourceGroup', name: 'prod-web-01') do
it { should exist }
it { should have_monitoring_agent_installed }
it { should_not have_endpoint_protection_installed([]) }
it { should have_only_approved_extensions(['MicrosoftMonitoringAgent']) }
its('type') { should eq 'Microsoft.Compute/virtualMachines' }
its('installed_extensions_types') { should include('MicrosoftMonitoringAgent') }
its('installed_extensions_names') { should include('LogAnalytics') }
enddescribe azure_network_security_group(resource_group: 'ProductionResourceGroup', name: 'ProdServers') do
it { should exist }
its('type') { should eq 'Microsoft.Network/networkSecurityGroups' }
its('security_rules') { should_not be_empty }
its('default_security_rules') { should_not be_empty }
it { should_not allow_rdp_from_internet }
it { should_not allow_ssh_from_internet }
it { should allow(source_ip_range: '0.0.0.0', destination_port: '22', direction: 'inbound') }
it { should allow_in(service_tag: 'Internet', port: %w{1433-1434 1521 4300-4350 5000-6000}) }
endThe generic resources and their derivations support following parameters unless stated otherwise in their specific resource page.
As an Azure resource provider enables new features, it releases a new version of the REST API. They are generally in the format of 2020-01-01.
InSpec Azure resources can be forced to use a specific version of the API to eliminate the behavioural changes between the tests using different API versions.
The latest version will be used unless a specific version is provided.
describe azure_virtual_machine(resource_group: 'my_group', name: 'my_VM', api_version: '2020-01-01') do
its('api_version_used_for_query_state') { should eq 'user_provided' }
its('api_version_used_for_query') { should eq '2020-01-01' }
end
# `default` api version can be used if it is supported by the resource provider.
describe azure_generic_resource(resource_provider: 'Microsoft.Compute/virtualMachines', name: 'my_VM', api_version: 'default') do
its('api_version_used_for_query_state') { should eq 'default' }
end
# `latest` version will be used if it is not provided
describe azure_virtual_networks do
its('api_version_used_for_query_state') { should eq 'latest' }
end
# `latest` version will be used if the provided is invalid
describe azure_network_security_groups(resource_group: 'my_group', api_version: 'invalid_api_version') do
its('api_version_used_for_query_state') { should eq 'latest' }
endMicrosoft Azure cloud services are available through a global and three national network of datacenter as described here.
The preferred data center can be defined via endpoint parameter.
Azure Global Cloud will be used if not provided.
azure_cloud(default)azure_china_cloudazure_us_government_L4azure_us_government_L5azure_german_cloud
describe azure_virtual_machines(endpoint: 'azure_german_cloud') do
it { should exist }
endIt can be defined as an environment variable or a resource parameter (has priority).
The predefined environment variables for each cloud deployments can be found here.
The behavior of the http client can be defined with the following parameters:
azure_retry_limit: Maximum number of retries (default -2, Integer).azure_retry_backoff: Pause in seconds between retries (default -0, Integer).azure_retry_backoff_factor: The amount to multiply each successive retry's interval amount by (default -1, Integer).
They can be defined as environment variables or resource parameters (has priority).
WARNING The following resources do not support api_version, endpoint and http_client parameters and they will be deprecated in the InSpec Azure version 2.
- azurerm_ad_user
- azurerm_ad_users
- azurerm_aks_cluster
- azurerm_aks_clusters
- azurerm_api_management
- azurerm_api_managements
- azurerm_application_gateway
- azurerm_application_gateways
- azurerm_cosmosdb_database_account
- azurerm_event_hub_authorization_rule
- azurerm_event_hub_event_hub
- azurerm_event_hub_namespace
- azurerm_hdinsight_cluster
- azurerm_iothub
- azurerm_iothub_event_hub_consumer_group
- azurerm_iothub_event_hub_consumer_groups
- azurerm_key_vault
- azurerm_key_vault_key
- azurerm_key_vault_keys
- azurerm_key_vault_secret
- azurerm_key_vault_secrets
- azurerm_key_vaults
- azurerm_load_balancer
- azurerm_load_balancers
- azurerm_locks
- azurerm_management_group
- azurerm_management_groups
- azurerm_mariadb_server
- azurerm_mariadb_servers
- azurerm_monitor_activity_log_alert
- azurerm_monitor_activity_log_alerts
- azurerm_monitor_log_profile
- azurerm_monitor_log_profiles
- azurerm_mysql_database
- azurerm_mysql_databases
- azurerm_mysql_server
- azurerm_mysql_servers
- azurerm_network_interface
- azurerm_network_interfaces
- azurerm_network_security_group
- azurerm_network_security_groups
- azurerm_network_watcher
- azurerm_network_watchers
- azurerm_postgresql_database
- azurerm_postgresql_databases
- azurerm_postgresql_server
- azurerm_postgresql_servers
- azurerm_public_ip
- azurerm_resource_groups
- azurerm_role_definition
- azurerm_role_definitions
- azurerm_security_center_policies
- azurerm_security_center_policy
- azurerm_sql_database
- azurerm_sql_databases
- azurerm_sql_server
- azurerm_sql_servers
- azurerm_storage_account_blob_container
- azurerm_storage_account_blob_containers
- azurerm_subnet
- azurerm_subnets
- azurerm_subscription
- azurerm_virtual_machine
- azurerm_virtual_machine_disk
- azurerm_virtual_machine_disks
- azurerm_virtual_machines
- azurerm_virtual_network
- azurerm_virtual_networks
- azurerm_webapp
- azurerm_webapps
See Connectors for more information on the different connection strategies we support.
If you'd like to contribute to this project please see Contributing Rules.
For a detailed walk-through of resource creation, see the Resource Creation Guide.
The static resource is an InSpec Azure resource that is used to interrogate a specific Azure resource, such as, azure_virtual_machine, azure_key_vaults.
As opposed to the generic resources, they might have some static properties created by processing the dynamic properties of a resource, such as, azure_virtual_machine.admin_username.
The easiest way to start is checking the existing static resources. They have detailed information on how to leverage the backend class within their comments.
The common parameters are:
resource_provider: Such asMicrosoft.Compute/virtualMachines. It has to be hardcoded in the code by the resource author via thespecific_resource_constraintmethod, and it should be the first parameter defined in the resource. This method includes user-supplied input validation.display_name: A generic one will be created unless defined.required_parameters: Define mandatory parameters. Theresource_groupand resourcenamein the singular resources are default mandatory in the base class.allowed_parameters: Define optional parameters. Theresource_groupis optional in plural resources, but this can be made mandatory in the static resource.resource_uri: Azure REST API URI of a resource. This parameter should be used when a resource does not reside in a resource group. It requiresadd_subscription_idto be set to eithertrueorfalse. See azure_policy_definition and azure_policy_definitions.add_subscription_id: It indicates whether the subscription ID should be included in theresource_urior not.
The singular resource is used to test a specific resource of a specific type and should include all of the properties available, such as, azure_virtual_machine.
- In most cases
resource_groupand resourcenameshould be required from the users and a single API call would be enough for creating methods on the resource. See azure_virtual_machine for a standard singular resource and how to create static methods from resource properties. - If it is beneficial to accept the resource name with a more specific keyword, such as
server_name, see azure_mysql_server. - If a resource exists in another resource, such as a subnet on a virtual network, see azure_subnet.
- If it is necessary to make an additional API call within a static method, the
create_additional_propertiesshould be used. See azure_key_vault.
A plural resource is used to test the collection of resources of a specific type, such as, azure_virtual_machines. This allows for tests to be written based on the group of resources.
- A standard plural resource does not require a parameter, except optional
resource_group. See azure_mysql_servers. - All plural resources use FilterTable to be able to provide filtering within returned resources. The filter criteria must be defined
table_schemaHash variable. - If the properties of the resource are to be manipulated before populating the FilterTable, a
populate_tablemethod has to be defined. See azure_virtual_machines. - If the resources exist in another resource, such as subnets of a virtual network, a
resource_pathhas to be created. For that, the identifiers of the parent resource,resource_groupand virtual network namevnet, must be required from the users. See azure_subnets.
The following instructions will help you get your development environment setup to run integration tests.
Copy .envrc-example to .envrc and fill in the fields with the values from your account.
export AZURE_SUBSCRIPTION_ID=<subscription id>
export AZURE_CLIENT_ID=<client id>
export AZURE_TENANT_ID=<tenant id>
export AZURE_CLIENT_SECRET=<client secret>For PowerShell, set the following environment variables
$env:AZURE_SUBSCRIPTION_ID="<subscription id>"
$env:AZURE_CLIENT_ID="<client id>"
$env:AZURE_CLIENT_SECRET="<client secret>"
$env:AZURE_TENANT_ID="<tenant id>"
Setup Azure CLI
- Follow the instructions for your platform here
- macOS:
brew update && brew install azure-cli
- macOS:
- Login with the azure-cli
rake azure:login
- Verify azure-cli is logged in:
az account show
First ensure your system has Terraform (Version 0.12.0) installed.
This environment may be used to run your profile against or to run integration tests on it. We are using Terraform workspaces to allow for teams to have completely unique environments without affecting each other.
Direnv is used to initialize an environment variable WORKSPACE to your username. We recommend using direnv and allowing it to run in your environment. However, if you prefer to not use direnv you may also source .envrc.
Remote state has been removed. The first time you run Terraform after having remote state removed you will be presented with a message like:
Do you want to migrate all workspaces to "local"?
Both the existing "azurerm" backend and the newly configured "local" backend support
workspaces. When migrating between backends, Terraform will copy all
workspaces (with the same names). THIS WILL OVERWRITE any conflicting
states in the destination.
Terraform initialization doesn't currently migrate only select workspaces.
If you want to migrate a select number of workspaces, you must manually
pull and push those states.
If you answer "yes", Terraform will migrate all states. If you answer
"no", Terraform will abort.
Enter a value: yes
Enter yes or press enter.
Creating a new environment:
rake azure:login
rake tf:apply
Creating a new environment with a Network Watcher:
rake azure:login
rake network_watcher tf:apply
You may only have a single Network Watcher per a subscription. Use this carefully if you are working with other team members. Updating a running environment (e.g. when you change the .tf file):
rake azure:login
rake tf:apply
Checking if your state has diverged from your plan:
rake azure:login
rake tf:plan
Destroying your environment:
rake azure:login
rake tf:destroy
To run Rubocop and Syntax check for Ruby and InSpec:
rake test:lint
To run unit tests:
rake test:unit
To run integration tests:
rake test:integration
To run lint and unit tests:
rake
To run integration tests including a Network Watcher:
rake network_watcher test:integration
By default, rake tasks will only use core components. Optional components have associated integrations that will be skipped unless you enable these. We have the following optional pieces that may be managed with Terraform.
Network Watcher may be enabled to run integration tests related to the Network Watcher. We recommend leaving this disabled unless you are specifically working on related resources. You may only have one Network Watcher enabled per an Azure subscription at a time. To enable Network Watcher:
rake options[network_watcher]
direnv allow # or source .envrc
rake tf:apply
Graph API support may be enabled to test with azure_graph related resources.
Each resource requires specific privileges granted to your service principal.
Please refer to the Microsoft Documentation for information on how to grant these permissions to your application.
If your account does not have access, leave this disabled.
Note: An Azure Administrator must grant your application these permissions.
rake options[graph]
direnv allow # or source .envrc
rake tf:apply
WARNING This is not supported by the resources starting with
azure_.
Managed Service Identity (MSI) is another way to connect to the Azure APIs.
This option starts an additional virtual machine with MSI enabled and a public ip address. You will need to put a hole in your firewall to connect to the virtual machine. You will also need to grant the contributor role to this identity for your subscription.
rake options[msi]
direnv allow # or source .envrc
rake tf:apply
Optional Components may be combined when running tasks:
rake options[option_1,option_2,option3]
direnv allow # or source .envrc
rake tf:apply
To disable optional components run rake options[] including only the optional components you wish to enable. Any omitted component will be disabled.
rake options[] # disable all optional components
rake options[option_1] # enables option_1 disabling all other optional components