1
#include <fmt/base.h>
2
#include <fmt/format.h>
3
#include <gtest/gtest-param-test.h>
4
#include <gtest/gtest.h>
5

            
6
#include <string>
7
#include <utility>
8
#include <vector>
9

            
10
#include "envoy/common/exception.h"
11
#include "envoy/extensions/transport_sockets/tls/v3/tls.pb.h"
12
#include "envoy/http/codec.h" // IWYU pragma: keep
13
#include "envoy/network/address.h"
14
#include "envoy/network/connection.h"
15
#include "envoy/network/transport_socket.h"
16

            
17
#include "source/common/common/logger.h"
18
#include "source/common/stats/isolated_store_impl.h"
19
#include "source/common/tls/server_context_config_impl.h"
20
#include "source/common/tls/server_ssl_socket.h"
21

            
22
#include "test/integration/fake_upstream.h"
23
#include "test/integration/ssl_utility.h"
24
#include "test/test_common/environment.h"
25
#include "test/test_common/utility.h"
26

            
27
#include "tests/cilium_http_integration.h"
28
#include "tests/cilium_tls_integration.h"
29

            
30
namespace Envoy {
31
namespace Cilium {
32

            
33
//
34
// Cilium filters with HTTP proxy & Downstream/Upstream TLS
35
//
36

            
37
// params: is_ingress ("true", "false")
38
const std::string cilium_tls_http_proxy_config_fmt = R"EOF(
39
admin:
40
  address:
41
    socket_address:
42
      address: 127.0.0.1
43
      port_value: 0
44
static_resources:
45
  clusters:
46
  - name: cluster1
47
    type: ORIGINAL_DST
48
    lb_policy: CLUSTER_PROVIDED
49
    connect_timeout:
50
      seconds: 1
51
  - name: tls-cluster
52
    type: ORIGINAL_DST
53
    lb_policy: CLUSTER_PROVIDED
54
    connect_timeout:
55
      seconds: 1
56
    transport_socket:
57
      name: "cilium.tls_wrapper"
58
      typed_config:
59
        "@type": type.googleapis.com/cilium.UpstreamTlsWrapperContext
60
    typed_extension_protocol_options:
61
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
62
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
63
        upstream_http_protocol_options:
64
          auto_sni: true
65
          auto_san_validation: true
66
        use_downstream_protocol_config: {{}}
67
  - name: xds-grpc-cilium
68
    connect_timeout:
69
      seconds: 5
70
    type: STATIC
71
    lb_policy: ROUND_ROBIN
72
    http2_protocol_options:
73
    load_assignment:
74
      cluster_name: xds-grpc-cilium
75
      endpoints:
76
      - lb_endpoints:
77
        - endpoint:
78
            address:
79
              pipe:
80
                path: /var/run/cilium/xds.sock
81
  listeners:
82
    name: http
83
    address:
84
      socket_address:
85
        address: 127.0.0.1
86
        port_value: 0
87
    listener_filters:
88
    - name: test_bpf_metadata
89
      typed_config:
90
        "@type": type.googleapis.com/cilium.TestBpfMetadata
91
        is_ingress: {0}
92
    filter_chains:
93
    - filters:
94
      - name: cilium.network
95
        typed_config:
96
          "@type": type.googleapis.com/cilium.NetworkFilter
97
      - name: envoy.http_connection_manager
98
        typed_config:
99
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
100
          stat_prefix: config_test
101
          codec_type: auto
102
          http_filters:
103
          - name: test_l7policy
104
            typed_config:
105
              "@type": type.googleapis.com/cilium.L7Policy
106
              access_log_path: "{{ test_udsdir }}/access_log.sock"
107
          - name: envoy.filters.http.router
108
          route_config:
109
            name: policy_enabled
110
            virtual_hosts:
111
              name: integration
112
              domains: "*"
113
              routes:
114
              - route:
115
                  cluster: cluster1
116
                  max_grpc_timeout:
117
                    seconds: 0
118
                    nanos: 0
119
                match:
120
                  prefix: "/"
121
    - filter_chain_match:
122
        transport_protocol: "cilium:default"
123
        server_names: [ "localhost" ]
124
      filters:
125
      - name: cilium.network
126
        typed_config:
127
          "@type": type.googleapis.com/cilium.NetworkFilter
128
      - name: envoy.http_connection_manager
129
        typed_config:
130
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
131
          stat_prefix: config_test
132
          codec_type: auto
133
          http_filters:
134
          - name: test_l7policy
135
            typed_config:
136
              "@type": type.googleapis.com/cilium.L7Policy
137
              access_log_path: "{{ test_udsdir }}/access_log.sock"
138
          - name: envoy.filters.http.router
139
          route_config:
140
            name: policy_enabled
141
            virtual_hosts:
142
              name: integration
143
              require_tls: ALL
144
              domains: "*"
145
              routes:
146
              - route:
147
                  cluster: tls-cluster
148
                  max_grpc_timeout:
149
                    seconds: 0
150
                    nanos: 0
151
                match:
152
                  prefix: "/"
153
      transport_socket:
154
        name: "cilium.tls_wrapper"
155
        typed_config:
156
          "@type": type.googleapis.com/cilium.DownstreamTlsWrapperContext
157
)EOF";
158

            
159
// certificate_chain from test/config/integration/certs/servercert.pem
160
// private_key from test/config/integration/certs/serverkey.pem
161
const std::string TLS_CERTS_CONFIG = R"EOF(version_info: "0"
162
resources:
163
- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret
164
  name: tls-certs
165
  tls_certificate:
166
    certificate_chain:
167
      inline_string: "-----BEGIN CERTIFICATE-----\nMIIEhTCCA22gAwIBAgIUQRkh3sY/JN5+tu5NX3Tbyx0Y8l8wDQYJKoZIhvcNAQEL\nBQAwdjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM\nDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsMEEx5ZnQgRW5n\naW5lZXJpbmcxEDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMjQwNDA4MTA0MjUzWhcNMjYw\nNDA4MTA0MjUzWjCBpjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx\nFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsM\nEEx5ZnQgRW5naW5lZXJpbmcxGjAYBgNVBAMMEVRlc3QgQmFja2VuZCBUZWFtMSQw\nIgYJKoZIhvcNAQkBFhViYWNrZW5kLXRlYW1AbHlmdC5jb20wggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQCqoyXM9pY5gDpLVap5mr0NtQjqCvh+GXZyP7BP\nP2S+oNtSaLLAe5+yNDJoldZSplLGYwrWWJtjWJedeQ5JnhpbFVKrGXDIBtQ/6B/v\noKEkdh3BOB79IKhbmNQTA9pFV+xypvM+IWFr4p5bvjTRgncdXdlzEf6g5ECNdgdi\nhlpdL3aAY/Ko6cEWAzaxypJAumzsaw4HX1HiBP7rhHHZrLsIPc6MZ/LhKztIgJIO\n3U2VOE4uRbcf1uBEkE6H63PKGBnuHJ5qkmLS6IoF9sl7pvydLj5tp1FB8twQMxwP\nWGRTZkpQ121zH5aBIEL1C/1WHgZ6AROEKvMK408e9fiAEfPLAgMBAAGjgdkwgdYw\nDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwIG\nCCsGAQUFBwMBMFoGA1UdEQRTMFGGHnNwaWZmZTovL2x5ZnQuY29tL2JhY2tlbmQt\ndGVhbYYXaHR0cDovL2JhY2tlbmQubHlmdC5jb22CCGx5ZnQuY29tggx3d3cubHlm\ndC5jb20wHQYDVR0OBBYEFF+sq41Nw9S3XL1yJQ51PLCa+mwUMB8GA1UdIwQYMBaA\nFBn+c0Qg6qbDyfGRTNk1jzuKuSOAMA0GCSqGSIb3DQEBCwUAA4IBAQB56Z7/YUQ6\nSkazZPO2Eodg/4eKHQPEluzbz13/wkTBMTewgLgXRCVow8025yt0NaQ9AQzrKELc\nWBD+BuoTA8koD52zXmG9kjpIzajIqv2urWIaH1vUzfM26uJgiQKXX3eo24fbGRQi\nW452PvGPYoGAtucrEg15MrGlfqLMPkNIJ3ufIWRh+ycriWb8kHe+TgB6XQQGhHdJ\nD0+MXSOkPoNM7I8hU2PNl29krHTl3npYK0zG4AOF6tbOuu6bta94kV8PQ4YBfojF\no8vYmMboYDfZnnh+92WT4Ra/BSIm/NXilo3mXOu+cuRP6Kl3kpJPT0zZIjI5DBLn\nQmJKb8oDcA7+\n-----END CERTIFICATE-----\n"
168
    private_key:
169
      inline_string: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqqMlzPaWOYA6S1WqeZq9DbUI6gr4fhl2cj+wTz9kvqDbUmiy\nwHufsjQyaJXWUqZSxmMK1libY1iXnXkOSZ4aWxVSqxlwyAbUP+gf76ChJHYdwTge\n/SCoW5jUEwPaRVfscqbzPiFha+KeW7400YJ3HV3ZcxH+oORAjXYHYoZaXS92gGPy\nqOnBFgM2scqSQLps7GsOB19R4gT+64Rx2ay7CD3OjGfy4Ss7SICSDt1NlThOLkW3\nH9bgRJBOh+tzyhgZ7hyeapJi0uiKBfbJe6b8nS4+badRQfLcEDMcD1hkU2ZKUNdt\ncx+WgSBC9Qv9Vh4GegEThCrzCuNPHvX4gBHzywIDAQABAoIBAQCpC+QBADGnWY9m\n3sF6o3+zuqvQIXo4gsVDPjFO8UC/UeC17Z9Y7aAyDV/7GKYxTzEl9SzhWProGvZp\nPWqYKBd4MNGrTBLdN1bC0RYCcaHy20lzCEQ7BUWFKQzAocp1dDt9AkRsQume1e2I\nehEdliCnaThptWQKxNXmzw1V4EBZm3Jf18azA82Op5O8uD8B7pLdM7cfXVfY5HIL\nN9HFY5yLJwM+N3M447StKQhfwohLtCuB8dVnYgVNKkqYfPyRSYT6h4OFJI+i1BRu\nyzEZoSVfa7oKAEStVH3G76M4TzKL5msU7AJrIogWFNYIy1jWEMJsCmhD5dbQhbJD\n9q1SgkIBAoGBAOJFaRl2PL7yf9RPh0E4iAJmqz9LxTk9PCa1Lu/EdtUdnqumPfVD\nfbsLxLUMYA5qQP411t+fFEgt2eBYj57WWhh035WhCpvhFhLgFqfXyFosI5Ku9xfE\nsOoCxzGOdCVfSi5PqL+cB49H6Msc5R0Wm1nr6Xz9vuW+U8AlxwdYSdNLAoGBAMEO\ngLej7FqBnnySXfTINFpXatPq4EaoMKqqI5Yjy0PlzBWbQtFV01zjo9xH9eCNRxrj\n1mz5tV3i1zyYapULL8hQ/qYVryf/sc4QGqEi2PPmk6KlR1729MMH83dWhuGgojyf\nkPy/+f5vqklRqQa90g01mea7O8mU10cUNmem85GBAoGBAMikiBfd8uvXmWaoxuUc\nve5zIDNWeyLQnAAu9doDOuSsCUFoftR37ovoWZu5x4vAyLUjBNDy/Ucr8WGw5loQ\n9X9uU70ZOpETPUGrmCtpeu4K6dhucgmPjtlTcVMOYQuqvdrnJFoUf9ecCl/h1YC/\nxS4ttbPyRk7vQNDILv7iWUSVAoGAK51xKwvXm+LowU/39hM88KQLOHE51fytcgEa\nJRNVGrPR1ZfMEqsHI1cyb9O6Es8YH1UV3mzTsrBK3B+7BI0QcHsL7M29UpYLv3gX\n7AuJZCDVfctFQokcZutm77EWq+a0gGm0QcXFXtwvZn0SaLl9uQpBCMWIDlSYBjDk\n0aoAIQECgYAfqxwy93/9Ib3hCT8Agft0vxYaycjyWtiu5Aw2hc2tKytWq+Lgi5Eb\npPSL18rxamvxMIJlERCmaoqJmDuNvGPtpv8TLlAz19ZEfrEIQs6J6k0G716cvZxE\nf4soMOrYismLOdHXsliIhvf4iHGnSMbIiN7jyjochK+maHTBE0GlOA==\n-----END RSA PRIVATE KEY-----\n"
170
)EOF";
171

            
172
// trusted_ca from test/config/integration/certs/upstreamcacert.pem
173
const std::string CA_CERTS_CONFIG = R"EOF(version_info: "0"
174
resources:
175
- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret
176
  name: ca-certs
177
  validation_context:
178
    trusted_ca:
179
      inline_string: "-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIUfXpfjZAzA9sFKKe0k9M1rCGG9rwwDQYJKoZIhvcNAQEL\nBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM\nDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsMEEx5ZnQgRW5n\naW5lZXJpbmcxGTAXBgNVBAMMEFRlc3QgVXBzdHJlYW0gQ0EwHhcNMjQwNDA4MTA0\nMjUzWhcNMjYwNDA4MTA0MjUzWjB/MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2Fs\naWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZ\nMBcGA1UECwwQTHlmdCBFbmdpbmVlcmluZzEZMBcGA1UEAwwQVGVzdCBVcHN0cmVh\nbSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANQ5VS5O8LtJdNY7\nL9sqH6vVhr9wyHsb7bvBSmg9JAxTU8vSFG/Uj4zoJDBYtEivU9F7leeqcqVLU9MA\n2vvYt/LS7/j2HOU0AfilbIGRJiho24AMlrkgXQSweVD+Y46hH42xythcZhwYS6JQ\nMpe0jkSk8SDUZTCCFeosbt8yTxOILgNsFUgUJ1pkUFyQQDSW+cYfruXgg/U/BdP2\nbme/E6Wf41KhZIZJTGzbxmgRrmF29ktOSwLyJcKpMCVNFforIBOKnF7ANKirnAS4\nFuBx6Q4peQ6/qwmXcucBD4X+YBoTi6+CZejW9LHcZX4gFjWKFlny4QJKxz2eFS+1\neudq86kCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nHQYDVR0OBBYEFHrsizu33Ld1ed/tUUow717Z5RCDMB8GA1UdIwQYMBaAFHrsizu3\n3Ld1ed/tUUow717Z5RCDMA0GCSqGSIb3DQEBCwUAA4IBAQCPlwh6v03l09vHYA8k\nFX0YVZDUKOcz8wtoRHwkTjetGRaDF2xEu2NGr/RHFS5EyJ9kuwgc1nOGS8lfqDk9\nCznok/2qsN+ctp571ufhK+EZf5FI9etQJP1f0YleXrP3KR3ztQ5zLGXCv6E0oqXi\n6ct4FZJwq5RdP4LYJUWCfCAf5z8Yr6nLUlXTW2Kwwi3+3isqc97jdRMkL37Y3CyR\nEgAHSbw26XozFmY+K7ptspwb8zPaWKMUDNSGJVnfCqo8ABWJbDcdRa/AZA4KXScP\nH/A2sZtKx8b3mOIu/uX5NQCO+e0Tvm6qqCSGr+Ykcn7HI6Rr43d19He/zn82oHZF\nqhaf\n-----END CERTIFICATE-----\n"
180
)EOF";
181

            
182
const std::string BASIC_TLS_POLICY_fmt = R"EOF(version_info: "0"
183
resources:
184
- "@type": type.googleapis.com/cilium.NetworkPolicy
185
  endpoint_ips:
186
  - '{{ ntop_ip_loopback_address }}'
187
  policy: 3
188
  ingress_per_port_policies:
189
  - port: {0}
190
    rules:
191
    - remote_policies: [ 1 ]
192
      http_rules:
193
        http_rules:
194
        - headers: [ {{ name: ':path', exact_match: '/allowed' }} ]
195
        - headers: [ {{ name: ':path', safe_regex_match: {{ google_re2: {{}}, regex: '.*public$' }} }} ]
196
        - headers: [ {{ name: ':authority', exact_match: 'allowedHOST' }} ]
197
        - headers: [ {{ name: ':authority', safe_regex_match: {{ google_re2: {{}}, regex: '.*REGEX.*' }} }} ]
198
        - headers: [ {{ name: ':method', exact_match: 'PUT' }}, {{ name: ':path', exact_match: '/public/opinions' }} ]
199
      upstream_tls_context:
200
        validation_context_sds_secret: ca-certs
201
      downstream_tls_context:
202
        tls_sds_secret: tls-certs
203
        alpn_protocols: [ "h2", "http/1.1" ]
204
    - remote_policies: [ 2 ]
205
      http_rules:
206
        http_rules:
207
        - headers: [ {{ name: ':path', exact_match: '/only-2-allowed' }} ]
208
  egress_per_port_policies:
209
  - port: {0}
210
    rules:
211
    - remote_policies: [ 1 ]
212
      http_rules:
213
        http_rules:
214
        - headers: [ {{ name: ':path', exact_match: '/allowed' }} ]
215
        - headers: [ {{ name: ':path', safe_regex_match: {{ google_re2: {{}}, regex: '.*public$' }} }} ]
216
        - headers: [ {{ name: ':authority', exact_match: 'allowedHOST' }} ]
217
        - headers: [ {{ name: ':authority', safe_regex_match: {{ google_re2: {{}}, regex: '.*REGEX.*' }} }} ]
218
        - headers: [ {{ name: ':method', exact_match: 'PUT' }}, {{ name: ':path', exact_match: '/public/opinions' }} ]
219
    - remote_policies: [ 2 ]
220
      http_rules:
221
        http_rules:
222
        - headers: [ {{ name: ':path', exact_match: '/only-2-allowed' }} ]
223
)EOF";
224

            
225
/*
226
 * Use filter_chain_match on a requestedServerName that is set by the cilium bpf
227
 * metadata filter based on the applicable network policy?
228
 * "example.domain.name.namespace"
229
 */
230
class CiliumHttpTLSIntegrationTest : public CiliumHttpIntegrationTest {
231
public:
232
8
  CiliumHttpTLSIntegrationTest(const std::string& config) : CiliumHttpIntegrationTest(config) {}
233
8
  ~CiliumHttpTLSIntegrationTest() override = default;
234

            
235
8
  void initialize() override {
236
8
    CiliumHttpIntegrationTest::initialize();
237
8
    fake_upstreams_[0]->setReadDisableOnNewConnection(false);
238

            
239
    // Set up the SSL client.
240
8
    Network::Address::InstanceConstSharedPtr address =
241
8
        Ssl::getSslAddress(version_, lookupPort("http"));
242
8
    context_ = createClientSslTransportSocketFactory(context_manager_, *api_);
243
8
    Network::ClientConnectionPtr ssl_client = dispatcher_->createClientConnection(
244
8
        address, Network::Address::InstanceConstSharedPtr(),
245
8
        context_->createTransportSocket(nullptr, nullptr), nullptr, nullptr);
246

            
247
8
    ssl_client->enableHalfClose(true);
248
8
    codec_client_ = makeHttpConnection(std::move(ssl_client));
249
8
  }
250

            
251
8
  void createUpstreams() override {
252
8
    if (upstream_tls_) {
253
8
      auto config = upstreamConfig();
254
8
      config.upstream_protocol_ = FakeHttpConnection::Type::HTTP1;
255
8
      config.enable_half_close_ = true;
256
8
      fake_upstreams_.emplace_back(
257
8
          new FakeUpstream(createUpstreamSslContext(), 0, version_, config));
258
8
    } else {
259
      CiliumHttpIntegrationTest::createUpstreams();
260
    }
261
8
  }
262

            
263
  // TODO(mattklein123): This logic is duplicated in various places. Cleanup in
264
  // a follow up.
265
8
  Network::DownstreamTransportSocketFactoryPtr createUpstreamSslContext() {
266
8
    envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext tls_context;
267
8
    auto* common_tls_context = tls_context.mutable_common_tls_context();
268
8
    auto* tls_cert = common_tls_context->add_tls_certificates();
269
8
    tls_cert->mutable_certificate_chain()->set_filename(TestEnvironment::runfilesPath(
270
8
        fmt::format("test/config/integration/certs/{}cert.pem", upstream_cert_name_)));
271
8
    tls_cert->mutable_private_key()->set_filename(TestEnvironment::runfilesPath(
272
8
        fmt::format("test/config/integration/certs/{}key.pem", upstream_cert_name_)));
273
8
    ENVOY_LOG_MISC(debug, "Fake Upstream Downstream TLS context: {}", tls_context.DebugString());
274

            
275
8
    auto server_config_or_error =
276
8
        Extensions::TransportSockets::Tls::ServerContextConfigImpl::create(tls_context,
277
8
                                                                           factory_context_, false);
278
    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
279
8
    THROW_IF_NOT_OK(server_config_or_error.status());
280
8
    auto cfg = std::move(server_config_or_error.value());
281

            
282
8
    static auto* upstream_stats_store = new Stats::IsolatedStoreImpl();
283
8
    auto factory_or_error = Extensions::TransportSockets::Tls::ServerSslSocketFactory::create(
284
8
        std::move(cfg), context_manager_, *upstream_stats_store->rootScope(),
285
8
        std::vector<std::string>{});
286
    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
287
8
    THROW_IF_NOT_OK(factory_or_error.status());
288
8
    return std::move(factory_or_error.value());
289
8
  }
290

            
291
8
  std::string testPolicyFmt() override {
292
8
    return TestEnvironment::substitute(BASIC_TLS_POLICY_fmt, GetParam());
293
8
  }
294

            
295
8
  std::vector<std::pair<std::string, std::string>> testSecrets() override {
296
8
    return std::vector<std::pair<std::string, std::string>>{
297
8
        {"tls-certs", TLS_CERTS_CONFIG},
298
8
        {"ca-certs", CA_CERTS_CONFIG},
299
8
    };
300
8
  }
301

            
302
4
  void denied(Http::TestRequestHeaderMapImpl&& headers) {
303
4
    initialize();
304
4
    auto response = codec_client_->makeHeaderOnlyRequest(headers);
305
4
    ASSERT_TRUE(response->waitForEndStream());
306

            
307
4
    EXPECT_TRUE(response->complete());
308
4
    EXPECT_EQ("403", response->headers().getStatusValue());
309
4
    cleanupUpstreamAndDownstream();
310
4
  }
311

            
312
  void failed(Http::TestRequestHeaderMapImpl&& headers) {
313
    initialize();
314
    auto response = codec_client_->makeHeaderOnlyRequest(headers);
315
    ASSERT_TRUE(response->waitForEndStream());
316

            
317
    EXPECT_TRUE(response->complete());
318
    EXPECT_EQ("503", response->headers().getStatusValue());
319
    cleanupUpstreamAndDownstream();
320
  }
321

            
322
4
  void accepted(Http::TestRequestHeaderMapImpl&& headers) {
323
4
    initialize();
324
4
    auto response = sendRequestAndWaitForResponse(headers, 0, default_response_headers_, 0);
325

            
326
4
    EXPECT_TRUE(response->complete());
327
4
    EXPECT_EQ("200", response->headers().getStatusValue());
328
4
    EXPECT_TRUE(upstream_request_->complete());
329
4
    EXPECT_EQ(0, upstream_request_->bodyLength());
330
4
    cleanupUpstreamAndDownstream();
331
4
  }
332

            
333
  // Upstream
334
  bool upstream_tls_{true};
335
  std::string upstream_cert_name_{"upstreamlocalhost"};
336

            
337
  // Downstream
338
  Network::UpstreamTransportSocketFactoryPtr context_;
339
};
340

            
341
class CiliumTLSHttpIntegrationTest : public CiliumHttpTLSIntegrationTest {
342
public:
343
  CiliumTLSHttpIntegrationTest()
344
8
      : CiliumHttpTLSIntegrationTest(fmt::format(
345
8
            fmt::runtime(TestEnvironment::substitute(cilium_tls_http_proxy_config_fmt, GetParam())),
346
8
            "true")) {}
347
};
348

            
349
INSTANTIATE_TEST_SUITE_P(IpVersions, CiliumTLSHttpIntegrationTest,
350
                         testing::ValuesIn(TestEnvironment::getIpVersionsForTest()));
351

            
352
1
TEST_P(CiliumTLSHttpIntegrationTest, DeniedPathPrefix) {
353
1
  denied({{":method", "GET"}, {":path", "/prefix"}, {":authority", "localhost"}});
354
1
}
355

            
356
1
TEST_P(CiliumTLSHttpIntegrationTest, AllowedPathPrefix) {
357
1
  accepted({{":method", "GET"}, {":path", "/allowed"}, {":authority", "localhost"}});
358
1
}
359

            
360
1
TEST_P(CiliumTLSHttpIntegrationTest, AllowedPathPrefixStrippedHeader) {
361
1
  accepted({{":method", "GET"},
362
1
            {":path", "/allowed"},
363
1
            {":authority", "localhost"},
364
1
            {"x-envoy-original-dst-host", "1.1.1.1:9999"}});
365
1
}
366

            
367
1
TEST_P(CiliumTLSHttpIntegrationTest, AllowedPathRegex) {
368
1
  accepted({{":method", "GET"}, {":path", "/maybe/public"}, {":authority", "localhost"}});
369
1
}
370

            
371
1
TEST_P(CiliumTLSHttpIntegrationTest, DeniedPath) {
372
1
  denied({{":method", "GET"}, {":path", "/maybe/private"}, {":authority", "localhost"}});
373
1
}
374

            
375
1
TEST_P(CiliumTLSHttpIntegrationTest, DeniedMethod) {
376
1
  denied({{":method", "POST"}, {":path", "/maybe/private"}, {":authority", "localhost"}});
377
1
}
378

            
379
1
TEST_P(CiliumTLSHttpIntegrationTest, AcceptedMethod) {
380
1
  accepted({{":method", "PUT"}, {":path", "/public/opinions"}, {":authority", "localhost"}});
381
1
}
382

            
383
1
TEST_P(CiliumTLSHttpIntegrationTest, L3DeniedPath) {
384
1
  denied({{":method", "GET"}, {":path", "/only-2-allowed"}, {":authority", "localhost"}});
385
1
}
386

            
387
} // namespace Cilium
388

            
389
} // namespace Envoy