14
14
15
15
import atexit
16
16
import base64
17
+ from collections import namedtuple
17
18
import copy
18
19
import datetime
19
20
import json
20
21
import logging
21
22
import os
22
23
import platform
24
+ import subprocess
23
25
import tempfile
24
26
import time
25
27
@@ -132,6 +134,46 @@ def as_data(self):
132
134
self ._data = f .read ()
133
135
return self ._data
134
136
137
+ class CommandTokenSource (object ):
138
+ def __init__ (self , cmd , args , tokenKey , expiryKey ):
139
+
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
+
135
177
136
178
class KubeConfigLoader (object ):
137
179
@@ -156,7 +198,34 @@ 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 ('missing access token cmd (cmd-path is an empty string in your kubeconfig file)' )
206
+ if 'scopes' in config and config ['scopes' ] != "" :
207
+ raise ConfigException ('scopes can only be used when kubectl is using a gcp service account key' )
208
+ args = []
209
+ if 'cmd-args' in config :
210
+ args = config ['cmd-args' ].split ()
211
+ else :
212
+ fields = config ['cmd-path' ].split ()
213
+ cmd = fields [0 ]
214
+ args = fields [1 :]
215
+
216
+ commandTokenSource = CommandTokenSource (
217
+ cmd , args ,
218
+ config .safe_get ('token-key' ),
219
+ config .safe_get ('expiry-key' ))
220
+ return commandTokenSource .token ()
221
+
159
222
def _refresh_credentials ():
223
+ # Refresh credentials using cmd-path
224
+ if ('auth-provider' in self ._user and
225
+ 'config' in self ._user ['auth-provider' ] and
226
+ 'cmd-path' in self ._user ['auth-provider' ]['config' ]):
227
+ return _refresh_credentials_with_cmd_path ()
228
+
160
229
credentials , project_id = google .auth .default (scopes = [
161
230
'https://www.googleapis.com/auth/cloud-platform' ,
162
231
'https://www.googleapis.com/auth/userinfo.email'
0 commit comments