github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/groups/helpers.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package groups 16 17 import ( 18 "fmt" 19 20 "github.com/cilium/cilium/pkg/k8s" 21 cilium_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 22 "github.com/cilium/cilium/pkg/policy/api" 23 24 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 ) 26 27 const ( 28 cnpKindName = "derivative" 29 parentCNP = "io.cilium.network.policy.parent.uuid" 30 cnpKindKey = "io.cilium.network.policy.kind" 31 ) 32 33 var ( 34 blockOwnerDeletionPtr = true 35 ) 36 37 func getDerivativeName(cnp *cilium_v2.CiliumNetworkPolicy) string { 38 return fmt.Sprintf( 39 "%s-togroups-%s", 40 cnp.GetObjectMeta().GetName(), 41 cnp.GetObjectMeta().GetUID()) 42 } 43 44 // createDerivativeCNP will return a new CNP based on the given rule. 45 func createDerivativeCNP(cnp *cilium_v2.CiliumNetworkPolicy) (*cilium_v2.CiliumNetworkPolicy, error) { 46 // CNP informer may provide a CNP object without APIVersion or Kind. 47 // Setting manually to make sure that the derivative policy works ok. 48 derivativeCNP := &cilium_v2.CiliumNetworkPolicy{ 49 ObjectMeta: v1.ObjectMeta{ 50 Name: getDerivativeName(cnp), 51 Namespace: cnp.ObjectMeta.Namespace, 52 OwnerReferences: []v1.OwnerReference{{ 53 APIVersion: cilium_v2.SchemeGroupVersion.String(), 54 Kind: cilium_v2.CNPKindDefinition, 55 Name: cnp.ObjectMeta.Name, 56 UID: cnp.ObjectMeta.UID, 57 BlockOwnerDeletion: &blockOwnerDeletionPtr, 58 }}, 59 Labels: map[string]string{ 60 parentCNP: string(cnp.ObjectMeta.UID), 61 cnpKindKey: cnpKindName, 62 }, 63 }, 64 } 65 66 rules, err := cnp.Parse() 67 if err != nil { 68 return nil, fmt.Errorf("Cannot parse policies: %s", err) 69 } 70 71 derivativeCNP.Specs = make(api.Rules, len(rules)) 72 for i, rule := range rules { 73 if rule.RequiresDerivative() { 74 derivativeCNP.Specs[i] = denyEgressRule() 75 } 76 } 77 78 for i, rule := range rules { 79 if !rule.RequiresDerivative() { 80 derivativeCNP.Specs[i] = rule 81 continue 82 } 83 newRule, err := rule.CreateDerivative() 84 if err != nil { 85 return derivativeCNP, err 86 } 87 derivativeCNP.Specs[i] = newRule 88 } 89 return derivativeCNP, nil 90 } 91 92 func denyEgressRule() *api.Rule { 93 return &api.Rule{ 94 Egress: []api.EgressRule{}, 95 } 96 } 97 98 func updateOrCreateCNP(cnp *cilium_v2.CiliumNetworkPolicy) (*cilium_v2.CiliumNetworkPolicy, error) { 99 k8sCNP, err := k8s.CiliumClient().CiliumV2().CiliumNetworkPolicies(cnp.ObjectMeta.Namespace). 100 Get(cnp.ObjectMeta.Name, v1.GetOptions{}) 101 if err == nil { 102 k8sCNP.ObjectMeta.Labels = cnp.ObjectMeta.Labels 103 k8sCNP.Spec = cnp.Spec 104 k8sCNP.Specs = cnp.Specs 105 k8sCNP.Status = cilium_v2.CiliumNetworkPolicyStatus{} 106 return k8s.CiliumClient().CiliumV2().CiliumNetworkPolicies(cnp.ObjectMeta.Namespace).Update(k8sCNP) 107 } 108 return k8s.CiliumClient().CiliumV2().CiliumNetworkPolicies(cnp.ObjectMeta.Namespace).Create(cnp) 109 } 110 111 func updateDerivativeStatus(cnp *cilium_v2.CiliumNetworkPolicy, derivativeName string, err error) error { 112 status := cilium_v2.CiliumNetworkPolicyNodeStatus{ 113 LastUpdated: cilium_v2.NewTimestamp(), 114 Enforcing: false, 115 } 116 117 if err != nil { 118 status.OK = false 119 status.Error = err.Error() 120 } else { 121 status.OK = true 122 } 123 124 // This CNP can be modified by cilium agent or operator. To be able to push 125 // the status correctly fetch the last version to avoid updates issues. 126 k8sCNPStatus, clientErr := k8s.CiliumClient().CiliumV2(). 127 CiliumNetworkPolicies(cnp.ObjectMeta.Namespace). 128 Get(cnp.ObjectMeta.Name, v1.GetOptions{}) 129 if clientErr != nil { 130 return fmt.Errorf("Cannot get Kubernetes policy: %s", clientErr) 131 } 132 if k8sCNPStatus.ObjectMeta.UID != cnp.ObjectMeta.UID { 133 // This case should not happen, but if the UID does not match make sure 134 // that the new policy is not in the cache to not loop over it. The 135 // kubernetes watcher should take care about that. 136 groupsCNPCache.DeleteCNP(k8sCNPStatus) 137 return fmt.Errorf("Policy UID mistmatch") 138 } 139 k8sCNPStatus.SetDerivedPolicyStatus(derivativeName, status) 140 groupsCNPCache.UpdateCNP(k8sCNPStatus) 141 // TODO: switch to JSON Patch 142 _, err = k8s.CiliumClient().CiliumV2().CiliumNetworkPolicies(cnp.ObjectMeta.Namespace).UpdateStatus(cnp) 143 return err 144 }