New Skeletal Resource aws_sns_subscription (#2697)

* Initial commit of skeletal resource aws_sns_subscription
* Fixes errors in documentation
* Clarifies documentation
* Wraps calls to aws api in catch_aws_errors metho
* Fixes integration tests

Signed-off-by: Matthew Dromazos <dromazmj@dukes.jmu.edu>
This commit is contained in:
Matthew Dromazos 2018-03-22 13:38:40 -04:00 committed by Jared Quick
parent eb5302074a
commit 9077a7b17b
6 changed files with 419 additions and 1 deletions

View file

@ -0,0 +1,125 @@
---
title: About the aws_sns_subscription Resource
---
# aws\_sns\_subscription
Use the `aws_sns_subscription` InSpec audit resource to test detailed properties of a AWS SNS Subscription.
<br>
## Syntax
An `aws_sns_subscription` resource block uses resource parameters to search for a SNS Subscription, and then tests that subscriptions properties. If no Subscriptions match, no error is raised, but the `exists` matcher will return `false` and all properties will be `nil`.
describe aws_sns_subscription('arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6') do
it { should exist }
end
<br>
## Examples
The following examples show how to use this InSpec audit resource.
As this is the initial release of `aws_sns_subscription`, its limited functionality precludes examples.
<br>
## Resource Parameters
This InSpec resource accepts the following parameters, which are used to search for the Security Group.
### subscription\_arn
The ARN (Amazon Resource Name) of the AWS SNS Subscription.
# Using Hash syntax
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6') do
it { should exist }
end
# Or omit hash syntax, rely on it being the default parameter
describe aws_sns_subscription('arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6') do
it { should exist }
end
<br>
## Matchers
### exists
The control will pass if the specified Aws Subscription was found. Use should_not if you want to verify that the specified Subscription does not exist.
# Test that a specific subscription exists.
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6')
it { should exist }
end
# Test that a Subscription does not exist.
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::NOGOOD:b214aff5-a2c7-438f-a753-8494493f2ff6')
it { should_not exist }
end
### be\_confirmation\_authenticated
Provides whether or not the subscription confirmation request was authenticated.
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::NOGOOD:b214aff5-a2c7-438f-a753-8494493f2ff6')
it { should be_confirmation_authenticated }
end
### have\_raw\_message\_delivery
Provides whether or not the original message is passed as is, not formatted as a json or yaml.
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::NOGOOD:b214aff5-a2c7-438f-a753-8494493f2ff6')
it { should have_raw_message_delivery }
end
## Properties
### endpoint
Provides the destination that the SNS Topic will send notifications to.
# Inspect the endpoint
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6' ) do
# If protocol is 'sms', this should be a phone number:
its('endpoint') { should cmp '+16105551234' }
# If protocol is 'email' or 'email-json', endpoint should be an email address
its('endpoint') { should cmp 'myemail@example.com' }
# If protocal is 'http', endpoint should be a URL beginning with 'https://'
its('endpoint') { should cmp 'https://www.exampleurl.com' }
# If the protocol is 'lambda', its endpoint should be the ARN of a AWS Lambda function
its('endpoint') { should cmp 'rn:aws:lambda:us-east-1:account-id:function:myfunction' }
end
### owner
Provides the AWS Owners ID.
# Inspect the owners ID
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6' ) do
its('owner') { should cmp '12345678' }
end
### protocol
Provides the Subscriptions protocol used. For example http, https, email, email-json, sqs, etc. For more information about protocols please visit https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html
# Inspect the endpoint
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6' ) do
its('protocol') { should cmp 'sqs' }
end
### topic\_arn
Provides the SNS Topic arn that the Subscription is associated with.
# Inspect the topic arn
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6' ) do
its('topic_arn') { should cmp 'arn:aws:sns:us-east-1::test-topic-01' }
end

View file

@ -35,6 +35,7 @@ require 'resources/aws/aws_s3_bucket'
require 'resources/aws/aws_s3_bucket_object'
require 'resources/aws/aws_security_group'
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_subnet'

View file

@ -0,0 +1,78 @@
class AwsSnsSubscription < Inspec.resource(1)
name 'aws_sns_subscription'
desc 'Verifies settings for an SNS Subscription'
example "
describe aws_sns_subscription('arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6') do
it { should_not have_raw_message_delivery }
it { should be_confirmation_authenticated }
its('owner') { should cmp '12345678' }
its('topic_arn') { should cmp 'arn:aws:sns:us-east-1::test-topic-01' }
its('endpoint') { should cmp 'arn:aws:sqs:us-east-1::test-queue-01' }
its('protocol') { should cmp 'sqs' }
end
"
supports platform: 'aws'
include AwsSingularResourceMixin
attr_reader :arn, :owner, :raw_message_delivery, :topic_arn, :endpoint, :protocol,
:confirmation_was_authenticated, :aws_response
alias confirmation_authenticated? confirmation_was_authenticated
alias raw_message_delivery? raw_message_delivery
def has_raw_message_delivery?
raw_message_delivery
end
def to_s
"SNS Subscription #{@arn}"
end
private
def validate_params(raw_params)
validated_params = check_resource_param_names(
raw_params: raw_params,
allowed_params: [:subscription_arn],
allowed_scalar_name: :subscription_arn,
allowed_scalar_type: String,
)
if validated_params.empty?
raise ArgumentError, 'You must provide a subscription_arn to aws_sns_subscription.'
end
validated_params
end
def fetch_from_api
backend = BackendFactory.create(inspec_runner)
catch_aws_errors do
begin
aws_response = backend.get_subscription_attributes(subscription_arn: @subscription_arn).attributes
@exists = true
@owner = aws_response['Owner']
@raw_message_delivery = aws_response['RawMessageDelivery'].eql?('true')
@topic_arn = aws_response['TopicArn']
@endpoint = aws_response['Endpoint']
@protocol = aws_response['Protocol']
@confirmation_was_authenticated = aws_response['ConfirmationWasAuthenticated'].eql?('true')
rescue Aws::SNS::Errors::NotFound
@exists = false
return
end
end
end
class Backend
class AwsClientApi < AwsBackendBase
BackendFactory.set_default_backend self
self.aws_client_class = Aws::SNS::Client
def get_subscription_attributes(criteria)
aws_service_client.get_subscription_attributes(criteria)
end
end
end
end

View file

@ -34,4 +34,30 @@ resource "aws_sns_topic" "sns_test_topic_2" {
output "sns_topic_no_subscription_arn" {
value = "${aws_sns_topic.sns_test_topic_2.arn}"
}
}
resource "aws_sns_topic" "topic_for_sub_03" {
name = "${terraform.env}-topic_for_sub_3_test"
}
resource "aws_sqs_queue" "sqs_for_sub_03" {
name = "${terraform.env}-sqs_for_sub_03"
}
resource "aws_sns_topic_subscription" "subscription_3" {
topic_arn = "${aws_sns_topic.topic_for_sub_03.arn}"
protocol = "sqs"
endpoint = "${aws_sqs_queue.sqs_for_sub_03.arn}"
}
output "sns_subscription_03_arn" {
value = "${aws_sns_topic_subscription.subscription_3.arn}"
}
output "sns_topic_3_arn" {
value = "${aws_sns_topic.topic_for_sub_03.arn}"
}
output "sqs_for_sub_03_arn" {
value = "${aws_sqs_queue.sqs_for_sub_03.arn}"
}

View file

@ -0,0 +1,44 @@
fixtures = {}
[
'sns_subscription_03_arn',
'sns_topic_3_arn',
'sqs_for_sub_03_arn',
'aws_account_id',
].each do |fixture_name|
fixtures[fixture_name] = attribute(
fixture_name,
default: "default.#{fixture_name}",
description: 'See ../build/sns.tf',
)
end
control "aws_sns_subscription recall of default VPC" do
# Test constructor scalar hit
describe aws_sns_subscription(fixtures['sns_subscription_03_arn']) do
it { should exist }
end
# Test constructor hash hit
describe aws_sns_subscription(subscription_arn: fixtures['sns_subscription_03_arn']) do
it { should exist }
end
describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1:721741954427:NonExistentSubscrtiption:bf007420-6-45-96-9c2bf144') do
it { should_not exist }
end
end
control "aws_sns_subscription properties" do
describe aws_sns_subscription(fixtures['sns_subscription_03_arn']) do
its('topic_arn') { should eq fixtures['sns_topic_3_arn'] }
its('endpoint') { should eq fixtures['sqs_for_sub_03_arn'] }
its('protocol') { should eq 'sqs' }
its('owner') { should cmp fixtures['aws_account_id'] }
end
end
control "aws_sns_subscription matchers" do
describe aws_sns_subscription(fixtures['sns_subscription_03_arn']) do
it { should_not have_raw_message_delivery }
it { should be_confirmation_authenticated }
end
end

View file

@ -0,0 +1,144 @@
require 'helper'
# MASSSB = MockAwsSNSSubscriptionSingularBackend
# Abbreviation not used outside this file
#=============================================================================#
# Constructor Tests
#=============================================================================#
class AwsSnsSubscriptionConstructorTest < Minitest::Test
def setup
AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic)
end
def test_empty_params_not_ok
assert_raises(ArgumentError) { AwsSnsSubscription.new }
end
def test_accepts_subscription_arn_as_scalar
AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f')
end
def test_accepts_subscription_arn_as_hash
AwsSnsSubscription.new(subscription_arn: 'arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f')
end
end
#=============================================================================#
# Search / Recall
#=============================================================================#
class AwsSnsSubscriptionRecallTest < Minitest::Test
def setup
AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic)
end
def test_search_hit_via_scalar_works
assert AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').exists?
end
def test_search_hit_via_hash_works
assert AwsSnsSubscription.new(subscription_arn: 'arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').exists?
end
def test_search_miss_is_not_an_exception
refute AwsSnsSubscription.new(subscription_arn: 'arn:aws:sns:us-west-2:0123456789012:my-topic_non_existent:8a21d249-4329-4871-00000-00000000').exists?
end
end
#=============================================================================#
# Properties
#=============================================================================#
class AwsSnsSubscriptionPropertiesTest < Minitest::Test
def setup
AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic)
end
def test_property_topic_arn
assert_equal('arn:aws:sns:us-west-2:0123456789012:my-topic2', AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').topic_arn)
assert_nil(AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000').topic_arn)
end
def test_property_endpoint
assert_equal('my-email2@example.com', AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').endpoint)
assert_nil(AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000').endpoint)
end
def test_property_protocol
assert_equal('https', AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').protocol)
assert_equal('email', AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f').protocol)
assert_nil(AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000').protocol)
end
def test_property_owner
assert_equal('0123456789012', AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').owner)
assert_nil(AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000').owner)
end
end
#=============================================================================#
# Matchers
#=============================================================================#
class AwsSnsSubscriptionMatchersTest < Minitest::Test
def setup
AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic)
end
def test_matcher_raw_message_delivery_positive
assert AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').raw_message_delivery?
end
def test_matcher_raw_message_delivery_negative
refute AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f').raw_message_delivery?
end
def test_matcher_confirmation_authenticated_positive
assert AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f').confirmation_authenticated?
end
def test_matcher_confirmation_authenticated_negative
refute AwsSnsSubscription.new('arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f').confirmation_authenticated?
end
end
#=============================================================================#
# Test Fixtures
#=============================================================================#
module AwsMASSSB
class Basic < AwsBackendBase
def get_subscription_attributes(query)
fixtures = OpenStruct.new({
'arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f' => OpenStruct.new({
"attributes" => OpenStruct.new({
"Endpoint": "my-email@example.com",
"Protocol": "email",
"RawMessageDelivery": "false",
"ConfirmationWasAuthenticated": "false",
"Owner": "0123456789012",
"SubscriptionArn": "arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f",
"TopicArn": "arn:aws:sns:us-west-2:0123456789012:my-topic"
}),
}),
'arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f' => OpenStruct.new({
"attributes" => OpenStruct.new({
"Endpoint": "my-email2@example.com",
"Protocol": "https",
"RawMessageDelivery": "true",
"ConfirmationWasAuthenticated": "true",
"Owner": "0123456789012",
"SubscriptionArn": "arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f",
"TopicArn": "arn:aws:sns:us-west-2:0123456789012:my-topic2"
}),
}),
})
return OpenStruct.new(fixtures[query[:subscription_arn]] ) unless fixtures[query[:subscription_arn]].nil?
raise Aws::SNS::Errors::NotFound.new(Seahorse::Client::Http::Request, "Key does not exist")
end
end
end