Skip to content

Commit 304a50c

Browse files
authored
Merge pull request kubernetes#2587 from ankeesler/exec-plugin-1-22
exec credential provider: pre-1.22 stuff (update with shipped metrics API, InteractiveMode API, GA API review)
2 parents 1157216 + 49ad081 commit 304a50c

File tree

2 files changed

+73
-7
lines changed
  • keps

2 files changed

+73
-7
lines changed

keps/prod-readiness/sig-auth/541.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
kep-number: 541
22
beta:
33
approver: "@deads2k"
4+
stable:
5+
approver: "@deads2k"

keps/sig-auth/541-external-credential-providers/README.md

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ users:
161161
# very large CA data, to this exec plugin as a part of the KUBERNETES_EXEC_INFO
162162
# environment variable. Optional. Defaults to false.
163163
provideClusterInfo: true
164+
165+
# The contract between the exec plugin and the standard input I/O stream. If the
166+
# contract cannot be satisfied, this plugin will not be run and an error will be
167+
# returned. Valid values are "Never" (this exec plugin never uses standard input),
168+
# "IfAvailable" (this exec plugin wants to use standard input if it is available),
169+
# or "Always" (this exec plugin requires standard input to function).
170+
#
171+
# In v1alpha1 and v1beta1, this is optional and defaults to IfAvailable. It is
172+
# required otherwise.
173+
interactiveMode: IfAvailable
164174
clusters:
165175
- name: my-cluster
166176
cluster:
@@ -213,7 +223,39 @@ type ExecConfig struct {
213223
// to false. Package k8s.io/client-go/tools/auth/exec provides helper methods for
214224
// reading this environment variable.
215225
ProvideClusterInfo bool `json:"provideClusterInfo"`
226+
227+
// InteractiveMode determines this plugin's relationship with standard input. Valid
228+
// values are "Never" (this exec plugin never uses standard input), "IfAvailable" (this
229+
// exec plugin wants to use standard input if it is available), or "Always" (this exec
230+
// plugin requires standard input to function). See ExecInteractiveMode values for more
231+
// details.
232+
//
233+
// If APIVersion is client.authentication.k8s.io/v1alpha1 or
234+
// client.authentication.k8s.io/v1beta1, then this field is optional and defaults
235+
// to "IfAvailable" when unset. Otherwise, this field is required.
236+
// +optional
237+
InteractiveMode ExecInteractiveMode `json:"interactiveMode,omitempty"`
216238
}
239+
240+
// ExecInteractiveMode is a string that describes an exec plugin's relationship with standard input.
241+
type ExecInteractiveMode string
242+
243+
const (
244+
// NeverExecInteractiveMode declares that this exec plugin never needs to use standard
245+
// input, and therefore the exec plugin will be run regardless of whether standard input is
246+
// available for user input.
247+
NeverExecInteractiveMode ExecInteractiveMode = "Never"
248+
// IfAvailableExecInteractiveMode declares that this exec plugin would like to use standard input
249+
// if it is available, but can still operate if standard input is not available. Therefore, the
250+
// exec plugin will be run regardless of whether stdin is available for user input. If standard
251+
// input is available for user input, then it will be provided to this exec plugin.
252+
IfAvailableExecInteractiveMode ExecInteractiveMode = "IfAvailable"
253+
// AlwaysExecInteractiveMode declares that this exec plugin requires standard input in order to
254+
// run, and therefore the exec plugin will only be run if standard input is available for user
255+
// input. If standard input is not available for user input, then the exec plugin will not be run
256+
// and an error will be returned by the exec plugin runner.
257+
AlwaysExecInteractiveMode ExecInteractiveMode = "Always"
258+
)
217259
```
218260

219261
`apiVersion` specifies the expected version of this API that the plugin
@@ -234,6 +276,14 @@ is missing.
234276
potentially contain very large CA data, to this exec plugin as a part
235277
of the `KUBERNETES_EXEC_INFO` environment variable.
236278

279+
`interactiveMode` specifies the contract between the exec plugin and the
280+
standard input I/O stream. If the contract cannot be satisfied, this plugin will
281+
not be run and an error will be returned. Valid values are "Never" (this exec
282+
plugin never uses standard input), "IfAvailable" (this exec plugin wants to use
283+
standard input if it is available), or "Always" (this exec plugin requires
284+
standard input to function). In v1alpha1 and v1beta1, this is optional and
285+
defaults to IfAvailable. It is required otherwise.
286+
237287
### Provider input format
238288

239289
In JSON:
@@ -243,6 +293,7 @@ In JSON:
243293
"apiVersion": "client.authentication.k8s.io/v1beta1",
244294
"kind": "ExecCredential",
245295
"spec": {
296+
"interactive": true,
246297
"cluster": {
247298
"server": "https://1.2.3.4:8080",
248299
"tls-server-name": "bar",
@@ -281,6 +332,9 @@ type ExecCredentialSpec struct {
281332
// ExecConfig.ProvideClusterInfo).
282333
// +optional
283334
Cluster *Cluster `json:"cluster,omitempty"`
335+
336+
// Interactive declares whether stdin has been passed to this exec plugin.
337+
Interactive bool `json:"interactive"`
284338
}
285339

286340
// Cluster contains information to allow an exec plugin to communicate with the
@@ -437,6 +491,11 @@ func LoadExecCredentialFromEnv() (runtime.Object, *rest.Config, error)
437491
func LoadExecCredential(data []byte) (runtime.Object, *rest.Config, error)
438492
```
439493

494+
The `interactive` field is used to communicate to the exec plugin whether
495+
standard input is available for use. This is helpful for plugins that can
496+
operate with and without standard input so that they can easily distinguish
497+
between the two cases.
498+
440499
### Provider output format
441500

442501
In JSON:
@@ -550,9 +609,12 @@ var (
550609
execPluginCalls = k8smetrics.NewCounterVec(
551610
&k8smetrics.CounterOpts{
552611
Name: "rest_client_exec_plugin_call_total",
553-
Help: "Number of calls to an exec plugin, partitioned by exit code.",
612+
Help: "Number of calls to an exec plugin, partitioned by the type of " +
613+
"event encountered (no_error, plugin_execution_error, plugin_not_found_error, " +
614+
"client_internal_error) and an optional exit code. The exit code will " +
615+
"be set to 0 if and only if the plugin call was successful.",
554616
},
555-
[]string{"code"},
617+
[]string{"code", "call_status"},
556618
)
557619
)
558620
```
@@ -572,8 +634,8 @@ type ExpiryMetric interface {
572634

573635
// CallsMetric counts calls that take place for a specific exec plugin.
574636
type CallsMetric interface {
575-
// Increment increments a counter per exitCode.
576-
Increment(exitCode int)
637+
// Increment increments a counter per exitCode and callStatus.
638+
Increment(exitCode int, callStatus string)
577639
}
578640

579641
var (
@@ -582,13 +644,13 @@ var (
582644
// ClientCertRotationAge is the age of a certificate that has just been rotated.
583645
ClientCertRotationAge DurationMetric = noopDuration{}
584646
// ExecPluginCalls is the number of calls made to an exec plugin, partitioned by
585-
// exit code.
647+
// exit code and call status.
586648
ExecPluginCalls CallsMetric = noopCalls{}
587649
)
588650
```
589651

590-
The `"code"` label of these metrics is an attempt to elucidate the exec plugin
591-
failure mode to the user.
652+
The `"code"` and `"call_status"` labels of these metrics are an attempt to
653+
elucidate the exec plugin failure mode to the user.
592654

593655
### Risks and Mitigations
594656

@@ -644,6 +706,8 @@ Integration (or e2e CLI) tests to confirm:
644706
+ Cert based auth
645707
- Interactive login flows work
646708
+ TTY forwarding between client and executable works
709+
+ `kubectl` commands and exec credential plugins do not fight for standard input
710+
+ All `InteractiveMode` values are supported
647711
- Metrics are reported as they should
648712

649713
### Graduation Criteria

0 commit comments

Comments
 (0)