Added integration tests for current resources

Closes #19

Signed-off-by: Russell Seymour <russell.seymour@turtlesystems.co.uk>
This commit is contained in:
Russell Seymour 2017-02-28 14:21:57 +00:00 committed by Christoph Hartmann
parent 668b4086f3
commit ec072cadd3
14 changed files with 334 additions and 77 deletions

2
.gitignore vendored
View file

@ -4,3 +4,5 @@
Gemfile.lock
inspec.lock
.kitchen
*.plan
*.tfstate*

View file

@ -11,6 +11,7 @@ group :development do
gem 'rubocop'
gem 'github_changelog_generator'
gem 'pry-coolline'
gem 'passgen'
end
group :inspec do

View file

@ -4,8 +4,8 @@ This resource pack provides resources for Azure Resources. It will ship with th
```
├── README.md - this readme
├── controls - contains example controls
└── libraries - contains Azure resources
└── test - contains integration tests
```
## Get Started
@ -212,14 +212,21 @@ control 'azure-1' do
end
```
### Using the example controls
## Testing
There a number of example controls that have been added to this resource. They are driven by environment variables to make them easier to run. For example the following would test a machine called `example-01` in the resource group `exmaple-rg`.
The `test/integration/verify/controls` directory contains all of the tests that are run during integration tests. These can be used as examples of how to use this resource pack.
Rake tasks have been configured to enable the running of the integration tests:
```bash
$> AZURE_VM_NAME='example-01' AZURE_RESOURCE_GROUP_NAME='example-rg' bundle exec inspec exec .
rake changelog # Generate a Change log from GitHub
rake lint # Run robocop linter
rake rubocop # Run Rubocop lint checks
rake test:integration # Perform Integration Tests
```
As with using the resources themselves the integration tests rely on a Service Principal Name being defined. Please see the information at the start of this page on how to generate this.
## License
| | |

View file

@ -2,6 +2,9 @@
require 'rake/testtask'
require 'rubocop/rake_task'
require 'inifile'
require 'passgen'
require_relative 'libraries/azure_backend'
# Rubocop
desc 'Run Rubocop lint checks'
@ -17,10 +20,59 @@ task lint: [:rubocop]
task default: [:lint]
namespace :test do
# Specify the directory for the integration tests
integration_dir = "test/integration"
# run inspec check to verify that the profile is properly configured
task :check do
dir = File.join(File.dirname(__FILE__))
sh("bundle exec inspec check #{dir}")
#task :check do
# dir = File.join(File.dirname(__FILE__))
# sh("bundle exec inspec check #{dir}")
#end
task :setup_integration_tests do
azure_backend = AzureConnection.new
creds = azure_backend.spn
# Determine the storage account name and the admin password
sa_name = (0...15).map { (65 + rand(26)).chr }.join.downcase
admin_password = Passgen::generate(length: 12, uppercase: true, lowercase: true, symbols: true, digits: true)
puts "----> Setup"
# Create the plan that can be applied to Azure
cmd = format("cd %s/build/ && terraform plan -var 'subscription_id=%s' -var 'client_id=%s' -var 'client_secret=%s' -var 'tenant_id=%s' -var='storage_account_name=%s' -var='admin_password=%s' -out inspec-azure.plan", integration_dir, creds[:subscription_id], creds[:client_id], creds[:client_secret], creds[:tenant_id], sa_name, admin_password)
sh(cmd)
# Apply the plan on Azure
cmd = format("cd %s/build/ && terraform apply inspec-azure.plan", integration_dir)
sh(cmd)
end
task :run_integration_tests do
puts "----> Run"
cmd = format("bundle exec inspec exec %s/verify", integration_dir)
sh(cmd)
end
task :cleanup_integration_tests do
azure_backend = AzureConnection.new
creds = azure_backend.spn
puts "----> Cleanup"
cmd = format("cd %s/build/ && terraform destroy -force -var 'subscription_id=%s' -var 'client_id=%s' -var 'client_secret=%s' -var 'tenant_id=%s' -var='admin_password=dummy' -var='storage_account_name=dummy'", integration_dir, creds[:subscription_id], creds[:client_id], creds[:client_secret], creds[:tenant_id])
sh(cmd)
end
desc "Perform Integration Tests"
task :integration do
Rake::Task["test:cleanup_integration_tests"].execute
Rake::Task["test:setup_integration_tests"].execute
Rake::Task["test:run_integration_tests"].execute
Rake::Task["test:cleanup_integration_tests"].execute
end
end

View file

@ -1,22 +0,0 @@
title 'Sample profile to test names resource group'
control 'azure-rg-1.0' do
impact 1.0
title 'Ensure that a resource group has the correct resources'
resource_group_name = ENV['AZURE_RESOURCE_GROUP_NAME']
describe azure_rg(name: resource_group_name) do
its('total') { should be >= 7 }
its('vm_count') { should eq 1 }
end
describe azure_rg(name: resource_group_name).where { type == 'Microsoft.Storage/storageAccounts' }.entries do
its('count') { should eq 1 }
end
describe azure_rg(name: resource_group_name).contains(parameter: 'name', value: 'example-VM-ip') do
it { should be true }
end
end

View file

@ -1,19 +0,0 @@
title 'Sample profile to test the data disks of a vm'
control 'azure-vm-datadisks-1.0' do
impact 1.0
title 'Ensure that the machine has 1 data disk'
hostname = ENV['AZURE_VM_NAME']
resource_group_name = ENV['AZURE_RESOURCE_GROUP_NAME']
describe azure_vm_datadisks(host: hostname, resource_group: resource_group_name) do
its('has_disks?') { should be true }
its('count') { should eq 1 }
end
describe azure_vm_datadisks(host: hostname, resource_group: resource_group_name).where { disk.zero? and size > 10 } do
its('entries') { should_not be_empty }
end
end

View file

@ -1,24 +0,0 @@
title 'Sample profile to test the Image SKU of a vm'
control 'azure-vm-1.0' do
impact 1.0
title 'Ensure that the machine has an image SKU of 16.04.0-LTS'
hostname = ENV['AZURE_VM_NAME']
resource_group_name = ENV['AZURE_RESOURCE_GROUP_NAME']
describe azure_vm(host: hostname, resource_group: resource_group_name) do
its('sku') { should eq '16.04-LTS' }
its('publisher') { should eq 'Canonical' }
its('offer') { should eq 'UbuntuServer' }
its('size') { should eq 'Standard_DS1_v2' }
its('location') { should eq 'westeurope' }
its('boot_diagnostics?') { should be true }
its('nic_count') { should eq 1 }
its('username') { should eq 'azure' }
its('password_authentication?') { should be false }
its('ssh_key_count') { should eq 1 }
its('os_type') { should eq 'Linux' }
end
end

View file

@ -40,6 +40,19 @@ class AzureConnection
# If a connection already exists then return it
return @conn if defined?(@conn)
creds = spn
# Create a new connection
token_provider = MsRestAzure::ApplicationTokenProvider.new(creds[:tenant_id], creds[:client_id], creds[:client_secret])
@conn = MsRest::TokenCredentials.new(token_provider)
end
# Method to retrieve the SPN credentials
# This is also used by the Rakefile to get the necessary creds to run the tests on the environment
# that has been created
#
# @author Russell Seymour
def spn
@subscription_id = azure_subscription_id
# Check that the credential exists
@ -50,9 +63,8 @@ class AzureConnection
client_id = ENV['AZURE_CLIENT_ID'] || @credentials[subscription_id]['client_id']
client_secret = ENV['AZURE_CLIENT_SECRET'] || @credentials[subscription_id]['client_secret']
# Create a new connection
token_provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
@conn = MsRest::TokenCredentials.new(token_provider)
# Return hash of the SPN information
{ subscription_id: subscription_id, client_id: client_id, client_secret: client_secret, tenant_id: tenant_id }
end
private

View file

@ -82,7 +82,11 @@ class AzureVm < Inspec.resource(1)
# @return [Boolean]
#
def boot_diagnostics?
vm.diagnostics_profile.boot_diagnostics.enabled
if vm.diagnostics_profile
vm.diagnostics_profile.boot_diagnostics.enabled
else
false
end
end
# Determine how many network cards are connected to the machine
@ -138,7 +142,7 @@ class AzureVm < Inspec.resource(1)
# @return [Integer]
#
def ssh_key_count
if !vm.os_profile.linux_configuration.nil?
if !vm.os_profile.linux_configuration.nil? && !vm.os_profile.linux_configuration.ssh.nil?
vm.os_profile.linux_configuration.ssh.public_keys.length
else
0

View file

@ -0,0 +1,173 @@
# Configure variables
variable "storage_account_name" {}
variable "admin_password" {}
variable "subscription_id" {}
variable "client_id" {}
variable "client_secret" {}
variable "tenant_id" {}
variable "location" {
default = "West Europe"
}
# Configure the Azure RM provider
provider "azurerm" {
subscription_id = "${var.subscription_id}"
client_id = "${var.client_id}"
client_secret = "${var.client_secret}"
tenant_id = "${var.tenant_id}"
}
# Create a resource group for the machine to be created in
resource "azurerm_resource_group" "rg" {
name = "Inspec-Azure"
location = "${var.location}"
}
# Create the storage account to be used
resource "azurerm_storage_account" "sa" {
name = "${var.storage_account_name}"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
account_type = "Standard_LRS"
}
# Create the container in which the hard disks for the machine(s) will be stored
resource "azurerm_storage_container" "container" {
name = "vhds"
resource_group_name = "${azurerm_resource_group.rg.name}"
storage_account_name = "${azurerm_storage_account.sa.name}"
container_access_type = "private"
}
# Create a Public IP
resource "azurerm_public_ip" "public_ip_1" {
name = "Inspec-PublicIP-1"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
public_ip_address_allocation = "dynamic"
domain_name_label = "linux-inspec-1"
}
# Create the virtual network for the machines
resource "azurerm_virtual_network" "vnet" {
name = "Inspec-VNet"
address_space = ["10.1.1.0/24"]
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
}
# Create the subnet
resource "azurerm_subnet" "subnet" {
name = "Inspec-Subnet"
resource_group_name = "${azurerm_resource_group.rg.name}"
virtual_network_name = "${azurerm_virtual_network.vnet.name}"
address_prefix = "10.1.1.0/24"
}
# Create the NIC for the machine
resource "azurerm_network_interface" "nic1" {
name = "Inspec-NIC-1"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
ip_configuration {
name = "ipConfiguration1"
subnet_id = "${azurerm_subnet.subnet.id}"
private_ip_address_allocation = "dynamic"
}
}
resource "azurerm_network_interface" "nic2" {
name = "Inspec-NIC-2"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
ip_configuration {
name = "ipConfiguration1"
subnet_id = "${azurerm_subnet.subnet.id}"
private_ip_address_allocation = "dynamic"
public_ip_address_id = "${azurerm_public_ip.public_ip_1.id}"
}
}
# Create the machine for testing
resource "azurerm_virtual_machine" "vm_linux_internal" {
name = "Linux-Internal-VM"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
network_interface_ids = ["${azurerm_network_interface.nic1.id}"]
vm_size = "Standard_DS2_v2"
# Configure machine with Ubuntu
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04.0-LTS"
version = "latest"
}
# Create the OS disk
storage_os_disk {
name = "linux-internal-osdisk"
vhd_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}${azurerm_storage_container.container.name}/linux-internal-osdisk.vhd"
caching = "ReadWrite"
create_option = "FromImage"
}
# Create 1 data disk to be used for testing
storage_data_disk {
name = "linux-datadisk-1"
vhd_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}${azurerm_storage_container.container.name}/linux-internal-datadisk-1.vhd"
disk_size_gb = 15
create_option = "empty"
lun = 0
}
# Specify the name of the machine and the access credentials
os_profile {
computer_name = "linux-internal-1"
admin_username = "azure"
admin_password = "${var.admin_password}"
}
os_profile_linux_config {
disable_password_authentication = false
}
}
resource "azurerm_virtual_machine" "vm_linux_external" {
name = "Linux-External-VM"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
network_interface_ids = ["${azurerm_network_interface.nic2.id}"]
vm_size = "Standard_DS2_v2"
# Configure machine with Ubuntu
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04.0-LTS"
version = "latest"
}
# Create the OS disk
storage_os_disk {
name = "linux-external-osdisk"
vhd_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}${azurerm_storage_container.container.name}/linux-external-osdisk.vhd"
caching = "ReadWrite"
create_option = "FromImage"
}
# Specify the name of the machine and the access credentials
os_profile {
computer_name = "linux-external-1"
admin_username = "azure"
admin_password = "${var.admin_password}"
}
os_profile_linux_config {
disable_password_authentication = false
}
}

View file

@ -0,0 +1,24 @@
title 'Virtual Machine Data Disks'
control 'azure-vm-datadisks-1.0' do
impact 1.0
title 'Ensure VM has 1 data disk and it is of the correct size'
# Set the name of the vm and resource_group
vm_internal = 'Linux-Internal-VM'
resource_group_name = 'Inspec-Azure'
# Ensure that the named machine has 1 data disk
describe azure_vm_datadisks(host: vm_internal, resource_group: resource_group_name) do
its('has_disks?') { should be true }
its('count') { should eq 1 }
end
# Ensure that the first data disk on the same machine size is greater than 10gb
describe azure_vm_datadisks(host: vm_internal, resource_group: resource_group_name).where { disk.zero? and size > 10 } do
its('entries') { should_not be_empty }
end
end

View file

@ -0,0 +1,19 @@
title 'Check Azure Resources'
control 'azure-resources-1.0' do
impact 1.0
title 'Check that the resource group has the correct resources'
# Ensure that the expected resources have been deployed
describe azure_rg(name: 'Inspec-Azure') do
its('total') { should eq 7 }
its('vm_count') { should eq 2 }
its('nic_count') { should eq 2 }
its('public_ip_count') { should eq 1 }
its('sa_count') { should eq 1 }
its('vnet_count') { should eq 1 }
end
end

View file

@ -0,0 +1,24 @@
title 'Virtual Machine Properties'
control 'azure-vm-1.0' do
impact 1.0
title 'Ensure VM was built with the correct Image and has the correct properties'
# Ensure that the virtual machine has been created with the correct attributes
describe azure_vm(host: 'Linux-Internal-VM', resource_group: 'Inspec-Azure') do
its('sku') { should eq '16.04.0-LTS' }
its('publisher') { should eq 'Canonical' }
its('offer') { should eq 'UbuntuServer' }
its('size') { should eq 'Standard_DS2_v2' }
its('location') { should eq 'westeurope' }
its('boot_diagnostics?') { should be false }
its('nic_count') { should eq 1 }
its('username') { should eq 'azure' }
its('password_authentication?') { should be true }
its('ssh_key_count') { should eq 0 }
its('os_type') { should eq 'Linux' }
end
end

View file

@ -0,0 +1,4 @@
name: inspec-azure-integration-tests
depends:
- name: azure
path: ../../../