aws_sqs_queue - new resource (#3674)

Signed-off-by: Amit Saha <amitsaha.in@gmail.com>
This commit is contained in:
Amit Saha 2018-12-21 06:33:21 +11:00 committed by Clinton Wolfe
parent 93223f5f2f
commit bbc07f5f11
6 changed files with 395 additions and 0 deletions

View file

@ -0,0 +1,126 @@
---
title: About the aws_sqs_queue Resource
---
# aws\_sqs\_queue
Use the `aws_sqs_queue` InSpec audit resource to test properties of a single AWS Simple Queue Service queue.
<br>
## Availability
### Installation
This resource is distributed along with InSpec itself. You can use it automatically.
### Version
This resource first became available in v3.1.4 of InSpec.
## Syntax
# Ensure that a queue exists and has a visibility timeout of 300 seconds
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
it { should exist }
its('visibility_timeout') { should be 300 }
end
# You may also use hash syntax to pass the URL
describe aws_sqs_queue(url: 'https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
it { should exist }
end
## Resource Parameters
### URL
This resource expects a single parameter, the SQS queue URL that uniquely identifies the SQS queue.
See also the [AWS documentation on SQS Queue identifiers](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-general-identifiers.html).
<br>
## Properties
### visibility\_timeout
An integer indicating the visibility timeout of the message in seconds
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
its('visibility_timeout') { should be 300}
end
### maximum\_message\_size
An integer indicating the maximum message size in bytes
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
its('maximum_message_size') { should be 262144 } # 256 KB
end
### delay\_seconds
An integer indicating the delay in seconds for the queue
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
its('delay_seconds') { should be 0 }
end
### message\_retention\_period
An integer indicating the maximum retention period for a message in seconds
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
its('message_retention_period') { should be 345600 } # 4 days
end
### receive\_message\_wait\_timeout\_seconds
An integer indicating the number of seconds an attempt to recieve a message will wait before returning
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
its('receive_message_wait_timeout_seconds') { should be 2 }
end
### is\_fifo\_queue
A boolean value indicate if this queue is a FIFO queue
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
its('is_fifo_queue') { should be false }
end
### content\_based\_deduplication
A boolean value indicate if content based dedcuplication is enabled or not
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue.fifo') do
its('is_fifo_queue') { should be true }
its('content_based_deduplication') { should be true }
end
<br>
## Matchers
This InSpec audit resource has the following special matchers. For a full list of available matchers, please visit our [matchers page](https://www.inspec.io/docs/reference/matchers/).
### exist
Indicates that the URL provided was found. Use `should_not` to test for SQS topics that should not exist.
# Expect good news
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueue') do
it { should exist }
end
# No bad news allowed
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/1212121/MyQueueWhichDoesntExist') do
it { should_not exist }
end
## AWS Permissions
Your [Principal](https://docs.aws.amazon.com/IAM/latest/UserGuide/intro-structure.html#intro-structure-principal) will need the `sqs:GetQueueAttributes` action with Effect set to Allow.
You can find detailed documentation at [Actions, Resources, and Condition Keys for Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-using-identity-based-policies.html).

View file

@ -51,6 +51,7 @@ require 'resources/aws/aws_security_groups'
require 'resources/aws/aws_sns_subscription'
require 'resources/aws/aws_sns_topic'
require 'resources/aws/aws_sns_topics'
require 'resources/aws/aws_sqs_queue'
require 'resources/aws/aws_subnet'
require 'resources/aws/aws_subnets'
require 'resources/aws/aws_vpc'

View file

@ -0,0 +1,62 @@
require 'uri'
class AwsSqsQueue < Inspec.resource(1)
name 'aws_sqs_queue'
desc 'Verifies settings for an SQS Queue'
example "
describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/519527725796/QueueName') do
it { should exist }
its('visiblity_timeout') { should be 300}
end
"
supports platform: 'aws'
include AwsSingularResourceMixin
attr_reader :arn, :is_fifo_queue, :visibility_timeout, :maximum_message_size, :message_retention_period, :delay_seconds, :receive_message_wait_timeout_seconds, :content_based_deduplication
private
def validate_params(raw_params)
validated_params = check_resource_param_names(
raw_params: raw_params,
allowed_params: [:url],
allowed_scalar_name: :url,
allowed_scalar_type: String,
)
# Validate the URL
unless validated_params[:url] =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w{https})}\z/
raise ArgumentError, 'Malformed URL for SQS. Expected an ARN of the form ' \
"'https://sqs.ap-southeast-2.amazonaws.com/111212121/MyQeueue'"
end
validated_params
end
def fetch_from_api
aws_response = BackendFactory.create(inspec_runner).get_queue_attributes(queue_url: @url, attribute_names: ['All']).attributes
@exists = true
@visibility_timeout = aws_response['VisibilityTimeout'].to_i
@maximum_message_size = aws_response['MaximumMessageSize'].to_i
@message_retention_period = aws_response['MessageRetentionPeriod'].to_i
@delay_seconds = aws_response['DelaySeconds'].to_i
@receive_message_wait_timeout_seconds = aws_response['ReceiveMessageWaitTimeSeconds'].to_i
# FIFO queues - these attributes only exist for FIFO queues, their presence indicates a FIFO
# queue
@is_fifo_queue = aws_response['FifoQueue'].nil? ? false: true
@content_based_deduplication = aws_response['ContentBasedDeduplication'].nil? ? false: true
rescue Aws::SQS::Errors::NonExistentQueue
@exists = false
end
# Uses the SDK API to really talk to AWS
class Backend
class AwsClientApi < AwsBackendBase
BackendFactory.set_default_backend(self)
self.aws_client_class = Aws::SQS::Client
def get_queue_attributes(criteria)
aws_service_client.get_queue_attributes(criteria)
end
end
end
end

View file

@ -0,0 +1,33 @@
#===========================================================================#
# SQS QUeue
#===========================================================================#
# Test fixture:
# sqs_queue_1 is a non-fifo queue
# sqs_queue_2 is a fifo queue
resource "aws_sqs_queue" "sqs_queue_1" {
name = "sqs_queue_1"
delay_seconds = 0
max_message_size = 262144 # 256 KB
message_retention_seconds = 345600 # 4 days
receive_wait_time_seconds = 2
visibility_timeout_seconds = 300 # 5 minutes
}
output "sqs_queue_1_url" {
value = "${aws_sqs_queue.sqs_queue_1.id}"
}
resource "aws_sqs_queue" "sqs_queue_2" {
name = "sqs_queue_2.fifo"
fifo_queue = true
content_based_deduplication = true
}
output "sqs_queue_2_url" {
value = "${aws_sqs_queue.sqs_queue_2.id}"
}

View file

@ -0,0 +1,47 @@
fixtures = {}
[
'sqs_queue_1_url',
'sqs_queue_2_url',
].each do |fixture_name|
fixtures[fixture_name] = attribute(
fixture_name,
default: "default.#{fixture_name}",
description: 'See ../build/sqs.tf',
)
end
control 'aws_sqs_queue lookup' do
sqs_queue1_url = fixtures['sqs_queue_1_url']
# Search miss
sqs_queue_url_non_existent = sqs_queue1_url + "random"
describe aws_sqs_queue(sqs_queue_url_non_existent) do
it { should_not exist }
end
# Search hit
describe aws_sqs_queue(sqs_queue1_url) do
it { should exist }
end
end
control "aws_sqs_queue properties" do
describe aws_sqs_queue(fixtures['sqs_queue_1_url']) do
its('delay_seconds') { should be 0 }
its('is_fifo_queue') { should be false }
its('visibility_timeout') { should be 300 }
its('maximum_message_size') { should be 262144 }
its('message_retention_period') { should be 345600 }
its('receive_message_wait_timeout_seconds') { should be 2 }
end
end
control "aws_sqs_queue fifo properties" do
describe aws_sqs_queue(fixtures['sqs_queue_2_url']) do
its('is_fifo_queue') { should be true }
its('content_based_deduplication') { should be true }
end
end

View file

@ -0,0 +1,126 @@
require 'helper'
# MSQB = MockSQsBackend
# Abbreviation not used outside this file
#=============================================================================#
# Constructor Tests
#=============================================================================#
class AwsSqsQueueConstructorTest < Minitest::Test
def setup
AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit)
end
def test_constructor_some_args_required
assert_raises(ArgumentError) { AwsSqsQueue.new }
end
def test_constructor_accepts_scalar_url
AwsSqsQueue.new('https://sqs.ap-southeast-2.amazonaws.com/5195277125796/MyQueue')
end
def test_constructor_accepts_url_as_hash
AwsSqsQueue.new(url: 'https://sqs.ap-southeast-2.amazonaws.com/5195277125796/MyQueue')
end
def test_constructor_rejects_unrecognized_resource_params
assert_raises(ArgumentError) { AwsSqsQueue.new(beep: 'boop') }
end
def test_constructor_rejects_non_https_url
[
'not-even-a-url',
'http://example.com', # http
].each do |example|
assert_raises(ArgumentError) { AwsSqsQueue.new(url: example) }
end
end
end
#=============================================================================#
# Search/Recall
#=============================================================================#
class AwsSqsQueueRecallTest < Minitest::Test
# No setup here - each test needs to explicitly declare
# what they want from the backend.
def test_recall_no_match_is_no_exception
AwsSqsQueue::BackendFactory.select(AwsMSQB::Miss)
queue = AwsSqsQueue.new('https://sqs.ap-southeast-2.amazonaws.com/12121/idontexist')
refute queue.exists?
end
def test_recall_match_single_result_works
AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit)
queue = AwsSqsQueue.new('https://sqs.ap-southeast-2.amazonaws.com/12121/iexist')
assert queue.exists?
end
end
#=============================================================================#
# Properties
#=============================================================================#
class AwsSqsQueuePropertiesTest < Minitest::Test
# No setup here - each test needs to explicitly declare
# what they want from the backend.
#---------------------------------------
# confirmed_subscription_count
#---------------------------------------
def test_visibility_timeout
AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit)
queue = AwsSqsQueue.new('https://sqs.ap-southeast-2.amazonaws.com/12121/iexist')
assert_equal(300, queue.visibility_timeout)
end
def test_not_fifo_queue
AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit)
queue = AwsSqsQueue.new('https://sqs.ap-southeast-2.amazonaws.com/12121/iexist')
refute queue.is_fifo_queue
end
def test_fifo_queue
AwsSqsQueue::BackendFactory.select(AwsMSQB::FifoQueue)
queue = AwsSqsQueue.new('https://sqs.ap-southeast-2.amazonaws.com/12121/iexist')
assert queue.is_fifo_queue
assert queue.content_based_deduplication
end
end
#=============================================================================#
# Test Fixtures
#=============================================================================#
module AwsMSQB
class Miss < AwsBackendBase
def get_queue_attributes(criteria)
raise Aws::SQS::Errors::NonExistentQueue.new("No SQS queue with URL #{criteria[:url]}", 'Nope')
end
end
class Hit < AwsBackendBase
def get_queue_attributes(_criteria)
OpenStruct.new({
attributes: {
"QueueArn" => "arn:aws:sqs:ap-southeast-2:519527721296:MyQueue",
"VisibilityTimeout" => 300
}
})
end
end
class FifoQueue < AwsBackendBase
def get_queue_attributes(_criteria)
OpenStruct.new({
attributes: {
"QueueArn" => "arn:aws:sqs:ap-southeast-2:519527721296:MyQueue.fifo",
"VisibilityTimeout" => 300,
"FifoQueue" => true,
"ContentBasedDeduplication" => true
}
})
end
end
end