awsudo 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []