github.com/cilium/cilium@v1.16.2/pkg/policy/api/ingress.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package api 5 6 import ( 7 "context" 8 9 slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 10 "github.com/cilium/cilium/pkg/slices" 11 ) 12 13 // IngressCommonRule is a rule that shares some of its fields across the 14 // IngressRule and IngressDenyRule. It's publicly exported so the code 15 // generators can generate code for this structure. 16 // 17 // +deepequal-gen:private-method=true 18 type IngressCommonRule struct { 19 // FromEndpoints is a list of endpoints identified by an 20 // EndpointSelector which are allowed to communicate with the endpoint 21 // subject to the rule. 22 // 23 // Example: 24 // Any endpoint with the label "role=backend" can be consumed by any 25 // endpoint carrying the label "role=frontend". 26 // 27 // +kubebuilder:validation:Optional 28 FromEndpoints []EndpointSelector `json:"fromEndpoints,omitempty"` 29 30 // FromRequires is a list of additional constraints which must be met 31 // in order for the selected endpoints to be reachable. These 32 // additional constraints do no by itself grant access privileges and 33 // must always be accompanied with at least one matching FromEndpoints. 34 // 35 // Example: 36 // Any Endpoint with the label "team=A" requires consuming endpoint 37 // to also carry the label "team=A". 38 // 39 // +kubebuilder:validation:Optional 40 FromRequires []EndpointSelector `json:"fromRequires,omitempty"` 41 42 // FromCIDR is a list of IP blocks which the endpoint subject to the 43 // rule is allowed to receive connections from. Only connections which 44 // do *not* originate from the cluster or from the local host are subject 45 // to CIDR rules. In order to allow in-cluster connectivity, use the 46 // FromEndpoints field. This will match on the source IP address of 47 // incoming connections. Adding a prefix into FromCIDR or into 48 // FromCIDRSet with no ExcludeCIDRs is equivalent. Overlaps are 49 // allowed between FromCIDR and FromCIDRSet. 50 // 51 // Example: 52 // Any endpoint with the label "app=my-legacy-pet" is allowed to receive 53 // connections from 10.3.9.1 54 // 55 // +kubebuilder:validation:Optional 56 FromCIDR CIDRSlice `json:"fromCIDR,omitempty"` 57 58 // FromCIDRSet is a list of IP blocks which the endpoint subject to the 59 // rule is allowed to receive connections from in addition to FromEndpoints, 60 // along with a list of subnets contained within their corresponding IP block 61 // from which traffic should not be allowed. 62 // This will match on the source IP address of incoming connections. Adding 63 // a prefix into FromCIDR or into FromCIDRSet with no ExcludeCIDRs is 64 // equivalent. Overlaps are allowed between FromCIDR and FromCIDRSet. 65 // 66 // Example: 67 // Any endpoint with the label "app=my-legacy-pet" is allowed to receive 68 // connections from 10.0.0.0/8 except from IPs in subnet 10.96.0.0/12. 69 // 70 // +kubebuilder:validation:Optional 71 FromCIDRSet CIDRRuleSlice `json:"fromCIDRSet,omitempty"` 72 73 // FromEntities is a list of special entities which the endpoint subject 74 // to the rule is allowed to receive connections from. Supported entities are 75 // `world`, `cluster` and `host` 76 // 77 // +kubebuilder:validation:Optional 78 FromEntities EntitySlice `json:"fromEntities,omitempty"` 79 80 // FromGroups is a directive that allows the integration with multiple outside 81 // providers. Currently, only AWS is supported, and the rule can select by 82 // multiple sub directives: 83 // 84 // Example: 85 // FromGroups: 86 // - aws: 87 // securityGroupsIds: 88 // - 'sg-XXXXXXXXXXXXX' 89 // 90 // +kubebuilder:validation:Optional 91 FromGroups []Groups `json:"fromGroups,omitempty"` 92 93 // FromNodes is a list of nodes identified by an 94 // EndpointSelector which are allowed to communicate with the endpoint 95 // subject to the rule. 96 // 97 // +kubebuilder:validation:Optional 98 FromNodes []EndpointSelector `json:"fromNodes,omitempty"` 99 100 // TODO: Move this to the policy package 101 // (https://github.com/cilium/cilium/issues/8353) 102 aggregatedSelectors EndpointSelectorSlice `json:"-"` 103 } 104 105 // DeepEqual returns true if both IngressCommonRule are deep equal. 106 // The semantic of a nil slice in one of its fields is different from the semantic 107 // of an empty non-nil slice, thus it explicitly checks for that case before calling 108 // the autogenerated method. 109 func (in *IngressCommonRule) DeepEqual(other *IngressCommonRule) bool { 110 if slices.XorNil(in.FromEndpoints, other.FromEndpoints) { 111 return false 112 } 113 if slices.XorNil(in.FromCIDR, other.FromCIDR) { 114 return false 115 } 116 if slices.XorNil(in.FromCIDRSet, other.FromCIDRSet) { 117 return false 118 } 119 if slices.XorNil(in.FromEntities, other.FromEntities) { 120 return false 121 } 122 123 return in.deepEqual(other) 124 } 125 126 // IngressRule contains all rule types which can be applied at ingress, 127 // i.e. network traffic that originates outside of the endpoint and 128 // is entering the endpoint selected by the endpointSelector. 129 // 130 // - All members of this structure are optional. If omitted or empty, the 131 // member will have no effect on the rule. 132 // 133 // - If multiple members are set, all of them need to match in order for 134 // the rule to take effect. The exception to this rule is FromRequires field; 135 // the effects of any Requires field in any rule will apply to all other 136 // rules as well. 137 // 138 // - FromEndpoints, FromCIDR, FromCIDRSet and FromEntities are mutually 139 // exclusive. Only one of these members may be present within an individual 140 // rule. 141 type IngressRule struct { 142 IngressCommonRule `json:",inline"` 143 144 // ToPorts is a list of destination ports identified by port number and 145 // protocol which the endpoint subject to the rule is allowed to 146 // receive connections on. 147 // 148 // Example: 149 // Any endpoint with the label "app=httpd" can only accept incoming 150 // connections on port 80/tcp. 151 // 152 // +kubebuilder:validation:Optional 153 ToPorts PortRules `json:"toPorts,omitempty"` 154 155 // ICMPs is a list of ICMP rule identified by type number 156 // which the endpoint subject to the rule is allowed to 157 // receive connections on. 158 // 159 // Example: 160 // Any endpoint with the label "app=httpd" can only accept incoming 161 // type 8 ICMP connections. 162 // 163 // +kubebuilder:validation:Optional 164 ICMPs ICMPRules `json:"icmps,omitempty"` 165 166 // Authentication is the required authentication type for the allowed traffic, if any. 167 // 168 // +kubebuilder:validation:Optional 169 Authentication *Authentication `json:"authentication,omitempty"` 170 } 171 172 // IngressDenyRule contains all rule types which can be applied at ingress, 173 // i.e. network traffic that originates outside of the endpoint and 174 // is entering the endpoint selected by the endpointSelector. 175 // 176 // - All members of this structure are optional. If omitted or empty, the 177 // member will have no effect on the rule. 178 // 179 // - If multiple members are set, all of them need to match in order for 180 // the rule to take effect. The exception to this rule is FromRequires field; 181 // the effects of any Requires field in any rule will apply to all other 182 // rules as well. 183 // 184 // - FromEndpoints, FromCIDR, FromCIDRSet, FromGroups and FromEntities are mutually 185 // exclusive. Only one of these members may be present within an individual 186 // rule. 187 type IngressDenyRule struct { 188 IngressCommonRule `json:",inline"` 189 190 // ToPorts is a list of destination ports identified by port number and 191 // protocol which the endpoint subject to the rule is not allowed to 192 // receive connections on. 193 // 194 // Example: 195 // Any endpoint with the label "app=httpd" can not accept incoming 196 // connections on port 80/tcp. 197 // 198 // +kubebuilder:validation:Optional 199 ToPorts PortDenyRules `json:"toPorts,omitempty"` 200 201 // ICMPs is a list of ICMP rule identified by type number 202 // which the endpoint subject to the rule is not allowed to 203 // receive connections on. 204 // 205 // Example: 206 // Any endpoint with the label "app=httpd" can not accept incoming 207 // type 8 ICMP connections. 208 // 209 // +kubebuilder:validation:Optional 210 ICMPs ICMPRules `json:"icmps,omitempty"` 211 } 212 213 // SetAggregatedSelectors creates a single slice containing all of the following 214 // fields within the IngressRule, converted to EndpointSelector, to be stored 215 // within the IngressRule for easy lookup while performing policy evaluation 216 // for the rule: 217 // * FromEntities 218 // * FromCIDR 219 // * FromCIDRSet 220 // 221 // FromEndpoints is not aggregated due to requirement folding in 222 // GetSourceEndpointSelectorsWithRequirements() 223 func (i *IngressCommonRule) SetAggregatedSelectors() { 224 // Goroutines can race setting i.aggregatedSelectors, but they will all compute the same result, so it does not matter. 225 226 // explicitly check for empty non-nil slices, it should not result in any identity being selected. 227 if (i.FromCIDR != nil && len(i.FromCIDR) == 0) || 228 (i.FromCIDRSet != nil && len(i.FromCIDRSet) == 0) || 229 (i.FromEntities != nil && len(i.FromEntities) == 0) { 230 i.aggregatedSelectors = nil 231 return 232 } 233 234 res := make(EndpointSelectorSlice, 0, len(i.FromEntities)+len(i.FromCIDR)+len(i.FromCIDRSet)) 235 res = append(res, i.FromEntities.GetAsEndpointSelectors()...) 236 res = append(res, i.FromCIDR.GetAsEndpointSelectors()...) 237 res = append(res, i.FromCIDRSet.GetAsEndpointSelectors()...) 238 239 i.aggregatedSelectors = res 240 } 241 242 // GetSourceEndpointSelectorsWithRequirements returns a slice of endpoints selectors covering 243 // all L3 source selectors of the ingress rule 244 func (i *IngressCommonRule) GetSourceEndpointSelectorsWithRequirements(requirements []slim_metav1.LabelSelectorRequirement) EndpointSelectorSlice { 245 if i.aggregatedSelectors == nil { 246 i.SetAggregatedSelectors() 247 } 248 249 // explicitly check for empty non-nil slices, it should not result in any identity being selected. 250 if i.aggregatedSelectors == nil || (i.FromEndpoints != nil && len(i.FromEndpoints) == 0) || 251 (i.FromNodes != nil && len(i.FromNodes) == 0) { 252 return nil 253 } 254 255 res := make(EndpointSelectorSlice, 0, len(i.FromEndpoints)+len(i.aggregatedSelectors)+len(i.FromNodes)) 256 if len(requirements) > 0 && len(i.FromEndpoints) > 0 { 257 for idx := range i.FromEndpoints { 258 sel := *i.FromEndpoints[idx].DeepCopy() 259 sel.MatchExpressions = append(sel.MatchExpressions, requirements...) 260 sel.SyncRequirementsWithLabelSelector() 261 // Even though this string is deep copied, we need to override it 262 // because we are updating the contents of the MatchExpressions. 263 sel.cachedLabelSelectorString = sel.LabelSelector.String() 264 res = append(res, sel) 265 } 266 } else { 267 res = append(res, i.FromEndpoints...) 268 res = append(res, i.FromNodes...) 269 } 270 271 return append(res, i.aggregatedSelectors...) 272 } 273 274 // AllowsWildcarding returns true if wildcarding should be performed upon 275 // policy evaluation for the given rule. 276 func (i *IngressCommonRule) AllowsWildcarding() bool { 277 return len(i.FromRequires) == 0 278 } 279 280 // RequiresDerivative returns true when the EgressCommonRule contains sections 281 // that need a derivative policy created in order to be enforced 282 // (e.g. FromGroups). 283 func (e *IngressCommonRule) RequiresDerivative() bool { 284 return len(e.FromGroups) > 0 285 } 286 287 // CreateDerivative will return a new rule based on the data gathered by the 288 // rules that creates a new derivative policy. 289 // In the case of FromGroups will call outside using the groups callback and this 290 // function can take a bit of time. 291 func (e *IngressRule) CreateDerivative(ctx context.Context) (*IngressRule, error) { 292 newRule := e.DeepCopy() 293 if !e.RequiresDerivative() { 294 return newRule, nil 295 } 296 newRule.FromCIDRSet = make(CIDRRuleSlice, 0, len(e.FromGroups)) 297 cidrSet, err := ExtractCidrSet(ctx, e.FromGroups) 298 if err != nil { 299 return &IngressRule{}, err 300 } 301 newRule.FromCIDRSet = append(e.FromCIDRSet, cidrSet...) 302 newRule.FromGroups = nil 303 e.SetAggregatedSelectors() 304 return newRule, nil 305 } 306 307 // CreateDerivative will return a new rule based on the data gathered by the 308 // rules that creates a new derivative policy. 309 // In the case of FromGroups will call outside using the groups callback and this 310 // function can take a bit of time. 311 func (e *IngressDenyRule) CreateDerivative(ctx context.Context) (*IngressDenyRule, error) { 312 newRule := e.DeepCopy() 313 if !e.RequiresDerivative() { 314 return newRule, nil 315 } 316 newRule.FromCIDRSet = make(CIDRRuleSlice, 0, len(e.FromGroups)) 317 cidrSet, err := ExtractCidrSet(ctx, e.FromGroups) 318 if err != nil { 319 return &IngressDenyRule{}, err 320 } 321 newRule.FromCIDRSet = append(e.FromCIDRSet, cidrSet...) 322 newRule.FromGroups = nil 323 e.SetAggregatedSelectors() 324 return newRule, nil 325 }