istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/plugin/authn/authentication.go (about)

     1  // Copyright Istio Authors
     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 authn
    16  
    17  import (
    18  	hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    19  
    20  	"istio.io/istio/pilot/pkg/model"
    21  	"istio.io/istio/pilot/pkg/networking"
    22  	"istio.io/istio/pilot/pkg/security/authn"
    23  	"istio.io/istio/pkg/log"
    24  )
    25  
    26  var authnLog = log.RegisterScope("authn", "authn debugging")
    27  
    28  type Builder struct {
    29  	applier      authn.PolicyApplier
    30  	trustDomains []string
    31  	proxy        *model.Proxy
    32  }
    33  
    34  func NewBuilder(push *model.PushContext, proxy *model.Proxy) *Builder {
    35  	return NewBuilderForService(push, proxy, nil)
    36  }
    37  
    38  func NewBuilderForService(push *model.PushContext, proxy *model.Proxy, svc *model.Service) *Builder {
    39  	applier := authn.NewPolicyApplier(push, proxy, svc)
    40  	trustDomains := TrustDomainsForValidation(push.Mesh)
    41  	return &Builder{
    42  		applier:      applier,
    43  		proxy:        proxy,
    44  		trustDomains: trustDomains,
    45  	}
    46  }
    47  
    48  func (b *Builder) ForPort(port uint32) authn.MTLSSettings {
    49  	if b == nil {
    50  		return authn.MTLSSettings{
    51  			Port: port,
    52  			Mode: model.MTLSDisable,
    53  		}
    54  	}
    55  	return b.applier.InboundMTLSSettings(port, b.proxy, b.trustDomains, authn.NoOverride)
    56  }
    57  
    58  func (b *Builder) ForHBONE() authn.MTLSSettings {
    59  	if b == nil {
    60  		return authn.MTLSSettings{
    61  			Port: model.HBoneInboundListenPort,
    62  			Mode: model.MTLSDisable,
    63  		}
    64  	}
    65  	// HBONE is always strict
    66  	return b.applier.InboundMTLSSettings(model.HBoneInboundListenPort, b.proxy, b.trustDomains, model.MTLSStrict)
    67  }
    68  
    69  func (b *Builder) ForPassthrough() []authn.MTLSSettings {
    70  	if b == nil {
    71  		return []authn.MTLSSettings{{
    72  			Port: 0,
    73  			Mode: model.MTLSDisable,
    74  		}}
    75  	}
    76  	//	We need to create configuration for the passthrough,
    77  	// but also any ports that are not explicitly declared in the Service but are in the mTLS port level settings.
    78  
    79  	resp := []authn.MTLSSettings{
    80  		// Full passthrough - no port match
    81  		b.applier.InboundMTLSSettings(0, b.proxy, b.trustDomains, authn.NoOverride),
    82  	}
    83  
    84  	// Then generate the per-port passthrough filter chains.
    85  	for port := range b.applier.PortLevelSetting() {
    86  		// Skip the per-port passthrough filterchain if the port is already handled by InboundMTLSConfiguration().
    87  		if !needPerPortPassthroughFilterChain(port, b.proxy) {
    88  			continue
    89  		}
    90  
    91  		authnLog.Debugf("InboundMTLSConfiguration: build extra pass through filter chain for %v:%d", b.proxy.ID, port)
    92  		resp = append(resp, b.applier.InboundMTLSSettings(port, b.proxy, b.trustDomains, authn.NoOverride))
    93  	}
    94  	return resp
    95  }
    96  
    97  func (b *Builder) BuildHTTP(class networking.ListenerClass) []*hcm.HttpFilter {
    98  	if b == nil {
    99  		return nil
   100  	}
   101  	if class == networking.ListenerClassSidecarOutbound {
   102  		// Only applies to inbound and gateways
   103  		return nil
   104  	}
   105  	if b.proxy.SupportsEnvoyExtendedJwt() {
   106  		filter := b.applier.JwtFilter(true, b.proxy.Type != model.SidecarProxy)
   107  		if filter != nil {
   108  			return []*hcm.HttpFilter{filter}
   109  		}
   110  		return nil
   111  	}
   112  	res := []*hcm.HttpFilter{}
   113  	if filter := b.applier.JwtFilter(false, false); filter != nil {
   114  		res = append(res, filter)
   115  	}
   116  	forSidecar := b.proxy.Type == model.SidecarProxy
   117  	if filter := b.applier.AuthNFilter(forSidecar); filter != nil {
   118  		res = append(res, filter)
   119  	}
   120  
   121  	return res
   122  }
   123  
   124  func needPerPortPassthroughFilterChain(port uint32, node *model.Proxy) bool {
   125  	// If there is any Sidecar defined, check if the port is explicitly defined there.
   126  	// This means the Sidecar resource takes precedence over the service. A port defined in service but not in Sidecar
   127  	// means the port is going to be handled by the pass through filter chain.
   128  	if node.SidecarScope.HasIngressListener() {
   129  		for _, ingressListener := range node.SidecarScope.Sidecar.Ingress {
   130  			if port == ingressListener.Port.Number {
   131  				return false
   132  			}
   133  		}
   134  		return true
   135  	}
   136  
   137  	// If there is no Sidecar, check if the port is appearing in any service.
   138  	for _, si := range node.ServiceTargets {
   139  		if port == si.Port.TargetPort {
   140  			return false
   141  		}
   142  	}
   143  	return true
   144  }