github.com/cilium/cilium@v1.16.2/pkg/policy/k8s/cilium_network_policy.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package k8s
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/sirupsen/logrus"
    10  
    11  	ipcacheTypes "github.com/cilium/cilium/pkg/ipcache/types"
    12  	"github.com/cilium/cilium/pkg/k8s/resource"
    13  	"github.com/cilium/cilium/pkg/k8s/types"
    14  	"github.com/cilium/cilium/pkg/logging/logfields"
    15  	"github.com/cilium/cilium/pkg/metrics"
    16  	"github.com/cilium/cilium/pkg/policy"
    17  	"github.com/cilium/cilium/pkg/source"
    18  	"github.com/cilium/cilium/pkg/time"
    19  )
    20  
    21  func (p *policyWatcher) onUpsert(
    22  	cnp *types.SlimCNP,
    23  	key resource.Key,
    24  	apiGroup string,
    25  	resourceID ipcacheTypes.ResourceID,
    26  ) error {
    27  	initialRecvTime := time.Now()
    28  
    29  	defer func() {
    30  		p.k8sResourceSynced.SetEventTimestamp(apiGroup)
    31  	}()
    32  
    33  	oldCNP, ok := p.cnpCache[key]
    34  	if ok {
    35  		// no generation change; this was a status update.
    36  		if oldCNP.Generation == cnp.Generation {
    37  			return nil
    38  		}
    39  		if oldCNP.DeepEqual(cnp) {
    40  			return nil
    41  		}
    42  
    43  		p.log.WithFields(logrus.Fields{
    44  			logfields.K8sAPIVersion:           cnp.TypeMeta.APIVersion,
    45  			logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name,
    46  			logfields.K8sNamespace:            cnp.ObjectMeta.Namespace,
    47  			"annotations.old":                 oldCNP.ObjectMeta.Annotations,
    48  			"annotations":                     cnp.ObjectMeta.Annotations,
    49  		}).Debug("Modified CiliumNetworkPolicy")
    50  	}
    51  
    52  	if cnp.RequiresDerivative() {
    53  		return nil
    54  	}
    55  
    56  	// check if this cnp was referencing or is now referencing at least one non-empty
    57  	// CiliumCIDRGroup and update the relevant metric accordingly.
    58  	cidrGroupRefs := getCIDRGroupRefs(cnp)
    59  	cidrsSets, _ := p.cidrGroupRefsToCIDRsSets(cidrGroupRefs)
    60  	if len(cidrsSets) > 0 {
    61  		p.cidrGroupPolicies[key] = struct{}{}
    62  	} else {
    63  		delete(p.cidrGroupPolicies, key)
    64  	}
    65  	metrics.CIDRGroupsReferenced.Set(float64(len(p.cidrGroupPolicies)))
    66  
    67  	// check if this cnp was referencing or is now referencing at least one ToServices rule
    68  	if hasToServices(cnp) {
    69  		p.toServicesPolicies[key] = struct{}{}
    70  	} else {
    71  		delete(p.toServicesPolicies, key)
    72  	}
    73  
    74  	return p.resolveCiliumNetworkPolicyRefs(cnp, key, initialRecvTime, resourceID)
    75  }
    76  
    77  func (p *policyWatcher) onDelete(
    78  	cnp *types.SlimCNP,
    79  	key resource.Key,
    80  	apiGroup string,
    81  	resourceID ipcacheTypes.ResourceID,
    82  ) error {
    83  	err := p.deleteCiliumNetworkPolicyV2(cnp, resourceID)
    84  	delete(p.cnpCache, key)
    85  
    86  	// Clear CIDRGroupRef index
    87  	delete(p.cidrGroupPolicies, key)
    88  	metrics.CIDRGroupsReferenced.Set(float64(len(p.cidrGroupPolicies)))
    89  
    90  	// Clear ToServices index
    91  	for svcID := range p.cnpByServiceID {
    92  		p.clearCNPForService(key, svcID)
    93  	}
    94  	delete(p.toServicesPolicies, key)
    95  
    96  	p.k8sResourceSynced.SetEventTimestamp(apiGroup)
    97  
    98  	return err
    99  }
   100  
   101  // resolveCiliumNetworkPolicyRefs resolves all the references to external resources
   102  // (e.g. CiliumCIDRGroups) in a CNP/CCNP, inlines them into a "translated" CNP,
   103  // and then adds the translated CNP to the policy repository.
   104  // If the CNP was successfully imported, the raw (i.e. untranslated) CNP/CCNP
   105  // is also added to p.cnpCache.
   106  func (p *policyWatcher) resolveCiliumNetworkPolicyRefs(
   107  	cnp *types.SlimCNP,
   108  	key resource.Key,
   109  	initialRecvTime time.Time,
   110  	resourceID ipcacheTypes.ResourceID,
   111  ) error {
   112  	// We need to deepcopy this structure because we are writing
   113  	// fields in cnp.Parse() in upsertCiliumNetworkPolicyV2.
   114  	// See https://github.com/cilium/cilium/blob/27fee207f5422c95479422162e9ea0d2f2b6c770/pkg/policy/api/ingress.go#L112-L134
   115  	translatedCNP := cnp.DeepCopy()
   116  
   117  	// Resolve CiliumCIDRGroup references
   118  	translationStart := time.Now()
   119  	p.resolveCIDRGroupRef(translatedCNP)
   120  	metrics.CIDRGroupTranslationTimeStats.Observe(time.Since(translationStart).Seconds())
   121  
   122  	// Resolve ToService references
   123  	p.resolveToServices(key, translatedCNP)
   124  
   125  	err := p.upsertCiliumNetworkPolicyV2(translatedCNP, initialRecvTime, resourceID)
   126  	if err == nil {
   127  		p.cnpCache[key] = cnp
   128  	}
   129  
   130  	return err
   131  }
   132  
   133  func (p *policyWatcher) upsertCiliumNetworkPolicyV2(cnp *types.SlimCNP, initialRecvTime time.Time, resourceID ipcacheTypes.ResourceID) error {
   134  	scopedLog := p.log.WithFields(logrus.Fields{
   135  		logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name,
   136  		logfields.K8sAPIVersion:           cnp.TypeMeta.APIVersion,
   137  		logfields.K8sNamespace:            cnp.ObjectMeta.Namespace,
   138  	})
   139  
   140  	scopedLog.Debug("Adding CiliumNetworkPolicy")
   141  
   142  	rules, policyImportErr := cnp.Parse()
   143  	if policyImportErr == nil {
   144  		_, policyImportErr = p.policyManager.PolicyAdd(rules, &policy.AddOptions{
   145  			Source:              source.CustomResource,
   146  			ProcessingStartTime: initialRecvTime,
   147  			Resource:            resourceID,
   148  			ReplaceByResource:   true,
   149  		})
   150  	}
   151  
   152  	if policyImportErr != nil {
   153  		scopedLog.WithError(policyImportErr).Warn("Unable to add CiliumNetworkPolicy")
   154  	} else {
   155  		scopedLog.Info("Imported CiliumNetworkPolicy")
   156  	}
   157  
   158  	return policyImportErr
   159  }
   160  
   161  func (p *policyWatcher) deleteCiliumNetworkPolicyV2(cnp *types.SlimCNP, resourceID ipcacheTypes.ResourceID) error {
   162  	scopedLog := p.log.WithFields(logrus.Fields{
   163  		logfields.CiliumNetworkPolicyName: cnp.ObjectMeta.Name,
   164  		logfields.K8sAPIVersion:           cnp.TypeMeta.APIVersion,
   165  		logfields.K8sNamespace:            cnp.ObjectMeta.Namespace,
   166  	})
   167  
   168  	scopedLog.Debug("Deleting CiliumNetworkPolicy")
   169  
   170  	_, err := p.policyManager.PolicyDelete(nil, &policy.DeleteOptions{
   171  		Source:           source.CustomResource,
   172  		Resource:         resourceID,
   173  		DeleteByResource: true,
   174  	})
   175  	if err == nil {
   176  		scopedLog.Info("Deleted CiliumNetworkPolicy")
   177  	} else {
   178  		scopedLog.WithError(err).Warn("Unable to delete CiliumNetworkPolicy")
   179  	}
   180  	return err
   181  }
   182  
   183  func (p *policyWatcher) registerResourceWithSyncFn(ctx context.Context, resource string, syncFn func() bool) {
   184  	p.k8sResourceSynced.BlockWaitGroupToSyncResources(ctx.Done(), nil, syncFn, resource)
   185  	p.k8sAPIGroups.AddAPI(resource)
   186  }
   187  
   188  // reportCNPChangeMetrics generates metrics for changes (Add, Update, Delete) to
   189  // Cilium Network Policies depending on the operation's success.
   190  func reportCNPChangeMetrics(err error) {
   191  	if err != nil {
   192  		metrics.PolicyChangeTotal.WithLabelValues(metrics.LabelValueOutcomeFail).Inc()
   193  	} else {
   194  		metrics.PolicyChangeTotal.WithLabelValues(metrics.LabelValueOutcomeSuccess).Inc()
   195  	}
   196  }
   197  
   198  func resourceIDForCiliumNetworkPolicy(key resource.Key, cnp *types.SlimCNP) ipcacheTypes.ResourceID {
   199  	resourceKind := ipcacheTypes.ResourceKindCNP
   200  	if len(key.Namespace) == 0 {
   201  		resourceKind = ipcacheTypes.ResourceKindCCNP
   202  	}
   203  	return ipcacheTypes.NewResourceID(
   204  		resourceKind,
   205  		cnp.ObjectMeta.Namespace,
   206  		cnp.ObjectMeta.Name,
   207  	)
   208  }