mirror of
https://github.com/inspec/inspec
synced 2024-11-26 22:50:36 +00:00
aws_sqs_queue - new resource (#3674)
Signed-off-by: Amit Saha <amitsaha.in@gmail.com>
This commit is contained in:
parent
93223f5f2f
commit
bbc07f5f11
6 changed files with 395 additions and 0 deletions
126
docs/resources/aws_sqs_queue.md.erb
Normal file
126
docs/resources/aws_sqs_queue.md.erb
Normal 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).
|
|
@ -51,6 +51,7 @@ require 'resources/aws/aws_security_groups'
|
||||||
require 'resources/aws/aws_sns_subscription'
|
require 'resources/aws/aws_sns_subscription'
|
||||||
require 'resources/aws/aws_sns_topic'
|
require 'resources/aws/aws_sns_topic'
|
||||||
require 'resources/aws/aws_sns_topics'
|
require 'resources/aws/aws_sns_topics'
|
||||||
|
require 'resources/aws/aws_sqs_queue'
|
||||||
require 'resources/aws/aws_subnet'
|
require 'resources/aws/aws_subnet'
|
||||||
require 'resources/aws/aws_subnets'
|
require 'resources/aws/aws_subnets'
|
||||||
require 'resources/aws/aws_vpc'
|
require 'resources/aws/aws_vpc'
|
||||||
|
|
62
lib/resources/aws/aws_sqs_queue.rb
Normal file
62
lib/resources/aws/aws_sqs_queue.rb
Normal 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
|
33
test/integration/aws/default/build/sqs.tf
Normal file
33
test/integration/aws/default/build/sqs.tf
Normal 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}"
|
||||||
|
}
|
|
@ -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
|
126
test/unit/resources/aws_sqs_queue_test.rb
Normal file
126
test/unit/resources/aws_sqs_queue_test.rb
Normal 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
|
Loading…
Reference in a new issue