From 58ee1f65153fcfa0b9bec3f75f8960f2efb48ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boles=C5=82aw=20Tekielski?= Date: Fri, 24 Jul 2020 12:45:47 +0000 Subject: [PATCH] Added support for querying public IP address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bolesław Tekielski --- README.md | 1 + docs/resources/azurerm_public_ip.md | 131 ++++++++++++++++++ libraries/azurerm_public_ip.rb | 38 +++++ libraries/support/azure/management.rb | 8 ++ terraform/azure.tf | 14 ++ terraform/outputs.tf | 5 + terraform/variables.tf | 5 + .../verify/controls/azurerm_public_ip.rb | 21 +++ 8 files changed, 223 insertions(+) create mode 100644 docs/resources/azurerm_public_ip.md create mode 100644 libraries/azurerm_public_ip.rb create mode 100644 test/integration/verify/controls/azurerm_public_ip.rb diff --git a/README.md b/README.md index 92805844f..e04011cb4 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ The following resources are available in the InSpec Azure Resource Pack - [azurerm_postgresql_databases](docs/resources/azurerm_postgresql_databases.md.erb) - [azurerm_postgresql_server](docs/resources/azurerm_postgresql_server.md.erb) - [azurerm_postgresql_servers](docs/resources/azurerm_postgresql_servers.md.erb) +- [azurerm_public_ip](docs/resources/azurerm_public_ip.md) - [azurerm_resource_groups](docs/resources/azurerm_resource_groups.md) - [azurerm_role_definition](docs/resources/azurerm_role_definition.md.erb) - [azurerm_role_definitions](docs/resources/azurerm_role_definitions.md.erb) diff --git a/docs/resources/azurerm_public_ip.md b/docs/resources/azurerm_public_ip.md new file mode 100644 index 000000000..50c70c6ac --- /dev/null +++ b/docs/resources/azurerm_public_ip.md @@ -0,0 +1,131 @@ +--- +title: About the azurerm_public_ip Resource +platform: azure +--- + +# azurerm\_public\_ip + +Use the `azurerm_public_ip` InSpec audit resource to test properties of an Azure Public IP address. + +
+ +## Azure REST API version + +This resource interacts with version `2020-05-01` of the Azure Management API. +For more information see the [official Azure documentation](https://docs.microsoft.com/en-us/rest/api/virtualnetwork/publicipaddresses/get). + +At the moment, there doesn't appear to be a way to select the version of the +Azure API docs. If you notice a newer version being referenced in the official +documentation please open an issue or submit a pull request using the updated +version. + +## Availability + +### Installation + +This resource is available in the `inspec-azure` [resource +pack](https://www.inspec.io/docs/reference/glossary/#resource-pack). To use it, add the +following to your `inspec.yml` in your top-level profile: + + depends: + - name: inspec-azure + git: https://github.com/inspec/inspec-azure.git + +You'll also need to setup your Azure credentials; see the resource pack +[README](https://github.com/inspec/inspec-azure#inspec-for-azure). + +## Syntax + +An `azurerm_public_ip` resource block identifies a public IP address by name and Resource Group. + + describe azurerm_public_ip(resource_group: 'example', name: 'addressName') do + ... + end + +
+ +## Examples + +### Test that an example Resource Group has the specified IP address + + describe azurerm_public_ip(resource_group: 'example', name: 'public_ip_address') do + it { should exist } + end + +### Test that a specified IP address IP is correct + + describe azurerm_public_ip(resource_group: 'example', name: 'ClusterName') do + its('properties.ipAddress') { should cmp '51.224.11.75' } + end + +
+ +## Parameters + + - `name` + - `resource_group` + +## Parameter Examples + +The Resource Group as well as the IP address name. + + describe azurerm_public_ip(resource_group: 'example', name: 'public_ip_address') do + it { should exist } + end + +## Attributes + +All of the attributes are avialable via dot notation. This is an example of the currently available attributes. + +``` +control 'azurerm_public_ip' do + describe azurerm_public_ip(resource_group: 'example', name: 'address_name') do + it { should exist } + its('location') { should cmp 'westeurope' } + its('properties.publicIPAddressVersion') { should eq 'IPv4' } + its('properties.sku.name') { should eq 'Standard' } + end +end +``` + + +### Other Attributes + +There are additional attributes that may be accessed that we have not +documented. Please take a look at the [Azure documentation](#-Azure-REST-API-version). +Any attribute in the response may be accessed with the key names separated by +dots (`.`). + +The API may not always return keys that do not have any associated data. There +may be cases where the deeply nested property may not have the desired +attribute along your call chain. If you find yourself writing tests against +properties that may be nil, fork this resource pack and add an accessor to the +resource. Within that accessor you'll be able to guard against nil keys. Pull +requests are always welcome. + +## 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 resource returns a result. Use `should_not` if you expect +zero matches. + + # If we expect 'AddressName' to always exist + describe azurerm_public_ip(resource_group: 'example', name: 'AddressName') do + it { should exist } + end + + # If we expect 'AddressName' to never exist + describe azurerm_public_ip(resource_group: 'example', name: 'AddressName') 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. diff --git a/libraries/azurerm_public_ip.rb b/libraries/azurerm_public_ip.rb new file mode 100644 index 000000000..bb3ac7ad5 --- /dev/null +++ b/libraries/azurerm_public_ip.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'azurerm_resource' + +class AzurermPublicIp < AzurermSingularResource + name 'azurerm_public_ip' + desc 'Verifies settings for public IP address' + example <<-EXAMPLE + describe azurerm_public_ip(resource_group: 'example', name: 'name') do + its(name) { should eq 'name'} + end + EXAMPLE + + ATTRS = %i( + name + id + etag + type + location + tags + properties + ).freeze + + attr_reader(*ATTRS) + + def initialize(resource_group: nil, name: nil) + resp = management.public_ip(resource_group, name) + return if has_error?(resp) + + assign_fields(ATTRS, resp) + + @exists = true + end + + def to_s + "'#{name}' Public IP address" + end +end diff --git a/libraries/support/azure/management.rb b/libraries/support/azure/management.rb index a9422e2f7..8c82a30f0 100644 --- a/libraries/support/azure/management.rb +++ b/libraries/support/azure/management.rb @@ -287,6 +287,14 @@ def postgresql_databases(resource_group, server_name) ) end + def public_ip(resource_group, address_name) + get( + url: link(location: "Microsoft.Network/publicIPAddresses/#{address_name}", + resource_group: resource_group), + api_version: '2020-05-01', + ) + end + def resource_groups get( url: link(location: 'resourcegroups', provider: false), diff --git a/terraform/azure.tf b/terraform/azure.tf index 6fb40362e..e370dc30c 100644 --- a/terraform/azure.tf +++ b/terraform/azure.tf @@ -1033,3 +1033,17 @@ resource "azurerm_application_gateway" "network" { policy_type = "Predefined" } } + +resource "random_string" "ip-address-random" { + length = 10 + special = false + upper = false +} + +resource "azurerm_public_ip" "public_ip_address" { + count = var.public_ip_address_count + name = random_string.ip-address-random.result + location = var.location + resource_group_name = azurerm_resource_group.rg.name + allocation_method = "Dynamic" +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf index 4e0a791bc..535df10fa 100644 --- a/terraform/outputs.tf +++ b/terraform/outputs.tf @@ -314,4 +314,9 @@ output "application_gateway_name" { output "hdinsight_cluster_name" { description = "HDINSIGHT cluster name." value = var.hd_insight_count > 0 ? azurerm_hdinsight_interactive_query_cluster.hdinsight_cluster.0.name : "" +} + +output "ap_address_name" { + description = "tha name of the azurerm_public_ip" + value = var.public_ip_address_count > 0 ? azurerm_public_ip.public_ip_address[0].name : "" } \ No newline at end of file diff --git a/terraform/variables.tf b/terraform/variables.tf index c0799af8e..8ba8e32b1 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -98,4 +98,9 @@ variable "lb_port" { variable "hd_insight_count" { # This is added due to resource constraints. default = 0 +} + +variable "public_ip_address_count" { + # This is added due to resource constraints. + default = 0 } \ No newline at end of file diff --git a/test/integration/verify/controls/azurerm_public_ip.rb b/test/integration/verify/controls/azurerm_public_ip.rb new file mode 100644 index 000000000..4e811cf25 --- /dev/null +++ b/test/integration/verify/controls/azurerm_public_ip.rb @@ -0,0 +1,21 @@ +resource_group = input('resource_group', value: nil) +address_name = input('ip_address_name', value: '') + +control 'azurerm_public_ip' do + only_if { !address_name.empty? } + describe azurerm_public_ip(resource_group: resource_group, name: address_name) do + it { should exist } + its('name') { should cmp address_name } + its('type') { should cmp 'Microsoft.Network/publicIPAddresses' } + its('properties.provisioningState') { should cmp 'Succeeded' } + its('properties.publicIPAddressVersion') { should eq 'IPv4' } + end + + describe azurerm_public_ip(resource_group: resource_group, name: 'fake') do + it { should_not exist } + end + + describe azurerm_public_ip(resource_group: 'does-not-exist', name: 'fake') do + it { should_not exist } + end +end