Merge pull request #37953 from liggitt/automount

Automatic merge from submit-queue (batch tested with PRs 37137, 41506, 41239, 41511, 37953)

Add field to control service account token automounting

Fixes https://github.com/kubernetes/kubernetes/issues/16779

* adds an `automountServiceAccountToken *bool` field to `ServiceAccount` and `PodSpec`
* if set in both the service account and pod, the pod wins
* if unset in both the service account and pod, we automount for backwards compatibility

```release-note
An `automountServiceAccountToken *bool` field was added to ServiceAccount and PodSpec objects. If set to `false` on a pod spec, no service account token is automounted in the pod. If set to `false` on a service account, no service account token is automounted for that service account unless explicitly overridden in the pod spec.
```
pull/6/head
Kubernetes Submit Queue 2017-02-15 20:05:13 -08:00 committed by GitHub
commit 97212f5b3a
26 changed files with 1616 additions and 1097 deletions

View File

@ -37886,6 +37886,10 @@
"description": "If specified, the pod's scheduling constraints",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.Affinity"
},
"automountServiceAccountToken": {
"description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.",
"type": "boolean"
},
"containers": {
"description": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers",
"type": "array",
@ -38767,6 +38771,10 @@
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources",
"type": "string"
},
"automountServiceAccountToken": {
"description": "AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level.",
"type": "boolean"
},
"imagePullSecrets": {
"description": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: http://kubernetes.io/docs/user-guide/secrets#manually-specifying-an-imagepullsecret",
"type": "array",

View File

@ -1322,6 +1322,10 @@
"type": "string",
"description": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead."
},
"automountServiceAccountToken": {
"type": "boolean",
"description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted."
},
"nodeName": {
"type": "string",
"description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements."

View File

@ -1327,6 +1327,10 @@
"type": "string",
"description": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead."
},
"automountServiceAccountToken": {
"type": "boolean",
"description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted."
},
"nodeName": {
"type": "string",
"description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements."

View File

@ -6729,6 +6729,10 @@
"type": "string",
"description": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead."
},
"automountServiceAccountToken": {
"type": "boolean",
"description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted."
},
"nodeName": {
"type": "string",
"description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements."

View File

@ -18265,6 +18265,10 @@
"type": "string",
"description": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead."
},
"automountServiceAccountToken": {
"type": "boolean",
"description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted."
},
"nodeName": {
"type": "string",
"description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements."
@ -20078,6 +20082,10 @@
"$ref": "v1.LocalObjectReference"
},
"description": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: http://kubernetes.io/docs/user-guide/secrets#manually-specifying-an-imagepullsecret"
},
"automountServiceAccountToken": {
"type": "boolean",
"description": "AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level."
}
}
},

View File

@ -4556,6 +4556,13 @@ The StatefulSet guarantees that a given network identity will always map to the
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">automountServiceAccountToken</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">nodeName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
@ -5081,7 +5088,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-06 11:50:05 UTC
Last updated 2017-02-14 05:29:50 UTC
</div>
</div>
</body>

View File

@ -4543,6 +4543,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">automountServiceAccountToken</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">nodeName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
@ -5013,7 +5020,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-06 11:50:30 UTC
Last updated 2017-02-14 05:30:28 UTC
</div>
</div>
</body>

View File

@ -4080,6 +4080,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">automountServiceAccountToken</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">nodeName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
@ -7304,7 +7311,7 @@ Both these may change in the future. Incoming requests are matched against the h
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-06 11:50:48 UTC
Last updated 2017-02-14 05:30:44 UTC
</div>
</div>
</body>

View File

@ -2887,6 +2887,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_localobjectreference">v1.LocalObjectReference</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">automountServiceAccountToken</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
</tbody>
</table>
@ -4790,6 +4797,13 @@ The resulting set of endpoints can be viewed as:<br>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">automountServiceAccountToken</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">nodeName</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
@ -9261,7 +9275,7 @@ Examples:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-06 11:49:57 UTC
Last updated 2017-02-14 05:29:43 UTC
</div>
</div>
</body>

View File

@ -12490,6 +12490,10 @@
"description": "If specified, the pod's scheduling constraints",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.Affinity"
},
"automountServiceAccountToken": {
"description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.",
"type": "boolean"
},
"containers": {
"description": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/containers",
"type": "array",

View File

@ -1887,6 +1887,9 @@ type PodSpec struct {
// ServiceAccountName is the name of the ServiceAccount to use to run this pod
// The pod will be allowed to use secrets referenced by the ServiceAccount
ServiceAccountName string
// AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.
// +optional
AutomountServiceAccountToken *bool
// NodeName is a request to schedule this pod onto a specific node. If it is non-empty,
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
@ -2425,6 +2428,11 @@ type ServiceAccount struct {
// can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet.
// +optional
ImagePullSecrets []LocalObjectReference
// AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted.
// Can be overridden at the pod level.
// +optional
AutomountServiceAccountToken *bool
}
// ServiceAccountList is a list of ServiceAccount objects

File diff suppressed because it is too large Load Diff

View File

@ -2569,6 +2569,10 @@ message PodSpec {
// +optional
optional string serviceAccount = 9;
// AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.
// +optional
optional bool automountServiceAccountToken = 21;
// NodeName is a request to schedule this pod onto a specific node. If it is non-empty,
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
// requirements.
@ -3307,6 +3311,11 @@ message ServiceAccount {
// More info: http://kubernetes.io/docs/user-guide/secrets#manually-specifying-an-imagepullsecret
// +optional
repeated LocalObjectReference imagePullSecrets = 3;
// AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted.
// Can be overridden at the pod level.
// +optional
optional bool automountServiceAccountToken = 4;
}
// ServiceAccountList is a list of ServiceAccount objects

File diff suppressed because it is too large Load Diff

View File

@ -2160,6 +2160,9 @@ type PodSpec struct {
// +k8s:conversion-gen=false
// +optional
DeprecatedServiceAccount string `json:"serviceAccount,omitempty" protobuf:"bytes,9,opt,name=serviceAccount"`
// AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.
// +optional
AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty" protobuf:"varint,21,opt,name=automountServiceAccountToken"`
// NodeName is a request to schedule this pod onto a specific node. If it is non-empty,
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
@ -2801,6 +2804,11 @@ type ServiceAccount struct {
// More info: http://kubernetes.io/docs/user-guide/secrets#manually-specifying-an-imagepullsecret
// +optional
ImagePullSecrets []LocalObjectReference `json:"imagePullSecrets,omitempty" protobuf:"bytes,3,rep,name=imagePullSecrets"`
// AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted.
// Can be overridden at the pod level.
// +optional
AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty" protobuf:"varint,4,opt,name=automountServiceAccountToken"`
}
// ServiceAccountList is a list of ServiceAccount objects

View File

@ -1301,6 +1301,7 @@ var map_PodSpec = map[string]string{
"nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://kubernetes.io/docs/user-guide/node-selection/README",
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md",
"serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.",
"automountServiceAccountToken": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.",
"nodeName": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.",
"hostNetwork": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.",
"hostPID": "Use the host's pid namespace. Optional: Default to false.",
@ -1681,10 +1682,11 @@ func (Service) SwaggerDoc() map[string]string {
}
var map_ServiceAccount = map[string]string{
"": "ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"secrets": "Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. More info: http://kubernetes.io/docs/user-guide/secrets",
"imagePullSecrets": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: http://kubernetes.io/docs/user-guide/secrets#manually-specifying-an-imagepullsecret",
"": "ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"secrets": "Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. More info: http://kubernetes.io/docs/user-guide/secrets",
"imagePullSecrets": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: http://kubernetes.io/docs/user-guide/secrets#manually-specifying-an-imagepullsecret",
"automountServiceAccountToken": "AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level.",
}
func (ServiceAccount) SwaggerDoc() map[string]string {

View File

@ -3086,6 +3086,7 @@ func autoConvert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conv
out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector))
out.ServiceAccountName = in.ServiceAccountName
// INFO: in.DeprecatedServiceAccount opted out of conversion generation
out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken))
out.NodeName = in.NodeName
// INFO: in.HostNetwork opted out of conversion generation
// INFO: in.HostPID opted out of conversion generation
@ -3127,6 +3128,7 @@ func autoConvert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conv
out.DNSPolicy = DNSPolicy(in.DNSPolicy)
out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector))
out.ServiceAccountName = in.ServiceAccountName
out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken))
out.NodeName = in.NodeName
if in.SecurityContext != nil {
in, out := &in.SecurityContext, &out.SecurityContext
@ -3992,6 +3994,7 @@ func autoConvert_v1_ServiceAccount_To_api_ServiceAccount(in *ServiceAccount, out
out.ObjectMeta = in.ObjectMeta
out.Secrets = *(*[]api.ObjectReference)(unsafe.Pointer(&in.Secrets))
out.ImagePullSecrets = *(*[]api.LocalObjectReference)(unsafe.Pointer(&in.ImagePullSecrets))
out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken))
return nil
}
@ -4003,6 +4006,7 @@ func autoConvert_api_ServiceAccount_To_v1_ServiceAccount(in *api.ServiceAccount,
out.ObjectMeta = in.ObjectMeta
out.Secrets = *(*[]ObjectReference)(unsafe.Pointer(&in.Secrets))
out.ImagePullSecrets = *(*[]LocalObjectReference)(unsafe.Pointer(&in.ImagePullSecrets))
out.AutomountServiceAccountToken = (*bool)(unsafe.Pointer(in.AutomountServiceAccountToken))
return nil
}

View File

@ -2303,6 +2303,11 @@ func DeepCopy_v1_PodSpec(in interface{}, out interface{}, c *conversion.Cloner)
(*out)[key] = val
}
}
if in.AutomountServiceAccountToken != nil {
in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken
*out = new(bool)
**out = **in
}
if in.SecurityContext != nil {
in, out := &in.SecurityContext, &out.SecurityContext
*out = new(PodSecurityContext)
@ -2948,6 +2953,11 @@ func DeepCopy_v1_ServiceAccount(in interface{}, out interface{}, c *conversion.C
*out = make([]LocalObjectReference, len(*in))
copy(*out, *in)
}
if in.AutomountServiceAccountToken != nil {
in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken
*out = new(bool)
**out = **in
}
return nil
}
}

View File

@ -2347,6 +2347,11 @@ func DeepCopy_api_PodSpec(in interface{}, out interface{}, c *conversion.Cloner)
(*out)[key] = val
}
}
if in.AutomountServiceAccountToken != nil {
in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken
*out = new(bool)
**out = **in
}
if in.SecurityContext != nil {
in, out := &in.SecurityContext, &out.SecurityContext
*out = new(PodSecurityContext)
@ -2980,6 +2985,11 @@ func DeepCopy_api_ServiceAccount(in interface{}, out interface{}, c *conversion.
*out = make([]LocalObjectReference, len(*in))
copy(*out, *in)
}
if in.AutomountServiceAccountToken != nil {
in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken
*out = new(bool)
**out = **in
}
return nil
}
}

View File

@ -1679,7 +1679,7 @@ func (x codecSelfer1234) decSliceStatefulSet(v *[]StatefulSet, d *codec1978.Deco
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 824)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 832)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -2481,7 +2481,7 @@ func (x codecSelfer1234) decSliceJob(v *[]Job, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 848)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 856)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -4534,7 +4534,7 @@ func (x codecSelfer1234) decSliceJob(v *[]Job, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 848)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 856)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -4772,7 +4772,7 @@ func (x codecSelfer1234) decSliceCronJob(v *[]CronJob, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 1096)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 1104)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -18858,7 +18858,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 888)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 896)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -18977,7 +18977,7 @@ func (x codecSelfer1234) decSliceDaemonSet(v *[]DaemonSet, d *codec1978.Decoder)
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 784)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 792)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -19691,7 +19691,7 @@ func (x codecSelfer1234) decSliceReplicaSet(v *[]ReplicaSet, d *codec1978.Decode
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 824)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 832)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -6383,6 +6383,13 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
Format: "",
},
},
"automountServiceAccountToken": {
SchemaProps: spec.SchemaProps{
Description: "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.",
Type: []string{"boolean"},
Format: "",
},
},
"nodeName": {
SchemaProps: spec.SchemaProps{
Description: "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.",
@ -8285,6 +8292,13 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
},
},
},
"automountServiceAccountToken": {
SchemaProps: spec.SchemaProps{
Description: "AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level.",
Type: []string{"boolean"},
Format: "",
},
},
},
},
},

View File

@ -222,7 +222,7 @@ func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
}
}
if s.MountServiceAccountToken {
if s.MountServiceAccountToken && shouldAutomount(serviceAccount, pod) {
if err := s.mountServiceAccountToken(serviceAccount, pod); err != nil {
if _, ok := err.(errors.APIStatus); ok {
return err
@ -239,6 +239,19 @@ func (s *serviceAccount) Admit(a admission.Attributes) (err error) {
return nil
}
func shouldAutomount(sa *api.ServiceAccount, pod *api.Pod) bool {
// Pod's preference wins
if pod.Spec.AutomountServiceAccountToken != nil {
return *pod.Spec.AutomountServiceAccountToken
}
// Then service account's
if sa.AutomountServiceAccountToken != nil {
return *sa.AutomountServiceAccountToken
}
// Default to true for backwards compatibility
return true
}
// enforceMountableSecrets indicates whether mountable secrets should be enforced for a particular service account
// A global setting of true will override any flag set on the individual service account
func (s *serviceAccount) enforceMountableSecrets(serviceAccount *api.ServiceAccount) bool {

View File

@ -35,6 +35,8 @@ import (
var serviceAccountTokenNamespaceVersion = utilversion.MustParseSemantic("v1.2.0")
var serviceAccountTokenAutomountVersion = utilversion.MustParseSemantic("v1.6.0-alpha.2")
var _ = framework.KubeDescribe("ServiceAccounts", func() {
f := framework.NewDefaultFramework("svcaccounts")
@ -239,4 +241,145 @@ var _ = framework.KubeDescribe("ServiceAccounts", func() {
})
}
})
It("should allow opting out of API token automount [Conformance]", func() {
framework.SkipUnlessServerVersionGTE(serviceAccountTokenAutomountVersion, f.ClientSet.Discovery())
var err error
trueValue := true
falseValue := false
mountSA := &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "mount"}, AutomountServiceAccountToken: &trueValue}
nomountSA := &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "nomount"}, AutomountServiceAccountToken: &falseValue}
mountSA, err = f.ClientSet.Core().ServiceAccounts(f.Namespace.Name).Create(mountSA)
framework.ExpectNoError(err)
nomountSA, err = f.ClientSet.Core().ServiceAccounts(f.Namespace.Name).Create(nomountSA)
framework.ExpectNoError(err)
// Standard get, update retry loop
framework.ExpectNoError(wait.Poll(time.Millisecond*500, framework.ServiceAccountProvisionTimeout, func() (bool, error) {
By("getting the auto-created API token")
sa, err := f.ClientSet.Core().ServiceAccounts(f.Namespace.Name).Get(mountSA.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
framework.Logf("mount service account was not found")
return false, nil
}
if err != nil {
framework.Logf("error getting mount service account: %v", err)
return false, err
}
if len(sa.Secrets) == 0 {
framework.Logf("mount service account has no secret references")
return false, nil
}
for _, secretRef := range sa.Secrets {
secret, err := f.ClientSet.Core().Secrets(f.Namespace.Name).Get(secretRef.Name, metav1.GetOptions{})
if err != nil {
framework.Logf("Error getting secret %s: %v", secretRef.Name, err)
continue
}
if secret.Type == v1.SecretTypeServiceAccountToken {
return true, nil
}
}
framework.Logf("default service account has no secret references to valid service account tokens")
return false, nil
}))
testcases := []struct {
PodName string
ServiceAccountName string
AutomountPodSpec *bool
ExpectTokenVolume bool
}{
{
PodName: "pod-service-account-defaultsa",
ServiceAccountName: "default",
AutomountPodSpec: nil,
ExpectTokenVolume: true, // default is true
},
{
PodName: "pod-service-account-mountsa",
ServiceAccountName: mountSA.Name,
AutomountPodSpec: nil,
ExpectTokenVolume: true,
},
{
PodName: "pod-service-account-nomountsa",
ServiceAccountName: nomountSA.Name,
AutomountPodSpec: nil,
ExpectTokenVolume: false,
},
// Make sure pod spec trumps when opting in
{
PodName: "pod-service-account-defaultsa-mountspec",
ServiceAccountName: "default",
AutomountPodSpec: &trueValue,
ExpectTokenVolume: true,
},
{
PodName: "pod-service-account-mountsa-mountspec",
ServiceAccountName: mountSA.Name,
AutomountPodSpec: &trueValue,
ExpectTokenVolume: true,
},
{
PodName: "pod-service-account-nomountsa-mountspec",
ServiceAccountName: nomountSA.Name,
AutomountPodSpec: &trueValue,
ExpectTokenVolume: true, // pod spec trumps
},
// Make sure pod spec trumps when opting out
{
PodName: "pod-service-account-defaultsa-nomountspec",
ServiceAccountName: "default",
AutomountPodSpec: &falseValue,
ExpectTokenVolume: false, // pod spec trumps
},
{
PodName: "pod-service-account-mountsa-nomountspec",
ServiceAccountName: mountSA.Name,
AutomountPodSpec: &falseValue,
ExpectTokenVolume: false, // pod spec trumps
},
{
PodName: "pod-service-account-nomountsa-nomountspec",
ServiceAccountName: nomountSA.Name,
AutomountPodSpec: &falseValue,
ExpectTokenVolume: false, // pod spec trumps
},
}
for _, tc := range testcases {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: tc.PodName},
Spec: v1.PodSpec{
Containers: []v1.Container{{Name: "token-test", Image: "gcr.io/google_containers/mounttest:0.7"}},
RestartPolicy: v1.RestartPolicyNever,
ServiceAccountName: tc.ServiceAccountName,
AutomountServiceAccountToken: tc.AutomountPodSpec,
},
}
createdPod, err := f.ClientSet.Core().Pods(f.Namespace.Name).Create(pod)
framework.ExpectNoError(err)
framework.Logf("created pod %s", tc.PodName)
hasServiceAccountTokenVolume := false
for _, c := range createdPod.Spec.Containers {
for _, vm := range c.VolumeMounts {
if vm.MountPath == serviceaccount.DefaultAPITokenMountPath {
hasServiceAccountTokenVolume = true
}
}
}
if hasServiceAccountTokenVolume != tc.ExpectTokenVolume {
framework.Failf("%s: expected volume=%v, got %v (%#v)", tc.PodName, tc.ExpectTokenVolume, hasServiceAccountTokenVolume, createdPod)
} else {
framework.Logf("pod %s service account token volume mount: %v", tc.PodName, hasServiceAccountTokenVolume)
}
}
})
})