New Skeletal Resource aws_config_delivery_channel (#2641)

* Initial commit of new skeletal resource aws_config_delivery_channel
* Changes delivery_frequency to be an integer and names delivery_frequency_in_hours
* Adds more documentation and clarifies descriptions
* Wraps API call in the aws_catch_errors function
* Changes config bucket name to use dashes instead of underscores
* Updates on master and changes directory location of build and integration files
* Fix integration tests to only create one ConfigRecorder

Signed-off-by: Matthew Dromazos <dromazmj@dukes.jmu.edu>
This commit is contained in:
Matthew Dromazos 2018-03-26 14:03:23 -04:00 committed by Jared Quick
parent afbb366e16
commit 0cbe5b60e5
5 changed files with 282 additions and 1 deletions

View file

@ -0,0 +1,79 @@
---
title: About the aws_config_delivery_channel Resource
---
# aws_config_delivery_channel
The AWS Config service can monitor and record changes to your AWS resource configurations. A Delivery Channel can record the changes
to an S3 Bucket, an SNS or both.
Use the `aws_config_delivery_channel` InSpec audit resource to examine how the AWS Config service delivers those change notifications.
<br>
## Syntax
An `aws_config_delivery_channel` resource block declares the tests for a single AWS Config delivery channel.
describe aws_config_delivery_channel('my_channel') do
it { should exist }
end
describe aws_config_delivery_channel(channel_name: 'my-channel') do
it { should exist }
end
<br>
## Examples
The following examples show how to use this InSpec audit resource.
### Test how frequent the channel writes configuration changes to the s3 bucket.
describe aws_config_delivery_channel(channel_name: 'my-recorder') do
its(delivery_frequency_in_hours) { should be > 3 }
end
## Properties
### s3_bucket_name
Provides the name of the s3 bucket that the channel sends configuration changes to. This is an optional value since a Delivery Channel can also talk to an SNS.
describe aws_config_delivery_channel(channel_name: 'my_channel')
its('s3_bucket_name') { should eq 'my_bucket' }
end
### s3_key_prefix
Provides the s3 object key prefix (or "path") under which configuration data will be recorded.
describe aws_config_delivery_channel(channel_name: 'my_channel')
its('s3_key_prefix') { should eq 'log/' }
end
### sns_topic_arn
Provides the ARN of the SNS topic for which the channel sends notifications about configuration changes.
describe aws_config_delivery_channel(channel_name: 'my_channel')
its('sns_topic_arn') { should eq 'arn:aws:sns:us-east-1:721741954427:sns_topic' }
end
### delivery_frequency_in_hours
Provides how often the AWS Config sends configuration changes to the s3 bucket in the delivery channel.
describe aws_config_delivery_channel(channel_name: 'my_channel')
its('delivery_frequency_in_hours') { should eq 24 }
its('delivery_frequency_in_hours') { should be > 24 }
end
<br>
## Matchers
This resource provides no matchers, aside from the standard exists matcher.

View file

@ -16,6 +16,7 @@ require 'resources/aws/aws_cloudtrail_trail'
require 'resources/aws/aws_cloudtrail_trails'
require 'resources/aws/aws_cloudwatch_alarm'
require 'resources/aws/aws_cloudwatch_log_metric_filter'
require 'resources/aws/aws_config_delivery_channel'
require 'resources/aws/aws_config_recorder'
require 'resources/aws/aws_ec2_instance'
require 'resources/aws/aws_iam_access_key'

View file

@ -0,0 +1,76 @@
class AwsConfigDeliveryChannel < Inspec.resource(1)
name 'aws_config_delivery_channel'
desc 'Verifies settings for AWS Config Delivery Channel'
example "
describe aws_config_delivery_channel do
it { should exist }
its('s3_bucket_name') { should eq 'my_bucket' }
its('sns_topic_arn') { should eq arn:aws:sns:us-east-1:721741954427:sns_topic' }
end
"
supports platform: 'aws'
include AwsSingularResourceMixin
attr_reader :channel_name, :s3_bucket_name, :s3_key_prefix, :sns_topic_arn,
:delivery_frequency_in_hours
def to_s
"Config_Delivery_Channel: #{@channel_name}"
end
private
def validate_params(raw_params)
validated_params = check_resource_param_names(
raw_params: raw_params,
allowed_params: [:channel_name],
allowed_scalar_name: :channel_name,
allowed_scalar_type: String,
)
# Make sure channel_name is given as param
if validated_params[:channel_name].nil?
raise ArgumentError, 'You must provide a channel_name to aws_config_delivery_channel'
end
validated_params
end
def fetch_from_api
backend = BackendFactory.create(inspec_runner)
query = { delivery_channel_names: [@channel_name] }
catch_aws_errors do
@resp = backend.describe_delivery_channels(query)
end
@exists = !@resp.empty?
return unless @exists
@channel = @resp.delivery_channels.first.to_h
@channel_name = @channel[:name]
@s3_bucket_name = @channel[:s3_bucket_name]
@s3_key_prefix = @channel[:s3_key_prefix]
@sns_topic_arn = @channel[:sns_topic_arn]
@delivery_frequency_in_hours = @channel[:config_snapshot_delivery_properties][:delivery_frequency] unless @channel[:config_snapshot_delivery_properties].nil?
frequencies = {
'One_Hour' => 1,
'TwentyFour_Hours' => 24,
'Three_Hours' => 3,
'Six_Hours' => 6,
'Twelve_Hours' => 12,
}
@delivery_frequency_in_hours = frequencies[@delivery_frequency_in_hours]
end
class Backend
class AwsClientApi < AwsBackendBase
BackendFactory.set_default_backend(self)
self.aws_client_class = Aws::ConfigService::Client
def describe_delivery_channels(query)
aws_service_client.describe_delivery_channels(query)
rescue Aws::ConfigService::Errors::NoSuchDeliveryChannelException
return {}
end
end
end
end

View file

@ -33,4 +33,81 @@ output "role_for_config_recorder_arn" {
output "config_recorder_name" {
value = "${aws_config_configuration_recorder.config_recorder.name}"
}
}
#======================================================#
# Configuration Delivery Channel
#======================================================#
# Note that since AWS accounts can only have one Config Recorder,
# we have to re-use it here (as well as its role).
resource "aws_config_delivery_channel" "delivery_channel_01" {
name = "delivery_channel_01"
s3_bucket_name = "${aws_s3_bucket.bucket_for_delivery_channel.bucket}"
depends_on = ["aws_config_configuration_recorder.config_recorder"]
sns_topic_arn = "${aws_sns_topic.sns_topic_for_delivery_channel.arn}"
snapshot_delivery_properties = {
delivery_frequency = "TwentyFour_Hours"
}
}
output "delivery_channel_01" {
value = "${aws_config_delivery_channel.delivery_channel_01.id}"
}
output "config_recorder_for_delivery_channel_role_arn" {
value = "${aws_iam_role.role_for_config_recorder.arn}"
}
#======================================================#
# IAM Roles
#======================================================#
resource "aws_iam_role_policy" "policy_for_delivery_channel" {
name = "policy_for_delivery_channel"
role = "${aws_iam_role.role_for_config_recorder.id}"
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": [
"${aws_s3_bucket.bucket_for_delivery_channel.arn}",
"${aws_s3_bucket.bucket_for_delivery_channel.arn}/*"
]
}
]
}
POLICY
}
#=================================================================#
# Config S3 Buckets
#=================================================================#
resource "aws_s3_bucket" "bucket_for_delivery_channel" {
bucket = "inspec-bucket-for-delivery-channel-${terraform.env}.chef.io"
acl = "public-read"
force_destroy = true
}
output "s3_bucket_for_delivery_channel" {
value = "${aws_s3_bucket.bucket_for_delivery_channel.id}"
}
#===========================================================================#
# SNS Topic
#===========================================================================#
resource "aws_sns_topic" "sns_topic_for_delivery_channel" {
name = "${terraform.env}-sns_topic_for_delivery_channel"
}
output "sns_topic_for_delivery_channel_arn" {
value = "${aws_sns_topic.sns_topic_for_delivery_channel.arn}"
}

View file

@ -0,0 +1,48 @@
fixtures = {}
[
'delivery_channel_01',
'config_recorder_for_delivery_channel_role_arn',
's3_bucket_for_delivery_channel',
'delivery_channel_01_bucket_prefix',
'sns_topic_for_delivery_channel_arn'
].each do |fixture_name|
fixtures[fixture_name] = attribute(
fixture_name,
default: "default.#{fixture_name}",
description: 'See ../build/iam.tf',
)
end
#======================================================#
# aws_config_delivery_channel - Singular
#======================================================#
#------------------- Recall / Miss -------------------#
control "aws_config_delivery_channel recall" do
# Test scalar param
describe aws_config_delivery_channel(fixtures['delivery_channel_01']) do
it { should exist }
end
# Test hash parameter
describe aws_config_delivery_channel(channel_name: fixtures['delivery_channel_01']) do
it { should exist }
end
# Test recorder that doesnt exist
describe aws_config_delivery_channel(channel_name: 'NonExistentChannel') do
it { should_not exist }
end
end
#------------------- Properties -------------------#
control "aws_config_delivery_channel properties" do
describe aws_config_delivery_channel(fixtures['delivery_channel_01']) do
its('s3_bucket_name') { should eq fixtures['s3_bucket_for_delivery_channel'] }
its('s3_key_prefix') { should eq nil }
its('sns_topic_arn') { should eq fixtures['sns_topic_for_delivery_channel_arn'] }
its('delivery_frequency_in_hours') { should eq 24 }
its('delivery_frequency_in_hours') { should be > 3 }
end
end