diff --git a/build/yamls/antrea-aks.yml b/build/yamls/antrea-aks.yml index 31071a95535..7bdf6e1ab99 100644 --- a/build/yamls/antrea-aks.yml +++ b/build/yamls/antrea-aks.yml @@ -656,6 +656,39 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array egress: @@ -803,6 +836,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array toServices: @@ -951,6 +1023,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array name: @@ -3606,6 +3717,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/antrea-eks.yml b/build/yamls/antrea-eks.yml index cf186bb8f59..d99613006bb 100644 --- a/build/yamls/antrea-eks.yml +++ b/build/yamls/antrea-eks.yml @@ -656,6 +656,39 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array egress: @@ -803,6 +836,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array toServices: @@ -951,6 +1023,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array name: @@ -3606,6 +3717,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/antrea-gke.yml b/build/yamls/antrea-gke.yml index d64995c56ed..7d36a536ba4 100644 --- a/build/yamls/antrea-gke.yml +++ b/build/yamls/antrea-gke.yml @@ -656,6 +656,39 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array egress: @@ -803,6 +836,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array toServices: @@ -951,6 +1023,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array name: @@ -3606,6 +3717,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/antrea-ipsec.yml b/build/yamls/antrea-ipsec.yml index 8759ec44cf9..5098c69b1b4 100644 --- a/build/yamls/antrea-ipsec.yml +++ b/build/yamls/antrea-ipsec.yml @@ -656,6 +656,39 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array egress: @@ -803,6 +836,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array toServices: @@ -951,6 +1023,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array name: @@ -3606,6 +3717,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/antrea-kind.yml b/build/yamls/antrea-kind.yml index 728ce57bd55..919c4a249f4 100644 --- a/build/yamls/antrea-kind.yml +++ b/build/yamls/antrea-kind.yml @@ -656,6 +656,39 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array egress: @@ -803,6 +836,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array toServices: @@ -951,6 +1023,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array name: @@ -3606,6 +3717,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/antrea.yml b/build/yamls/antrea.yml index f6b6aa44209..373681dd9a4 100644 --- a/build/yamls/antrea.yml +++ b/build/yamls/antrea.yml @@ -656,6 +656,39 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array egress: @@ -803,6 +836,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array toServices: @@ -951,6 +1023,45 @@ spec: matchLabels: x-kubernetes-preserve-unknown-fields: true type: object + serviceAccounts: + items: + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + items: + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + type: array + type: object + type: array + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array type: object type: array name: @@ -3606,6 +3717,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/base/controller-rbac.yml b/build/yamls/base/controller-rbac.yml index 2d41344e102..f0f5b570db4 100644 --- a/build/yamls/base/controller-rbac.yml +++ b/build/yamls/base/controller-rbac.yml @@ -17,6 +17,7 @@ rules: - namespaces - services - configmaps + - serviceaccounts verbs: - get - watch diff --git a/build/yamls/base/crds.yml b/build/yamls/base/crds.yml index 00ac35e194c..b1ef4d8ca8f 100644 --- a/build/yamls/base/crds.yml +++ b/build/yamls/base/crds.yml @@ -807,6 +807,39 @@ spec: x-kubernetes-preserve-unknown-fields: true group: type: string + serviceAccounts: + type: array + items: + type: object + properties: + name: + type: string + namespace: + type: string + selector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true ingress: type: array items: @@ -951,6 +984,45 @@ spec: format: cidr group: type: string + serviceAccounts: + type: array + items: + type: object + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true name: type: string enableLogging: @@ -1101,6 +1173,45 @@ spec: type: string fqdn: type: string + serviceAccounts: + type: array + items: + type: object + oneOf: + - required: + - name + - namespace + - required: + - selector + properties: + name: + type: string + namespace: + type: string + selector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + enum: + - In + - NotIn + - Exists + - DoesNotExist + type: string + values: + type: array + items: + type: string + pattern: "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" + matchLabels: + x-kubernetes-preserve-unknown-fields: true toServices: type: array items: diff --git a/cmd/antrea-controller/controller.go b/cmd/antrea-controller/controller.go index a2ce52e3a13..8a1855745c8 100644 --- a/cmd/antrea-controller/controller.go +++ b/cmd/antrea-controller/controller.go @@ -113,6 +113,7 @@ func run(o *Options) error { podInformer := informerFactory.Core().V1().Pods() namespaceInformer := informerFactory.Core().V1().Namespaces() serviceInformer := informerFactory.Core().V1().Services() + serviceAccountInformer := informerFactory.Core().V1().ServiceAccounts() networkPolicyInformer := informerFactory.Networking().V1().NetworkPolicies() nodeInformer := informerFactory.Core().V1().Nodes() cnpInformer := crdInformerFactory.Crd().V1alpha1().ClusterNetworkPolicies() @@ -158,6 +159,7 @@ func run(o *Options) error { groupEntityIndex, namespaceInformer, serviceInformer, + serviceAccountInformer, networkPolicyInformer, cnpInformer, anpInformer, diff --git a/pkg/apis/crd/v1alpha1/types.go b/pkg/apis/crd/v1alpha1/types.go index f47291b4b8c..b265704e6bc 100644 --- a/pkg/apis/crd/v1alpha1/types.go +++ b/pkg/apis/crd/v1alpha1/types.go @@ -434,6 +434,8 @@ type NetworkPolicyPeer struct { // Exact FQDNs, i.e. "google.com", "db-svc.default.svc.cluster.local" // Wildcard expressions, i.e. "*wayfair.com". FQDN string `json:"fqdn,omitempty"` + // ... + ServiceAccounts []ServiceAccounts `json:"serviceAccounts,omitempty"` } type PeerNamespaces struct { @@ -587,3 +589,9 @@ type TierList struct { Items []Tier `json:"items"` } + +type ServiceAccounts struct { + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` + Selector *metav1.LabelSelector `json:"selector,omitempty"` +} diff --git a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go index 5c38d6c7010..b6135aaf067 100644 --- a/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go @@ -298,6 +298,13 @@ func (in *NetworkPolicyPeer) DeepCopyInto(out *NetworkPolicyPeer) { *out = new(v1.LabelSelector) (*in).DeepCopyInto(*out) } + if in.ServiceAccounts != nil { + in, out := &in.ServiceAccounts, &out.ServiceAccounts + *out = make([]ServiceAccounts, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -525,6 +532,27 @@ func (in *Rule) DeepCopy() *Rule { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccounts) DeepCopyInto(out *ServiceAccounts) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccounts. +func (in *ServiceAccounts) DeepCopy() *ServiceAccounts { + if in == nil { + return nil + } + out := new(ServiceAccounts) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceReference) DeepCopyInto(out *ServiceReference) { *out = *in diff --git a/pkg/controller/grouping/custom_label.go b/pkg/controller/grouping/custom_label.go new file mode 100644 index 00000000000..059502eb4ca --- /dev/null +++ b/pkg/controller/grouping/custom_label.go @@ -0,0 +1,44 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grouping + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" +) + +const ( + CustomLabelKeyPrefix = "antrea.io/reserved-label-" + ServiceAccountLabelKey = "service-account" +) + +// getServiceAccountLabel returns a key and a value of a label that is used for +// ServiceAccount selector. For non-PodEntityType, it will return empty string. +func getServiceAccountLabel(entityType entityType, obj metav1.Object) (string, string) { + if entityType == podEntityType { + return CustomLabelKeyPrefix + ServiceAccountLabelKey, obj.(*v1.Pod).Spec.ServiceAccountName + } + return "", "" +} + +// getAllLabelsKey returns a key string of all labels of a labelItem. +func getAllLabelsKey(entityType entityType, obj metav1.Object) string { + labelsKey := labels.Set(obj.GetLabels()).String() + if key, value := getServiceAccountLabel(entityType, obj); key != "" { + labelsKey += "," + key + "=" + value + } + return labelsKey +} diff --git a/pkg/controller/grouping/group_entity_index.go b/pkg/controller/grouping/group_entity_index.go index ac43c06eb10..b7fcf1be736 100644 --- a/pkg/controller/grouping/group_entity_index.go +++ b/pkg/controller/grouping/group_entity_index.go @@ -366,6 +366,7 @@ func (i *GroupEntityIndex) createLabelItem(entityType entityType, eItem *entityI entityItemKeys: sets.NewString(), selectorItemKeys: sets.NewString(), } + addCustomLabel(lItem, entityType, eItem.entity) // Create the labelItem. i.labelItems[eItem.labelItemKey] = lItem // Add it to the labelItemIndex. @@ -764,7 +765,7 @@ func getEntityItemKeyByName(entityType entityType, namespace, name string) strin // getLabelItemKey returns the label key used in labelItems. func getLabelItemKey(entityType entityType, obj metav1.Object) string { - return fmt.Sprint(entityType) + "/" + obj.GetNamespace() + "/" + labels.Set(obj.GetLabels()).String() + return fmt.Sprint(entityType) + "/" + obj.GetNamespace() + "/" + getAllLabelsKey(entityType, obj) } // getGroupItemKey returns the group key used in groupItems. @@ -776,3 +777,11 @@ func getGroupItemKey(groupType GroupType, name string) string { func getSelectorItemKey(selector *types.GroupSelector) string { return selector.NormalizedName } + +// addCustomLabel ... +func addCustomLabel(labelItem *labelItem, entityType entityType, obj metav1.Object) { + if key, value := getServiceAccountLabel(entityType, obj); key != "" { + labelItem.labels[key] = value + } + return +} diff --git a/pkg/controller/networkpolicy/clusternetworkpolicy.go b/pkg/controller/networkpolicy/clusternetworkpolicy.go index e0b9b0487c8..b50f1c6682e 100644 --- a/pkg/controller/networkpolicy/clusternetworkpolicy.go +++ b/pkg/controller/networkpolicy/clusternetworkpolicy.go @@ -24,6 +24,7 @@ import ( "antrea.io/antrea/pkg/apis/controlplane" crdv1alpha1 "antrea.io/antrea/pkg/apis/crd/v1alpha1" + "antrea.io/antrea/pkg/controller/grouping" "antrea.io/antrea/pkg/controller/networkpolicy/store" antreatypes "antrea.io/antrea/pkg/controller/types" utilsets "antrea.io/antrea/pkg/util/sets" @@ -261,6 +262,7 @@ func (n *NetworkPolicyController) deleteNamespace(old interface{}) { // in case of ADD event or modified and store the updated instance, in case // of an UPDATE event. func (n *NetworkPolicyController) processClusterNetworkPolicy(cnp *crdv1alpha1.ClusterNetworkPolicy) *antreatypes.NetworkPolicy { + n.translateServiceAccounts(cnp) hasPerNamespaceRule := hasPerNamespaceRule(cnp) // If one of the ACNP rule is a per-namespace rule (a peer in that rule has namspaces.Match set // to Self), the policy will need to be converted to appliedTo per rule policy, as the appliedTo @@ -382,6 +384,59 @@ func (n *NetworkPolicyController) processClusterNetworkPolicy(cnp *crdv1alpha1.C return internalNetworkPolicy } +// translateServiceAccounts ... +func (n *NetworkPolicyController) translateServiceAccounts(acnp *crdv1alpha1.ClusterNetworkPolicy) { + // saToPSelNSel returns a crdv1alpha1.NetworkPolicyPeer with PodSelector + + // NamespaceSelector based on ServiceAccount Name + Namespace + saToPSelNSel := func(saNs, saName string) crdv1alpha1.NetworkPolicyPeer { + return crdv1alpha1.NetworkPolicyPeer{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{grouping.CustomLabelKeyPrefix + grouping.ServiceAccountLabelKey: saName}, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"kubernetes.io/metadata.name": saNs}, + }, + } + } + + // translateNetworkPolicyPeers ... + translateNetworkPolicyPeers := func(networkPolicyPeers []crdv1alpha1.NetworkPolicyPeer) []crdv1alpha1.NetworkPolicyPeer { + var newPeers []crdv1alpha1.NetworkPolicyPeer + for _, peer := range networkPolicyPeers { + if peer.ServiceAccounts != nil && len(peer.ServiceAccounts) > 0 { + for _, sa := range peer.ServiceAccounts { + if sa.Selector != nil { + saSelector, err := metav1.LabelSelectorAsSelector(sa.Selector) + if err != nil { + continue + } + selSas, err := n.serviceAccountLister.List(saSelector) + if err != nil { + continue + } + for _, selSa := range selSas { + newPeers = append(newPeers, saToPSelNSel(selSa.Namespace, selSa.Name)) + } + } + if sa.Name != "" && sa.Namespace != "" { + newPeers = append(newPeers, saToPSelNSel(sa.Namespace, sa.Name)) + } + } + } else { + newPeers = append(newPeers, peer) + } + } + return newPeers + } + acnp.Spec.AppliedTo = translateNetworkPolicyPeers(acnp.Spec.AppliedTo) + for _, ingressRule := range acnp.Spec.Ingress { + ingressRule.From = translateNetworkPolicyPeers(ingressRule.From) + } + for _, egressRule := range acnp.Spec.Egress { + egressRule.To = translateNetworkPolicyPeers(egressRule.To) + } +} + // hasPerNamespaceRule returns true if there is at least one per-namespace rule func hasPerNamespaceRule(cnp *crdv1alpha1.ClusterNetworkPolicy) bool { for _, ingress := range cnp.Spec.Ingress { diff --git a/pkg/controller/networkpolicy/networkpolicy_controller.go b/pkg/controller/networkpolicy/networkpolicy_controller.go index 3f15efb7b09..31387f8aba2 100644 --- a/pkg/controller/networkpolicy/networkpolicy_controller.go +++ b/pkg/controller/networkpolicy/networkpolicy_controller.go @@ -139,6 +139,10 @@ type NetworkPolicyController struct { // serviceListerSynced is a function which returns true if the Service shared informer has been synced at least once. serviceListerSynced cache.InformerSynced + serviceAccountInformer coreinformers.ServiceAccountInformer + serviceAccountLister corelisters.ServiceAccountLister + serviceAccountSynced cache.InformerSynced + networkPolicyInformer networkinginformers.NetworkPolicyInformer // networkPolicyLister is able to list/get Network Policies and is populated by the shared informer passed to // NewNetworkPolicyController. @@ -290,6 +294,7 @@ func NewNetworkPolicyController(kubeClient clientset.Interface, groupingInterface grouping.Interface, namespaceInformer coreinformers.NamespaceInformer, serviceInformer coreinformers.ServiceInformer, + serviceAccountInformer coreinformers.ServiceAccountInformer, networkPolicyInformer networkinginformers.NetworkPolicyInformer, cnpInformer secinformers.ClusterNetworkPolicyInformer, anpInformer secinformers.NetworkPolicyInformer, @@ -336,6 +341,9 @@ func NewNetworkPolicyController(kubeClient clientset.Interface, n.serviceInformer = serviceInformer n.serviceLister = serviceInformer.Lister() n.serviceListerSynced = serviceInformer.Informer().HasSynced + n.serviceAccountInformer = serviceAccountInformer + n.serviceAccountLister = serviceAccountInformer.Lister() + n.serviceAccountSynced = serviceInformer.Informer().HasSynced n.cnpInformer = cnpInformer n.cnpLister = cnpInformer.Lister() n.cnpListerSynced = cnpInformer.Informer().HasSynced @@ -430,9 +438,14 @@ func (n *NetworkPolicyController) GetConnectedAgentNum() int { // toGroupSelector converts the podSelector, namespaceSelector and externalEntitySelector // and NetworkPolicy Namespace to a networkpolicy.GroupSelector object. func toGroupSelector(namespace string, podSelector, nsSelector, extEntitySelector *metav1.LabelSelector) *antreatypes.GroupSelector { + klog.Infof("podSelector %v", podSelector) + klog.Infof("nsSelector %v", nsSelector) groupSelector := antreatypes.GroupSelector{} if podSelector != nil { - pSelector, _ := metav1.LabelSelectorAsSelector(podSelector) + pSelector, err := metav1.LabelSelectorAsSelector(podSelector) + if err != nil { + klog.Info(err.Error()) + } groupSelector.PodSelector = pSelector } if extEntitySelector != nil { @@ -449,6 +462,7 @@ func toGroupSelector(namespace string, podSelector, nsSelector, extEntitySelecto } name := generateNormalizedName(groupSelector.Namespace, groupSelector.PodSelector, groupSelector.NamespaceSelector, groupSelector.ExternalEntitySelector) groupSelector.NormalizedName = name + klog.Infof("groupSelector %v", groupSelector) return &groupSelector } diff --git a/pkg/controller/networkpolicy/networkpolicy_controller_test.go b/pkg/controller/networkpolicy/networkpolicy_controller_test.go index b9914400f75..f1fc2888bcd 100644 --- a/pkg/controller/networkpolicy/networkpolicy_controller_test.go +++ b/pkg/controller/networkpolicy/networkpolicy_controller_test.go @@ -104,6 +104,7 @@ func newController(objects ...runtime.Object) (*fake.Clientset, *networkPolicyCo groupEntityIndex, informerFactory.Core().V1().Namespaces(), informerFactory.Core().V1().Services(), + informerFactory.Core().V1().ServiceAccounts(), informerFactory.Networking().V1().NetworkPolicies(), crdInformerFactory.Crd().V1alpha1().ClusterNetworkPolicies(), crdInformerFactory.Crd().V1alpha1().NetworkPolicies(), diff --git a/pkg/controller/networkpolicy/validate.go b/pkg/controller/networkpolicy/validate.go index 46482d43418..534137449eb 100644 --- a/pkg/controller/networkpolicy/validate.go +++ b/pkg/controller/networkpolicy/validate.go @@ -456,6 +456,18 @@ func (v *antreaPolicyValidator) validateAppliedTo(ingress, egress []crdv1alpha1. if numAppliedToInRules > 0 && (numAppliedToInRules != len(ingress)+len(egress)) { return "appliedTo field should either be set in all rules or in none of them", false } + for _, eachAppliedTo := range specAppliedTo { + if eachAppliedTo.ServiceAccounts != nil { + if eachAppliedTo.PodSelector != nil || eachAppliedTo.NamespaceSelector != nil || eachAppliedTo.Group != "" { + return "serviceAccounts cannot be set with other peers in rules", false + } + for _, sa := range eachAppliedTo.ServiceAccounts { + if (sa.Name == "") != (sa.Namespace == "") { + return "inside serviceAccounts name and namespace must be used together", false + } + } + } + } return "", true } @@ -467,12 +479,19 @@ func (v *antreaPolicyValidator) validatePeers(ingress, egress []crdv1alpha1.Rule if peer.NamespaceSelector != nil && peer.Namespaces != nil { return "namespaces and namespaceSelector cannot be set at the same time for a single NetworkPolicyPeer", false } - if peer.Group == "" { - continue - } - if peer.PodSelector != nil || peer.IPBlock != nil || peer.NamespaceSelector != nil { + if peer.Group != "" && (peer.PodSelector != nil || peer.IPBlock != nil || peer.NamespaceSelector != nil || peer.ExternalEntitySelector != nil || peer.ServiceAccounts != nil || peer.FQDN != "") { return "group cannot be set with other peers in rules", false } + if peer.ServiceAccounts != nil { + if peer.PodSelector != nil || peer.IPBlock != nil || peer.NamespaceSelector != nil || peer.ExternalEntitySelector != nil || peer.Group != "" || peer.FQDN != "" { + return "serviceAccounts cannot be set with other peers in rules", false + } + for _, sa := range peer.ServiceAccounts { + if (sa.Name == "") != (sa.Namespace == "") { + return "inside serviceAccounts name and namespace must be used together", false + } + } + } } return "", true }