mirror of
https://github.com/inspec/inspec
synced 2024-11-23 13:13:22 +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_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'
|
||||
|
|
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