Skip to content

Commit

Permalink
CS-10 first cut. Got some testing stuff in place and the basic fetch/…
Browse files Browse the repository at this point in the history
…parse and sg convergence code going
  • Loading branch information
Eric Kascic committed Feb 18, 2016
0 parents commit 6761078
Show file tree
Hide file tree
Showing 21 changed files with 3,344 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--color
--format documentation
9 changes: 9 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
source 'https://rubygems.org'

gem 'aws-sdk'
gem 'cfndsl'

group :test do
gem 'awspec'
gem 'aws-int-test-rspec-helper'
end
72 changes: 72 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (4.2.5.1)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
aws-int-test-rspec-helper (0.0.2)
aws-sdk (= 2.2.17)
cfndsl (= 0.4.0)
rspec (= 3.4.0)
aws-sdk (2.2.17)
aws-sdk-resources (= 2.2.17)
aws-sdk-core (2.2.17)
jmespath (~> 1.0)
aws-sdk-resources (2.2.17)
aws-sdk-core (= 2.2.17)
aws_config (0.0.2)
awsecrets (1.1.0)
aws-sdk (~> 2.1)
aws_config
awspec (0.32.0)
activesupport
aws-sdk (~> 2.1)
awsecrets (~> 1)
rspec (~> 3.0)
rspec-its
term-ansicolor
thor
cfndsl (0.4.0)
diff-lcs (1.2.5)
i18n (0.7.0)
jmespath (1.1.3)
json (1.8.3)
minitest (5.8.4)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-core (3.4.2)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
rspec-mocks (3.4.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
term-ansicolor (1.3.2)
tins (~> 1.0)
thor (0.19.1)
thread_safe (0.3.5)
tins (1.8.2)
tzinfo (1.2.2)
thread_safe (~> 0.1)

PLATFORMS
ruby

DEPENDENCIES
aws-int-test-rspec-helper
aws-sdk
awspec
cfndsl

BUNDLED WITH
1.10.6
5 changes: 5 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new('awspec') do |t|
t.pattern = 'awspec/**/*_spec.rb'
end
task :default => :awspec
15 changes: 15 additions & 0 deletions awspec/lambda_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require_relative 'spec_helper'

ENV['CLOUDFRONT_ONLY_SECURITY_GROUP_LAMBDA_FUNCTION_NAME'] = 'g-sgUpdaterLambdaFunction-1AIT730QWM7QZ'

describe lambda(ENV['CLOUDFRONT_ONLY_SECURITY_GROUP_LAMBDA_FUNCTION_NAME']) do
it { should exist }
its(:handler) { should eq 'JRubyHandlerWrapper::handler' }
its(:runtime) { should eq 'java8' }
its(:timeout) { should eq 240 }
its(:memory_size) { should eq 512 }

its(:role) {
should_not eq nil
}
end
1 change: 1 addition & 0 deletions awspec/secrets.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
region: eu-west-1
2 changes: 2 additions & 0 deletions awspec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require 'awspec'
Awsecrets.load(secrets_path: File.expand_path('./secrets.yml', File.dirname(__FILE__)))
73 changes: 73 additions & 0 deletions cfn/lambda_cfndsl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require 'json'
CloudFormation {
Description 'Create Lambda function to update an sg with CloudFront IP'

Lambda_Function('sgUpdaterLambdaFunction') {
Handler 'JRubyHandlerWrapper::handler'
Runtime 'java8'
Timeout 240
MemorySize 512
Role FnGetAtt('lambdaExecutionRole', 'Arn')
Code({
'S3Bucket' => 'stelligent-binary-artifact-repo',
'S3Key' => 'cloudfront-only-security-group-1.0.0-SNAPSHOT.jar',
'S3ObjectVersion' => 'YVXfy1Jly49xDcdkmDMfSxWOKeZ3aGQv'
})
}

IAM_Role('lambdaExecutionRole') {
AssumeRolePolicyDocument(JSON.load <<-END
{
"Statement":[
{
"Action":[
"sts:AssumeRole"
],
"Effect":"Allow",
"Principal":{
"Service":[
"lambda.amazonaws.com"
]
}
}
],
"Version":"2012-10-17"
}
END
)

Policies([
{
'PolicyName' => 'ReceiveMessagesAndUpdateSecGroups',
'PolicyDocument' => (JSON.load <<-END
{
"Statement":[
{
"Action":[
"ec2:AuthorizeSecurityGroupEgress",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupEgress",
"ec2:RevokeSecurityGroupIngress"
],
"Effect":"Allow",
"Resource":"*"
},
{
"Action":[
"sns:List*",
"sns:Get*",
"sns:Confirm*",
"sns:Subscribe"
],
"Effect":"Allow",
"Resource":"*"
}
],
"Version":"2012-10-17"
}
END
)
}
])
}
}
10 changes: 10 additions & 0 deletions features/start.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Feature:
As a devsecops guy
I would like to have a security group of my choice
only allow cloudfront ingress and keep in step with changes to cloudfront ips


Scenario:
Given a security group id
When cloudfront ip is changed
Then only cloudfront ip are allowed on ingress
29 changes: 29 additions & 0 deletions lib/aws_ip_range_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'json'

class AwsIpRangeParser

# region == nil => all regions
def parse(json:,
region:nil,
service:)
ranges = JSON.load(json)

fail 'json is malformed. must have prefixes key' if ranges['prefixes'].nil?

matching_service_prefixes = ranges['prefixes'].select do |prefix|
prefix['service'] == service
end

fail "#{service} not found in supplied json" unless matching_service_prefixes.size > 0

matching_service_prefixes = ranges['prefixes'].select do |prefix|
if region.nil?
prefix['service'] == service
else
prefix['service'] == service and prefix['region'] == region
end
end
matching_service_prefixes.map { |prefixes| prefixes['ip_prefix']}
end

end
18 changes: 18 additions & 0 deletions lib/cloudfront_ip_range_fetcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'open-uri'

class CloudFrontIpRangeFetcher
IP_RANGE_ENDPOINT = 'https://ip-ranges.amazonaws.com/ip-ranges.json'

def fetch
uri = URI.parse endpoint

AwsIpRangeParser.new.parse json: uri.read,
service: 'CLOUDFRONT'
end

private

def endpoint
IP_RANGE_ENDPOINT
end
end
44 changes: 44 additions & 0 deletions lib/security_group_converger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'aws-sdk'

class SecurityGroupConverger

def converge_ingress(sg_id:, ingress_rules:)
security_group = Aws::EC2::SecurityGroup.new(sg_id)

wipe_ingress_rules(security_group)

ingress_rules.each do |ingress_rule|
security_group.authorize_ingress ip_protocol: ingress_rule[:protocol],
from_port: ingress_rule[:port],
to_port: ingress_rule[:port],
cidr_ip: ingress_rule[:cidr]
end
end

#
# probably need to discover them, cache them, add the new ones then delete the old ones
# so there is no interruption in service?
def wipe_ingress_rules(security_group)
security_group.ip_permissions.each do |ip_permission|
if ip_permission.ip_ranges.length > 0
ip_permission.ip_ranges.each do |ip_range|
puts ip_range
security_group.revoke_ingress ip_protocol: ip_permission['ip_protocol'],
from_port: ip_permission['from_port'],
to_port: ip_permission['to_port'],
cidr_ip: ip_range['cidr_ip']
end
else
fail 'something is wrong to be here'
ip_permission.user_id_group_pairs.each do |user_id_group_pair|
security_group.revoke_ingress ip_protocol: ip_permission['ip_protocol'],
from_port: ip_permission['from_port'],
to_port: ip_permission['to_port'],
source_security_group_id: user_id_group_pair['group_id']
end
end
end


end
end
Loading

0 comments on commit 6761078

Please sign in to comment.