istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/security/model/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 model 16 17 import ( 18 gotls "crypto/tls" 19 "strings" 20 21 core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 22 tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" 23 24 networking "istio.io/api/networking/v1alpha3" 25 "istio.io/istio/pilot/pkg/model" 26 "istio.io/istio/pilot/pkg/model/credentials" 27 "istio.io/istio/pilot/pkg/networking/util" 28 pm "istio.io/istio/pkg/model" 29 "istio.io/istio/pkg/security" 30 "istio.io/istio/pkg/spiffe" 31 ) 32 33 const ( 34 // SDSClusterName is the name of the cluster for SDS connections 35 SDSClusterName = pm.SDSClusterName 36 37 // SDSDefaultResourceName is the default name in sdsconfig, used for fetching normal key/cert. 38 SDSDefaultResourceName = pm.SDSDefaultResourceName 39 40 // SDSRootResourceName is the sdsconfig name for root CA, used for fetching root cert. 41 SDSRootResourceName = pm.SDSRootResourceName 42 43 // ThirdPartyJwtPath is the token volume mount file name for k8s trustworthy jwt token. 44 ThirdPartyJwtPath = "/var/run/secrets/tokens/istio-token" 45 46 // SdsCaSuffix is the suffix of the sds resource name for root CA. 47 SdsCaSuffix = credentials.SdsCaSuffix 48 49 // EnvoyJwtFilterName is the name of the Envoy JWT filter. This should be the same as the name defined 50 // in https://github.com/envoyproxy/envoy/blob/v1.9.1/source/extensions/filters/http/well_known_names.h#L48 51 EnvoyJwtFilterName = "envoy.filters.http.jwt_authn" 52 ) 53 54 var SDSAdsConfig = &core.ConfigSource{ 55 ConfigSourceSpecifier: &core.ConfigSource_Ads{ 56 Ads: &core.AggregatedConfigSource{}, 57 }, 58 // We intentionally do *not* set InitialFetchTimeout to 0s here, as this is used for 59 // credentialName SDS which may refer to secrets which do not exist. We do not want to block the 60 // entire listener/cluster in these cases. 61 ResourceApiVersion: core.ApiVersion_V3, 62 } 63 64 // ConstructSdsSecretConfigForCredential constructs SDS secret configuration used 65 // from certificates referenced by credentialName in DestinationRule or Gateway. 66 // Currently this is served by a local SDS server, but in the future replaced by 67 // Istiod SDS server. 68 func ConstructSdsSecretConfigForCredential(name string, credentialSocketExist bool) *tls.SdsSecretConfig { 69 if name == "" { 70 return nil 71 } 72 if name == credentials.BuiltinGatewaySecretTypeURI { 73 return ConstructSdsSecretConfig(SDSDefaultResourceName) 74 } 75 if name == credentials.BuiltinGatewaySecretTypeURI+SdsCaSuffix { 76 return ConstructSdsSecretConfig(SDSRootResourceName) 77 } 78 // if credentialSocketExist exists and credentialName is using SDSExternalCredentialPrefix 79 // SDS will be served via SDSExternalClusterName 80 if credentialSocketExist && strings.HasPrefix(name, security.SDSExternalCredentialPrefix) { 81 return ConstructSdsSecretConfigForCredentialSocket(name) 82 } 83 84 return &tls.SdsSecretConfig{ 85 Name: credentials.ToResourceName(name), 86 SdsConfig: SDSAdsConfig, 87 } 88 } 89 90 // ConstructSdsSecretConfigForCredentialSocket constructs SDS Secret Configuration based on CredentialNameSocketPath 91 // if CredentialNameSocketPath exists, use a static cluster 'sds-external' 92 func ConstructSdsSecretConfigForCredentialSocket(name string) *tls.SdsSecretConfig { 93 return &tls.SdsSecretConfig{ 94 Name: name, 95 SdsConfig: &core.ConfigSource{ 96 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 97 ApiConfigSource: &core.ApiConfigSource{ 98 ApiType: core.ApiConfigSource_GRPC, 99 SetNodeOnFirstMessageOnly: true, 100 TransportApiVersion: core.ApiVersion_V3, 101 GrpcServices: []*core.GrpcService{ 102 { 103 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 104 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: security.SDSExternalClusterName}, 105 }, 106 }, 107 }, 108 }, 109 }, 110 ResourceApiVersion: core.ApiVersion_V3, 111 }, 112 } 113 } 114 115 // ConstructSdsSecretConfig constructs SDS Secret Configuration for workload proxy. 116 func ConstructSdsSecretConfig(name string) *tls.SdsSecretConfig { 117 return pm.ConstructSdsSecretConfig(name) 118 } 119 120 func AppendURIPrefixToTrustDomain(trustDomainAliases []string) []string { 121 res := make([]string, 0, len(trustDomainAliases)) 122 for _, td := range trustDomainAliases { 123 res = append(res, spiffe.URIPrefix+td+"/") 124 } 125 return res 126 } 127 128 // ApplyToCommonTLSContext completes the commonTlsContext 129 func ApplyToCommonTLSContext(tlsContext *tls.CommonTlsContext, proxy *model.Proxy, 130 subjectAltNames []string, crl string, trustDomainAliases []string, validateClient bool, 131 ) { 132 // These are certs being mounted from within the pod. Rather than reading directly in Envoy, 133 // which does not support rotation, we will serve them over SDS by reading the files. 134 // We should check if these certs have values, if yes we should use them or otherwise fall back to defaults. 135 res := security.SdsCertificateConfig{ 136 CertificatePath: proxy.Metadata.TLSServerCertChain, 137 PrivateKeyPath: proxy.Metadata.TLSServerKey, 138 CaCertificatePath: proxy.Metadata.TLSServerRootCert, 139 } 140 141 // TODO: if subjectAltName ends with *, create a prefix match as well. 142 // TODO: if user explicitly specifies SANs - should we alter his explicit config by adding all spifee aliases? 143 matchSAN := util.StringToExactMatch(subjectAltNames) 144 if len(trustDomainAliases) > 0 { 145 matchSAN = append(matchSAN, util.StringToPrefixMatch(AppendURIPrefixToTrustDomain(trustDomainAliases))...) 146 } 147 148 // configure server listeners with SDS. 149 if validateClient { 150 defaultValidationContext := &tls.CertificateValidationContext{ 151 MatchSubjectAltNames: matchSAN, 152 } 153 if crl != "" { 154 defaultValidationContext.Crl = &core.DataSource{ 155 Specifier: &core.DataSource_Filename{ 156 Filename: crl, 157 }, 158 } 159 } 160 tlsContext.ValidationContextType = &tls.CommonTlsContext_CombinedValidationContext{ 161 CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{ 162 DefaultValidationContext: defaultValidationContext, 163 ValidationContextSdsSecretConfig: ConstructSdsSecretConfig(model.GetOrDefault(res.GetRootResourceName(), SDSRootResourceName)), 164 }, 165 } 166 167 } 168 tlsContext.TlsCertificateSdsSecretConfigs = []*tls.SdsSecretConfig{ 169 ConstructSdsSecretConfig(model.GetOrDefault(res.GetResourceName(), SDSDefaultResourceName)), 170 } 171 } 172 173 // ApplyCustomSDSToClientCommonTLSContext applies the customized sds to CommonTlsContext 174 // Used for building upstream TLS context for egress gateway's TLS/mTLS origination 175 func ApplyCustomSDSToClientCommonTLSContext(tlsContext *tls.CommonTlsContext, 176 tlsOpts *networking.ClientTLSSettings, credentialSocketExist bool, 177 ) { 178 if tlsOpts.Mode == networking.ClientTLSSettings_MUTUAL { 179 // create SDS config for gateway to fetch key/cert from agent. 180 tlsContext.TlsCertificateSdsSecretConfigs = []*tls.SdsSecretConfig{ 181 ConstructSdsSecretConfigForCredential(tlsOpts.CredentialName, credentialSocketExist), 182 } 183 } 184 185 // If the InsecureSkipVerify is true, there is no need to configure CA Cert and SAN. 186 if tlsOpts.GetInsecureSkipVerify().GetValue() { 187 return 188 } 189 190 // create SDS config for gateway to fetch certificate validation context 191 // at gateway agent. 192 defaultValidationContext := &tls.CertificateValidationContext{ 193 MatchSubjectAltNames: util.StringToExactMatch(tlsOpts.SubjectAltNames), 194 } 195 tlsContext.ValidationContextType = &tls.CommonTlsContext_CombinedValidationContext{ 196 CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{ 197 DefaultValidationContext: defaultValidationContext, 198 ValidationContextSdsSecretConfig: ConstructSdsSecretConfigForCredential( 199 tlsOpts.CredentialName+SdsCaSuffix, credentialSocketExist), 200 }, 201 } 202 } 203 204 // ApplyCredentialSDSToServerCommonTLSContext applies the credentialName sds (Gateway/DestinationRule) to CommonTlsContext 205 // Used for building both gateway/sidecar TLS context 206 func ApplyCredentialSDSToServerCommonTLSContext(tlsContext *tls.CommonTlsContext, 207 tlsOpts *networking.ServerTLSSettings, credentialSocketExist bool, 208 ) { 209 // create SDS config for gateway/sidecar to fetch key/cert from agent. 210 tlsContext.TlsCertificateSdsSecretConfigs = []*tls.SdsSecretConfig{ 211 ConstructSdsSecretConfigForCredential(tlsOpts.CredentialName, credentialSocketExist), 212 } 213 // If tls mode is MUTUAL/OPTIONAL_MUTUAL, create SDS config for gateway/sidecar to fetch certificate validation context 214 // at gateway agent. Otherwise, use the static certificate validation context config. 215 if tlsOpts.Mode == networking.ServerTLSSettings_MUTUAL || tlsOpts.Mode == networking.ServerTLSSettings_OPTIONAL_MUTUAL { 216 defaultValidationContext := &tls.CertificateValidationContext{ 217 MatchSubjectAltNames: util.StringToExactMatch(tlsOpts.SubjectAltNames), 218 VerifyCertificateSpki: tlsOpts.VerifyCertificateSpki, 219 VerifyCertificateHash: tlsOpts.VerifyCertificateHash, 220 } 221 tlsContext.ValidationContextType = &tls.CommonTlsContext_CombinedValidationContext{ 222 CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{ 223 DefaultValidationContext: defaultValidationContext, 224 ValidationContextSdsSecretConfig: ConstructSdsSecretConfigForCredential( 225 tlsOpts.CredentialName+SdsCaSuffix, credentialSocketExist), 226 }, 227 } 228 } else if len(tlsOpts.SubjectAltNames) > 0 { 229 tlsContext.ValidationContextType = &tls.CommonTlsContext_ValidationContext{ 230 ValidationContext: &tls.CertificateValidationContext{ 231 MatchSubjectAltNames: util.StringToExactMatch(tlsOpts.SubjectAltNames), 232 }, 233 } 234 } 235 } 236 237 func EnforceGoCompliance(ctx *gotls.Config) { 238 pm.EnforceGoCompliance(ctx) 239 } 240 241 func EnforceCompliance(ctx *tls.CommonTlsContext) { 242 pm.EnforceCompliance(ctx) 243 }