portalign 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.md +9 -0
- data/README.md +95 -0
- data/Rakefile +4 -0
- data/bin/portalign +14 -0
- data/lib/portalign/config.rb +93 -0
- data/lib/portalign/version.rb +3 -0
- data/lib/portalign.rb +102 -0
- data/spec/portalign/config_spec.rb +57 -0
- data/spec/portalign_spec.rb +77 -0
- data/spec/spec_helper.rb +9 -0
- metadata +93 -0
data/LICENSE.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2012 The Agile League, LLC
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
portalign
|
2
|
+
=========
|
3
|
+
By Micah Wedemeyer of [The Agile League](http://agileleague.com)
|
4
|
+
|
5
|
+
|
6
|
+
Summary
|
7
|
+
=======
|
8
|
+
A tool to automatically add and remove your current IP address to Amazon EC2 security groups.
|
9
|
+
|
10
|
+
Description
|
11
|
+
===========
|
12
|
+
|
13
|
+
It's good policy to keep your security groups as restrictive as
|
14
|
+
possible. But, as is often the case with security, convenience suffers
|
15
|
+
as you get more secure. portalign is a tool that allows you to maintain
|
16
|
+
restrictive policies in your security groups while also giving
|
17
|
+
convenient access.
|
18
|
+
|
19
|
+
With portalign, you can easily update a security group to add your
|
20
|
+
current IP address to the list of allowed IPs for a port (usually 22).
|
21
|
+
So, instead of complicated port knocking schemes or ssh tunnelling
|
22
|
+
through other allowed EC2 nodes, you can ssh directly in to your machine
|
23
|
+
normally.
|
24
|
+
|
25
|
+
When you're done working on the node, portalign can restore the policy back to extreme strictness. Enable the port, do your work, disable the port. Easy and secure.
|
26
|
+
|
27
|
+
Quick Start
|
28
|
+
===========
|
29
|
+
|
30
|
+
* gem install portalign
|
31
|
+
* create a .portalign.yml file in your current project with your AWS
|
32
|
+
credentials and the security group.
|
33
|
+
* portalign
|
34
|
+
* ssh me@myserver (do what you need to on the server)
|
35
|
+
* portalign -d (to remove the authorization when you're done)
|
36
|
+
|
37
|
+
|
38
|
+
Installation
|
39
|
+
============
|
40
|
+
|
41
|
+
* gem install portalign
|
42
|
+
|
43
|
+
Configuration
|
44
|
+
=============
|
45
|
+
|
46
|
+
The preferred configuration method is using a .portalign.yml file. It
|
47
|
+
will look for one in $HOME/.portalign.yml and $PWD/.portalign.yml Any
|
48
|
+
settings found in the current directory will override those in the $HOME
|
49
|
+
directory. So, if you have multiple projects with different security
|
50
|
+
groups, you can set your AWS credentials in one file (in $HOME) and put
|
51
|
+
the various security groups in configuration files in each project.
|
52
|
+
|
53
|
+
Example File:
|
54
|
+
|
55
|
+
access_key_id: "acb1234"
|
56
|
+
secret_access_key: "1234abc"
|
57
|
+
security_groups:
|
58
|
+
- "mygroup"
|
59
|
+
- "othergroup"
|
60
|
+
ports:
|
61
|
+
- 22
|
62
|
+
- 8080
|
63
|
+
- 10000
|
64
|
+
|
65
|
+
Note: As you're probably aware, your AWS credentials are the keys to the kingdom. It's a good idea to restrict and protect the .portalign.yml file as you would a private key. chmod 600 is a good start.
|
66
|
+
|
67
|
+
Configuration Options
|
68
|
+
---------------------
|
69
|
+
* access_key_id - AWS access key
|
70
|
+
* secret_access_key - AWS secret access key
|
71
|
+
* security_groups - A list of EC2 security groups (by name, not id)
|
72
|
+
* ports - A list of ports to open (defaults to 22)
|
73
|
+
* protocol - The protocol (tcp, udp, icmp), defaults to tcp
|
74
|
+
|
75
|
+
Usage
|
76
|
+
=====
|
77
|
+
To add your current IP to the security group
|
78
|
+
|
79
|
+
portalign
|
80
|
+
|
81
|
+
To add 0.0.0.0/0 (wide open, allow any IP) to the security group
|
82
|
+
|
83
|
+
portalign -w
|
84
|
+
|
85
|
+
To remove your current IP (and 0.0.0.0/0) from the security group
|
86
|
+
|
87
|
+
portalign -d
|
88
|
+
|
89
|
+
You can also specify many configuration options on the command line. Those specified on the command line will override anything from a config file.
|
90
|
+
|
91
|
+
portalign --access-key-id=abc123 --secret-access-key=123abc --ports=22,80 --security-groups=mygroup,othergroup
|
92
|
+
|
93
|
+
License
|
94
|
+
-------
|
95
|
+
See LICENSE.md for details.
|
data/Rakefile
ADDED
data/bin/portalign
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib portalign]))
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib portalign config]))
|
5
|
+
|
6
|
+
args = ARGV
|
7
|
+
config = Portalign.build_config(args)
|
8
|
+
valid, msg = Portalign.validate_config(config)
|
9
|
+
if valid
|
10
|
+
Portalign.run(config)
|
11
|
+
else
|
12
|
+
puts msg
|
13
|
+
exit
|
14
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
class Portalign
|
5
|
+
module Config
|
6
|
+
CONFIG_FILE_NAME = ".portalign.yml"
|
7
|
+
CONFIG_FILE_PATHS = ["#{ENV["HOME"]}/#{CONFIG_FILE_NAME}", "#{CONFIG_FILE_NAME}"]
|
8
|
+
|
9
|
+
def self.load_from_file
|
10
|
+
{}.tap do |config|
|
11
|
+
config_file_paths.each do |config_path|
|
12
|
+
if File.exist?(config_path)
|
13
|
+
YAML.load_file(config_path).each do |k,v|
|
14
|
+
config[k.to_sym] = v
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
%w(ports security_groups).each {|opt| force_array(config, opt)}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parse_opts(args)
|
24
|
+
{}.tap do |config|
|
25
|
+
opts = OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: portalign [options]"
|
27
|
+
opts.separator ""
|
28
|
+
opts.separator "General options:"
|
29
|
+
opts.on("--access-key-id=ACCESS_KEY_ID", "The AWS access key id. Better to specify in a config file. See README") do |access_key_id|
|
30
|
+
config[:access_key_id] = access_key_id
|
31
|
+
end
|
32
|
+
opts.on("--secret-access-key=SECRET_ACCESS_KEY", "The AWS secret access key. Better to specify in a config file. See README") do |secret_access_key|
|
33
|
+
config[:secret_access_key] = secret_access_key
|
34
|
+
end
|
35
|
+
opts.on("-p PORTS", "--ports=PORTS", Array, "A comma delimited list of ports to align. Defaults to 22") do |ports|
|
36
|
+
config[:ports] = ports.map(&:to_i)
|
37
|
+
end
|
38
|
+
opts.on("-s SECURITY_GROUPS", "--security_groups=SECURITY_GROUPS", Array, "A comma delimited list of security groups to update.") do |security_groups|
|
39
|
+
config[:security_groups] = security_groups
|
40
|
+
end
|
41
|
+
opts.on("--protocol=PROTOCOL", [:tcp, :udp, :icmp], "The protocol to use. Defaults to tcp.") do |protocol|
|
42
|
+
config[:protocol] = protocol
|
43
|
+
end
|
44
|
+
opts.on("-d", "--deauthorize", "Remove the current IP (and 0.0.0.0/0) from the security groups.") do |deauthorize|
|
45
|
+
config[:deauthorize] = deauthorize
|
46
|
+
end
|
47
|
+
opts.on("-w", "--wide", "Authorizes 0.0.0.0/0 in the security groups.") do |wide|
|
48
|
+
config[:wide] = wide
|
49
|
+
end
|
50
|
+
opts.separator ""
|
51
|
+
opts.separator "Common options:"
|
52
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
53
|
+
puts opts
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
opts.on_tail("-v", "--version", "Show version") do
|
57
|
+
puts "portalign v#{Portalign::VERSION}"
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.parse!(args)
|
63
|
+
|
64
|
+
%w(ports security_groups).each {|opt| force_array(config, opt)}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.validate_config(config)
|
69
|
+
unless config.keys.include?(:access_key_id) && config.keys.include?(:secret_access_key)
|
70
|
+
return [false, "You must specify an AWS access_key_id and secret_access_key"]
|
71
|
+
end
|
72
|
+
|
73
|
+
unless config[:security_groups] && config[:security_groups].any?
|
74
|
+
return [false, "You must specify at least one security group."]
|
75
|
+
end
|
76
|
+
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def self.config_file_paths
|
83
|
+
CONFIG_FILE_PATHS
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.force_array(config, option)
|
87
|
+
option = option.to_sym
|
88
|
+
if config[option]
|
89
|
+
config[option] = config[option].is_a?(Array) ? config[option] : [config[option]]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/portalign.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require "aws"
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), "portalign", "version")
|
5
|
+
require File.join(File.dirname(__FILE__), "portalign", "config")
|
6
|
+
|
7
|
+
class Portalign
|
8
|
+
CHECK_IP_URL = "http://checkip.dyndns.org"
|
9
|
+
CHECK_IP_REGEX = /(\d+\.){3}\d+/
|
10
|
+
|
11
|
+
NARROW_CIDR = "32"
|
12
|
+
WIDE_IP = "0.0.0.0"
|
13
|
+
WIDE_CIDR = "0"
|
14
|
+
|
15
|
+
def self.build_config(args)
|
16
|
+
{
|
17
|
+
:ports => [22],
|
18
|
+
:wide => false,
|
19
|
+
:deauthorize => false,
|
20
|
+
:protocol => "tcp"
|
21
|
+
}.merge!(Config.load_from_file).merge!(Config.parse_opts(args))
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.validate_config(config)
|
25
|
+
Config.validate_config(config)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run(config)
|
29
|
+
unless config[:wide]
|
30
|
+
ip_address = resolve_ip
|
31
|
+
exit unless ip_address
|
32
|
+
puts "Resolved local IP to #{ip_address}"
|
33
|
+
end
|
34
|
+
|
35
|
+
ec2 = ec2_instance(config[:access_key_id], config[:secret_access_key])
|
36
|
+
|
37
|
+
if config[:deauthorize]
|
38
|
+
deauthorize_ingress(ec2, ip_address, NARROW_CIDR, config[:security_groups], config[:ports], config[:protocol])
|
39
|
+
elsif config[:wide]
|
40
|
+
authorize_ingress(ec2, WIDE_IP, WIDE_CIDR, config[:security_groups], config[:ports], config[:protocol])
|
41
|
+
else
|
42
|
+
authorize_ingress(ec2, ip_address, NARROW_CIDR, config[:security_groups], config[:ports], config[:protocol])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.authorize_ingress(ec2, ip_address, cidr, security_groups, ports, protocol)
|
47
|
+
security_groups.each do |security_group|
|
48
|
+
ports.each do |port|
|
49
|
+
puts "Authorizing #{ip_address}/#{cidr} for #{security_group} on port #{port}"
|
50
|
+
begin
|
51
|
+
ec2.authorize_security_group_IP_ingress(security_group, port, port, protocol, "#{ip_address}/#{cidr}")
|
52
|
+
rescue Aws::AwsError => e
|
53
|
+
# It will throw an error if already authorized, but that's OK
|
54
|
+
# with us.
|
55
|
+
unless e.message =~ /has already been authorized/
|
56
|
+
raise
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.deauthorize_ingress(ec2, ip_address, cidr, security_groups, ports, protocol)
|
64
|
+
security_groups.each do |security_group|
|
65
|
+
ports.each do |port|
|
66
|
+
# We deauthorize both the specific IP and also the wide open IP
|
67
|
+
puts "Deauthorizing #{ip_address}/#{cidr} for #{security_group} on port #{port}"
|
68
|
+
ec2.revoke_security_group_IP_ingress(security_group, port, port, protocol, "#{ip_address}/#{cidr}")
|
69
|
+
|
70
|
+
puts "Deauthorizing #{WIDE_IP}/#{WIDE_CIDR} for #{security_group} on port #{port}"
|
71
|
+
ec2.revoke_security_group_IP_ingress(security_group, port, port, protocol, "#{WIDE_IP}/#{WIDE_CIDR}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.resolve_ip
|
77
|
+
# TODO: Perhaps have several services in case one is down?
|
78
|
+
begin
|
79
|
+
parse_checkip(call_checkip)
|
80
|
+
rescue Exception => e
|
81
|
+
puts "Unable to resolve local IP address. Exiting."
|
82
|
+
puts "Error: #{e.message}"
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def self.ec2_instance(access_key_id, secret_access_key)
|
90
|
+
logger = Logger.new(File.new("/dev/null", "w"))
|
91
|
+
@ec2_instance ||= Aws::Ec2.new(access_key_id, secret_access_key, :logger => logger)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.call_checkip
|
95
|
+
open(CHECK_IP_URL).read
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.parse_checkip(response)
|
99
|
+
match_data = CHECK_IP_REGEX.match(response)
|
100
|
+
match_data ? match_data[0] : nil
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
describe Portalign::Config do
|
5
|
+
let(:access_key_id) { "123abc" }
|
6
|
+
let(:secret_access_key) { "abc123" }
|
7
|
+
let(:ports) { [22,80] }
|
8
|
+
let(:security_groups) { ["mygroup"] }
|
9
|
+
|
10
|
+
context "reading from the YAML files" do
|
11
|
+
|
12
|
+
let(:config1) do
|
13
|
+
t = Tempfile.new("config1")
|
14
|
+
t.write("access_key_id: wrong_key\n")
|
15
|
+
t.write("secret_access_key: wrong_key\n")
|
16
|
+
t.write("security_groups: #{security_groups.join(',')}\n")
|
17
|
+
t.close
|
18
|
+
t
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:config2) do
|
22
|
+
t = Tempfile.new("config2")
|
23
|
+
t.write("access_key_id: #{access_key_id}\n")
|
24
|
+
t.write("secret_access_key: #{secret_access_key}\n")
|
25
|
+
t.write("ports:\n")
|
26
|
+
ports.each { |p| t.write("- #{p}\n") }
|
27
|
+
t.close
|
28
|
+
t
|
29
|
+
end
|
30
|
+
|
31
|
+
before do
|
32
|
+
Portalign::Config.stub(:config_file_paths).and_return([config1.path, config2.path])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should parse the files in order" do
|
36
|
+
Portalign::Config.load_from_file.should == {
|
37
|
+
:access_key_id => access_key_id,
|
38
|
+
:secret_access_key => secret_access_key,
|
39
|
+
:ports => ports,
|
40
|
+
:security_groups => security_groups
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
context "parsing the CLI options" do
|
47
|
+
let(:args) { "--access-key-id=#{access_key_id} --secret-access-key #{secret_access_key} --ports=#{ports.join(',')} -s #{security_groups.join(',')}".split(/\s/) }
|
48
|
+
it "should extract all the options" do
|
49
|
+
Portalign::Config.parse_opts(args).should == {
|
50
|
+
:access_key_id => access_key_id,
|
51
|
+
:secret_access_key => secret_access_key,
|
52
|
+
:ports => ports,
|
53
|
+
:security_groups => security_groups
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Portalign do
|
4
|
+
|
5
|
+
let(:portalign_config) do
|
6
|
+
{
|
7
|
+
:access_key_id => "54321",
|
8
|
+
:secret_access_key => "12345",
|
9
|
+
:security_groups => "portalign",
|
10
|
+
:ports => 22,
|
11
|
+
:protocol => "tcp"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:current_ip) { "66.56.44.38" }
|
16
|
+
|
17
|
+
let(:checkip_response) do
|
18
|
+
"<html><head><title>Current IP Check</title></head><body>Current IP Address: #{current_ip}</body></html>"
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:ec2_instance) { stub("ec2_instance") }
|
22
|
+
|
23
|
+
before do
|
24
|
+
Portalign.stub(:call_checkip).and_return(checkip_response)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "#resolve_ip" do
|
28
|
+
it "should call checkip" do
|
29
|
+
Portalign.should_receive(:call_checkip).and_return(checkip_response)
|
30
|
+
Portalign.resolve_ip
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should get the correct IP address" do
|
34
|
+
Portalign.resolve_ip.should == current_ip
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "#authorize_ingress" do
|
39
|
+
context "successfully" do
|
40
|
+
it "should update the security group" do
|
41
|
+
ec2_instance.should_receive(:authorize_security_group_IP_ingress).with(
|
42
|
+
portalign_config[:security_groups],
|
43
|
+
portalign_config[:ports],
|
44
|
+
portalign_config[:ports],
|
45
|
+
"tcp",
|
46
|
+
"#{current_ip}/32"
|
47
|
+
)
|
48
|
+
|
49
|
+
Portalign.authorize_ingress(ec2_instance, current_ip, Portalign::NARROW_CIDR, [portalign_config[:security_groups]], [portalign_config[:ports]], portalign_config[:protocol])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "#deauthorize_ingress" do
|
55
|
+
context "successfully" do
|
56
|
+
it "should update the security group" do
|
57
|
+
ec2_instance.should_receive(:revoke_security_group_IP_ingress).with(
|
58
|
+
portalign_config[:security_groups],
|
59
|
+
portalign_config[:ports],
|
60
|
+
portalign_config[:ports],
|
61
|
+
"tcp",
|
62
|
+
"#{current_ip}/32"
|
63
|
+
)
|
64
|
+
|
65
|
+
ec2_instance.should_receive(:revoke_security_group_IP_ingress).with(
|
66
|
+
portalign_config[:security_groups],
|
67
|
+
portalign_config[:ports],
|
68
|
+
portalign_config[:ports],
|
69
|
+
"tcp",
|
70
|
+
"0.0.0.0/0"
|
71
|
+
)
|
72
|
+
|
73
|
+
Portalign.deauthorize_ingress(ec2_instance, current_ip, Portalign::NARROW_CIDR, [portalign_config[:security_groups]], [portalign_config[:ports]], portalign_config[:protocol])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: portalign
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Micah Wedemeyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: aws
|
16
|
+
requirement: &70273097692780 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - =
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.5.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70273097692780
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70273097692380 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70273097692380
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &70273097691800 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.10.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70273097691800
|
47
|
+
description: Easily set and unset your current IP as an allowed ingress for a given
|
48
|
+
EC2 security group. This allows you to securely close port 22 (or whatever you use
|
49
|
+
for SSH) except for your current exact IP.
|
50
|
+
email: micah@agileleague.com
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- lib/portalign/config.rb
|
56
|
+
- lib/portalign/version.rb
|
57
|
+
- lib/portalign.rb
|
58
|
+
- bin/portalign
|
59
|
+
- Rakefile
|
60
|
+
- LICENSE.md
|
61
|
+
- README.md
|
62
|
+
- spec/portalign/config_spec.rb
|
63
|
+
- spec/portalign_spec.rb
|
64
|
+
- spec/spec_helper.rb
|
65
|
+
homepage: http://github.com/agileleague/portalign
|
66
|
+
licenses: []
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.3.6
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.8.15
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: A tool to automatically add and remove your current IP address to Amazon
|
89
|
+
EC2 security groups.
|
90
|
+
test_files:
|
91
|
+
- spec/portalign/config_spec.rb
|
92
|
+
- spec/portalign_spec.rb
|
93
|
+
- spec/spec_helper.rb
|