github.com/cilium/cilium@v1.16.2/pkg/policy/groups/actions.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package groups 5 6 import ( 7 "context" 8 9 "github.com/sirupsen/logrus" 10 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 12 "github.com/cilium/cilium/pkg/controller" 13 cilium_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 14 "github.com/cilium/cilium/pkg/k8s/client" 15 "github.com/cilium/cilium/pkg/logging/logfields" 16 "github.com/cilium/cilium/pkg/metrics" 17 ) 18 19 var ( 20 controllerManager = controller.NewManager() 21 22 addDerivativeCNPControllerGroup = controller.NewGroup("add-derivative-cilium-network-policy") 23 updateDerivativeCNPControllerGroup = controller.NewGroup("update-derivative-cilium-network-policy") 24 deleteDerivativeCNPControllerGroup = controller.NewGroup("delete-derivative-cilium-network-policy") 25 26 addDerivativeCCNPControllerGroup = controller.NewGroup("add-derivative-clusterwide-cilium-network-policy") 27 updateDerivativeCCNPControllerGroup = controller.NewGroup("update-derivative-clusterwide-cilium-network-policy") 28 deleteDerivativeCCNPControllerGroup = controller.NewGroup("delete-derivative-clusterwide-cilium-network-policy") 29 ) 30 31 // AddDerivativeCNPIfNeeded will create a new CNP if the given CNP has any rules 32 // that need to create a new derivative policy. 33 // It returns a boolean, true in case that all actions are correct, false if 34 // something fails. 35 func AddDerivativeCNPIfNeeded(clientset client.Clientset, cnp *cilium_v2.CiliumNetworkPolicy) bool { 36 if !cnp.RequiresDerivative() { 37 log.WithFields(logrus.Fields{ 38 logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name, 39 logfields.K8sNamespace: cnp.ObjectMeta.Namespace, 40 }).Debug("CNP does not have derivative policies, skipped") 41 return true 42 } 43 controllerManager.UpdateController( 44 "add-derivative-cnp-"+cnp.ObjectMeta.Name, 45 controller.ControllerParams{ 46 Group: addDerivativeCNPControllerGroup, 47 DoFunc: func(ctx context.Context) error { 48 return addDerivativePolicy(ctx, clientset, cnp, false) 49 }, 50 }) 51 return true 52 } 53 54 // AddDerivativeCCNPIfNeeded will create a new CCNP if the given NetworkPolicy has any rules 55 // that need to create a new derivative policy. 56 // It returns a boolean, true in case that all actions are correct, false if 57 // something fails. 58 func AddDerivativeCCNPIfNeeded(clientset client.Clientset, cnp *cilium_v2.CiliumNetworkPolicy) bool { 59 if !cnp.RequiresDerivative() { 60 log.WithFields(logrus.Fields{ 61 logfields.CiliumClusterwideNetworkPolicyName: cnp.ObjectMeta.Name, 62 }).Debug("CCNP does not have derivative policies, skipped") 63 return true 64 } 65 controllerManager.UpdateController( 66 "add-derivative-ccnp-"+cnp.ObjectMeta.Name, 67 controller.ControllerParams{ 68 Group: addDerivativeCCNPControllerGroup, 69 DoFunc: func(ctx context.Context) error { 70 return addDerivativePolicy(ctx, clientset, cnp, true) 71 }, 72 }) 73 return true 74 } 75 76 // UpdateDerivativeCNPIfNeeded updates or creates a CNP if the given CNP has 77 // any rule that needs to create a new derivative policy(eg: ToGroups). In case 78 // that the new CNP does not have any derivative policy and the old one had 79 // one, it will delete the old policy. 80 // The function returns true if an update is required for the derivative policy 81 // and false otherwise. 82 func UpdateDerivativeCNPIfNeeded(clientset client.Clientset, newCNP *cilium_v2.CiliumNetworkPolicy, oldCNP *cilium_v2.CiliumNetworkPolicy) bool { 83 if !newCNP.RequiresDerivative() && oldCNP.RequiresDerivative() { 84 log.WithFields(logrus.Fields{ 85 logfields.CiliumNetworkPolicyName: newCNP.ObjectMeta.Name, 86 logfields.K8sNamespace: newCNP.ObjectMeta.Namespace, 87 }).Info("New CNP does not have derivative policy, but old had. Deleting old policies") 88 89 controllerManager.UpdateController( 90 "delete-derivative-cnp-"+oldCNP.ObjectMeta.Name, 91 controller.ControllerParams{ 92 Group: deleteDerivativeCNPControllerGroup, 93 DoFunc: func(ctx context.Context) error { 94 return DeleteDerivativeCNP(ctx, clientset, oldCNP) 95 }, 96 }) 97 return false 98 } 99 100 if !newCNP.RequiresDerivative() { 101 return false 102 } 103 104 controllerManager.UpdateController( 105 "update-derivative-cnp-"+newCNP.ObjectMeta.Name, 106 controller.ControllerParams{ 107 Group: updateDerivativeCNPControllerGroup, 108 DoFunc: func(ctx context.Context) error { 109 return addDerivativePolicy(ctx, clientset, newCNP, false) 110 }, 111 }) 112 return true 113 } 114 115 // UpdateDerivativeCCNPIfNeeded updates or creates a CCNP if the given CCNP has 116 // any rule that needs to create a new derivative policy(eg: ToGroups). In case 117 // that the new CCNP does not have any derivative policy and the old one had 118 // one, it will delete the old policy. 119 // The function returns true if an update is required for the derivative policy 120 // and false otherwise. 121 func UpdateDerivativeCCNPIfNeeded(clientset client.Clientset, newCCNP *cilium_v2.CiliumNetworkPolicy, oldCCNP *cilium_v2.CiliumNetworkPolicy) bool { 122 if !newCCNP.RequiresDerivative() && oldCCNP.RequiresDerivative() { 123 log.WithFields(logrus.Fields{ 124 logfields.CiliumClusterwideNetworkPolicyName: newCCNP.ObjectMeta.Name, 125 }).Info("New CCNP does not have derivative policy, but old had. Deleting old policies") 126 127 controllerManager.UpdateController( 128 "delete-derivative-ccnp-"+oldCCNP.ObjectMeta.Name, 129 controller.ControllerParams{ 130 Group: deleteDerivativeCCNPControllerGroup, 131 DoFunc: func(ctx context.Context) error { 132 return DeleteDerivativeCCNP(ctx, clientset, oldCCNP) 133 }, 134 }) 135 return false 136 } 137 138 if !newCCNP.RequiresDerivative() { 139 return false 140 } 141 142 controllerManager.UpdateController( 143 "update-derivative-ccnp-"+newCCNP.ObjectMeta.Name, 144 controller.ControllerParams{ 145 Group: updateDerivativeCCNPControllerGroup, 146 DoFunc: func(ctx context.Context) error { 147 return addDerivativePolicy(ctx, clientset, newCCNP, true) 148 }, 149 }) 150 return true 151 } 152 153 // DeleteDerivativeFromCache deletes the given CNP from the groupsCNPCache to 154 // no continue pooling new data. 155 func DeleteDerivativeFromCache(cnp *cilium_v2.CiliumNetworkPolicy) { 156 groupsCNPCache.DeleteCNP(cnp) 157 } 158 159 // DeleteDerivativeCNP if the given policy has a derivative constraint,the 160 // given CNP will be deleted from store and the cache. 161 func DeleteDerivativeCNP(ctx context.Context, clientset client.Clientset, cnp *cilium_v2.CiliumNetworkPolicy) error { 162 scopedLog := log.WithFields(logrus.Fields{ 163 logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name, 164 logfields.K8sNamespace: cnp.ObjectMeta.Namespace, 165 }) 166 167 if !cnp.RequiresDerivative() { 168 scopedLog.Debug("CNP does not have derivative policies, skipped") 169 return nil 170 } 171 172 err := clientset.CiliumV2().CiliumNetworkPolicies(cnp.ObjectMeta.Namespace).DeleteCollection( 173 ctx, 174 v1.DeleteOptions{}, 175 v1.ListOptions{LabelSelector: parentCNP + "=" + string(cnp.ObjectMeta.UID)}) 176 177 if err != nil { 178 return err 179 } 180 181 DeleteDerivativeFromCache(cnp) 182 return nil 183 } 184 185 // DeleteDerivativeCCNP if the given policy has a derivative constraint, the 186 // given CCNP will be deleted from store and the cache. 187 func DeleteDerivativeCCNP(ctx context.Context, clientset client.Clientset, ccnp *cilium_v2.CiliumNetworkPolicy) error { 188 scopedLog := log.WithFields(logrus.Fields{ 189 logfields.CiliumClusterwideNetworkPolicyName: ccnp.ObjectMeta.Name, 190 }) 191 192 if !ccnp.RequiresDerivative() { 193 scopedLog.Debug("CCNP does not have derivative policies, skipped") 194 return nil 195 } 196 197 err := clientset.CiliumV2().CiliumClusterwideNetworkPolicies().DeleteCollection( 198 ctx, 199 v1.DeleteOptions{}, 200 v1.ListOptions{LabelSelector: parentCNP + "=" + string(ccnp.ObjectMeta.UID)}) 201 if err != nil { 202 return err 203 } 204 205 DeleteDerivativeFromCache(ccnp) 206 return nil 207 } 208 209 func addDerivativePolicy(ctx context.Context, clientset client.Clientset, cnp *cilium_v2.CiliumNetworkPolicy, clusterScoped bool) error { 210 var ( 211 scopedLog *logrus.Entry 212 derivativePolicy v1.Object 213 derivativeCNP *cilium_v2.CiliumNetworkPolicy 214 derivativeCCNP *cilium_v2.CiliumClusterwideNetworkPolicy 215 derivativeErr, err error 216 ) 217 if clusterScoped { 218 scopedLog = log.WithFields(logrus.Fields{ 219 logfields.CiliumClusterwideNetworkPolicyName: cnp.ObjectMeta.Name, 220 }) 221 } else { 222 scopedLog = log.WithFields(logrus.Fields{ 223 logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name, 224 logfields.K8sNamespace: cnp.ObjectMeta.Namespace, 225 }) 226 } 227 228 // If the createDerivativeCNP() fails, a new all block rule will be inserted and 229 // the derivative status in the parent policy will be updated with the 230 // error. 231 if clusterScoped { 232 derivativeCCNP, derivativeErr = createDerivativeCCNP(ctx, cnp) 233 derivativePolicy = derivativeCCNP 234 } else { 235 derivativeCNP, derivativeErr = createDerivativeCNP(ctx, cnp) 236 derivativePolicy = derivativeCNP 237 } 238 239 if derivativeErr != nil { 240 metrics.PolicyChangeTotal.WithLabelValues(metrics.LabelValueOutcomeFail).Inc() 241 scopedLog.WithError(derivativeErr).Error("Cannot create derivative rule. Installing deny-all rule.") 242 statusErr := updateDerivativeStatus(clientset, cnp, derivativePolicy.GetName(), derivativeErr, clusterScoped) 243 if statusErr != nil { 244 scopedLog.WithError(statusErr).Error("Cannot update status for derivative policy") 245 } 246 return derivativeErr 247 } 248 249 groupsCNPCache.UpdateCNP(cnp) 250 if clusterScoped { 251 _, err = updateOrCreateCCNP(clientset, derivativeCCNP) 252 } else { 253 _, err = updateOrCreateCNP(clientset, derivativeCNP) 254 } 255 256 if err != nil { 257 statusErr := updateDerivativeStatus(clientset, cnp, derivativePolicy.GetName(), err, clusterScoped) 258 if statusErr != nil { 259 metrics.PolicyChangeTotal.WithLabelValues(metrics.LabelValueOutcomeFail).Inc() 260 scopedLog.WithError(err).Error("Cannot update status for derivative policy") 261 } 262 return statusErr 263 } 264 metrics.PolicyChangeTotal.WithLabelValues(metrics.LabelValueOutcomeSuccess).Inc() 265 266 err = updateDerivativeStatus(clientset, cnp, derivativePolicy.GetName(), nil, clusterScoped) 267 if err != nil { 268 scopedLog.WithError(err).Error("Cannot update status for derivative policy") 269 } 270 return err 271 }