awsudo 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8e4b45a3d628800167e5024b822807b35157daa3
4
+ data.tar.gz: 6d4ba8e55a5795fa72b89f1c4e4d9aa4212a3da5
5
+ SHA512:
6
+ metadata.gz: 18fe20ae36c9fb52041fa179880bba1131ba220f87d50955f4befc8d1a6bc3d03b7bda06e7f353613e2e39c2a47326196f7d0bf8f82eead9eaa94d24e3d15271
7
+ data.tar.gz: e1d3e25b4cd51d0494a99f0fd772f499704deefb3f25340a89fa8e28e2a17823450e823a267b78b385b349696a356d0fe46dfecc385dd1ee119126c55db82686
File without changes
@@ -0,0 +1,20 @@
1
+ How to contribute
2
+ =================
3
+ Thanks for your interest!
4
+
5
+ Contributing is easy. After signing the [Contributor License Agreement (CLA)](https://ea.tap.thinksmart.com/prod/Portal/ShowWorkFlow/AnonymousEmbed/26adfdf8-b74e-4212-bb4a-3e756b722c32) just follow the steps described below.
6
+
7
+ Getting Started
8
+ ---------------
9
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
10
+ * Fork the repository on GitHub
11
+
12
+ Making changes
13
+ ---------------
14
+ * Create a topic branch from where you want to base your work.
15
+ * Make commits of logical units, adding messages for describing what was done.
16
+
17
+ Submitting changes
18
+ ------------------
19
+ * Push your changes to a topic branch in your fork of the repository.
20
+ * Submit a pull request to the repository.
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
13
+ its contributors may be used to endorse or promote products derived
14
+ from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
17
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,79 @@
1
+ awsudo + aws-agent
2
+ ==================
3
+
4
+ Overview
5
+ ------------
6
+
7
+ **awsudo** enables users to execute commands that make API calls to AWS under
8
+ the security context of an IAM role. The IAM role is assumed only upon
9
+ successful authentication against a SAML compliant federation service.
10
+
11
+ **aws-agent** enables users to authenticate against a SAML compliant federation
12
+ service once, after which aws-agent provides temporary credentials to awsudo
13
+ to use.
14
+
15
+ Synopsis
16
+ ------------
17
+
18
+ awsudo {role-name | role-arn} command
19
+
20
+ aws-agent
21
+
22
+ Requirements
23
+ ------------
24
+
25
+ * UNIX, UNIX-like or GNU/Linux operating system
26
+ * SAML compliant federation service
27
+ * ruby 1.9 or above
28
+ * ruby gems: aws-sdk
29
+
30
+ Install
31
+ ------------
32
+
33
+ sudo gem install awsudo
34
+
35
+ Configuration
36
+ ------------
37
+
38
+ awsudo and aws-agent expect a configuration file named .awsudo in your home directory
39
+ containing the values for your identity provider login url and the SAML provider name
40
+ configured in AWS. This is an example, your setup may vary:
41
+
42
+ IDP_LOGIN_URL = https://sts.example.com/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices
43
+ SAML_PROVIDER_NAME = ADFS
44
+
45
+ In addition to .awsudo, you can create .aws-roles in your home directory to map
46
+ IAM roles ARNs to more easy to remember alias names, one per line, separated by spaces. Example:
47
+
48
+ myaccount-admin arn:aws:iam::123456789012:role/myaccount-admin
49
+
50
+ Examples
51
+ ------------
52
+
53
+ ### awsudo
54
+
55
+ $ awsudo arn:aws:iam::123456789012:role/myaccount-admin aws ec2 describe-tags --region us-west-2
56
+
57
+ $ awsudo myaccount-admin aws ec2 describe-instances --region us-east-1
58
+
59
+ awsudo will ask your federated credentials every time. To avoid this use aws-agent as follows:
60
+
61
+ ### aws-agent
62
+
63
+ $ aws-agent
64
+ Login: username
65
+ Password:
66
+ AWS_AUTH_SOCK=/var/folders/xz/lx178g0d0rb36x95446zwgd80000gp/T/aws-20150623-20990-58v1c4/agent; export AWS_AUTH_SOCK;
67
+
68
+ then execute the commands printed by aws-agent. awsudo will now ask for temporary credentials to aws-agent.
69
+
70
+ Author
71
+ -------
72
+
73
+ [Gerardo Santana Gomez Garrido](https://github.com/santana)
74
+
75
+ Contributors
76
+ -------------
77
+ * [Matthew Wygant](https://github.com/mkwygant)
78
+ * [Ivan Zenteno](https://github.com/k001)
79
+ * [David Hannon](https://github.com/dhannon)
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
3
+
4
+ require 'awsudo'
5
+ require 'logger'
6
+ require 'socket'
7
+ require 'tmpdir'
8
+
9
+ def usage
10
+ warn <<EOS
11
+ Usage:
12
+
13
+ #{File.basename $0}
14
+ EOS
15
+ exit 1
16
+ end
17
+
18
+ config = Hash[*File.read(File.join(ENV['HOME'], '.awsudo')).
19
+ scan(/^(\w+)\s*=\s*(.*)$/).flatten]
20
+ AWSUDO.config(config['IDP_LOGIN_URL'], config['SAML_PROVIDER_NAME'])
21
+
22
+ LOGFILE = File.join(ENV['HOME'], ".aws-agent.log")
23
+ logger = Logger.new(LOGFILE, "weekly")
24
+ logger.progname = "aws-agent"
25
+ logger.level = Logger::WARN
26
+
27
+ username, password = AWSUDO.get_federated_credentials
28
+
29
+ socket_dir = Dir.mktmpdir("aws-")
30
+ socket_name = File.join(socket_dir, "agent")
31
+ puts "AWS_AUTH_SOCK=#{socket_name}; export AWS_AUTH_SOCK;"
32
+ Process.daemon
33
+ $0 = 'aws-agent'
34
+ Process.setrlimit(Process::RLIMIT_CORE, 0, 0)
35
+ UNIXServer.open(socket_name) do |socket|
36
+ loop do
37
+ Thread.new(socket.accept) do |client|
38
+ logger.debug "thread started"
39
+ logger.debug "connection accepted: #{socket.inspect}"
40
+ begin
41
+ role = client.gets.strip
42
+ logger.debug "role received: #{role}"
43
+ role_arn = AWSUDO.resolve_role(role)
44
+ logger.debug "role ARN resolved: #{role_arn}"
45
+ saml_assertion = AWSUDO.get_saml_assertion(username, password)
46
+ credentials = AWSUDO.assume_role_with_saml(saml_assertion, role_arn)
47
+ client.puts credentials.to_h.to_json
48
+ rescue => e
49
+ logger.error e
50
+ error = {:error => e}.to_json
51
+ client.print error
52
+ ensure
53
+ logger.debug "Closing connection"
54
+ client.close
55
+ logger.debug "Connection closed"
56
+ end
57
+ logger.debug "Thread ending"
58
+ end
59
+ end
60
+ end
61
+
62
+ FileUtils.rmdir socket_dir
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
3
+
4
+ require 'awsudo'
5
+
6
+ def usage
7
+ warn <<-EOS
8
+ Usage:
9
+
10
+ #{File.basename $0} {role-name | role-arn} command
11
+ EOS
12
+ exit 1
13
+ end
14
+
15
+ usage if ARGV.size < 2
16
+
17
+ config = Hash[*File.read(File.join(ENV['HOME'], '.awsudo')).
18
+ scan(/^(\w+)\s*=\s*(.*)$/).flatten]
19
+ AWSUDO.config(config['IDP_LOGIN_URL'], config['SAML_PROVIDER_NAME'])
20
+
21
+ role = ARGV.shift
22
+ credentials =
23
+ begin
24
+ AWSUDO.assume_role(role)
25
+ rescue => e
26
+ warn e
27
+ exit 2
28
+ end
29
+
30
+ ENV['AWS_ACCESS_KEY_ID'] = credentials['access_key_id'] || credentials[:access_key_id]
31
+ ENV['AWS_SECRET_ACCESS_KEY'] = credentials['secret_access_key'] || credentials[:secret_access_key]
32
+ ENV['AWS_SESSION_TOKEN'] = credentials['session_token'] || credentials[:session_token]
33
+
34
+ exec *ARGV if ARGV.size > 0
@@ -0,0 +1,101 @@
1
+ # Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
2
+
3
+ require 'aws-sdk'
4
+ require 'io/console'
5
+ require 'json'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'rexml/document'
9
+ require 'socket'
10
+ require 'uri'
11
+
12
+ module AWSUDO
13
+ AWS_ROLES = File.join(ENV['HOME'], '.aws-roles')
14
+
15
+ class << self
16
+ attr_reader :idp_login_url, :saml_provider_name
17
+ end
18
+
19
+ def self.config(idp_login_url, saml_provider_name)
20
+ @idp_login_url = idp_login_url
21
+ @saml_provider_name = saml_provider_name
22
+ end
23
+
24
+ def self.get_federated_credentials
25
+ fd = IO.sysopen("/dev/tty", "w")
26
+ console = IO.new(fd,"w")
27
+ console.print "Login: "
28
+ username = STDIN.gets.chomp
29
+ console.print "Password: "
30
+ password = STDIN.noecho(&:gets).chomp
31
+ console.print "\n"
32
+ [username, password]
33
+ end
34
+
35
+ def self.assume_role_using_agent(role)
36
+ socket_name = ENV['AWS_AUTH_SOCK']
37
+ credentials = UNIXSocket.open(socket_name) do |client|
38
+ client.puts role
39
+ response = client.gets
40
+ raise "Connection closed by peer" if response.nil?
41
+ JSON.parse(response.strip)
42
+ end
43
+
44
+ raise credentials['error'] if credentials['error']
45
+ credentials
46
+ end
47
+
48
+ def self.assume_role_using_password(role)
49
+ username, password = get_federated_credentials
50
+ saml_assertion = get_saml_assertion(username, password)
51
+ role_arn = resolve_role(role)
52
+ assume_role_with_saml(saml_assertion, role_arn).to_h
53
+ end
54
+
55
+ def self.assume_role(role)
56
+ assume_role_using_agent(role) rescue assume_role_using_password(role)
57
+ end
58
+
59
+ def self.get_saml_assertion(username, password)
60
+ uri = URI.parse(idp_login_url)
61
+
62
+ http = Net::HTTP.new(uri.host, uri.port)
63
+ http.use_ssl = true
64
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
65
+
66
+ req = Net::HTTP::Post.new(uri.request_uri)
67
+ req.set_form_data({'username' => username, 'password' => password})
68
+ res = http.request(req)
69
+
70
+ raise "Authentication failed" if res['Location'].nil?
71
+ uri = URI.parse(res['Location'])
72
+ req = Net::HTTP::Get.new(uri.request_uri)
73
+ req['Cookie'] = res['Set-Cookie']
74
+ http = Net::HTTP.new(uri.host, uri.port)
75
+ http.use_ssl = true
76
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
77
+ res = http.request(req)
78
+
79
+ doc = REXML::Document.new(res.body)
80
+ REXML::XPath.first(doc, '/html/body/form/input[@name = "SAMLResponse"]/@value').to_s
81
+ end
82
+
83
+ def self.assume_role_with_saml(saml_assertion, role_arn)
84
+ principal_arn = "#{role_arn[/^arn:aws:iam::\d+:/]}saml-provider/#{saml_provider_name}"
85
+ sts = Aws::STS::Client.new(credentials: Aws::Credentials.new('a', 'b', 'c'), region: 'us-east-1')
86
+ sts.assume_role_with_saml(
87
+ role_arn: role_arn,
88
+ principal_arn: principal_arn,
89
+ saml_assertion: saml_assertion).credentials
90
+ end
91
+
92
+ def self.resolve_role(role, roles_filename = AWS_ROLES)
93
+ return role if role =~ /^arn:aws:iam::\d+:role\/\S+$/
94
+ raise "`#{role}' is not a valid role" if role =~ /\s/
95
+ line = File.readlines(roles_filename).find {|line| line =~ /^#{role}\s+arn:aws:iam::\d+:role\/\S+\s*$/ }
96
+ raise "`#{role}' is not a valid role" if line.nil?
97
+ role_arn = line.split(/\s+/)[1]
98
+ raise "`#{role}' is not a valid role" if role_arn.nil?
99
+ role_arn
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awsudo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gerardo Santana Gomez Garrido
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ description: |
28
+ awsudo enables users to execute commands that make API calls to AWS under the
29
+ security context of an IAM role. The IAM role is assumed only upon successful
30
+ authentication against a SAML compliant federation service.
31
+
32
+ aws-agent enables users to authenticate against a SAML compliant federation
33
+ service once, after which aws-agent provides temporary credentials to awsudo to
34
+ use.
35
+ email: gsantana@ea.com
36
+ executables:
37
+ - awsudo
38
+ - aws-agent
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - bin/aws-agent
43
+ - bin/awsudo
44
+ - lib/awsudo.rb
45
+ - LICENSE
46
+ - CHANGELOG.md
47
+ - CONTRIBUTING.md
48
+ - README.md
49
+ homepage: https://github.com/electronicarts/awsudo
50
+ licenses: []
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.0.14
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: executes a command with the permissions given by an AWS IAM role
72
+ test_files: []