aws-google 0.1.2 → 0.1.3

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.
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