istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/pilot/forwardproxy/envoy_config_generator.go (about) 1 //go:build integ 2 // +build integ 3 4 // Copyright Istio Authors 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package forwardproxy 19 20 import ( 21 "fmt" 22 23 envoy_accesslogv3 "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3" 24 envoy_bootstrap "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3" 25 envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" 26 envoy_core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 27 envoy_listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" 28 envoy_route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" 29 envoy_fileaccesslogv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/file/v3" 30 envoy_clusters_dynamic_forward_proxy "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/dynamic_forward_proxy/v3" 31 envoy_common_dynamic_forward_proxy "github.com/envoyproxy/go-control-plane/envoy/extensions/common/dynamic_forward_proxy/v3" 32 envoy_filters_dynamic_forward_proxy "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/dynamic_forward_proxy/v3" 33 envoy_hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" 34 envoy_dns_cares "github.com/envoyproxy/go-control-plane/envoy/extensions/network/dns_resolver/cares/v3" 35 envoy_tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" 36 37 "istio.io/istio/pilot/pkg/util/protoconv" 38 "istio.io/istio/pkg/util/protomarshal" 39 ) 40 41 const ( 42 HTTP1 = "HTTP1" 43 HTTP2 = "HTTP2" 44 ) 45 46 type ListenerSettings struct { 47 Port uint32 48 HTTPVersion string 49 TLSEnabled bool 50 } 51 52 func (l ListenerSettings) TLSEnabledStr() string { 53 if l.TLSEnabled { 54 return "TLS" 55 } 56 return "noTLS" 57 } 58 59 func GenerateForwardProxyBootstrapConfig(listeners []ListenerSettings) (string, error) { 60 bootstrap := &envoy_bootstrap.Bootstrap{ 61 Admin: &envoy_bootstrap.Admin{ 62 Address: createSocketAddress("127.0.0.1", 9902), 63 }, 64 StaticResources: &envoy_bootstrap.Bootstrap_StaticResources{ 65 Listeners: []*envoy_listener.Listener{}, 66 Clusters: []*envoy_cluster.Cluster{ 67 { 68 Name: "dynamic_forward_proxy_cluster", 69 LbPolicy: envoy_cluster.Cluster_CLUSTER_PROVIDED, 70 ClusterDiscoveryType: &envoy_cluster.Cluster_ClusterType{ 71 ClusterType: &envoy_cluster.Cluster_CustomClusterType{ 72 Name: "envoy.clusters.dynamic_forward_proxy", 73 TypedConfig: protoconv.MessageToAny(&envoy_clusters_dynamic_forward_proxy.ClusterConfig{ 74 ClusterImplementationSpecifier: &envoy_clusters_dynamic_forward_proxy.ClusterConfig_DnsCacheConfig{ 75 DnsCacheConfig: dynamicForwardProxyCacheConfig, 76 }, 77 }), 78 }, 79 }, 80 }, 81 }, 82 }, 83 } 84 for _, listenerSettings := range listeners { 85 listenerName := fmt.Sprintf("http_forward_proxy_%d", listenerSettings.Port) 86 hcm := createHTTPConnectionManager(listenerName, listenerSettings.HTTPVersion) 87 bootstrap.StaticResources.Listeners = append(bootstrap.StaticResources.Listeners, &envoy_listener.Listener{ 88 Name: listenerName, 89 Address: createSocketAddress("::", listenerSettings.Port), 90 FilterChains: []*envoy_listener.FilterChain{ 91 { 92 Filters: []*envoy_listener.Filter{ 93 { 94 Name: "envoy.filters.network.http_connection_manager", 95 ConfigType: &envoy_listener.Filter_TypedConfig{ 96 TypedConfig: protoconv.MessageToAny(hcm), 97 }, 98 }, 99 }, 100 TransportSocket: createTransportSocket(listenerSettings.TLSEnabled), 101 }, 102 }, 103 StatPrefix: fmt.Sprintf("http_forward_proxy_%d", listenerSettings.Port), 104 }) 105 } 106 return protomarshal.ToYAML(bootstrap) 107 } 108 109 var dynamicForwardProxyCacheConfig = &envoy_common_dynamic_forward_proxy.DnsCacheConfig{ 110 Name: "dynamic_forward_proxy_cache_config", 111 TypedDnsResolverConfig: &envoy_core.TypedExtensionConfig{ 112 Name: "envoy.network.dns_resolver.cares", 113 TypedConfig: protoconv.MessageToAny(&envoy_dns_cares.CaresDnsResolverConfig{ 114 Resolvers: []*envoy_core.Address{ 115 createSocketAddress("8.8.8.8", 53), 116 }, 117 DnsResolverOptions: &envoy_core.DnsResolverOptions{ 118 UseTcpForDnsLookups: true, 119 NoDefaultSearchDomain: true, 120 }, 121 UseResolversAsFallback: true, 122 }), 123 }, 124 } 125 126 func createAccessLog(listenerName string) []*envoy_accesslogv3.AccessLog { 127 return []*envoy_accesslogv3.AccessLog{ 128 { 129 Name: "envoy.access_loggers.file", 130 ConfigType: &envoy_accesslogv3.AccessLog_TypedConfig{ 131 TypedConfig: protoconv.MessageToAny(&envoy_fileaccesslogv3.FileAccessLog{ 132 Path: "/dev/stdout", 133 AccessLogFormat: &envoy_fileaccesslogv3.FileAccessLog_LogFormat{ 134 LogFormat: &envoy_core.SubstitutionFormatString{ 135 Format: &envoy_core.SubstitutionFormatString_TextFormatSource{ 136 TextFormatSource: &envoy_core.DataSource{ 137 Specifier: &envoy_core.DataSource_InlineString{ 138 InlineString: createAccessLogFormat(listenerName), 139 }, 140 }, 141 }, 142 }, 143 }, 144 }), 145 }, 146 }, 147 } 148 } 149 150 func createHTTPConnectionManager(listenerName, httpVersion string) *envoy_hcm.HttpConnectionManager { 151 hcm := &envoy_hcm.HttpConnectionManager{ 152 AccessLog: createAccessLog(listenerName), 153 HttpFilters: []*envoy_hcm.HttpFilter{ 154 { 155 Name: "envoy.filters.http.dynamic_forward_proxy", 156 ConfigType: &envoy_hcm.HttpFilter_TypedConfig{ 157 TypedConfig: protoconv.MessageToAny(&envoy_filters_dynamic_forward_proxy.FilterConfig{ 158 ImplementationSpecifier: &envoy_filters_dynamic_forward_proxy.FilterConfig_DnsCacheConfig{ 159 DnsCacheConfig: dynamicForwardProxyCacheConfig, 160 }, 161 }), 162 }, 163 }, 164 { 165 Name: "envoy.filters.http.router", 166 }, 167 }, 168 RouteSpecifier: &envoy_hcm.HttpConnectionManager_RouteConfig{ 169 RouteConfig: &envoy_route.RouteConfiguration{ 170 Name: "default", 171 VirtualHosts: []*envoy_route.VirtualHost{ 172 { 173 Name: "http_forward_proxy", 174 Domains: []string{"*"}, 175 Routes: []*envoy_route.Route{ 176 { 177 Action: &envoy_route.Route_Route{ 178 Route: &envoy_route.RouteAction{ 179 ClusterSpecifier: &envoy_route.RouteAction_Cluster{ 180 Cluster: "dynamic_forward_proxy_cluster", 181 }, 182 UpgradeConfigs: []*envoy_route.RouteAction_UpgradeConfig{ 183 { 184 UpgradeType: "CONNECT", 185 ConnectConfig: &envoy_route.RouteAction_UpgradeConfig_ConnectConfig{}, 186 }, 187 }, 188 }, 189 }, 190 Match: &envoy_route.RouteMatch{ 191 PathSpecifier: &envoy_route.RouteMatch_ConnectMatcher_{}, 192 }, 193 }, 194 }, 195 }, 196 }, 197 }, 198 }, 199 StatPrefix: "http_forward_proxy", 200 } 201 if httpVersion == HTTP1 { 202 hcm.CodecType = envoy_hcm.HttpConnectionManager_HTTP1 203 hcm.HttpProtocolOptions = &envoy_core.Http1ProtocolOptions{} 204 } 205 if httpVersion == HTTP2 { 206 hcm.CodecType = envoy_hcm.HttpConnectionManager_HTTP2 207 hcm.Http2ProtocolOptions = &envoy_core.Http2ProtocolOptions{ 208 AllowConnect: true, 209 } 210 } 211 return hcm 212 } 213 214 func createTransportSocket(tlsEnabled bool) *envoy_core.TransportSocket { 215 if !tlsEnabled { 216 return nil 217 } 218 return &envoy_core.TransportSocket{ 219 Name: "envoy.transport_sockets.tls", 220 ConfigType: &envoy_core.TransportSocket_TypedConfig{ 221 TypedConfig: protoconv.MessageToAny(&envoy_tls.DownstreamTlsContext{ 222 CommonTlsContext: &envoy_tls.CommonTlsContext{ 223 TlsCertificates: []*envoy_tls.TlsCertificate{ 224 { 225 CertificateChain: &envoy_core.DataSource{ 226 Specifier: &envoy_core.DataSource_Filename{ 227 Filename: "/etc/envoy/external-forward-proxy-cert.pem", 228 }, 229 }, 230 PrivateKey: &envoy_core.DataSource{ 231 Specifier: &envoy_core.DataSource_Filename{ 232 Filename: "/etc/envoy/external-forward-proxy-key.pem", 233 }, 234 }, 235 }, 236 }, 237 }, 238 }), 239 }, 240 } 241 } 242 243 func createSocketAddress(addr string, port uint32) *envoy_core.Address { 244 return &envoy_core.Address{ 245 Address: &envoy_core.Address_SocketAddress{ 246 SocketAddress: &envoy_core.SocketAddress{ 247 Address: addr, 248 PortSpecifier: &envoy_core.SocketAddress_PortValue{ 249 PortValue: port, 250 }, 251 Ipv4Compat: true, 252 }, 253 }, 254 } 255 } 256 257 func createAccessLogFormat(listenerName string) string { 258 return "[%START_TIME%] " + listenerName + " \"%PROTOCOL% %REQ(:METHOD)% %REQ(:AUTHORITY)%\" " + 259 "%RESPONSE_CODE% %RESPONSE_FLAGS% %RESPONSE_CODE_DETAILS% " + 260 "%CONNECTION_TERMINATION_DETAILS% \"%UPSTREAM_TRANSPORT_FAILURE_REASON%\" " + 261 "\"%UPSTREAM_HOST%\" %UPSTREAM_CLUSTER% %UPSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_REMOTE_ADDRESS%\n" 262 }