aws-google 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a88d08ce22738aaf30652e7e195a581cb44bd1797e0d65f02405f0f39850170f
4
- data.tar.gz: ed9433f72205cb4d139674e4cd3a26285cf75595b149235f52d636ebde60552d
3
+ metadata.gz: 29e2bac01a2d62b1b156badf3fda404596d56fef92f5b8de438095362abea600
4
+ data.tar.gz: d25ac4ca974f4991120814679678a923375ede8bbfd0b189917344596f0d79ec
5
5
  SHA512:
6
- metadata.gz: b706382bcfe06a1362f595d2f2193866c35e05d68d595bfb9b23d0f9f74d99229a3bc93046bdcbd003eb366da05b0c1085e1d639412011a0ce094d81e70703e5
7
- data.tar.gz: 0b8a9f86ceb0fd79ddafa76c76d4c5bf3d53b338f10bd2086afdb5f3aed8a3638398fefe891852d03608e34dbe25e6329d96c54081d9a453c7836b54e9823bfd
6
+ metadata.gz: e2e26e77654e356c81c424dd76d679c09304f44a846bff66d6d204c845d9a918e0bac3dd99d6922c9e4cfb363d773dbcfd679c29f736e46eb52acccb5f4ba0f6
7
+ data.tar.gz: 9226a37c273473589a4f56ea3e49a7a9bb652d42b436e39f62f41124ccbd36bf101e4edbd6ee7d5a44e4138e91c135f72d5a6292f8149cc4e3f2272b809add19
data/README.md CHANGED
@@ -21,8 +21,8 @@ Or install it yourself as:
21
21
  ## Usage
22
22
 
23
23
  - Visit the [Google API Console](https://console.developers.google.com/) to create/obtain OAuth 2.0 Client ID credentials (client ID and client secret) for an application in your Google account.
24
- - Create an AWS IAM Role with the desired IAM policies attached, and a 'trust relationship' (`AssumeRolePolicyDocument`) allowing the `sts:AssumeRoleWithWebIdentity` action to be permitted
25
- by your Google Client ID and a specific set of Google Account IDs:
24
+ - Create an AWS IAM Role with the desired IAM policies attached, and a ['trust policy'](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#term_trust-policy) ([`AssumeRolePolicyDocument`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html)) allowing the [`sts:AssumeRoleWithWebIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html) action with [Web Identity Federation condition keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#condition-keys-wif) authorizing
25
+ your Google Client ID (`accounts.google.com:aud`) and a specific set of Google Account IDs (`accounts.google.com:sub`):
26
26
 
27
27
  ```json
28
28
  {
@@ -36,9 +36,7 @@ by your Google Client ID and a specific set of Google Account IDs:
36
36
  "Action": "sts:AssumeRoleWithWebIdentity",
37
37
  "Condition": {
38
38
  "StringEquals": {
39
- "accounts.google.com:aud": "123456789012-abcdefghijklmnopqrstuvwzyz0123456.apps.googleusercontent.com"
40
- },
41
- "ForAnyValue:StringEquals": {
39
+ "accounts.google.com:aud": "123456789012-abcdefghijklmnopqrstuvwzyz0123456.apps.googleusercontent.com",
42
40
  "accounts.google.com:sub": [
43
41
  "000000000000000000000",
44
42
  "111111111111111111111"
@@ -79,6 +77,17 @@ Aws::Google.config = {
79
77
  puts Aws::STS::Client.new.get_caller_identity
80
78
  ```
81
79
 
80
+ - Or, set `credential_process` in your AWS config profile ([`~/.aws/config`](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-where)) to `aws-google` to [Source Credentials with an External Process](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html) without any change to your application code:
81
+
82
+ ```
83
+ [profile my_google]
84
+ credential_process = aws-google --profile my_google
85
+ aws_role = arn:aws:iam::[AccountID]:role/[Role]
86
+ google_client_id = 123456789012-abcdefghijklmnopqrstuvwzyz0123456.apps.googleusercontent.com
87
+ google_client_secret = 01234567890abcdefghijklmn
88
+
89
+ ```
90
+
82
91
  ## Development
83
92
 
84
93
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -23,11 +23,11 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency 'aws-sdk-core', '~> 3'
25
25
  spec.add_dependency 'google-api-client', '~> 0.23'
26
- spec.add_dependency 'launchy', '~> 2' # Peer dependency of Google::APIClient::InstalledAppFlow
26
+ spec.add_dependency 'launchy', '~> 2'
27
27
 
28
28
  spec.add_development_dependency 'activesupport', '~> 5'
29
- spec.add_development_dependency 'bundler', '~> 1'
30
- spec.add_development_dependency 'minitest', '~> 5.10'
29
+ spec.add_development_dependency 'bundler'
30
+ spec.add_development_dependency 'minitest', '~> 5.14.2'
31
31
  spec.add_development_dependency 'mocha', '~> 1.5'
32
32
  spec.add_development_dependency 'rake', '~> 12'
33
33
  spec.add_development_dependency 'timecop', '~> 0.8'
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # CLI to retrieve AWS credentials in credential_process format.
4
+ # Ref: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html
5
+
6
+ require 'aws/google'
7
+ require 'time'
8
+ require 'json'
9
+ require 'optparse'
10
+
11
+ def error(msg)
12
+ puts msg
13
+ exit 1
14
+ end
15
+
16
+ options = {}
17
+ OptionParser.new do |opts|
18
+ opts.on('-p PROFILE', '--profile PROFILE', 'Profile') do |p|
19
+ options[:profile] = p
20
+ end
21
+ opts.on('-v', '--version', 'Version') do
22
+ require 'aws/google/version'
23
+ puts Aws::Google::VERSION
24
+ exit 0
25
+ end
26
+ opts.on('-r ROLE', '--role ROLE', 'AWS Role arn') do |r|
27
+ options[:role_arn] = r
28
+ end
29
+ opts.on('-i ID', '--client-id ID', 'Google Client ID') do |id|
30
+ options[:google_client_id] = id
31
+ end
32
+ opts.on('-s SECRET', '--client-secret SECRET', 'Google Client Secret') do |secret|
33
+ options[:google_client_secret] = secret
34
+ end
35
+ opts.on('-h DOMAIN', '--domain DOMAIN', 'Google Domain') do |hd|
36
+ options[:domain] = hd
37
+ end
38
+ opts.on('-d DURATION', '--duration DURATION', 'Duration in seconds') do |d|
39
+ options[:duration_seconds] = d.to_i
40
+ end
41
+ opts.on('--port PORT', 'Port number for local server') do |p|
42
+ options[:port] = p.to_i
43
+ end
44
+ opts.on('--online', 'Online authentication, no refresh token') do |o|
45
+ options[:online] = true
46
+ end
47
+ end.parse!
48
+
49
+ config = Aws.shared_config
50
+ profile = options[:profile] || ENV['AWS_PROFILE'] || 'default'
51
+
52
+ options[:role_arn] ||= config.get('aws_role', profile: profile) ||
53
+ error('Missing config: aws_role')
54
+ options[:google_client_id] ||= config.get('google_client_id', profile: profile) ||
55
+ error('Missing config: google_client_id')
56
+ options[:google_client_secret] ||= config.get('google_client_secret', profile: profile) ||
57
+ error('Missing config: google_client_secret')
58
+
59
+ # Cache temporary-session credentials in a separately-named profile.
60
+ # Stored credentials take priority over credential_process,
61
+ # so they would never be refreshed if stored in the same profile.
62
+ options[:profile] += '_session'
63
+ google = Aws::Google.new(options)
64
+ credentials = google.credentials
65
+ output = {
66
+ Version: 1,
67
+ AccessKeyId: credentials.access_key_id,
68
+ SecretAccessKey: credentials.secret_access_key,
69
+ SessionToken: credentials.session_token,
70
+ Expiration: Time.at(google.expiration.to_i).iso8601
71
+ }
72
+ require 'json'
73
+ puts output.to_json
@@ -39,7 +39,7 @@ module Aws
39
39
  # @option options [String] :online if `true` only a temporary access token will be provided,
40
40
  # a long-lived refresh token will not be created and stored on the filesystem.
41
41
  # @option options [String] :port port for local server to listen on to capture oauth browser redirect.
42
- # Defaults to an out-of-band authentication process.
42
+ # Defaults to 1234. Set to nil or 0 to use an out-of-band authentication process.
43
43
  # @option options [::Google::Auth::ClientId] :google_id
44
44
  def initialize(options = {})
45
45
  @oauth_attempted = false
@@ -56,7 +56,7 @@ module Aws
56
56
  @client = options[:client] || Aws::STS::Client.new(credentials: nil)
57
57
  @domain = options[:domain]
58
58
  @online = options[:online]
59
- @port = options[:port]
59
+ @port = options[:port] || 1234
60
60
 
61
61
  # Use existing AWS credentials stored in the shared config if available.
62
62
  # If this is `nil` or expired, #refresh will be called on the first AWS API service call
@@ -105,8 +105,18 @@ module Aws
105
105
  credentials.tap(&storage.method(:write_credentials))
106
106
  end
107
107
 
108
+ def silence_output
109
+ outs = [$stdout, $stderr]
110
+ clones = outs.map(&:clone)
111
+ outs.each { |io| io.reopen '/dev/null'}
112
+ yield
113
+ ensure
114
+ outs.each_with_index { |io, i| io.reopen(clones[i]) }
115
+ end
116
+
108
117
  def get_oauth_code(client, options)
109
- raise 'fallback' unless @port
118
+ raise 'fallback' unless @port && !@port.zero?
119
+
110
120
  require 'launchy'
111
121
  require 'webrick'
112
122
  code = nil
@@ -123,26 +133,29 @@ module Aws
123
133
  end
124
134
  trap('INT') { server.shutdown }
125
135
  client.redirect_uri = "http://localhost:#{@port}"
126
- launchy = Launchy.open(client.authorization_uri(options).to_s)
127
- server_thread = Thread.new do
128
- begin
129
- server.start
130
- ensure server.shutdown
136
+ silence_output do
137
+ launchy = Launchy.open(client.authorization_uri(options).to_s)
138
+ server_thread = Thread.new do
139
+ begin
140
+ server.start
141
+ ensure server.shutdown
142
+ end
143
+ end
144
+ while server_thread.alive?
145
+ raise 'fallback' if !launchy.alive? && !launchy.value.success?
146
+
147
+ sleep 0.1
131
148
  end
132
- end
133
- while server_thread.alive?
134
- raise 'fallback' if !launchy.alive? && !launchy.value.success?
135
- sleep 0.1
136
149
  end
137
150
  code || raise('fallback')
138
151
  rescue StandardError
139
152
  trap('INT', 'DEFAULT')
140
153
  # Fallback to out-of-band authentication if browser launch failed.
141
154
  client.redirect_uri = 'oob'
142
- url = client.authorization_uri(options)
143
- print "\nOpen the following URL in a browser and enter the " \
144
- "resulting code after authorization:\n#{url}\n> "
145
- gets
155
+ return ENV['OAUTH_CODE'] if ENV['OAUTH_CODE']
156
+
157
+ raise RuntimeError, 'Open the following URL in a browser to get a code,' \
158
+ "export to $OAUTH_CODE and rerun:\n#{client.authorization_uri(options)}", []
146
159
  end
147
160
 
148
161
  def refresh
@@ -176,7 +189,7 @@ module Aws
176
189
  raise e, "\nYour Google ID does not have access to the requested AWS Role. Ask your administrator to provide access.
177
190
  Role: #{@assume_role_params[:role_arn]}
178
191
  Email: #{token_params['email']}
179
- Google ID: #{token_params['sub']}", e.backtrace
192
+ Google ID: #{token_params['sub']}", []
180
193
  end
181
194
 
182
195
  c = assume_role.credentials
@@ -1,5 +1,5 @@
1
1
  module Aws
2
2
  class Google
3
- VERSION = '0.1.2'.freeze
3
+ VERSION = '0.1.3'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-google
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Will Jordan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-18 00:00:00.000000000 Z
11
+ date: 2020-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core
@@ -70,30 +70,30 @@ dependencies:
70
70
  name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '1'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '1'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: minitest
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '5.10'
89
+ version: 5.14.2
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '5.10'
96
+ version: 5.14.2
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: mocha
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -153,7 +153,8 @@ dependencies:
153
153
  description: Use Google OAuth as an AWS credential provider.
154
154
  email:
155
155
  - will@code.org
156
- executables: []
156
+ executables:
157
+ - aws-google
157
158
  extensions: []
158
159
  extra_rdoc_files: []
159
160
  files:
@@ -166,6 +167,7 @@ files:
166
167
  - aws-google.gemspec
167
168
  - bin/console
168
169
  - bin/setup
170
+ - exe/aws-google
169
171
  - lib/aws/google.rb
170
172
  - lib/aws/google/credential_provider.rb
171
173
  - lib/aws/google/version.rb
@@ -189,8 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
191
  - !ruby/object:Gem::Version
190
192
  version: '0'
191
193
  requirements: []
192
- rubyforge_project:
193
- rubygems_version: 2.7.4
194
+ rubygems_version: 3.1.2
194
195
  signing_key:
195
196
  specification_version: 4
196
197
  summary: Use Google OAuth as an AWS credential provider