20
20
import logging
21
21
import os
22
22
import platform
23
+ import subprocess
23
24
import tempfile
24
25
import time
26
+ from collections import namedtuple
25
27
26
28
import google .auth
27
29
import google .auth .transport .requests
@@ -133,6 +135,46 @@ def as_data(self):
133
135
return self ._data
134
136
135
137
138
+ class CommandTokenSource (object ):
139
+ def __init__ (self , cmd , args , tokenKey , expiryKey ):
140
+ self ._cmd = cmd
141
+ self ._args = args
142
+ if not tokenKey :
143
+ self ._tokenKey = '{.access_token}'
144
+ else :
145
+ self ._tokenKey = tokenKey
146
+ if not expiryKey :
147
+ self ._expiryKey = '{.token_expiry}'
148
+ else :
149
+ self ._expiryKey = expiryKey
150
+
151
+ def token (self ):
152
+ fullCmd = self ._cmd + (" " ) + " " .join (self ._args )
153
+ process = subprocess .Popen (
154
+ [self ._cmd ] + self ._args ,
155
+ stdout = subprocess .PIPE ,
156
+ stderr = subprocess .PIPE ,
157
+ universal_newlines = True )
158
+ (stdout , stderr ) = process .communicate ()
159
+ exit_code = process .wait ()
160
+ if exit_code != 0 :
161
+ msg = 'cmd-path: process returned %d' % exit_code
162
+ msg += "\n Cmd: %s" % fullCmd
163
+ stderr = stderr .strip ()
164
+ if stderr :
165
+ msg += '\n Stderr: %s' % stderr
166
+ raise ConfigException (msg )
167
+ try :
168
+ data = json .loads (stdout )
169
+ except ValueError as de :
170
+ raise ConfigException (
171
+ 'exec: failed to decode process output: %s' % de )
172
+ A = namedtuple ('A' , ['token' , 'expiry' ])
173
+ return A (
174
+ token = data ['credential' ]['access_token' ],
175
+ expiry = parse_rfc3339 (data ['credential' ]['token_expiry' ]))
176
+
177
+
136
178
class KubeConfigLoader (object ):
137
179
138
180
def __init__ (self , config_dict , active_context = None ,
@@ -156,7 +198,38 @@ def __init__(self, config_dict, active_context=None,
156
198
self ._config_base_path = config_base_path
157
199
self ._config_persister = config_persister
158
200
201
+ def _refresh_credentials_with_cmd_path ():
202
+ config = self ._user ['auth-provider' ]['config' ]
203
+ cmd = config ['cmd-path' ]
204
+ if len (cmd ) == 0 :
205
+ raise ConfigException (
206
+ 'missing access token cmd '
207
+ '(cmd-path is an empty string in your kubeconfig file)' )
208
+ if 'scopes' in config and config ['scopes' ] != "" :
209
+ raise ConfigException (
210
+ 'scopes can only be used '
211
+ 'when kubectl is using a gcp service account key' )
212
+ args = []
213
+ if 'cmd-args' in config :
214
+ args = config ['cmd-args' ].split ()
215
+ else :
216
+ fields = config ['cmd-path' ].split ()
217
+ cmd = fields [0 ]
218
+ args = fields [1 :]
219
+
220
+ commandTokenSource = CommandTokenSource (
221
+ cmd , args ,
222
+ config .safe_get ('token-key' ),
223
+ config .safe_get ('expiry-key' ))
224
+ return commandTokenSource .token ()
225
+
159
226
def _refresh_credentials ():
227
+ # Refresh credentials using cmd-path
228
+ if ('auth-provider' in self ._user and
229
+ 'config' in self ._user ['auth-provider' ] and
230
+ 'cmd-path' in self ._user ['auth-provider' ]['config' ]):
231
+ return _refresh_credentials_with_cmd_path ()
232
+
160
233
credentials , project_id = google .auth .default (scopes = [
161
234
'https://www.googleapis.com/auth/cloud-platform' ,
162
235
'https://www.googleapis.com/auth/userinfo.email'
0 commit comments