Change-Id: I27eb6182535524337d6ff6855e334a30d9c84aaa
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/5382
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: gerrit-photon <photon-checkins@vmware.com>
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 |
-From 0f361d3f8a3f313f790e0a819aad8006f5393444 Mon Sep 17 00:00:00 2001 |
|
| 1 |
+From 328d693b17ae4910e8af5ef63a3a7c2414434f7a Mon Sep 17 00:00:00 2001 |
|
| 2 | 2 |
From: Bo Gan <ganb@vmware.com> |
| 3 | 3 |
Date: Sun, 10 Jun 2018 02:16:47 -0700 |
| 4 |
-Subject: [PATCH] Cascade Kubernetes patches for v1.9.6 (3a784cd) |
|
| 4 |
+Subject: [PATCH] Cascade Kubernetes patches for v1.9.6 (1f4aedb) |
|
| 5 | 5 |
|
| 6 | 6 |
--- |
| 7 | 7 |
api/swagger-spec/apps_v1alpha1.json | 21 + |
| ... | ... |
@@ -26,14 +26,14 @@ Subject: [PATCH] Cascade Kubernetes patches for v1.9.6 (3a784cd) |
| 26 | 26 |
pkg/cloudprovider/providers/cascade/OWNERS | 3 + |
| 27 | 27 |
pkg/cloudprovider/providers/cascade/apitypes.go | 229 ++++++ |
| 28 | 28 |
pkg/cloudprovider/providers/cascade/auth.go | 145 ++++ |
| 29 |
- pkg/cloudprovider/providers/cascade/cascade.go | 218 ++++++ |
|
| 29 |
+ pkg/cloudprovider/providers/cascade/cascade.go | 218 +++++ |
|
| 30 | 30 |
.../providers/cascade/cascade_disks.go | 225 ++++++ |
| 31 | 31 |
.../providers/cascade/cascade_instances.go | 91 +++ |
| 32 | 32 |
.../providers/cascade/cascade_instances_test.go | 43 + |
| 33 | 33 |
.../providers/cascade/cascade_loadbalancer.go | 284 +++++++ |
| 34 |
- pkg/cloudprovider/providers/cascade/client.go | 394 ++++++++++ |
|
| 34 |
+ pkg/cloudprovider/providers/cascade/client.go | 399 ++++++++++ |
|
| 35 | 35 |
pkg/cloudprovider/providers/cascade/oidcclient.go | 297 +++++++ |
| 36 |
- pkg/cloudprovider/providers/cascade/restclient.go | 262 +++++++ |
|
| 36 |
+ pkg/cloudprovider/providers/cascade/restclient.go | 262 ++++++ |
|
| 37 | 37 |
pkg/cloudprovider/providers/cascade/tests_owed | 5 + |
| 38 | 38 |
pkg/cloudprovider/providers/cascade/utils.go | 25 + |
| 39 | 39 |
pkg/cloudprovider/providers/providers.go | 1 + |
| ... | ... |
@@ -42,15 +42,15 @@ Subject: [PATCH] Cascade Kubernetes patches for v1.9.6 (3a784cd) |
| 42 | 42 |
pkg/volume/cascade_disk/BUILD | 43 + |
| 43 | 43 |
pkg/volume/cascade_disk/OWNERS | 2 + |
| 44 | 44 |
pkg/volume/cascade_disk/attacher.go | 265 +++++++ |
| 45 |
- pkg/volume/cascade_disk/cascade_disk.go | 391 ++++++++++ |
|
| 45 |
+ pkg/volume/cascade_disk/cascade_disk.go | 391 +++++++++ |
|
| 46 | 46 |
pkg/volume/cascade_disk/cascade_util.go | 152 ++++ |
| 47 | 47 |
.../admission/persistentvolume/label/admission.go | 54 ++ |
| 48 | 48 |
plugin/pkg/admission/vke/BUILD | 60 ++ |
| 49 |
- plugin/pkg/admission/vke/admission.go | 506 ++++++++++++ |
|
| 50 |
- plugin/pkg/admission/vke/admission_test.go | 865 +++++++++++++++++++++ |
|
| 49 |
+ plugin/pkg/admission/vke/admission.go | 555 +++++++++++++ |
|
| 50 |
+ plugin/pkg/admission/vke/admission_test.go | 882 +++++++++++++++++++++ |
|
| 51 | 51 |
staging/src/k8s.io/api/core/v1/generated.pb.go | 310 +++++++- |
| 52 | 52 |
staging/src/k8s.io/api/core/v1/types.go | 26 +- |
| 53 |
- 46 files changed, 5182 insertions(+), 29 deletions(-) |
|
| 53 |
+ 46 files changed, 5253 insertions(+), 29 deletions(-) |
|
| 54 | 54 |
create mode 100644 pkg/cloudprovider/providers/cascade/BUILD |
| 55 | 55 |
create mode 100644 pkg/cloudprovider/providers/cascade/OWNERS |
| 56 | 56 |
create mode 100644 pkg/cloudprovider/providers/cascade/apitypes.go |
| ... | ... |
@@ -1716,7 +1716,7 @@ index 0000000..bec5491 |
| 1716 | 1716 |
+} |
| 1717 | 1717 |
diff --git a/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go b/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go |
| 1718 | 1718 |
new file mode 100644 |
| 1719 |
-index 0000000..e28282f |
|
| 1719 |
+index 0000000..fac37e5 |
|
| 1720 | 1720 |
--- /dev/null |
| 1721 | 1721 |
+++ b/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go |
| 1722 | 1722 |
@@ -0,0 +1,284 @@ |
| ... | ... |
@@ -1880,7 +1880,7 @@ index 0000000..e28282f |
| 1880 | 1880 |
+ loadBalancerName := cloudprovider.GetLoadBalancerName(k8sService) |
| 1881 | 1881 |
+ logger.Infof("Load balancer name: %s", loadBalancerName)
|
| 1882 | 1882 |
+ |
| 1883 |
-+ task, err := cc.apiClient.DeleteLoadBalancer(StringPtr(loadBalancerName)) |
|
| 1883 |
++ task, err := cc.apiClient.DeleteLoadBalancer(StringPtr(loadBalancerName), k8sService.Name) |
|
| 1884 | 1884 |
+ if err != nil {
|
| 1885 | 1885 |
+ logger.Errorf("Failed to delete load balancer. Error: [%v]", err)
|
| 1886 | 1886 |
+ // If we get a NotFound error, we assume that the load balancer is already deleted. So we don't return an error |
| ... | ... |
@@ -2007,10 +2007,10 @@ index 0000000..e28282f |
| 2007 | 2007 |
\ No newline at end of file |
| 2008 | 2008 |
diff --git a/pkg/cloudprovider/providers/cascade/client.go b/pkg/cloudprovider/providers/cascade/client.go |
| 2009 | 2009 |
new file mode 100644 |
| 2010 |
-index 0000000..72049e0 |
|
| 2010 |
+index 0000000..e4494e4 |
|
| 2011 | 2011 |
--- /dev/null |
| 2012 | 2012 |
+++ b/pkg/cloudprovider/providers/cascade/client.go |
| 2013 |
-@@ -0,0 +1,394 @@ |
|
| 2013 |
+@@ -0,0 +1,399 @@ |
|
| 2014 | 2014 |
+package cascade |
| 2015 | 2015 |
+ |
| 2016 | 2016 |
+import ( |
| ... | ... |
@@ -2329,9 +2329,14 @@ index 0000000..72049e0 |
| 2329 | 2329 |
+} |
| 2330 | 2330 |
+ |
| 2331 | 2331 |
+// DeleteLoadBalancer deletes a load balancer by name |
| 2332 |
-+func (api *Client) DeleteLoadBalancer(loadBalancerName *string) (*Task, error) {
|
|
| 2332 |
++func (api *Client) DeleteLoadBalancer(loadBalancerName *string, subDomain string) (*Task, error) {
|
|
| 2333 | 2333 |
+ uri := fmt.Sprintf("%s/v1/tenants/%s/clusters/%s/loadbalancers/%s", api.cfg.endpoint, api.cfg.tenantName,
|
| 2334 | 2334 |
+ api.cfg.clusterID, StringVal(loadBalancerName)) |
| 2335 |
++ |
|
| 2336 |
++ if len(subDomain) > 0 {
|
|
| 2337 |
++ uri = fmt.Sprintf(uri + "?sub-domain=%s", subDomain) |
|
| 2338 |
++ } |
|
| 2339 |
++ |
|
| 2335 | 2340 |
+ res, err := api.restClient.Delete(uri, api.options.TokenOptions) |
| 2336 | 2341 |
+ if err != nil {
|
| 2337 | 2342 |
+ return nil, err |
| ... | ... |
@@ -4124,10 +4129,10 @@ index 0000000..d0bb7c7 |
| 4124 | 4124 |
\ No newline at end of file |
| 4125 | 4125 |
diff --git a/plugin/pkg/admission/vke/admission.go b/plugin/pkg/admission/vke/admission.go |
| 4126 | 4126 |
new file mode 100644 |
| 4127 |
-index 0000000..6bd7592 |
|
| 4127 |
+index 0000000..c2714cb |
|
| 4128 | 4128 |
--- /dev/null |
| 4129 | 4129 |
+++ b/plugin/pkg/admission/vke/admission.go |
| 4130 |
-@@ -0,0 +1,506 @@ |
|
| 4130 |
+@@ -0,0 +1,555 @@ |
|
| 4131 | 4131 |
+package vke |
| 4132 | 4132 |
+ |
| 4133 | 4133 |
+import ( |
| ... | ... |
@@ -4156,11 +4161,13 @@ index 0000000..6bd7592 |
| 4156 | 4156 |
+ PluginName = "VMwareAdmissionController" |
| 4157 | 4157 |
+ |
| 4158 | 4158 |
+ systemUnsecuredUser = "system:unsecured" |
| 4159 |
++ systemNodesGroup = "system:nodes" |
|
| 4160 |
++ systemMasterGroup = "system:master" |
|
| 4161 |
++ systemNodePrefix = "system:node:" |
|
| 4162 |
++ systemClusterPrefix = "system:clusterID:" |
|
| 4159 | 4163 |
+ privilegedNamespace = "vke-system" |
| 4160 | 4164 |
+ privilegedServiceAccount = "system:serviceaccount:" + privilegedNamespace + ":" |
| 4161 | 4165 |
+ reservedPrefix = "vke" |
| 4162 |
-+ kubeletGroup = "system:nodes" |
|
| 4163 |
-+ kubeProxyGroup = "vke:kube-proxies" |
|
| 4164 | 4166 |
+ reservedTolerationKey = "Dedicated" |
| 4165 | 4167 |
+ reservedTolerationValue = "Master" |
| 4166 | 4168 |
+ masterNodePrefix = "master" |
| ... | ... |
@@ -4180,10 +4187,12 @@ index 0000000..6bd7592 |
| 4180 | 4180 |
+ psp *extensions.PodSecurityPolicy |
| 4181 | 4181 |
+ strategyFactory podsecuritypolicy.StrategyFactory |
| 4182 | 4182 |
+ privilegedGroup string |
| 4183 |
++ clusterID string |
|
| 4183 | 4184 |
+} |
| 4184 | 4185 |
+ |
| 4185 | 4186 |
+// vmwareAdmissionControllerConfig holds config data for VMwareAdmissionController. |
| 4186 | 4187 |
+type vmwareAdmissionControllerConfig struct {
|
| 4188 |
++ ClusterID string `yaml:"clusterID"` |
|
| 4187 | 4189 |
+ PrivilegedGroup string `yaml:"privilegedGroup"` |
| 4188 | 4190 |
+ PodSecurityPolicyFile string `yaml:"podSecurityPolicyFile"` |
| 4189 | 4191 |
+} |
| ... | ... |
@@ -4205,6 +4214,10 @@ index 0000000..6bd7592 |
| 4205 | 4205 |
+ return validateSystemUnsecuredUser(vac, a) |
| 4206 | 4206 |
+ } |
| 4207 | 4207 |
+ |
| 4208 |
++ if isCertificateFromNode(a) {
|
|
| 4209 |
++ return validateNodeCertificate(vac, a) |
|
| 4210 |
++ } |
|
| 4211 |
++ |
|
| 4208 | 4212 |
+ if isPrivilegedNamespace(a) {
|
| 4209 | 4213 |
+ return admission.NewForbidden(a, |
| 4210 | 4214 |
+ fmt.Errorf("%s validation failed: cannot modify resources in namespace %s", PluginName, a.GetNamespace()))
|
| ... | ... |
@@ -4255,6 +4268,7 @@ index 0000000..6bd7592 |
| 4255 | 4255 |
+ psp: psp, |
| 4256 | 4256 |
+ strategyFactory: podsecuritypolicy.NewSimpleStrategyFactory(), |
| 4257 | 4257 |
+ privilegedGroup: config.VMwareAdmissionController.PrivilegedGroup, |
| 4258 |
++ clusterID: config.VMwareAdmissionController.ClusterID, |
|
| 4258 | 4259 |
+ }, nil |
| 4259 | 4260 |
+} |
| 4260 | 4261 |
+ |
| ... | ... |
@@ -4348,12 +4362,9 @@ index 0000000..6bd7592 |
| 4348 | 4348 |
+ |
| 4349 | 4349 |
+ // If the request comes from a user belonging to a privileged group, then we allow it. Only calls from Cascade |
| 4350 | 4350 |
+ // controller will belong to this privileged group. |
| 4351 |
-+ // If the request comes from kubelet or kube-proxy, we allow those too. We don't want to prevent kubelet from being |
|
| 4352 |
-+ // able to create a privileged pod or update nodes. The same way we don't want to prevent kube-proxy from creating |
|
| 4353 |
-+ // events. |
|
| 4354 | 4351 |
+ groups := a.GetUserInfo().GetGroups() |
| 4355 | 4352 |
+ for _, group := range groups {
|
| 4356 |
-+ if group == vac.privilegedGroup || group == kubeletGroup || group == kubeProxyGroup {
|
|
| 4353 |
++ if group == vac.privilegedGroup {
|
|
| 4357 | 4354 |
+ return true |
| 4358 | 4355 |
+ } |
| 4359 | 4356 |
+ } |
| ... | ... |
@@ -4385,6 +4396,49 @@ index 0000000..6bd7592 |
| 4385 | 4385 |
+ return nil |
| 4386 | 4386 |
+} |
| 4387 | 4387 |
+ |
| 4388 |
++func isCertificateFromNode(a admission.Attributes) bool {
|
|
| 4389 |
++ // If the request came from a user with group = systemNodesGroup, then we assume that the request comes from a node |
|
| 4390 |
++ // which uses a certificate for authentication. |
|
| 4391 |
++ groups := a.GetUserInfo().GetGroups() |
|
| 4392 |
++ for _, group := range groups {
|
|
| 4393 |
++ if group == systemNodesGroup {
|
|
| 4394 |
++ return true |
|
| 4395 |
++ } |
|
| 4396 |
++ } |
|
| 4397 |
++ return false |
|
| 4398 |
++} |
|
| 4399 |
++ |
|
| 4400 |
++func validateNodeCertificate(vac *vmwareAdmissionController, a admission.Attributes) (err error) {
|
|
| 4401 |
++ // If the groups have system:cluster:cluster-id as one of the groups, then validate that the cluster ID belongs to |
|
| 4402 |
++ // this cluster. If not fail. This prevents cross cluster access using certificates. |
|
| 4403 |
++ invalidClusterID := false |
|
| 4404 |
++ masterNode := false |
|
| 4405 |
++ groups := a.GetUserInfo().GetGroups() |
|
| 4406 |
++ for _, group := range groups {
|
|
| 4407 |
++ if strings.HasPrefix(group, systemClusterPrefix) {
|
|
| 4408 |
++ groupParts := strings.Split(group, ":") |
|
| 4409 |
++ if vac.clusterID != "" && groupParts[len(groupParts)-1] != vac.clusterID {
|
|
| 4410 |
++ invalidClusterID = true |
|
| 4411 |
++ } |
|
| 4412 |
++ } |
|
| 4413 |
++ if group == systemMasterGroup {
|
|
| 4414 |
++ masterNode = true |
|
| 4415 |
++ } |
|
| 4416 |
++ } |
|
| 4417 |
++ if invalidClusterID {
|
|
| 4418 |
++ return admission.NewForbidden(a, fmt.Errorf("%s validation failed: request is not from this cluster", PluginName))
|
|
| 4419 |
++ } |
|
| 4420 |
++ |
|
| 4421 |
++ // If a worker node name does not have the node prefix, then fail. This is needed for the request to go through node |
|
| 4422 |
++ // restriction admission controller. If it is not set, then a user can bypass node restriction admission controller |
|
| 4423 |
++ // and modify the master node. |
|
| 4424 |
++ name := a.GetUserInfo().GetName() |
|
| 4425 |
++ if !strings.HasPrefix(name, systemNodePrefix) && !masterNode {
|
|
| 4426 |
++ return admission.NewForbidden(a, fmt.Errorf("%s validation failed: username is invalid", PluginName))
|
|
| 4427 |
++ } |
|
| 4428 |
++ return nil |
|
| 4429 |
++} |
|
| 4430 |
++ |
|
| 4388 | 4431 |
+func isPrivilegedNamespace(a admission.Attributes) bool {
|
| 4389 | 4432 |
+ // If the namespace mentioned in the resource is privileged, return true. We will hit this for calls made to all |
| 4390 | 4433 |
+ // resources in this namespace and during delete and update operation on the namespace itself. |
| ... | ... |
@@ -4636,10 +4690,10 @@ index 0000000..6bd7592 |
| 4636 | 4636 |
+} |
| 4637 | 4637 |
diff --git a/plugin/pkg/admission/vke/admission_test.go b/plugin/pkg/admission/vke/admission_test.go |
| 4638 | 4638 |
new file mode 100644 |
| 4639 |
-index 0000000..7f8ec60 |
|
| 4639 |
+index 0000000..4ce4a1f |
|
| 4640 | 4640 |
--- /dev/null |
| 4641 | 4641 |
+++ b/plugin/pkg/admission/vke/admission_test.go |
| 4642 |
-@@ -0,0 +1,865 @@ |
|
| 4642 |
+@@ -0,0 +1,882 @@ |
|
| 4643 | 4643 |
+package vke |
| 4644 | 4644 |
+ |
| 4645 | 4645 |
+import ( |
| ... | ... |
@@ -4657,10 +4711,12 @@ index 0000000..7f8ec60 |
| 4657 | 4657 |
+ |
| 4658 | 4658 |
+const ( |
| 4659 | 4659 |
+ testServiceAccountsGroup = "system.test\\cascade-controller-service-accounts" |
| 4660 |
++ clusterID = "cluster-id" |
|
| 4660 | 4661 |
+ defaultConfigFileFormat = ` |
| 4661 | 4662 |
+vmwareAdmissionController: |
| 4662 | 4663 |
+ privilegedGroup: %s |
| 4663 | 4664 |
+ podSecurityPolicyFile: %s |
| 4665 |
++ clusterID: %s |
|
| 4664 | 4666 |
+` |
| 4665 | 4667 |
+ pspFileName = "/tmp/psp.yaml" |
| 4666 | 4668 |
+ pspConfigFile = ` |
| ... | ... |
@@ -4988,13 +5044,7 @@ index 0000000..7f8ec60 |
| 4988 | 4988 |
+ "allowed: kubelet group creates pod in vke-system namespace": {
|
| 4989 | 4989 |
+ operation: kadmission.Create, |
| 4990 | 4990 |
+ pod: newTestPodBuilder().withNamespace(privilegedNamespace).build(), |
| 4991 |
-+ userInfo: newTestUserBuilder().withGroup(kubeletGroup).build(), |
|
| 4992 |
-+ shouldPassValidate: true, |
|
| 4993 |
-+ }, |
|
| 4994 |
-+ "allowed: kubeProxy group creates pod in vke-system namespace": {
|
|
| 4995 |
-+ operation: kadmission.Create, |
|
| 4996 |
-+ pod: newTestPodBuilder().withNamespace(privilegedNamespace).build(), |
|
| 4997 |
-+ userInfo: newTestUserBuilder().withGroup(kubeProxyGroup).build(), |
|
| 4991 |
++ userInfo: newTestUserBuilder().withGroup(systemNodesGroup).withName("system:node:worker").build(),
|
|
| 4998 | 4992 |
+ shouldPassValidate: true, |
| 4999 | 4993 |
+ }, |
| 5000 | 4994 |
+ "denied: regular lightwave group does not grant privileged access": {
|
| ... | ... |
@@ -5009,6 +5059,27 @@ index 0000000..7f8ec60 |
| 5009 | 5009 |
+ userInfo: newTestUserBuilder().withGroup("test1\\group1").withGroup(testServiceAccountsGroup).build(),
|
| 5010 | 5010 |
+ shouldPassValidate: true, |
| 5011 | 5011 |
+ }, |
| 5012 |
++ "denied: cross cluster acccess": {
|
|
| 5013 |
++ operation: kadmission.Create, |
|
| 5014 |
++ pod: newTestPodBuilder().build(), |
|
| 5015 |
++ userInfo: newTestUserBuilder().withName("system:node:worker").withGroup("system:clusterID:some-cluster-id").
|
|
| 5016 |
++ withGroup("system:nodes").withGroup("system:worker").build(),
|
|
| 5017 |
++ shouldPassValidate: false, |
|
| 5018 |
++ }, |
|
| 5019 |
++ "denied: node restriction admission controller bypass": {
|
|
| 5020 |
++ operation: kadmission.Create, |
|
| 5021 |
++ pod: newTestPodBuilder().build(), |
|
| 5022 |
++ userInfo: newTestUserBuilder().withGroup("system:clusterID:cluster-id").withGroup("system:nodes").
|
|
| 5023 |
++ withGroup("system:worker").build(),
|
|
| 5024 |
++ shouldPassValidate: false, |
|
| 5025 |
++ }, |
|
| 5026 |
++ "allowed: master node to bypass node restriction admission controller": {
|
|
| 5027 |
++ operation: kadmission.Create, |
|
| 5028 |
++ pod: newTestPodBuilder().build(), |
|
| 5029 |
++ userInfo: newTestUserBuilder().withName("kubernetes-master").withGroup("system:clusterID:cluster-id").
|
|
| 5030 |
++ withGroup("system:nodes").withGroup("system:master").build(),
|
|
| 5031 |
++ shouldPassValidate: true, |
|
| 5032 |
++ }, |
|
| 5012 | 5033 |
+ } |
| 5013 | 5034 |
+ for k, v := range tests {
|
| 5014 | 5035 |
+ testPodValidation(k, v.operation, v.pod, v.name, v.userInfo, v.shouldPassValidate, t) |
| ... | ... |
@@ -5284,7 +5355,7 @@ index 0000000..7f8ec60 |
| 5284 | 5284 |
+func testPodValidation(testCaseName string, op kadmission.Operation, pod *kapi.Pod, name string, userInfo user.Info, |
| 5285 | 5285 |
+ shouldPassValidate bool, t *testing.T) {
|
| 5286 | 5286 |
+ |
| 5287 |
-+ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName) |
|
| 5287 |
++ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName, clusterID) |
|
| 5288 | 5288 |
+ configFile := strings.NewReader(defaultConfigFile) |
| 5289 | 5289 |
+ plugin, err := NewVMwareAdmissionController(configFile) |
| 5290 | 5290 |
+ if err != nil {
|
| ... | ... |
@@ -5310,7 +5381,7 @@ index 0000000..7f8ec60 |
| 5310 | 5310 |
+func testResourceValidation(testCaseName string, op kadmission.Operation, resource, subresource, name, namespace string, |
| 5311 | 5311 |
+ userInfo user.Info, shouldPassValidate bool, t *testing.T) {
|
| 5312 | 5312 |
+ |
| 5313 |
-+ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName) |
|
| 5313 |
++ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName, clusterID) |
|
| 5314 | 5314 |
+ configFile := strings.NewReader(defaultConfigFile) |
| 5315 | 5315 |
+ plugin, err := NewVMwareAdmissionController(configFile) |
| 5316 | 5316 |
+ if err != nil {
|
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 |
-From 0dc83e12d98eb7aaa682bf6c251c89ff842e2275 Mon Sep 17 00:00:00 2001 |
|
| 1 |
+From a9402d16a92e04e25ede3816872855e9a89fb812 Mon Sep 17 00:00:00 2001 |
|
| 2 | 2 |
From: Bo Gan <ganb@vmware.com> |
| 3 | 3 |
Date: Sun, 10 Jun 2018 02:13:51 -0700 |
| 4 |
-Subject: [PATCH] Cascade Kubernetes patches for v1.10.2 (3a784cd) |
|
| 4 |
+Subject: [PATCH] Cascade Kubernetes patches for v1.10.2 (1f4aedb) |
|
| 5 | 5 |
|
| 6 | 6 |
--- |
| 7 | 7 |
api/swagger-spec/apps_v1alpha1.json | 21 + |
| ... | ... |
@@ -28,11 +28,11 @@ Subject: [PATCH] Cascade Kubernetes patches for v1.10.2 (3a784cd) |
| 28 | 28 |
pkg/cloudprovider/providers/cascade/cascade.go | 214 +++++ |
| 29 | 29 |
.../providers/cascade/cascade_disks.go | 227 ++++++ |
| 30 | 30 |
.../providers/cascade/cascade_instances.go | 92 +++ |
| 31 |
- .../providers/cascade/cascade_instances_test.go | 44 ++ |
|
| 31 |
+ .../providers/cascade/cascade_instances_test.go | 44 + |
|
| 32 | 32 |
.../providers/cascade/cascade_loadbalancer.go | 285 +++++++ |
| 33 |
- pkg/cloudprovider/providers/cascade/client.go | 394 ++++++++++ |
|
| 33 |
+ pkg/cloudprovider/providers/cascade/client.go | 399 ++++++++++ |
|
| 34 | 34 |
pkg/cloudprovider/providers/cascade/oidcclient.go | 297 +++++++ |
| 35 |
- pkg/cloudprovider/providers/cascade/restclient.go | 262 +++++++ |
|
| 35 |
+ pkg/cloudprovider/providers/cascade/restclient.go | 262 ++++++ |
|
| 36 | 36 |
pkg/cloudprovider/providers/cascade/tests_owed | 5 + |
| 37 | 37 |
pkg/cloudprovider/providers/cascade/utils.go | 25 + |
| 38 | 38 |
pkg/cloudprovider/providers/providers.go | 1 + |
| ... | ... |
@@ -41,16 +41,16 @@ Subject: [PATCH] Cascade Kubernetes patches for v1.10.2 (3a784cd) |
| 41 | 41 |
pkg/security/podsecuritypolicy/util/util.go | 3 + |
| 42 | 42 |
pkg/volume/cascade_disk/BUILD | 43 + |
| 43 | 43 |
pkg/volume/cascade_disk/OWNERS | 2 + |
| 44 |
- pkg/volume/cascade_disk/attacher.go | 264 +++++++ |
|
| 45 |
- pkg/volume/cascade_disk/cascade_disk.go | 390 ++++++++++ |
|
| 44 |
+ pkg/volume/cascade_disk/attacher.go | 264 ++++++ |
|
| 45 |
+ pkg/volume/cascade_disk/cascade_disk.go | 390 +++++++++ |
|
| 46 | 46 |
pkg/volume/cascade_disk/cascade_util.go | 152 ++++ |
| 47 | 47 |
.../admission/persistentvolume/label/admission.go | 54 ++ |
| 48 | 48 |
plugin/pkg/admission/vke/BUILD | 60 ++ |
| 49 |
- plugin/pkg/admission/vke/admission.go | 505 ++++++++++++ |
|
| 50 |
- plugin/pkg/admission/vke/admission_test.go | 865 +++++++++++++++++++++ |
|
| 49 |
+ plugin/pkg/admission/vke/admission.go | 554 +++++++++++++ |
|
| 50 |
+ plugin/pkg/admission/vke/admission_test.go | 882 +++++++++++++++++++++ |
|
| 51 | 51 |
staging/src/k8s.io/api/core/v1/generated.pb.go | 310 +++++++- |
| 52 | 52 |
staging/src/k8s.io/api/core/v1/types.go | 24 +- |
| 53 |
- 46 files changed, 5183 insertions(+), 29 deletions(-) |
|
| 53 |
+ 46 files changed, 5254 insertions(+), 29 deletions(-) |
|
| 54 | 54 |
create mode 100644 pkg/cloudprovider/providers/cascade/BUILD |
| 55 | 55 |
create mode 100644 pkg/cloudprovider/providers/cascade/OWNERS |
| 56 | 56 |
create mode 100644 pkg/cloudprovider/providers/cascade/apitypes.go |
| ... | ... |
@@ -1716,7 +1716,7 @@ index 0000000..8fb314d |
| 1716 | 1716 |
+} |
| 1717 | 1717 |
diff --git a/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go b/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go |
| 1718 | 1718 |
new file mode 100644 |
| 1719 |
-index 0000000..1038639 |
|
| 1719 |
+index 0000000..6338072 |
|
| 1720 | 1720 |
--- /dev/null |
| 1721 | 1721 |
+++ b/pkg/cloudprovider/providers/cascade/cascade_loadbalancer.go |
| 1722 | 1722 |
@@ -0,0 +1,285 @@ |
| ... | ... |
@@ -1881,7 +1881,7 @@ index 0000000..1038639 |
| 1881 | 1881 |
+ loadBalancerName := cloudprovider.GetLoadBalancerName(k8sService) |
| 1882 | 1882 |
+ logger.Infof("Load balancer name: %s", loadBalancerName)
|
| 1883 | 1883 |
+ |
| 1884 |
-+ task, err := cc.apiClient.DeleteLoadBalancer(StringPtr(loadBalancerName)) |
|
| 1884 |
++ task, err := cc.apiClient.DeleteLoadBalancer(StringPtr(loadBalancerName), k8sService.Name) |
|
| 1885 | 1885 |
+ if err != nil {
|
| 1886 | 1886 |
+ logger.Errorf("Failed to delete load balancer. Error: [%v]", err)
|
| 1887 | 1887 |
+ // If we get a NotFound error, we assume that the load balancer is already deleted. So we don't return an error |
| ... | ... |
@@ -2007,10 +2007,10 @@ index 0000000..1038639 |
| 2007 | 2007 |
+} |
| 2008 | 2008 |
diff --git a/pkg/cloudprovider/providers/cascade/client.go b/pkg/cloudprovider/providers/cascade/client.go |
| 2009 | 2009 |
new file mode 100644 |
| 2010 |
-index 0000000..72049e0 |
|
| 2010 |
+index 0000000..e4494e4 |
|
| 2011 | 2011 |
--- /dev/null |
| 2012 | 2012 |
+++ b/pkg/cloudprovider/providers/cascade/client.go |
| 2013 |
-@@ -0,0 +1,394 @@ |
|
| 2013 |
+@@ -0,0 +1,399 @@ |
|
| 2014 | 2014 |
+package cascade |
| 2015 | 2015 |
+ |
| 2016 | 2016 |
+import ( |
| ... | ... |
@@ -2329,9 +2329,14 @@ index 0000000..72049e0 |
| 2329 | 2329 |
+} |
| 2330 | 2330 |
+ |
| 2331 | 2331 |
+// DeleteLoadBalancer deletes a load balancer by name |
| 2332 |
-+func (api *Client) DeleteLoadBalancer(loadBalancerName *string) (*Task, error) {
|
|
| 2332 |
++func (api *Client) DeleteLoadBalancer(loadBalancerName *string, subDomain string) (*Task, error) {
|
|
| 2333 | 2333 |
+ uri := fmt.Sprintf("%s/v1/tenants/%s/clusters/%s/loadbalancers/%s", api.cfg.endpoint, api.cfg.tenantName,
|
| 2334 | 2334 |
+ api.cfg.clusterID, StringVal(loadBalancerName)) |
| 2335 |
++ |
|
| 2336 |
++ if len(subDomain) > 0 {
|
|
| 2337 |
++ uri = fmt.Sprintf(uri + "?sub-domain=%s", subDomain) |
|
| 2338 |
++ } |
|
| 2339 |
++ |
|
| 2335 | 2340 |
+ res, err := api.restClient.Delete(uri, api.options.TokenOptions) |
| 2336 | 2341 |
+ if err != nil {
|
| 2337 | 2342 |
+ return nil, err |
| ... | ... |
@@ -4149,10 +4154,10 @@ index 0000000..2fb36c7 |
| 4149 | 4149 |
\ No newline at end of file |
| 4150 | 4150 |
diff --git a/plugin/pkg/admission/vke/admission.go b/plugin/pkg/admission/vke/admission.go |
| 4151 | 4151 |
new file mode 100644 |
| 4152 |
-index 0000000..e05e7be |
|
| 4152 |
+index 0000000..64c2d16 |
|
| 4153 | 4153 |
--- /dev/null |
| 4154 | 4154 |
+++ b/plugin/pkg/admission/vke/admission.go |
| 4155 |
-@@ -0,0 +1,505 @@ |
|
| 4155 |
+@@ -0,0 +1,554 @@ |
|
| 4156 | 4156 |
+package vke |
| 4157 | 4157 |
+ |
| 4158 | 4158 |
+import ( |
| ... | ... |
@@ -4181,11 +4186,13 @@ index 0000000..e05e7be |
| 4181 | 4181 |
+ PluginName = "VMwareAdmissionController" |
| 4182 | 4182 |
+ |
| 4183 | 4183 |
+ systemUnsecuredUser = "system:unsecured" |
| 4184 |
++ systemNodesGroup = "system:nodes" |
|
| 4185 |
++ systemMasterGroup = "system:master" |
|
| 4186 |
++ systemNodePrefix = "system:node:" |
|
| 4187 |
++ systemClusterPrefix = "system:clusterID:" |
|
| 4184 | 4188 |
+ privilegedNamespace = "vke-system" |
| 4185 | 4189 |
+ privilegedServiceAccount = "system:serviceaccount:" + privilegedNamespace + ":" |
| 4186 | 4190 |
+ reservedPrefix = "vke" |
| 4187 |
-+ kubeletGroup = "system:nodes" |
|
| 4188 |
-+ kubeProxyGroup = "vke:kube-proxies" |
|
| 4189 | 4191 |
+ reservedTolerationKey = "Dedicated" |
| 4190 | 4192 |
+ reservedTolerationValue = "Master" |
| 4191 | 4193 |
+ masterNodePrefix = "master" |
| ... | ... |
@@ -4205,10 +4212,12 @@ index 0000000..e05e7be |
| 4205 | 4205 |
+ psp *extensions.PodSecurityPolicy |
| 4206 | 4206 |
+ strategyFactory podsecuritypolicy.StrategyFactory |
| 4207 | 4207 |
+ privilegedGroup string |
| 4208 |
++ clusterID string |
|
| 4208 | 4209 |
+} |
| 4209 | 4210 |
+ |
| 4210 | 4211 |
+// vmwareAdmissionControllerConfig holds config data for VMwareAdmissionController. |
| 4211 | 4212 |
+type vmwareAdmissionControllerConfig struct {
|
| 4213 |
++ ClusterID string `yaml:"clusterID"` |
|
| 4212 | 4214 |
+ PrivilegedGroup string `yaml:"privilegedGroup"` |
| 4213 | 4215 |
+ PodSecurityPolicyFile string `yaml:"podSecurityPolicyFile"` |
| 4214 | 4216 |
+} |
| ... | ... |
@@ -4230,6 +4239,10 @@ index 0000000..e05e7be |
| 4230 | 4230 |
+ return validateSystemUnsecuredUser(vac, a) |
| 4231 | 4231 |
+ } |
| 4232 | 4232 |
+ |
| 4233 |
++ if isCertificateFromNode(a) {
|
|
| 4234 |
++ return validateNodeCertificate(vac, a) |
|
| 4235 |
++ } |
|
| 4236 |
++ |
|
| 4233 | 4237 |
+ if isPrivilegedNamespace(a) {
|
| 4234 | 4238 |
+ return admission.NewForbidden(a, |
| 4235 | 4239 |
+ fmt.Errorf("%s validation failed: cannot modify resources in namespace %s", PluginName, a.GetNamespace()))
|
| ... | ... |
@@ -4280,6 +4293,7 @@ index 0000000..e05e7be |
| 4280 | 4280 |
+ psp: psp, |
| 4281 | 4281 |
+ strategyFactory: podsecuritypolicy.NewSimpleStrategyFactory(), |
| 4282 | 4282 |
+ privilegedGroup: config.VMwareAdmissionController.PrivilegedGroup, |
| 4283 |
++ clusterID: config.VMwareAdmissionController.ClusterID, |
|
| 4283 | 4284 |
+ }, nil |
| 4284 | 4285 |
+} |
| 4285 | 4286 |
+ |
| ... | ... |
@@ -4373,12 +4387,9 @@ index 0000000..e05e7be |
| 4373 | 4373 |
+ |
| 4374 | 4374 |
+ // If the request comes from a user belonging to a privileged group, then we allow it. Only calls from Cascade |
| 4375 | 4375 |
+ // controller will belong to this privileged group. |
| 4376 |
-+ // If the request comes from kubelet or kube-proxy, we allow those too. We don't want to prevent kubelet from being |
|
| 4377 |
-+ // able to create a privileged pod or update nodes. The same way we don't want to prevent kube-proxy from creating |
|
| 4378 |
-+ // events. |
|
| 4379 | 4376 |
+ groups := a.GetUserInfo().GetGroups() |
| 4380 | 4377 |
+ for _, group := range groups {
|
| 4381 |
-+ if group == vac.privilegedGroup || group == kubeletGroup || group == kubeProxyGroup {
|
|
| 4378 |
++ if group == vac.privilegedGroup {
|
|
| 4382 | 4379 |
+ return true |
| 4383 | 4380 |
+ } |
| 4384 | 4381 |
+ } |
| ... | ... |
@@ -4410,6 +4421,49 @@ index 0000000..e05e7be |
| 4410 | 4410 |
+ return nil |
| 4411 | 4411 |
+} |
| 4412 | 4412 |
+ |
| 4413 |
++func isCertificateFromNode(a admission.Attributes) bool {
|
|
| 4414 |
++ // If the request came from a user with group = systemNodesGroup, then we assume that the request comes from a node |
|
| 4415 |
++ // which uses a certificate for authentication. |
|
| 4416 |
++ groups := a.GetUserInfo().GetGroups() |
|
| 4417 |
++ for _, group := range groups {
|
|
| 4418 |
++ if group == systemNodesGroup {
|
|
| 4419 |
++ return true |
|
| 4420 |
++ } |
|
| 4421 |
++ } |
|
| 4422 |
++ return false |
|
| 4423 |
++} |
|
| 4424 |
++ |
|
| 4425 |
++func validateNodeCertificate(vac *vmwareAdmissionController, a admission.Attributes) (err error) {
|
|
| 4426 |
++ // If the groups have system:cluster:cluster-id as one of the groups, then validate that the cluster ID belongs to |
|
| 4427 |
++ // this cluster. If not fail. This prevents cross cluster access using certificates. |
|
| 4428 |
++ invalidClusterID := false |
|
| 4429 |
++ masterNode := false |
|
| 4430 |
++ groups := a.GetUserInfo().GetGroups() |
|
| 4431 |
++ for _, group := range groups {
|
|
| 4432 |
++ if strings.HasPrefix(group, systemClusterPrefix) {
|
|
| 4433 |
++ groupParts := strings.Split(group, ":") |
|
| 4434 |
++ if vac.clusterID != "" && groupParts[len(groupParts)-1] != vac.clusterID {
|
|
| 4435 |
++ invalidClusterID = true |
|
| 4436 |
++ } |
|
| 4437 |
++ } |
|
| 4438 |
++ if group == systemMasterGroup {
|
|
| 4439 |
++ masterNode = true |
|
| 4440 |
++ } |
|
| 4441 |
++ } |
|
| 4442 |
++ if invalidClusterID {
|
|
| 4443 |
++ return admission.NewForbidden(a, fmt.Errorf("%s validation failed: request is not from this cluster", PluginName))
|
|
| 4444 |
++ } |
|
| 4445 |
++ |
|
| 4446 |
++ // If a worker node name does not have the node prefix, then fail. This is needed for the request to go through node |
|
| 4447 |
++ // restriction admission controller. If it is not set, then a user can bypass node restriction admission controller |
|
| 4448 |
++ // and modify the master node. |
|
| 4449 |
++ name := a.GetUserInfo().GetName() |
|
| 4450 |
++ if !strings.HasPrefix(name, systemNodePrefix) && !masterNode {
|
|
| 4451 |
++ return admission.NewForbidden(a, fmt.Errorf("%s validation failed: username is invalid", PluginName))
|
|
| 4452 |
++ } |
|
| 4453 |
++ return nil |
|
| 4454 |
++} |
|
| 4455 |
++ |
|
| 4413 | 4456 |
+func isPrivilegedNamespace(a admission.Attributes) bool {
|
| 4414 | 4457 |
+ // If the namespace mentioned in the resource is privileged, return true. We will hit this for calls made to all |
| 4415 | 4458 |
+ // resources in this namespace and during delete and update operation on the namespace itself. |
| ... | ... |
@@ -4660,10 +4714,10 @@ index 0000000..e05e7be |
| 4660 | 4660 |
+} |
| 4661 | 4661 |
diff --git a/plugin/pkg/admission/vke/admission_test.go b/plugin/pkg/admission/vke/admission_test.go |
| 4662 | 4662 |
new file mode 100644 |
| 4663 |
-index 0000000..7f8ec60 |
|
| 4663 |
+index 0000000..4ce4a1f |
|
| 4664 | 4664 |
--- /dev/null |
| 4665 | 4665 |
+++ b/plugin/pkg/admission/vke/admission_test.go |
| 4666 |
-@@ -0,0 +1,865 @@ |
|
| 4666 |
+@@ -0,0 +1,882 @@ |
|
| 4667 | 4667 |
+package vke |
| 4668 | 4668 |
+ |
| 4669 | 4669 |
+import ( |
| ... | ... |
@@ -4681,10 +4735,12 @@ index 0000000..7f8ec60 |
| 4681 | 4681 |
+ |
| 4682 | 4682 |
+const ( |
| 4683 | 4683 |
+ testServiceAccountsGroup = "system.test\\cascade-controller-service-accounts" |
| 4684 |
++ clusterID = "cluster-id" |
|
| 4684 | 4685 |
+ defaultConfigFileFormat = ` |
| 4685 | 4686 |
+vmwareAdmissionController: |
| 4686 | 4687 |
+ privilegedGroup: %s |
| 4687 | 4688 |
+ podSecurityPolicyFile: %s |
| 4689 |
++ clusterID: %s |
|
| 4688 | 4690 |
+` |
| 4689 | 4691 |
+ pspFileName = "/tmp/psp.yaml" |
| 4690 | 4692 |
+ pspConfigFile = ` |
| ... | ... |
@@ -5012,13 +5068,7 @@ index 0000000..7f8ec60 |
| 5012 | 5012 |
+ "allowed: kubelet group creates pod in vke-system namespace": {
|
| 5013 | 5013 |
+ operation: kadmission.Create, |
| 5014 | 5014 |
+ pod: newTestPodBuilder().withNamespace(privilegedNamespace).build(), |
| 5015 |
-+ userInfo: newTestUserBuilder().withGroup(kubeletGroup).build(), |
|
| 5016 |
-+ shouldPassValidate: true, |
|
| 5017 |
-+ }, |
|
| 5018 |
-+ "allowed: kubeProxy group creates pod in vke-system namespace": {
|
|
| 5019 |
-+ operation: kadmission.Create, |
|
| 5020 |
-+ pod: newTestPodBuilder().withNamespace(privilegedNamespace).build(), |
|
| 5021 |
-+ userInfo: newTestUserBuilder().withGroup(kubeProxyGroup).build(), |
|
| 5015 |
++ userInfo: newTestUserBuilder().withGroup(systemNodesGroup).withName("system:node:worker").build(),
|
|
| 5022 | 5016 |
+ shouldPassValidate: true, |
| 5023 | 5017 |
+ }, |
| 5024 | 5018 |
+ "denied: regular lightwave group does not grant privileged access": {
|
| ... | ... |
@@ -5033,6 +5083,27 @@ index 0000000..7f8ec60 |
| 5033 | 5033 |
+ userInfo: newTestUserBuilder().withGroup("test1\\group1").withGroup(testServiceAccountsGroup).build(),
|
| 5034 | 5034 |
+ shouldPassValidate: true, |
| 5035 | 5035 |
+ }, |
| 5036 |
++ "denied: cross cluster acccess": {
|
|
| 5037 |
++ operation: kadmission.Create, |
|
| 5038 |
++ pod: newTestPodBuilder().build(), |
|
| 5039 |
++ userInfo: newTestUserBuilder().withName("system:node:worker").withGroup("system:clusterID:some-cluster-id").
|
|
| 5040 |
++ withGroup("system:nodes").withGroup("system:worker").build(),
|
|
| 5041 |
++ shouldPassValidate: false, |
|
| 5042 |
++ }, |
|
| 5043 |
++ "denied: node restriction admission controller bypass": {
|
|
| 5044 |
++ operation: kadmission.Create, |
|
| 5045 |
++ pod: newTestPodBuilder().build(), |
|
| 5046 |
++ userInfo: newTestUserBuilder().withGroup("system:clusterID:cluster-id").withGroup("system:nodes").
|
|
| 5047 |
++ withGroup("system:worker").build(),
|
|
| 5048 |
++ shouldPassValidate: false, |
|
| 5049 |
++ }, |
|
| 5050 |
++ "allowed: master node to bypass node restriction admission controller": {
|
|
| 5051 |
++ operation: kadmission.Create, |
|
| 5052 |
++ pod: newTestPodBuilder().build(), |
|
| 5053 |
++ userInfo: newTestUserBuilder().withName("kubernetes-master").withGroup("system:clusterID:cluster-id").
|
|
| 5054 |
++ withGroup("system:nodes").withGroup("system:master").build(),
|
|
| 5055 |
++ shouldPassValidate: true, |
|
| 5056 |
++ }, |
|
| 5036 | 5057 |
+ } |
| 5037 | 5058 |
+ for k, v := range tests {
|
| 5038 | 5059 |
+ testPodValidation(k, v.operation, v.pod, v.name, v.userInfo, v.shouldPassValidate, t) |
| ... | ... |
@@ -5308,7 +5379,7 @@ index 0000000..7f8ec60 |
| 5308 | 5308 |
+func testPodValidation(testCaseName string, op kadmission.Operation, pod *kapi.Pod, name string, userInfo user.Info, |
| 5309 | 5309 |
+ shouldPassValidate bool, t *testing.T) {
|
| 5310 | 5310 |
+ |
| 5311 |
-+ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName) |
|
| 5311 |
++ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName, clusterID) |
|
| 5312 | 5312 |
+ configFile := strings.NewReader(defaultConfigFile) |
| 5313 | 5313 |
+ plugin, err := NewVMwareAdmissionController(configFile) |
| 5314 | 5314 |
+ if err != nil {
|
| ... | ... |
@@ -5334,7 +5405,7 @@ index 0000000..7f8ec60 |
| 5334 | 5334 |
+func testResourceValidation(testCaseName string, op kadmission.Operation, resource, subresource, name, namespace string, |
| 5335 | 5335 |
+ userInfo user.Info, shouldPassValidate bool, t *testing.T) {
|
| 5336 | 5336 |
+ |
| 5337 |
-+ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName) |
|
| 5337 |
++ defaultConfigFile := fmt.Sprintf(defaultConfigFileFormat, testServiceAccountsGroup, pspFileName, clusterID) |
|
| 5338 | 5338 |
+ configFile := strings.NewReader(defaultConfigFile) |
| 5339 | 5339 |
+ plugin, err := NewVMwareAdmissionController(configFile) |
| 5340 | 5340 |
+ if err != nil {
|
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
Summary: Kubernetes cluster management |
| 2 | 2 |
Name: kubernetes |
| 3 | 3 |
Version: 1.10.2 |
| 4 |
-Release: 8%{?dist}
|
|
| 4 |
+Release: 9%{?dist}
|
|
| 5 | 5 |
License: ASL 2.0 |
| 6 | 6 |
URL: https://github.com/kubernetes/kubernetes/archive/v%{version}.tar.gz
|
| 7 | 7 |
Source0: kubernetes-%{version}.tar.gz
|
| ... | ... |
@@ -207,6 +207,8 @@ fi |
| 207 | 207 |
/opt/vmware/kubernetes/windows/amd64/kubectl.exe |
| 208 | 208 |
|
| 209 | 209 |
%changelog |
| 210 |
+* Fri Jul 20 2018 Bo Gan <ganb@vmware.com> 1.10.2-9 |
|
| 211 |
+- Update vke patch (1f4aedb) |
|
| 210 | 212 |
* Tue Jul 03 2018 Bo Gan <ganb@vmware.com> 1.10.2-8 |
| 211 | 213 |
- Update vke patch (3a784cd) |
| 212 | 214 |
* Tue Jun 19 2018 Bo Gan <ganb@vmware.com> 1.10.2-7 |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
Summary: Kubernetes cluster management |
| 2 | 2 |
Name: kubernetes |
| 3 | 3 |
Version: 1.9.6 |
| 4 |
-Release: 7%{?dist}
|
|
| 4 |
+Release: 8%{?dist}
|
|
| 5 | 5 |
License: ASL 2.0 |
| 6 | 6 |
URL: https://github.com/kubernetes/kubernetes/archive/v%{version}.tar.gz
|
| 7 | 7 |
Source0: kubernetes-v%{version}.tar.gz
|
| ... | ... |
@@ -185,6 +185,8 @@ fi |
| 185 | 185 |
%{_bindir}/pause-amd64
|
| 186 | 186 |
|
| 187 | 187 |
%changelog |
| 188 |
+* Fri Jul 20 2018 Bo Gan <ganb@vmware.com> 1.9.6-8 |
|
| 189 |
+- Update vke patch (1f4aedb) |
|
| 188 | 190 |
* Tue Jul 03 2018 Bo Gan <ganb@vmware.com> 1.9.6-7 |
| 189 | 191 |
- Update vke patch (3a784cd) |
| 190 | 192 |
* Tue Jun 19 2018 Bo Gan <ganb@vmware.com> 1.9.6-6 |