github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/resolve.go (about)

     1  // Copyright 2018-2019 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 policy
    16  
    17  import (
    18  	"github.com/cilium/cilium/pkg/identity"
    19  	"github.com/cilium/cilium/pkg/policy/trafficdirection"
    20  )
    21  
    22  // selectorPolicy is a structure which contains the resolved policy for a
    23  // particular Identity across all layers (L3, L4, and L7), with the policy
    24  // still determined in terms of EndpointSelectors.
    25  type selectorPolicy struct {
    26  	// Revision is the revision of the policy repository used to generate
    27  	// this selectorPolicy.
    28  	Revision uint64
    29  
    30  	// SelectorCache managing selectors in L4Policy
    31  	SelectorCache *SelectorCache
    32  
    33  	// L4Policy contains the computed L4 and L7 policy.
    34  	L4Policy *L4Policy
    35  
    36  	// CIDRPolicy contains the L3 (not L4) CIDR-based policy.
    37  	CIDRPolicy *CIDRPolicy
    38  
    39  	// IngressPolicyEnabled specifies whether this policy contains any policy
    40  	// at ingress.
    41  	IngressPolicyEnabled bool
    42  
    43  	// EgressPolicyEnabled specifies whether this policy contains any policy
    44  	// at egress.
    45  	EgressPolicyEnabled bool
    46  }
    47  
    48  func (p *selectorPolicy) Attach() {
    49  	if p.L4Policy != nil {
    50  		p.L4Policy.Attach()
    51  	}
    52  }
    53  
    54  // EndpointPolicy is a structure which contains the resolved policy across all
    55  // layers (L3, L4, and L7), distilled against a set of identities.
    56  type EndpointPolicy struct {
    57  	// Note that all Endpoints sharing the same identity will be
    58  	// referring to a shared selectorPolicy!
    59  	*selectorPolicy
    60  
    61  	// PolicyMapState contains the state of this policy as it relates to the
    62  	// datapath. In the future, this will be factored out of this object to
    63  	// decouple the policy as it relates to the datapath vs. its userspace
    64  	// representation.
    65  	// It maps each Key to the proxy port if proxy redirection is needed.
    66  	// Proxy port 0 indicates no proxy redirection.
    67  	// All fields within the Key and the proxy port must be in host byte-order.
    68  	PolicyMapState MapState
    69  
    70  	// PolicyMapChanges collects pending changes to the PolicyMapState
    71  	PolicyMapChanges MapChanges
    72  
    73  	// PolicyOwner describes any type which consumes this EndpointPolicy object.
    74  	PolicyOwner PolicyOwner
    75  }
    76  
    77  // PolicyOwner is anything which consumes a EndpointPolicy.
    78  type PolicyOwner interface {
    79  	LookupRedirectPort(l4 *L4Filter) uint16
    80  	GetSecurityIdentity() *identity.Identity
    81  }
    82  
    83  // newSelectorPolicy returns an empty selectorPolicy stub.
    84  func newSelectorPolicy(revision uint64, selectorCache *SelectorCache) *selectorPolicy {
    85  	return &selectorPolicy{
    86  		Revision:      revision,
    87  		SelectorCache: selectorCache,
    88  	}
    89  }
    90  
    91  // insertUser adds a user to the L4Policy so that incremental
    92  // updates of the L4Policy may be fowarded.
    93  func (p *selectorPolicy) insertUser(user *EndpointPolicy) {
    94  	if p.L4Policy != nil {
    95  		p.L4Policy.insertUser(user)
    96  	}
    97  }
    98  
    99  // Detach releases resources held by a selectorPolicy to enable
   100  // successful eventual GC.  Note that the selectorPolicy itself if not
   101  // modified in any way, so that it can be used concurrently.
   102  func (p *selectorPolicy) Detach() {
   103  	if p.L4Policy != nil {
   104  		p.L4Policy.Detach(p.SelectorCache)
   105  	}
   106  }
   107  
   108  // DistillPolicy filters down the specified selectorPolicy (which acts
   109  // upon selectors) into a set of concrete map entries based on the
   110  // SelectorCache. These can subsequently be plumbed into the datapath.
   111  //
   112  // Must be performed while holding the Repository lock.
   113  func (p *selectorPolicy) DistillPolicy(policyOwner PolicyOwner) *EndpointPolicy {
   114  	calculatedPolicy := &EndpointPolicy{
   115  		selectorPolicy: p,
   116  		PolicyMapState: make(MapState),
   117  		PolicyOwner:    policyOwner,
   118  	}
   119  
   120  	if !p.IngressPolicyEnabled || !p.EgressPolicyEnabled {
   121  		calculatedPolicy.PolicyMapState.AllowAllIdentities(
   122  			!p.IngressPolicyEnabled, !p.EgressPolicyEnabled)
   123  	}
   124  
   125  	// Register the new EndpointPolicy as a receiver of delta
   126  	// updates.  Any updates happening after this, but before
   127  	// computeDesiredL4PolicyMapEntires() call finishes may
   128  	// already be applied to the PolicyMapState, specifically:
   129  	//
   130  	// - PolicyMapChanges may contain an addition of an entry that
   131  	//   is already added to the PolicyMapState
   132  	//
   133  	// - PolicyMapChanges may congtain a deletion of an entry that
   134  	//   has already been deleted from PolicyMapState
   135  	p.insertUser(calculatedPolicy)
   136  
   137  	// Must come after the 'insertUser()' above to guarantee
   138  	// PolicyMapCanges will contain all changes that are applied
   139  	// after the computation of PolicyMapState has started.
   140  	calculatedPolicy.computeDesiredL4PolicyMapEntries()
   141  	calculatedPolicy.PolicyMapState.DetermineAllowLocalhostIngress(p.L4Policy)
   142  
   143  	return calculatedPolicy
   144  }
   145  
   146  // computeDesiredL4PolicyMapEntries transforms the EndpointPolicy.L4Policy into
   147  // the datapath-friendly format inside EndpointPolicy.PolicyMapState.
   148  func (p *EndpointPolicy) computeDesiredL4PolicyMapEntries() {
   149  
   150  	if p.L4Policy == nil {
   151  		return
   152  	}
   153  	p.computeDirectionL4PolicyMapEntries(p.L4Policy.Ingress, trafficdirection.Ingress)
   154  	p.computeDirectionL4PolicyMapEntries(p.L4Policy.Egress, trafficdirection.Egress)
   155  }
   156  
   157  func (p *EndpointPolicy) computeDirectionL4PolicyMapEntries(l4PolicyMap L4PolicyMap, direction trafficdirection.TrafficDirection) {
   158  	for _, filter := range l4PolicyMap {
   159  		keysFromFilter := filter.ToKeys(direction)
   160  		for _, keyFromFilter := range keysFromFilter {
   161  			var proxyPort uint16
   162  			// Preserve the already-allocated proxy ports for redirects that
   163  			// already exist.
   164  			if filter.IsRedirect() {
   165  				proxyPort = p.PolicyOwner.LookupRedirectPort(filter)
   166  				// If the currently allocated proxy port is 0, this is a new
   167  				// redirect, for which no port has been allocated yet. Ignore
   168  				// it for now. This will be configured by
   169  				// e.addNewRedirectsFromMap once the port has been allocated.
   170  				if proxyPort == 0 {
   171  					continue
   172  				}
   173  			}
   174  			p.PolicyMapState[keyFromFilter] = MapStateEntry{ProxyPort: proxyPort}
   175  		}
   176  	}
   177  }
   178  
   179  // NewEndpointPolicy returns an empty EndpointPolicy stub.
   180  func NewEndpointPolicy(repo *Repository) *EndpointPolicy {
   181  	return &EndpointPolicy{
   182  		selectorPolicy: newSelectorPolicy(0, repo.GetSelectorCache()),
   183  	}
   184  }