1// Copyright 2018 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 15package model 16 17import ( 18 "fmt" 19 "reflect" 20 "testing" 21 22 "github.com/davecgh/go-spew/spew" 23 auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth" 24 core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" 25 26 "istio.io/istio/pilot/pkg/features" 27 "istio.io/istio/pilot/pkg/model" 28 "istio.io/istio/pilot/pkg/networking/util" 29) 30 31func TestConstructSdsSecretConfig(t *testing.T) { 32 gRPCConfig := &core.GrpcService_GoogleGrpc{ 33 TargetUri: "/tmp/sdsuds.sock", 34 StatPrefix: SDSStatPrefix, 35 ChannelCredentials: &core.GrpcService_GoogleGrpc_ChannelCredentials{ 36 CredentialSpecifier: &core.GrpcService_GoogleGrpc_ChannelCredentials_LocalCredentials{ 37 LocalCredentials: &core.GrpcService_GoogleGrpc_GoogleLocalCredentials{}, 38 }, 39 }, 40 } 41 42 gRPCConfig.CredentialsFactoryName = FileBasedMetadataPlugName 43 gRPCConfig.CallCredentials = ConstructgRPCCallCredentials(K8sSATrustworthyJwtFileName, K8sSAJwtTokenHeaderKey) 44 45 cases := []struct { 46 serviceAccount string 47 sdsUdsPath string 48 expected *auth.SdsSecretConfig 49 }{ 50 { 51 serviceAccount: "spiffe://cluster.local/ns/bar/sa/foo", 52 sdsUdsPath: "/tmp/sdsuds.sock", 53 expected: &auth.SdsSecretConfig{ 54 Name: "spiffe://cluster.local/ns/bar/sa/foo", 55 SdsConfig: &core.ConfigSource{ 56 InitialFetchTimeout: features.InitialFetchTimeout, 57 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 58 ApiConfigSource: &core.ApiConfigSource{ 59 ApiType: core.ApiConfigSource_GRPC, 60 GrpcServices: []*core.GrpcService{ 61 { 62 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 63 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: SDSClusterName}, 64 }, 65 }, 66 }, 67 RefreshDelay: nil, 68 }, 69 }, 70 }, 71 }, 72 }, 73 { 74 serviceAccount: "spiffe://cluster.local/ns/bar/sa/foo", 75 sdsUdsPath: "/tmp/sdsuds.sock", 76 expected: &auth.SdsSecretConfig{ 77 Name: "spiffe://cluster.local/ns/bar/sa/foo", 78 SdsConfig: &core.ConfigSource{ 79 InitialFetchTimeout: features.InitialFetchTimeout, 80 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 81 ApiConfigSource: &core.ApiConfigSource{ 82 ApiType: core.ApiConfigSource_GRPC, 83 GrpcServices: []*core.GrpcService{ 84 { 85 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 86 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: SDSClusterName}, 87 }, 88 }, 89 }, 90 RefreshDelay: nil, 91 }, 92 }, 93 }, 94 }, 95 }, 96 { 97 serviceAccount: "", 98 sdsUdsPath: "/tmp/sdsuds.sock", 99 expected: nil, 100 }, 101 { 102 serviceAccount: "", 103 sdsUdsPath: "spiffe://cluster.local/ns/bar/sa/foo", 104 expected: nil, 105 }, 106 } 107 108 for _, c := range cases { 109 if got := ConstructSdsSecretConfig(c.serviceAccount, c.sdsUdsPath); !reflect.DeepEqual(got, c.expected) { 110 t.Errorf("ConstructSdsSecretConfig: got(%#v) != want(%#v)\n", got, c.expected) 111 fmt.Println(got) 112 fmt.Println(c.expected) 113 } 114 } 115} 116 117func TestConstructSdsSecretConfigWithCustomUds(t *testing.T) { 118 cases := []struct { 119 serviceAccount string 120 sdsUdsPath string 121 expected *auth.SdsSecretConfig 122 }{ 123 { 124 serviceAccount: "spiffe://cluster.local/ns/bar/sa/foo", 125 sdsUdsPath: "/tmp/sdsuds.sock", 126 expected: &auth.SdsSecretConfig{ 127 Name: "spiffe://cluster.local/ns/bar/sa/foo", 128 SdsConfig: &core.ConfigSource{ 129 InitialFetchTimeout: features.InitialFetchTimeout, 130 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 131 ApiConfigSource: &core.ApiConfigSource{ 132 ApiType: core.ApiConfigSource_GRPC, 133 GrpcServices: []*core.GrpcService{ 134 { 135 TargetSpecifier: &core.GrpcService_GoogleGrpc_{ 136 GoogleGrpc: &core.GrpcService_GoogleGrpc{ 137 TargetUri: "/tmp/sdsuds.sock", 138 StatPrefix: SDSStatPrefix, 139 }, 140 }, 141 }, 142 }, 143 RefreshDelay: nil, 144 }, 145 }, 146 }, 147 }, 148 }, 149 { 150 serviceAccount: "", 151 sdsUdsPath: "/tmp/sdsuds.sock", 152 expected: nil, 153 }, 154 { 155 serviceAccount: "spiffe://cluster.local/ns/bar/sa/foo", 156 sdsUdsPath: "", 157 expected: nil, 158 }, 159 } 160 161 for _, c := range cases { 162 if got := ConstructSdsSecretConfigWithCustomUds(c.serviceAccount, c.sdsUdsPath); !reflect.DeepEqual(got, c.expected) { 163 t.Errorf("ConstructSdsSecretConfig: got(%#v) != want(%#v)\n", got, c.expected) 164 } 165 } 166} 167 168func TestApplyToCommonTLSContext(t *testing.T) { 169 testCases := []struct { 170 name string 171 sdsUdsPath string 172 node *model.Proxy 173 result *auth.CommonTlsContext 174 }{ 175 { 176 name: "MTLSStrict using SDS", 177 sdsUdsPath: "/tmp/sdsuds.sock", 178 node: &model.Proxy{ 179 Metadata: &model.NodeMetadata{ 180 SdsEnabled: true, 181 }, 182 }, 183 result: &auth.CommonTlsContext{ 184 TlsCertificateSdsSecretConfigs: []*auth.SdsSecretConfig{ 185 { 186 Name: "default", 187 SdsConfig: &core.ConfigSource{ 188 InitialFetchTimeout: features.InitialFetchTimeout, 189 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 190 ApiConfigSource: &core.ApiConfigSource{ 191 ApiType: core.ApiConfigSource_GRPC, 192 GrpcServices: []*core.GrpcService{ 193 { 194 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 195 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: SDSClusterName}, 196 }, 197 }, 198 }, 199 }, 200 }, 201 }, 202 }, 203 }, 204 ValidationContextType: &auth.CommonTlsContext_CombinedValidationContext{ 205 CombinedValidationContext: &auth.CommonTlsContext_CombinedCertificateValidationContext{ 206 DefaultValidationContext: &auth.CertificateValidationContext{MatchSubjectAltNames: util.StringToExactMatch([]string{})}, 207 ValidationContextSdsSecretConfig: &auth.SdsSecretConfig{ 208 Name: "ROOTCA", 209 SdsConfig: &core.ConfigSource{ 210 InitialFetchTimeout: features.InitialFetchTimeout, 211 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 212 ApiConfigSource: &core.ApiConfigSource{ 213 ApiType: core.ApiConfigSource_GRPC, 214 GrpcServices: []*core.GrpcService{ 215 { 216 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 217 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: SDSClusterName}, 218 }, 219 }, 220 }, 221 }, 222 }, 223 }, 224 }, 225 }, 226 }, 227 }, 228 }, 229 { 230 name: "MTLS using SDS with custom certs in metadata", 231 sdsUdsPath: "/tmp/sdsuds.sock", 232 node: &model.Proxy{ 233 Metadata: &model.NodeMetadata{ 234 SdsEnabled: true, 235 TLSServerCertChain: "serverCertChain", 236 TLSServerKey: "serverKey", 237 TLSServerRootCert: "servrRootCert", 238 }, 239 }, 240 result: &auth.CommonTlsContext{ 241 TlsCertificateSdsSecretConfigs: []*auth.SdsSecretConfig{ 242 { 243 Name: "file-cert:serverCertChain~serverKey", 244 SdsConfig: &core.ConfigSource{ 245 InitialFetchTimeout: features.InitialFetchTimeout, 246 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 247 ApiConfigSource: &core.ApiConfigSource{ 248 ApiType: core.ApiConfigSource_GRPC, 249 GrpcServices: []*core.GrpcService{ 250 { 251 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 252 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: SDSClusterName}, 253 }, 254 }, 255 }, 256 }, 257 }, 258 }, 259 }, 260 }, 261 ValidationContextType: &auth.CommonTlsContext_CombinedValidationContext{ 262 CombinedValidationContext: &auth.CommonTlsContext_CombinedCertificateValidationContext{ 263 DefaultValidationContext: &auth.CertificateValidationContext{MatchSubjectAltNames: util.StringToExactMatch([]string{})}, 264 ValidationContextSdsSecretConfig: &auth.SdsSecretConfig{ 265 Name: "file-root:servrRootCert", 266 SdsConfig: &core.ConfigSource{ 267 InitialFetchTimeout: features.InitialFetchTimeout, 268 ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ 269 ApiConfigSource: &core.ApiConfigSource{ 270 ApiType: core.ApiConfigSource_GRPC, 271 GrpcServices: []*core.GrpcService{ 272 { 273 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ 274 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: SDSClusterName}, 275 }, 276 }, 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 }, 284 }, 285 }, 286 { 287 name: "ISTIO_MUTUAL SDS without node meta", 288 sdsUdsPath: "/tmp/sdsuds.sock", 289 node: &model.Proxy{ 290 Metadata: &model.NodeMetadata{}, 291 }, 292 result: &auth.CommonTlsContext{ 293 TlsCertificates: []*auth.TlsCertificate{ 294 { 295 CertificateChain: &core.DataSource{ 296 Specifier: &core.DataSource_Filename{ 297 Filename: "/etc/certs/cert-chain.pem", 298 }, 299 }, 300 PrivateKey: &core.DataSource{ 301 Specifier: &core.DataSource_Filename{ 302 Filename: "/etc/certs/key.pem", 303 }, 304 }, 305 }, 306 }, 307 ValidationContextType: &auth.CommonTlsContext_ValidationContext{ 308 ValidationContext: &auth.CertificateValidationContext{ 309 TrustedCa: &core.DataSource{ 310 Specifier: &core.DataSource_Filename{ 311 Filename: "/etc/certs/root-cert.pem", 312 }, 313 }, 314 }, 315 }, 316 }, 317 }, 318 { 319 name: "ISTIO_MUTUAL with custom cert paths from proxy node metadata and SDS disabled", 320 sdsUdsPath: "/tmp/sdsuds.sock", 321 node: &model.Proxy{ 322 Metadata: &model.NodeMetadata{ 323 TLSServerCertChain: "/custom/path/to/cert-chain.pem", 324 TLSServerKey: "/custom-key.pem", 325 TLSServerRootCert: "/custom/path/to/root.pem", 326 }, 327 }, 328 result: &auth.CommonTlsContext{ 329 TlsCertificates: []*auth.TlsCertificate{ 330 { 331 CertificateChain: &core.DataSource{ 332 Specifier: &core.DataSource_Filename{ 333 Filename: "/custom/path/to/cert-chain.pem", 334 }, 335 }, 336 PrivateKey: &core.DataSource{ 337 Specifier: &core.DataSource_Filename{ 338 Filename: "/custom-key.pem", 339 }, 340 }, 341 }, 342 }, 343 ValidationContextType: &auth.CommonTlsContext_ValidationContext{ 344 ValidationContext: &auth.CertificateValidationContext{ 345 TrustedCa: &core.DataSource{ 346 Specifier: &core.DataSource_Filename{ 347 Filename: "/custom/path/to/root.pem", 348 }, 349 }, 350 }, 351 }, 352 }, 353 }, 354 } 355 356 for _, test := range testCases { 357 t.Run(test.name, func(t *testing.T) { 358 tlsContext := &auth.CommonTlsContext{} 359 ApplyToCommonTLSContext(tlsContext, test.node.Metadata, test.sdsUdsPath, []string{}) 360 361 if !reflect.DeepEqual(tlsContext, test.result) { 362 t.Errorf("got() = %v, want %v", spew.Sdump(tlsContext), spew.Sdump(test.result)) 363 } 364 }) 365 } 366} 367