@@ -150,6 +150,11 @@ users:
150
150
On Fedora: dnf install example-client-go-exec-plugin
151
151
152
152
...
153
+
154
+ # Whether or not to provide cluster information, which could potentially contain
155
+ # very large CA data, to this exec plugin as a part of the KUBERNETES_EXEC_INFO
156
+ # environment variable.
157
+ provideClusterInfo : true
153
158
clusters :
154
159
- name : my-cluster
155
160
cluster :
@@ -195,6 +200,12 @@ type ExecConfig struct {
195
200
// present. For example, `brew install foo-cli` might be a good InstallHint for
196
201
// foo-cli on Mac OS systems.
197
202
InstallHint string `json:"installHint,omitempty"`
203
+
204
+ // ProvideClusterInfo determines whether or not to provide cluster information,
205
+ // which could potentially contain very large CA data, to this exec plugin as a
206
+ // part of the KUBERNETES_EXEC_INFO environment variable. By default, it is set
207
+ // to false.
208
+ ProvideClusterInfo bool `json:"provideClusterInfo"`
198
209
}
199
210
```
200
211
@@ -212,6 +223,10 @@ variables set in the client process are also passed to the provider.
212
223
` installHint ` specifies help text to print to the user when the required binary
213
224
is missing.
214
225
226
+ ` provideClusterInfo ` specifies whether to provide cluster information, which could
227
+ potentially contain very large CA data, to this exec plugin as a part
228
+ of the ` KUBERNETES_EXEC_INFO ` environment variable.
229
+
215
230
### Provider input format
216
231
217
232
In JSON:
@@ -252,39 +267,69 @@ type ExecCredential struct {
252
267
// the transport.
253
268
type ExecCredentialSpec struct {
254
269
// Cluster contains information to allow an exec plugin to communicate with the
255
- // kubernetes cluster being authenticated to.
256
- Cluster Cluster ` json:"cluster"`
270
+ // kubernetes cluster being authenticated to. Note that Cluster is non-nil only
271
+ // when provideClusterInfo is set to true in the exec provider config (i.e.,
272
+ // ExecConfig.ProvideClusterInfo).
273
+ // +optional
274
+ Cluster *Cluster ` json:"cluster,omitempty"`
257
275
}
258
276
259
277
// Cluster contains information to allow an exec plugin to communicate with the
260
278
// kubernetes cluster being authenticated to.
279
+ //
280
+ // To ensure that this struct contains everything someone would need to communicate
281
+ // with a kubernetes cluster (just like they would via a kubeconfig), the fields
282
+ // should shadow "k8s.io/client-go/tools/clientcmd/api/v1".Cluster, with the exception
283
+ // of CertificateAuthority, since CA data will always be passed to the plugin as bytes.
261
284
type Cluster struct {
262
285
// Server is the address of the kubernetes cluster (https://hostname:port).
263
286
Server string ` json:"server"`
264
- // ServerName is passed to the server for SNI and is used in the client to
287
+ // TLSServerName is passed to the server for SNI and is used in the client to
265
288
// check server certificates against. If ServerName is empty, the hostname
266
289
// used to contact the server is used.
267
290
// +optional
268
- ServerName string ` json:"serverName,omitempty"`
291
+ TLSServerName string ` json:"tls-server-name,omitempty"`
292
+ // InsecureSkipTLSVerify skips the validity check for the server's certificate.
293
+ // This will make your HTTPS connections insecure.
294
+ // +optional
295
+ InsecureSkipTLSVerify bool ` json:"insecure-skip-tls-verify,omitempty"`
269
296
// CAData contains PEM-encoded certificate authority certificates.
270
297
// If empty, system roots should be used.
271
298
// +listType=atomic
272
299
// +optional
273
- CAData []byte ` json:"caData ,omitempty"`
300
+ CertificateAuthorityData []byte ` json:"certificate-authority-data ,omitempty"`
274
301
// ProxyURL is the URL to the proxy to be used for all requests to this
275
302
// cluster.
276
303
// +optional
277
304
ProxyURL string ` json:"proxy-url,omitempty"`
278
- // Config holds additional config data that is specific to the exec plugin
279
- // with regards to the cluster being authenticated to.
305
+ // Config holds additional config data that is specific to the exec
306
+ // plugin with regards to the cluster being authenticated to.
307
+ //
308
+ // This data is sourced from the clientcmd Cluster object's extensions[exec] field:
309
+ //
310
+ // clusters:
311
+ // - name: my-cluster
312
+ // cluster:
313
+ // ...
314
+ // extensions:
315
+ // - name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config
316
+ // extension:
317
+ // audience: 06e3fbd18de8 # arbitrary config
318
+ //
319
+ // In some environments, the user config may be exactly the same across many clusters
320
+ // (i.e. call this exec plugin) minus some details that are specific to each cluster
321
+ // such as the audience. This field allows the per cluster config to be directly
322
+ // specified with the cluster info. Using this field to store secret data is not
323
+ // recommended as one of the prime benefits of exec plugins is that no secrets need
324
+ // to be stored directly in the kubeconfig.
280
325
// +optional
281
326
Config runtime.RawExtension ` json:"config,omitempty"`
282
327
}
283
328
```
284
329
285
330
The Go struct for the ` clusters.[...].cluster.extensions[...].extension ` field:
286
331
287
- ``` golang
332
+ ``` go
288
333
// Cluster contains information about how to communicate with a kubernetes cluster
289
334
type Cluster struct {
290
335
// Server is the address of the kubernetes cluster (https://hostname:port).
@@ -313,20 +358,72 @@ has completed parsing its `kubeconfig`, flags and environment variables).
313
358
This allows the executable to perform different actions based on the current
314
359
cluster (i.e. get a token for a particular cluster). The ` Cluster ` struct is
315
360
flexible in that it not only provides all details required to communicate with
316
- the cluster (hostname and TLS config), but that is also allows arbitrary
361
+ the cluster as one would via a ` kubeconfig ` (i.e. everything from
362
+ ` "k8s.io/client-go/tools/clientcmd/api/v1".Cluster ` ), but also allows arbitrary
317
363
per-cluster configuration to be passed to the executable via the ` config ` field.
318
364
This field can contain arbitrary data that is passed to the executable without
319
365
modification. This allows extra user-defined data (i.e. an OAuth client ID for
320
366
audience scoping) to be passed through the ` spec.cluster ` field. The user
321
- configures this via the ` kubeconfig ` 's ` clusters.[...].cluster.extensions[exec].extension `
322
- field. The ` exec ` named extension is reserved for this purpose.
367
+ configures this via the ` kubeconfig ` 's ` clusters.[...].cluster.extensions[client.authentication.k8s.io/exec].extension `
368
+ field. The ` client.authentication.k8s.io/exec ` named extension is reserved for this
369
+ purpose.
370
+
371
+ The ` spec.cluster ` field is a pointer so that the plugin can easily determine whether
372
+ the cluster information is valid. The cluster information will only be provided when 1)
373
+ the ` ExecCredential ` version supports the ` spec.cluster ` field (note: ` v1alpha1 `
374
+ does not support this field) and 2) the ` provideClusterInfo ` field is set to ` true `
375
+ for this ` kubeconfig ` ` AuthInfo ` entry. The ` provideClusterInfo ` option is opt-in for
376
+ the following reasons.
377
+ 1 . To prevent potentially large CA bundles from being set in the environment via the
378
+ ` Cluster.CertificateAuthorityData ` field and causing system issues.
379
+ 1 . To design for the majority of plugins that will not use this cluster information
380
+ (this is an assumption).
381
+ 1 . To give the ` kubeconfig ` creator, which most likely understands the runtime and
382
+ security properties of the exec plugin, the power to enable or disable this
383
+ cluster information being set in the environment for a plugin to consume.
384
+
385
+ To ensure that the ` Cluster ` struct maintains the same cluster connection
386
+ capabilities as one gets from a ` kubeconfig ` , the ` Cluster ` fields (Go and JSON) must
387
+ be named the same as ` "k8s.io/client-go/tools/clientcmd/api/v1".Cluster ` , with the
388
+ exception of ` CertificateAuthority ` , which has been left out since CA data will always
389
+ be passed to the plugin as bytes.
323
390
324
391
This data is passed to the executable via the ` KUBERNETES_EXEC_INFO ` environment
325
392
variable in a JSON serialized object. Note that an environment variable is used
326
393
over passing this information via standard input because standard input is
327
394
reserved for interactive flows between the user and executable (i.e. to prompt
328
395
for username and password).
329
396
397
+ To make it easier for a plugin to use this ` KUBERNETES_EXEC_INFO ` environment
398
+ variable to connect to the referent cluster, a set of helper functions will be added
399
+ to create a ` "k8s.io/client-go/rest".Config ` from the ` KUBERNETES_EXEC_INFO `
400
+ environment variable. These helper functions will live in
401
+ ` k8s.io/client-go/tools/auth/exec/exec.go ` so that non-plugin developers won't pull
402
+ in this new package and the new package can safely depend on
403
+ ` k8s.io/client-go/rest ` . The helper functions are as follows.
404
+
405
+ ``` golang
406
+ // LoadExecCredentialFromEnv is a helper-wrapper around LoadExecCredential that loads from the
407
+ // well-known KUBERNETES_EXEC_INFO environment variable.
408
+ //
409
+ // When the KUBERNETES_EXEC_INFO environment variable is not set or is empty, then this function
410
+ // will immediately return an error.
411
+ func LoadExecCredentialFromEnv () (runtime .Object , *rest .Config , error )
412
+
413
+ // LoadExecCredential loads the configuration needed for an exec plugin to communicate with a
414
+ // cluster.
415
+ //
416
+ // LoadExecCredential expects the provided data to be a serialized client.authentication.k8s.io
417
+ // ExecCredential object (of any version). If the provided data is invalid (i.e., it cannot be
418
+ // unmarshalled into any known client.authentication.k8s.io ExecCredential version), an error will
419
+ // be returned. A successfully unmarshalled ExecCredential will be returned as the first return
420
+ // value.
421
+ //
422
+ // If the provided data is successfully unmarshalled, but it does not contain cluster information
423
+ // (i.e., ExecCredential.Spec.Cluster == nil), then the returned rest.Config and error will be nil.
424
+ func LoadExecCredential(data []byte) (runtime.Object, *rest.Config, error)
425
+ ```
426
+
330
427
### Provider output format
331
428
332
429
In JSON:
@@ -416,6 +513,13 @@ Unit tests to confirm:
416
513
+ Credentials are used across many requests (as long as they are still valid)
417
514
- Single flight all calls to a given executable (when the config is the same)
418
515
- Reasonable timeout to executable calls so clients do not hang indefinitely
516
+ - ` "k8s.io/client-go/pkg/apis/clientauthentication".Cluster ` (and external types)
517
+ fields (Go and JSON) properly shadow
518
+ ` "k8s.io/client-go/tools/clientcmd/api/v1".Cluster ` fields (with the exception of
519
+ ` CertificateAuthority ` for reasons stated in design) so
520
+ that structs are kept up to date
521
+ - Helper methods properly create ` "k8s.io/client-go/rest".Config ` from
522
+ ` "k8s.io/client-go/pkg/apis/clientauthentication".Cluster `
419
523
420
524
Integration (or e2e CLI) tests to confirm:
421
525
0 commit comments