1
#include <gmock/gmock-spec-builders.h>
2
#include <spdlog/common.h>
3

            
4
#include <cstdint>
5
#include <memory>
6
#include <string>
7
#include <utility>
8

            
9
#include "envoy/common/exception.h"
10
#include "envoy/config/core/v3/config_source.pb.h"
11
#include "envoy/init/manager.h"
12
#include "envoy/server/transport_socket_config.h"
13
#include "envoy/service/discovery/v3/discovery.pb.h"
14
#include "envoy/ssl/context.h"
15
#include "envoy/ssl/context_config.h"
16

            
17
#include "source/common/common/assert.h"
18
#include "source/common/common/base_logger.h"
19
#include "source/common/common/logger.h"
20
#include "source/common/config/decoded_resource_impl.h"
21
#include "source/common/protobuf/message_validator_impl.h"
22
#include "source/common/protobuf/utility.h"
23
#include "source/common/secret/sds_api.h"
24

            
25
#include "test/common/stats/stat_test_utility.h"
26
#include "test/mocks/server/admin.h"
27
#include "test/mocks/server/factory_context.h"
28
#include "test/test_common/utility.h"
29

            
30
#include "absl/strings/string_view.h"
31
#include "cilium/accesslog.h"
32
#include "cilium/network_policy.h"
33
#include "gtest/gtest.h"
34

            
35
namespace Envoy {
36
namespace Cilium {
37

            
38
#define ON_CALL_SDS_SECRET_PROVIDER(SECRET_MANAGER, PROVIDER_TYPE, API_TYPE)                       \
39
76
  ON_CALL(SECRET_MANAGER, findOrCreate##PROVIDER_TYPE##Provider(_, _, _, _))                       \
40
76
      .WillByDefault(Invoke([](const envoy::config::core::v3::ConfigSource& sds_config_source,     \
41
76
                               const std::string& config_name,                                     \
42
76
                               Server::Configuration::ServerFactoryContext& server_context,        \
43
76
                               Init::Manager& init_manager) {                                      \
44
5
        auto secret_provider = Secret::API_TYPE##SdsApi::create(server_context, sds_config_source, \
45
5
                                                                config_name, []() {});             \
46
5
        init_manager.add(*secret_provider->initTarget());                                          \
47
5
        return secret_provider;                                                                    \
48
5
      }))
49

            
50
class CiliumNetworkPolicyTest : public ::testing::Test {
51
protected:
52
19
  CiliumNetworkPolicyTest() {
53
1254
    for (Logger::Logger& logger : Logger::Registry::loggers()) {
54
1254
      logger.setLevel(spdlog::level::trace);
55
1254
    }
56
19
  }
57
19
  ~CiliumNetworkPolicyTest() override = default;
58

            
59
19
  void SetUp() override {
60
    // Mock SDS secrets with a real implementation, which will not return anything if there is no
61
    // SDS server. This is only useful for testing functionality with a missing secret.
62
19
    ON_CALL(factory_context_.server_factory_context_, secretManager())
63
19
        .WillByDefault(ReturnRef(secret_manager_));
64

            
65
19
    ON_CALL_SDS_SECRET_PROVIDER(secret_manager_, TlsCertificate, TlsCertificate);
66
19
    ON_CALL_SDS_SECRET_PROVIDER(secret_manager_, CertificateValidationContext,
67
19
                                CertificateValidationContext);
68
19
    ON_CALL_SDS_SECRET_PROVIDER(secret_manager_, TlsSessionTicketKeysContext, TlsSessionTicketKeys);
69
19
    ON_CALL_SDS_SECRET_PROVIDER(secret_manager_, GenericSecret, GenericSecret);
70

            
71
19
    policy_map_ = std::make_shared<NetworkPolicyMap>(factory_context_);
72
19
  }
73

            
74
19
  void TearDown() override {
75
19
    ASSERT(policy_map_.use_count() == 1);
76
19
    policy_map_.reset();
77
19
  }
78

            
79
39
  std::string updateFromYaml(const std::string& config) {
80
39
    envoy::service::discovery::v3::DiscoveryResponse message;
81
39
    MessageUtil::loadFromYaml(config, message, ProtobufMessage::getNullValidationVisitor());
82
39
    NetworkPolicyDecoder network_policy_decoder;
83
39
    const auto decoded_resources_or_error = Config::DecodedResourcesWrapper::create(
84
39
        network_policy_decoder, message.resources(), message.version_info());
85
39
    THROW_IF_NOT_OK_REF(decoded_resources_or_error.status());
86
39
    const auto decoded_resources = std::move(decoded_resources_or_error.value().get());
87

            
88
39
    EXPECT_TRUE(policy_map_->getImpl()
89
39
                    .onConfigUpdate(decoded_resources->refvec_, message.version_info())
90
39
                    .ok());
91
39
    return message.version_info();
92
39
  }
93

            
94
20
  testing::AssertionResult validate(const std::string& pod_ip, const std::string& expected) {
95
20
    const auto& policy = policy_map_->getPolicyInstance(pod_ip, false);
96
20
    auto str = policy.string();
97
20
    if (str != expected) {
98
2
      return testing::AssertionFailure() << "Policy:\n"
99
2
                                         << str << "Does not match expected:\n"
100
2
                                         << expected;
101
2
    }
102
18
    return testing::AssertionSuccess();
103
20
  }
104

            
105
  testing::AssertionResult allowed(bool ingress, const std::string& pod_ip, uint64_t remote_id,
106
264
                                   uint16_t port, Http::TestRequestHeaderMapImpl&& headers) {
107
264
    const auto& policy = policy_map_->getPolicyInstance(pod_ip, false);
108
    // test network layer policy first
109
264
    if (!policy.allowed(ingress, proxy_id_, remote_id, "", port)) {
110
135
      return testing::AssertionFailure();
111
135
    }
112
129
    Cilium::AccessLog::Entry log_entry;
113
129
    return policy.allowed(ingress, proxy_id_, remote_id, port, headers, log_entry)
114
129
               ? testing::AssertionSuccess()
115
129
               : testing::AssertionFailure();
116
264
  }
117
  testing::AssertionResult ingressAllowed(const std::string& pod_ip, uint64_t remote_id,
118
                                          uint16_t port,
119
206
                                          Http::TestRequestHeaderMapImpl&& headers = {}) {
120
206
    return allowed(true, pod_ip, remote_id, port, std::move(headers));
121
206
  }
122
  testing::AssertionResult egressAllowed(const std::string& pod_ip, uint64_t remote_id,
123
                                         uint16_t port,
124
58
                                         Http::TestRequestHeaderMapImpl&& headers = {}) {
125
58
    return allowed(false, pod_ip, remote_id, port, std::move(headers));
126
58
  }
127

            
128
  testing::AssertionResult tlsAllowed(bool ingress, const std::string& pod_ip, uint64_t remote_id,
129
                                      uint16_t port, absl::string_view sni,
130
35
                                      bool& tls_socket_required, bool& raw_socket_allowed) {
131
35
    const auto& policy = policy_map_->getPolicyInstance(pod_ip, false);
132

            
133
35
    auto port_policy = policy.findPortPolicy(ingress, port);
134
35
    const Envoy::Ssl::ContextConfig* config = nullptr;
135

            
136
    // TLS context lookup does not check SNI
137
35
    tls_socket_required = false;
138
35
    raw_socket_allowed = false;
139
35
    Envoy::Ssl::ContextSharedPtr ctx =
140
35
        !ingress ? port_policy.getClientTlsContext(proxy_id_, remote_id, sni, &config,
141
15
                                                   raw_socket_allowed)
142
35
                 : port_policy.getServerTlsContext(proxy_id_, remote_id, sni, &config,
143
20
                                                   raw_socket_allowed);
144

            
145
    // separate policy lookup for validation
146
35
    bool allowed = policy.allowed(ingress, proxy_id_, remote_id, sni, port);
147

            
148
    // if connection is allowed without TLS socket then TLS context is not required
149
35
    if (raw_socket_allowed) {
150
4
      EXPECT_TRUE(ctx == nullptr && config == nullptr);
151
4
      tls_socket_required = false;
152
4
    }
153

            
154
    // if TLS config or context is returned then connection is not allowed without TLS socket
155
35
    if (ctx != nullptr || config != nullptr) {
156
8
      EXPECT_FALSE(raw_socket_allowed);
157
8
      tls_socket_required = true;
158
8
    }
159

            
160
    // config must exist if ctx is returned
161
35
    if (ctx != nullptr) {
162
      EXPECT_TRUE(config != nullptr);
163
    }
164

            
165
35
    EXPECT_TRUE(allowed == (tls_socket_required || raw_socket_allowed));
166

            
167
35
    if (!allowed) {
168
23
      return testing::AssertionFailure() << pod_ip << " policy not allowing id " << remote_id
169
23
                                         << " on port " << port << " with SNI \"" << sni << "\"";
170
23
    }
171

            
172
    // sanity check
173
12
    EXPECT_TRUE(!(tls_socket_required && raw_socket_allowed) &&
174
12
                (tls_socket_required || raw_socket_allowed));
175

            
176
12
    if (raw_socket_allowed) {
177
4
      return testing::AssertionSuccess()
178
4
             << pod_ip << " policy allows id " << remote_id << " on port " << port << " with SNI \""
179
4
             << sni << "\" without TLS socket";
180
4
    }
181

            
182
8
    if (tls_socket_required && ctx != nullptr) {
183
      return testing::AssertionSuccess()
184
             << pod_ip << " policy allows id " << remote_id << " on port " << port << " with SNI \""
185
             << sni << "\" with TLS socket";
186
    }
187

            
188
8
    if (tls_socket_required && ctx == nullptr) {
189
8
      return testing::AssertionSuccess()
190
8
             << pod_ip << " policy allows id " << remote_id << " on port " << port << " with SNI \""
191
8
             << sni << "\" but missing TLS context";
192
8
    }
193

            
194
    return testing::AssertionFailure();
195
8
  }
196

            
197
  testing::AssertionResult tlsIngressAllowed(const std::string& pod_ip, uint64_t remote_id,
198
                                             uint16_t port, absl::string_view sni,
199
20
                                             bool& tls_socket_required, bool& raw_socket_allowed) {
200
20
    return tlsAllowed(true, pod_ip, remote_id, port, sni, tls_socket_required, raw_socket_allowed);
201
20
  }
202

            
203
  testing::AssertionResult tlsEgressAllowed(const std::string& pod_ip, uint64_t remote_id,
204
                                            uint16_t port, absl::string_view sni,
205
15
                                            bool& tls_socket_required, bool& raw_socket_allowed) {
206
15
    return tlsAllowed(false, pod_ip, remote_id, port, sni, tls_socket_required, raw_socket_allowed);
207
15
  }
208

            
209
1
  std::string updatesRejectedStatName() {
210
1
    return policy_map_->getImpl().stats_.updates_rejected_.name();
211
1
  }
212

            
213
  NiceMock<Server::Configuration::MockFactoryContext> factory_context_;
214
  NiceMock<Secret::MockSecretManager> secret_manager_;
215
  std::shared_ptr<NetworkPolicyMap> policy_map_;
216
  NiceMock<Stats::TestUtil::TestStore> store_;
217
  uint32_t proxy_id_ = 42;
218
};
219

            
220
1
TEST_F(CiliumNetworkPolicyTest, UpdatesRejectedStatName) {
221
1
  EXPECT_EQ("cilium.policy.updates_rejected", updatesRejectedStatName());
222
1
}
223

            
224
1
TEST_F(CiliumNetworkPolicyTest, EmptyPolicyUpdate) {
225
1
  EXPECT_TRUE(policy_map_->getImpl().onConfigUpdate({}, "1").ok());
226
1
  EXPECT_FALSE(validate("10.1.2.3", "")); // Policy not found
227
1
}
228

            
229
1
TEST_F(CiliumNetworkPolicyTest, SimplePolicyUpdate) {
230
1
  std::string version;
231
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
232
1
)EOF"));
233
1
  EXPECT_EQ(version, "0");
234
1
  EXPECT_FALSE(validate("10.1.2.3", "")); // Policy not found
235
1
}
236

            
237
1
TEST_F(CiliumNetworkPolicyTest, OverlappingPortRange) {
238
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
239
1
resources:
240
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
241
1
  endpoint_ips:
242
1
  - "10.1.2.3"
243
1
  endpoint_id: 42
244
1
  ingress_per_port_policies:
245
1
  - port: 23
246
1
    rules:
247
1
    - remote_policies: [ 42 ]
248
1
    - remote_policies: [ 45 ]
249
1
  - port: 80
250
1
    rules:
251
1
    - remote_policies: [ 44 ]
252
1
  - port: 92
253
1
    rules:
254
1
    - deny: true
255
1
  - port: 40
256
1
    end_port: 99
257
1
    rules:
258
1
    - remote_policies: [ 43 ]
259
1
)EOF"));
260

            
261
1
  std::string expected = R"EOF(ingress:
262
1
  rules:
263
1
    [23-23]:
264
1
    - rules:
265
1
      - remotes: [45]
266
1
      - remotes: [42]
267
1
    [40-79]:
268
1
    - rules:
269
1
      - remotes: [43]
270
1
    [80-80]:
271
1
    - rules:
272
1
      - remotes: [44]
273
1
      - remotes: [43]
274
1
    [81-91]:
275
1
    - rules:
276
1
      - remotes: [43]
277
1
    [92-92]:
278
1
    - rules:
279
1
      - remotes: []
280
1
        deny: true
281
1
      - remotes: [43]
282
1
    [93-99]:
283
1
    - rules:
284
1
      - remotes: [43]
285
1
egress:
286
1
  rules: []
287
1
)EOF";
288

            
289
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
290

            
291
  // Ingress from 42 is allowed on port 23
292
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 42, 23));
293
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 23));
294
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 23));
295

            
296
  // port 92 is denied from everyone
297
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 42, 92));
298
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 92));
299
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 92));
300

            
301
  // Ingress from 43 is allowed on all ports of the range:
302
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 39));
303
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 40));
304
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 79));
305
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
306
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 81));
307
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 99));
308
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 100));
309

            
310
  // 44 is only allowed to port 80
311
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 39));
312
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 40));
313
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 79));
314
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 44, 80));
315
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 81));
316
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 99));
317
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 100));
318

            
319
  // No egress is allowed:
320
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
321
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
322

            
323
  // Same with policies added in reverse order
324
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
325
1
resources:
326
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
327
1
  endpoint_ips:
328
1
  - "10.1.2.3"
329
1
  endpoint_id: 42
330
1
  ingress_per_port_policies:
331
1
  - port: 40
332
1
    end_port: 99
333
1
    rules:
334
1
    - remote_policies: [ 43 ]
335
1
  - port: 92
336
1
    rules:
337
1
    - deny: true
338
1
  - port: 80
339
1
    rules:
340
1
    - remote_policies: [ 44 ]
341
1
  - port: 23
342
1
    rules:
343
1
    - remote_policies: [ 42 ]
344
1
    - remote_policies: [ 45 ]
345
1
)EOF"));
346

            
347
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
348

            
349
  // Ingress from 42 is allowed on port 23
350
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 42, 23));
351
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 23));
352
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 23));
353

            
354
  // port 92 is denied from everyone
355
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 42, 92));
356
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 92));
357
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 92));
358

            
359
  // Ingress from 43 is allowed on all ports of the range:
360
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 39));
361
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 40));
362
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 79));
363
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
364
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 81));
365
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 99));
366
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 100));
367

            
368
  // 44 is only allowed to port 80
369
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 39));
370
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 40));
371
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 79));
372
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 44, 80));
373
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 81));
374
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 99));
375
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 100));
376

            
377
  // No egress is allowed:
378
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
379
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
380
1
}
381

            
382
1
TEST_F(CiliumNetworkPolicyTest, OverlappingPortRanges) {
383
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
384
1
resources:
385
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
386
1
  endpoint_ips:
387
1
  - "10.1.2.3"
388
1
  endpoint_id: 42
389
1
  ingress_per_port_policies:
390
1
  - port: 80
391
1
    end_port: 8080
392
1
    rules:
393
1
    - remote_policies: [ 43 ]
394
1
  - port: 4040
395
1
    end_port: 9999
396
1
    rules:
397
1
    - remote_policies: [ 44 ]
398
1
)EOF"));
399

            
400
1
  std::string expected = R"EOF(ingress:
401
1
  rules:
402
1
    [80-4039]:
403
1
    - rules:
404
1
      - remotes: [43]
405
1
    [4040-8080]:
406
1
    - rules:
407
1
      - remotes: [43]
408
1
      - remotes: [44]
409
1
    [8081-9999]:
410
1
    - rules:
411
1
      - remotes: [44]
412
1
egress:
413
1
  rules: []
414
1
)EOF";
415

            
416
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
417

            
418
  // Ingress from 43 is allowed to ports 80-8080 only:
419
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
420
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
421
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 81));
422
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4039));
423
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
424
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4041));
425
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8079));
426
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
427
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8081));
428
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9998));
429
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9999));
430
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 10000));
431

            
432
  // No egress is allowed:
433
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
434
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
435

            
436
  // Same with policies added in reverse order
437
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
438
1
resources:
439
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
440
1
  endpoint_ips:
441
1
  - "10.1.2.3"
442
1
  endpoint_id: 42
443
1
  ingress_per_port_policies:
444
1
  - port: 4040
445
1
    end_port: 9999
446
1
    rules:
447
1
    - remote_policies: [ 44 ]
448
1
  - port: 80
449
1
    end_port: 8080
450
1
    rules:
451
1
    - remote_policies: [ 43 ]
452
1
)EOF"));
453

            
454
  // remotes are in insertion order
455
1
  expected = R"EOF(ingress:
456
1
  rules:
457
1
    [80-4039]:
458
1
    - rules:
459
1
      - remotes: [43]
460
1
    [4040-8080]:
461
1
    - rules:
462
1
      - remotes: [44]
463
1
      - remotes: [43]
464
1
    [8081-9999]:
465
1
    - rules:
466
1
      - remotes: [44]
467
1
egress:
468
1
  rules: []
469
1
)EOF";
470

            
471
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
472

            
473
  // Ingress from 43 is allowed to ports 80-8080 only:
474
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
475
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
476
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 81));
477
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4039));
478
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
479
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4041));
480
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8079));
481
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
482
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8081));
483
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9998));
484
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9999));
485
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 10000));
486

            
487
  // No egress is allowed:
488
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
489
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
490
1
}
491

            
492
1
TEST_F(CiliumNetworkPolicyTest, DuplicatePorts) {
493
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
494
1
resources:
495
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
496
1
  endpoint_ips:
497
1
  - "10.1.2.3"
498
1
  endpoint_id: 42
499
1
  ingress_per_port_policies:
500
1
  - port: 80
501
1
    rules:
502
1
    - remote_policies: [ 43 ]
503
1
  - port: 80
504
1
    rules:
505
1
    - remote_policies: [ 43 ]
506
1
)EOF"));
507

            
508
1
  std::string expected = R"EOF(ingress:
509
1
  rules:
510
1
    [80-80]:
511
1
    - rules:
512
1
      - remotes: [43]
513
1
      - remotes: [43]
514
1
egress:
515
1
  rules: []
516
1
)EOF";
517

            
518
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
519

            
520
  // Ingress from 43 is allowed on port 80 only:
521
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
522
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080));
523
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 8080));
524
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 80));
525
  // No egress is allowed:
526
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
527
1
}
528

            
529
1
TEST_F(CiliumNetworkPolicyTest, DuplicatePortRange) {
530
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
531
1
resources:
532
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
533
1
  endpoint_ips:
534
1
  - "10.1.2.3"
535
1
  endpoint_id: 42
536
1
  ingress_per_port_policies:
537
1
  - port: 80
538
1
    end_port: 8080
539
1
    rules:
540
1
    - remote_policies: [ 43 ]
541
1
  - port: 80
542
1
    rules:
543
1
    - remote_policies: [ 43 ]
544
1
)EOF"));
545

            
546
1
  std::string expected = R"EOF(ingress:
547
1
  rules:
548
1
    [80-80]:
549
1
    - rules:
550
1
      - remotes: [43]
551
1
      - remotes: [43]
552
1
    [81-8080]:
553
1
    - rules:
554
1
      - remotes: [43]
555
1
egress:
556
1
  rules: []
557
1
)EOF";
558

            
559
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
560

            
561
  // Ingress is allowed:
562
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
563
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
564
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 81));
565
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8079));
566
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
567
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8081));
568

            
569
  // No egress is allowed:
570
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
571
1
}
572

            
573
1
TEST_F(CiliumNetworkPolicyTest, InvalidPortRange) {
574
1
  EXPECT_THROW_WITH_MESSAGE(
575
1
      updateFromYaml(R"EOF(version_info: "1"
576
1
resources:
577
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
578
1
  endpoint_ips:
579
1
  - "10.1.2.3"
580
1
  endpoint_id: 42
581
1
  ingress_per_port_policies:
582
1
  - port: 80
583
1
    end_port: 60
584
1
    rules:
585
1
    - remote_policies: [ 43 ]
586
1
  - port: 4040
587
1
    end_port: 9999
588
1
    rules:
589
1
    - remote_policies: [ 43 ]
590
1
)EOF"),
591
1
      EnvoyException,
592
1
      "PortNetworkPolicy: Invalid port range, end port is less than start port 80-60");
593

            
594
  // No ingress is allowed:
595
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80));
596
  // No egress is allowed:
597
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
598
1
}
599

            
600
1
TEST_F(CiliumNetworkPolicyTest, InvalidWildcardPortRange) {
601
1
  EXPECT_THROW_WITH_MESSAGE(
602
1
      updateFromYaml(R"EOF(version_info: "1"
603
1
resources:
604
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
605
1
  endpoint_ips:
606
1
  - "10.1.2.3"
607
1
  endpoint_id: 42
608
1
  ingress_per_port_policies:
609
1
  - port: 0
610
1
    end_port: 80
611
1
    rules:
612
1
    - remote_policies: [ 43 ]
613
1
  - port: 4040
614
1
    end_port: 9999
615
1
    rules:
616
1
    - remote_policies: [ 43 ]
617
1
)EOF"),
618
1
      EnvoyException,
619
1
      "PortNetworkPolicy: Invalid port range including the wildcard zero port 0-80");
620

            
621
  // No ingress is allowed:
622
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80));
623
  // No egress is allowed:
624
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
625
1
}
626

            
627
// Zero end port is treated as no range
628
1
TEST_F(CiliumNetworkPolicyTest, ZeroPortRange) {
629
1
  std::string version;
630
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
631
1
resources:
632
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
633
1
  endpoint_ips:
634
1
  - "10.1.2.3"
635
1
  endpoint_id: 42
636
1
  ingress_per_port_policies:
637
1
  - port: 80
638
1
    end_port: 0
639
1
    rules:
640
1
    - remote_policies: [ 43 ]
641
1
  - port: 4040
642
1
    end_port: 9999
643
1
    rules:
644
1
    - remote_policies: [ 43 ]
645
1
)EOF"));
646
1
  EXPECT_EQ(version, "1");
647
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
648

            
649
1
  std::string expected = R"EOF(ingress:
650
1
  rules:
651
1
    [80-80]:
652
1
    - rules:
653
1
      - remotes: [43]
654
1
    [4040-9999]:
655
1
    - rules:
656
1
      - remotes: [43]
657
1
egress:
658
1
  rules: []
659
1
)EOF";
660

            
661
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
662

            
663
  // Allowed remote ID, port, & path:
664
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
665
  // Wrong remote ID:
666
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80));
667
  // Allowed port:
668
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
669
  // Path is ignored:
670
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
671

            
672
  // No egress is allowed:
673
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80));
674
1
}
675

            
676
1
TEST_F(CiliumNetworkPolicyTest, HttpPolicyUpdate) {
677
1
  std::string version;
678
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
679
1
)EOF"));
680
1
  EXPECT_EQ(version, "0");
681
1
  EXPECT_FALSE(policy_map_->exists("10.1.2.3"));
682
  // No policy for the pod
683
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
684

            
685
  // 1st update
686
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
687
1
resources:
688
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
689
1
  endpoint_ips:
690
1
  - "10.1.2.3"
691
1
  endpoint_id: 42
692
1
  ingress_per_port_policies:
693
1
  - port: 80
694
1
    rules:
695
1
    - remote_policies: [ 43 ]
696
1
      http_rules:
697
1
        http_rules:
698
1
        - headers:
699
1
          - name: ':path'
700
1
            exact_match: '/allowed'
701
1
)EOF"));
702
1
  EXPECT_EQ(version, "1");
703
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
704

            
705
1
  std::string expected = R"EOF(ingress:
706
1
  rules:
707
1
    [80-80]:
708
1
    - rules:
709
1
      - remotes: [43]
710
1
        http_rules:
711
1
        - headers:
712
1
          - name: ":path"
713
1
            value: "/allowed"
714
1
egress:
715
1
  rules: []
716
1
)EOF";
717

            
718
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
719

            
720
  // Allowed remote ID, port, & path:
721
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
722
  // Wrong remote ID:
723
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
724
  // Wrong port:
725
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
726
  // Wrong path:
727
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
728

            
729
  // No egress is allowed:
730
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
731

            
732
  // 2nd update
733
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
734
1
resources:
735
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
736
1
  endpoint_ips:
737
1
  - "10.1.2.3"
738
1
  endpoint_id: 42
739
1
  ingress_per_port_policies:
740
1
  - port: 80
741
1
    rules:
742
1
    - remote_policies: [ 43 ]
743
1
      http_rules:
744
1
        http_rules:
745
1
        - headers:
746
1
          - name: ':path'
747
1
            exact_match: '/allowed'
748
1
  egress_per_port_policies:
749
1
  - port: 80
750
1
    rules:
751
1
    - remote_policies: [ 43, 44 ]
752
1
      http_rules:
753
1
        http_rules:
754
1
        - headers:
755
1
          - name: ':path'
756
1
            safe_regex_match:
757
1
              google_re2: {}
758
1
              regex: '.*public$'
759
1
)EOF"));
760
1
  EXPECT_EQ(version, "2");
761
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
762

            
763
1
  expected = R"EOF(ingress:
764
1
  rules:
765
1
    [80-80]:
766
1
    - rules:
767
1
      - remotes: [43]
768
1
        http_rules:
769
1
        - headers:
770
1
          - name: ":path"
771
1
            value: "/allowed"
772
1
egress:
773
1
  rules:
774
1
    [80-80]:
775
1
    - rules:
776
1
      - remotes: [43,44]
777
1
        http_rules:
778
1
        - headers:
779
1
          - name: ":path"
780
1
            regex: <hidden>
781
1
)EOF";
782

            
783
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
784

            
785
  // Allowed remote ID, port, & path:
786
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
787
  // Wrong remote ID:
788
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
789
  // Wrong port:
790
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
791
  // Wrong path:
792
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
793

            
794
  // Allowed remote ID, port, & path:
795
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
796
  // Allowed remote ID, port, & path:
797
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 44, 80, {{":path", "/public"}}));
798
  // Wrong remote ID:
799
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 40, 80, {{":path", "/public"}}));
800
  // Wrong port:
801
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080, {{":path", "/public"}}));
802
  // Wrong path:
803
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/publicz"}}));
804

            
805
  // 3rd update with Ingress deny rules
806
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
807
1
resources:
808
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
809
1
  endpoint_ips:
810
1
  - "10.1.2.3"
811
1
  endpoint_id: 42
812
1
  ingress_per_port_policies:
813
1
  - port: 80
814
1
    rules:
815
1
    - remote_policies: [ 43 ]
816
1
      http_rules:
817
1
        http_rules:
818
1
        - headers:
819
1
          - name: ':path'
820
1
            exact_match: '/allowed'
821
1
  - port: 80
822
1
    end_port: 10000
823
1
    rules:
824
1
    - deny: true
825
1
  egress_per_port_policies:
826
1
  - port: 80
827
1
    rules:
828
1
    - remote_policies: [ 43, 44 ]
829
1
      http_rules:
830
1
        http_rules:
831
1
        - headers:
832
1
          - name: ':path'
833
1
            safe_regex_match:
834
1
              google_re2: {}
835
1
              regex: '.*public$'
836
1
)EOF"));
837
1
  EXPECT_EQ(version, "2");
838
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
839

            
840
1
  expected = R"EOF(ingress:
841
1
  rules:
842
1
    [80-80]:
843
1
    - rules:
844
1
      - remotes: []
845
1
        deny: true
846
1
      - remotes: [43]
847
1
        http_rules:
848
1
        - headers:
849
1
          - name: ":path"
850
1
            value: "/allowed"
851
1
    [81-10000]:
852
1
    - rules:
853
1
      - remotes: []
854
1
        deny: true
855
1
egress:
856
1
  rules:
857
1
    [80-80]:
858
1
    - rules:
859
1
      - remotes: [43,44]
860
1
        http_rules:
861
1
        - headers:
862
1
          - name: ":path"
863
1
            regex: <hidden>
864
1
)EOF";
865

            
866
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
867

            
868
  // Denied remote ID, port, & path:
869
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
870
  // Wrong remote ID:
871
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
872
  // Wrong port:
873
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
874
  // Denied remote ID & wrong path:
875
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
876

            
877
  // Allowed remote ID, port, & path:
878
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
879
  // Allowed remote ID, port, & path:
880
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 44, 80, {{":path", "/public"}}));
881
  // Wrong remote ID:
882
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 40, 80, {{":path", "/public"}}));
883
  // Wrong port:
884
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080, {{":path", "/public"}}));
885
  // Wrong path:
886
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/publicz"}}));
887

            
888
  // 4th update with matching proxy_id in policy
889
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
890
1
resources:
891
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
892
1
  endpoint_ips:
893
1
  - "10.1.2.3"
894
1
  endpoint_id: 42
895
1
  ingress_per_port_policies:
896
1
  - port: 80
897
1
    rules:
898
1
    - remote_policies: [ 43 ]
899
1
      http_rules:
900
1
        http_rules:
901
1
        - headers:
902
1
          - name: ':path'
903
1
            exact_match: '/allowed'
904
1
  - port: 80
905
1
    end_port: 10000
906
1
    rules:
907
1
    - proxy_id: 42
908
1
  egress_per_port_policies:
909
1
  - port: 80
910
1
    rules:
911
1
    - remote_policies: [ 43, 44 ]
912
1
      http_rules:
913
1
        http_rules:
914
1
        - headers:
915
1
          - name: ':path'
916
1
            safe_regex_match:
917
1
              google_re2: {}
918
1
              regex: '.*public$'
919
1
)EOF"));
920
1
  EXPECT_EQ(version, "2");
921
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
922

            
923
1
  expected = R"EOF(ingress:
924
1
  rules:
925
1
    [80-80]:
926
1
    - rules:
927
1
      - remotes: [43]
928
1
        http_rules:
929
1
        - headers:
930
1
          - name: ":path"
931
1
            value: "/allowed"
932
1
      - remotes: []
933
1
        proxy_id: 42
934
1
    [81-10000]:
935
1
    - rules:
936
1
      - remotes: []
937
1
        proxy_id: 42
938
1
egress:
939
1
  rules:
940
1
    [80-80]:
941
1
    - rules:
942
1
      - remotes: [43,44]
943
1
        http_rules:
944
1
        - headers:
945
1
          - name: ":path"
946
1
            regex: <hidden>
947
1
)EOF";
948

            
949
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
950

            
951
  // Allowed remote ID, port, & path:
952
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
953
  // Matching proxy ID:
954
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
955
  // Matching proxy ID:
956
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
957
  // Matching proxy ID:
958
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
959

            
960
  // Port out of range:
961
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79, {{":path", "/allowed"}}));
962
  // Port out of range:
963
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 10001, {{":path", "/notallowed"}}));
964

            
965
  // 5th update with non-matching proxy_id in policy
966
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
967
1
resources:
968
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
969
1
  endpoint_ips:
970
1
  - "10.1.2.3"
971
1
  endpoint_id: 42
972
1
  ingress_per_port_policies:
973
1
  - port: 80
974
1
    rules:
975
1
    - remote_policies: [ 43 ]
976
1
      http_rules:
977
1
        http_rules:
978
1
        - headers:
979
1
          - name: ':path'
980
1
            exact_match: '/allowed'
981
1
  - port: 80
982
1
    end_port: 10000
983
1
    rules:
984
1
    - proxy_id: 99
985
1
  egress_per_port_policies:
986
1
  - port: 80
987
1
    rules:
988
1
    - remote_policies: [ 43, 44 ]
989
1
      http_rules:
990
1
        http_rules:
991
1
        - headers:
992
1
          - name: ':path'
993
1
            safe_regex_match:
994
1
              google_re2: {}
995
1
              regex: '.*public$'
996
1
)EOF"));
997
1
  EXPECT_EQ(version, "2");
998
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
999

            
1
  expected = R"EOF(ingress:
1
  rules:
1
    [80-80]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
      - remotes: []
1
        proxy_id: 99
1
    [81-10000]:
1
    - rules:
1
      - remotes: []
1
        proxy_id: 99
1
egress:
1
  rules:
1
    [80-80]:
1
    - rules:
1
      - remotes: [43,44]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            regex: <hidden>
1
)EOF";
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Allowed remote ID, port, & path:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // Non-matching proxy ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Non-matching proxy ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Non-matching proxy ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79, {{":path", "/allowed"}}));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 10001, {{":path", "/notallowed"}}));
1
}
1
TEST_F(CiliumNetworkPolicyTest, HttpOverlappingPortRanges) {
1
  std::string version;
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
1
)EOF"));
1
  EXPECT_EQ(version, "0");
1
  EXPECT_FALSE(policy_map_->exists("10.1.2.3"));
  // No policy for the pod
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // 1st update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allowed'
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':method'
1
            exact_match: 'GET'
1
)EOF"));
1
  EXPECT_EQ(version, "1");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
1
  std::string expected = R"EOF(ingress:
1
  rules:
1
    [80-80]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":method"
1
            value: "GET"
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
egress:
1
  rules: []
1
)EOF";
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Allowed remote ID, port, & method OR path:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":method", "GET"}, {":path", "/also_allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Wrong path:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
  // 2nd update with overlapping port range and a single port
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 70
1
    end_port: 90
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allowed'
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':method'
1
            exact_match: 'GET'
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
1
  expected = R"EOF(ingress:
1
  rules:
1
    [70-79]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
    [80-80]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":method"
1
            value: "GET"
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
    [81-90]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
egress:
1
  rules: []
1
)EOF";
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Allowed remote ID, port, & method OR path:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 70, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 90, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":method", "GET"}, {":path", "/also_allowed"}}));
  // wrong port for GET
1
  EXPECT_FALSE(
1
      ingressAllowed("10.1.2.3", 43, 70, {{":method", "GET"}, {":path", "/also_allowed"}}));
1
  EXPECT_FALSE(
1
      ingressAllowed("10.1.2.3", 43, 90, {{":method", "GET"}, {":path", "/also_allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Wrong path:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
  // 3rd update with overlapping port ranges
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 70
1
    end_port: 90
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allowed'
1
  - port: 80
1
    end_port: 8080
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':method'
1
            exact_match: 'GET'
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
1
  expected = R"EOF(ingress:
1
  rules:
1
    [70-79]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
    [80-90]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":path"
1
            value: "/allowed"
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":method"
1
            value: "GET"
1
    [91-8080]:
1
    - rules:
1
      - remotes: [43]
1
        http_rules:
1
        - headers:
1
          - name: ":method"
1
            value: "GET"
1
egress:
1
  rules: []
1
)EOF";
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Allowed remote ID, port, & method OR path:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 70, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 90, {{":method", "PUSH"}, {":path", "/allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":method", "GET"}, {":path", "/also_allowed"}}));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 90, {{":method", "GET"}, {":path", "/also_allowed"}}));
1
  EXPECT_TRUE(
1
      ingressAllowed("10.1.2.3", 43, 8080, {{":method", "GET"}, {":path", "/also_allowed"}}));
  // wrong port for GET
1
  EXPECT_FALSE(
1
      ingressAllowed("10.1.2.3", 43, 70, {{":method", "GET"}, {":path", "/also_allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Wrong path:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
1
}
1
TEST_F(CiliumNetworkPolicyTest, TcpPolicyUpdate) {
1
  std::string version;
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
1
)EOF"));
1
  EXPECT_EQ(version, "0");
1
  EXPECT_FALSE(policy_map_->exists("10.1.2.3"));
  // No policy for the pod
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // 1st update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
)EOF"));
1
  EXPECT_EQ(version, "1");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Path does not matter:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
  // 2nd update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
  egress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43, 44 ]
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Path does not matter
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 44, 80, {{":path", "/public"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 40, 80, {{":path", "/public"}}));
  // Wrong port:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080, {{":path", "/public"}}));
  // Path does not matter:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/publicz"}}));
1
}
1
TEST_F(CiliumNetworkPolicyTest, PortRanges) {
1
  std::string version;
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
1
)EOF"));
1
  EXPECT_EQ(version, "0");
1
  EXPECT_FALSE(policy_map_->exists("10.1.2.3"));
  // No policy for the pod
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80));
  // 1st update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    end_port: 8080
1
    rules:
1
    - remote_policies: [ 43 ]
1
)EOF"));
1
  EXPECT_EQ(version, "1");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
  // Path does not matter
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // Port within the range:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
  // Port at the end of the range:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8081));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80));
  // 2nd update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    end_port: 8080
1
    rules:
1
    - remote_policies: [ 43 ]
1
  - port: 9000
1
    end_port: 9999
1
    rules:
1
    - remote_policies: [ 44 ]
1
  egress_per_port_policies:
1
  - port: 80
1
    end_port: 90
1
    rules:
1
    - remote_policies: [ 43, 44 ]
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
  // Wrong remote ID:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 40, 80));
  // Path does not matter
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // Port within the range:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
  // Port at the end of the range:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8081));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 44, 9000));
  // Port within the range:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 44, 9500));
  // Port at the end of the range:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 44, 9999));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 8999));
  // Port out of range:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 10000));
  // Wrong remote IDs:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 44, 80));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9000));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9500));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 9999));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80));
  // Path does not matter:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/publicz"}}));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 44, 80));
  // Wrong remote ID:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 40, 80));
  // Port within the range:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 85));
  // Port at the end of the range:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 90));
  // Port out of range:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 79));
  // Port out of range:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 91));
  // 3rd update, ranges with HTTP
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    end_port: 8080
1
    rules:
1
    - remote_policies: [ 43 ]
1
  - port: 9000
1
    end_port: 9999
1
    rules:
1
    - remote_policies: [ 44 ]
1
  egress_per_port_policies:
1
  - port: 80
1
    end_port: 90
1
    rules:
1
    - remote_policies: [ 43, 44 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allowed'
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allows'
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/public'
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID, port, & path:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // Wrong path:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/publicz"}}));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 44, 80, {{":path", "/allows"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 40, 80, {{":path", "/public"}}));
  // Port within the range:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 85, {{":path", "/allows"}}));
  // Port at the end of the range:
1
  EXPECT_TRUE(egressAllowed("10.1.2.3", 43, 90, {{":path", "/public"}}));
  // Port out of range:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 79, {{":path", "/allows"}}));
  // Port out of range:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 91, {{":path", "/public"}}));
1
}
1
TEST_F(CiliumNetworkPolicyTest, HttpPolicyUpdateToMissingSDS) {
1
  std::string version;
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
1
)EOF"));
1
  EXPECT_EQ(version, "0");
1
  EXPECT_FALSE(policy_map_->exists("10.1.2.3"));
  // No policy for the pod
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // 1st update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allowed'
1
)EOF"));
1
  EXPECT_EQ(version, "1");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID, port, & path:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Wrong path:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 80, {{":path", "/public"}}));
  // 2nd update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      http_rules:
1
        http_rules:
1
        - headers:
1
          - name: ':path'
1
            exact_match: '/allowed'
1
          header_matches:
1
          - name: 'bearer-token'
1
            value_sds_secret: 'nonexisting-sds-secret'
1
            mismatch_action: REPLACE_ON_MISMATCH
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Drop due to the missing SDS secret
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/allowed"}}));
  // Wrong remote ID:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 40, 80, {{":path", "/allowed"}}));
  // Wrong port:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 8080, {{":path", "/allowed"}}));
  // Wrong path:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80, {{":path", "/notallowed"}}));
1
}
1
TEST_F(CiliumNetworkPolicyTest, TlsPolicyUpdate) {
1
  bool tls_socket_required;
1
  bool raw_socket_allowed;
1
  std::string version;
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "0"
1
)EOF"));
1
  EXPECT_EQ(version, "0");
1
  EXPECT_FALSE(policy_map_->exists("10.1.2.3"));
  // No policy for the pod
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
  // SNI does not make a difference
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
  // 1st update without TLS requirements
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
)EOF"));
1
  EXPECT_EQ(version, "1");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID & port:
1
  EXPECT_TRUE(tlsIngressAllowed("10.1.2.3", 43, 80, "example.com", tls_socket_required,
1
                                raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_TRUE(raw_socket_allowed);
  // SNI does not matter:
1
  EXPECT_TRUE(tlsIngressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_TRUE(raw_socket_allowed);
  // Wrong remote ID:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 40, 80, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong port:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 8080, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // No egress is allowed:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // TLS SNI update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      server_names: [ "cilium.io", "example.com" ]
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(tlsIngressAllowed("10.1.2.3", 43, 80, "example.com", tls_socket_required,
1
                                raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_TRUE(raw_socket_allowed);
  // Allowed remote ID, port, incorrect SNI:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "www.example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(
1
      tlsIngressAllowed("10.1.2.3", 43, 80, "cilium.io", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_TRUE(raw_socket_allowed);
  // Missing SNI:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong remote ID:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 40, 80, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong port:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 8080, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // No egress is allowed:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // TLS Interception update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  egress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      server_names: [ "cilium.io", "example.com" ]
1
      downstream_tls_context:
1
        tls_sds_secret: "secret1"
1
      upstream_tls_context:
1
        validation_context_sds_secret: "cacerts"
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(
1
      tlsEgressAllowed("10.1.2.3", 43, 80, "example.com", tls_socket_required, raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port, incorrect SNI:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 80, "www.example.com", tls_socket_required,
1
                                raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(
1
      tlsEgressAllowed("10.1.2.3", 43, 80, "cilium.io", tls_socket_required, raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Missing SNI:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong remote ID:
1
  EXPECT_FALSE(
1
      tlsEgressAllowed("10.1.2.3", 40, 80, "example.com", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong port:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 8080, "example.com", tls_socket_required,
1
                                raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // No igress is allowed:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // TLS Termination update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      server_names: [ "cilium.io", "example.com" ]
1
      downstream_tls_context:
1
        tls_sds_secret: "secret1"
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(tlsIngressAllowed("10.1.2.3", 43, 80, "example.com", tls_socket_required,
1
                                raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port, incorrect SNI:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "www.example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(
1
      tlsIngressAllowed("10.1.2.3", 43, 80, "cilium.io", tls_socket_required, raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Missing SNI:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong remote ID:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 40, 80, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong port:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 8080, "example.com", tls_socket_required,
1
                                 raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // No egress is allowed:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // TLS Origination update
1
  EXPECT_NO_THROW(version = updateFromYaml(R"EOF(version_info: "2"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  egress_per_port_policies:
1
  - port: 80
1
    rules:
1
    - remote_policies: [ 43 ]
1
      upstream_tls_context:
1
        validation_context_sds_secret: "cacerts"
1
)EOF"));
1
  EXPECT_EQ(version, "2");
1
  EXPECT_TRUE(policy_map_->exists("10.1.2.3"));
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(
1
      tlsEgressAllowed("10.1.2.3", 43, 80, "example.com", tls_socket_required, raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port,  SNI:
1
  EXPECT_TRUE(tlsEgressAllowed("10.1.2.3", 43, 80, "www.example.com", tls_socket_required,
1
                               raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Allowed remote ID, port, SNI:
1
  EXPECT_TRUE(
1
      tlsEgressAllowed("10.1.2.3", 43, 80, "cilium.io", tls_socket_required, raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Empty SNI:
1
  EXPECT_TRUE(tlsEgressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_TRUE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong remote ID:
1
  EXPECT_FALSE(
1
      tlsEgressAllowed("10.1.2.3", 40, 80, "example.com", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // Wrong port:
1
  EXPECT_FALSE(tlsEgressAllowed("10.1.2.3", 43, 8080, "example.com", tls_socket_required,
1
                                raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
  // No igress is allowed:
1
  EXPECT_FALSE(tlsIngressAllowed("10.1.2.3", 43, 80, "", tls_socket_required, raw_socket_allowed));
1
  EXPECT_FALSE(tls_socket_required);
1
  EXPECT_FALSE(raw_socket_allowed);
1
}
1
TEST_F(CiliumNetworkPolicyTest, EmptyRulesAllow) {
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies: [{}]
1
)EOF"));
1
  std::string expected = R"EOF(ingress:
1
  rules:
1
    [0-0]:
1
    - rules:
1
egress:
1
  rules: []
1
)EOF";
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Ingress from 43 is denied to ports 80-4039, but allowed on ports 4040-9999:
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 79));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 80));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 81));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4039));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4041));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8079));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8081));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 9998));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 9999));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 10000));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
1
}
1
TEST_F(CiliumNetworkPolicyTest, SNIPatternMatching) {
  // Test empty pattern
1
  SniPattern empty("");
1
  EXPECT_FALSE(empty.matches("example.com"));
1
  EXPECT_FALSE(empty.matches("EXAMPLE.COM"));
1
  EXPECT_FALSE(empty.matches("www.example.com"));
1
  EXPECT_FALSE(empty.matches("notexample.com"));
1
  EXPECT_FALSE(empty.matches(""));
  // Test exact matches
1
  SniPattern exact("example.com");
1
  EXPECT_TRUE(exact.matches("example.com"));
1
  EXPECT_TRUE(exact.matches("EXAMPLE.COM"));
1
  EXPECT_FALSE(exact.matches("www.example.com"));
1
  EXPECT_FALSE(exact.matches("notexample.com"));
1
  EXPECT_FALSE(exact.matches(""));
  // Test wildcard matches
1
  SniPattern wild("*.example.com");
1
  EXPECT_TRUE(wild.matches("foo.example.com"));
1
  EXPECT_TRUE(wild.matches("bar.example.com"));
1
  EXPECT_TRUE(wild.matches("FOO.EXAMPLE.COM"));
1
  EXPECT_FALSE(wild.matches("example.com"));
1
  EXPECT_FALSE(wild.matches("foo.bar.example.com"));
1
  EXPECT_FALSE(wild.matches("fooexample.com"));
1
  EXPECT_FALSE(wild.matches(""));
  // Test subdomain wildcard matches
1
  SniPattern subwild("*.sub.example.com");
1
  EXPECT_TRUE(subwild.matches("foo.sub.example.com"));
1
  EXPECT_TRUE(subwild.matches("bar.sub.example.com"));
1
  EXPECT_FALSE(subwild.matches("sub.example.com"));
1
  EXPECT_FALSE(subwild.matches("foo.example.com"));
1
  EXPECT_FALSE(subwild.matches("foo.bar.sub.example.com"));
  // Test subdomain double wildcard matches
1
  SniPattern double_wildcard("**.sub.example.com");
1
  EXPECT_TRUE(double_wildcard.matches("foo.sub.example.com"));
1
  EXPECT_TRUE(double_wildcard.matches("bar.sub.example.com"));
1
  EXPECT_FALSE(double_wildcard.matches("sub.example.com"));
1
  EXPECT_FALSE(double_wildcard.matches("foo.example.com"));
1
  EXPECT_TRUE(double_wildcard.matches("foo.bar.sub.example.com"));
  // Test with unsupported wildcard label
1
  SniPattern wildcard_label("*example.com");
1
  EXPECT_FALSE(wildcard_label.matches("foo.example.com"));
1
  EXPECT_FALSE(wildcard_label.matches("bar.example.com"));
1
  EXPECT_FALSE(wildcard_label.matches("FOO.EXAMPLE.COM"));
1
  EXPECT_FALSE(wildcard_label.matches("example.com"));
1
  EXPECT_FALSE(wildcard_label.matches("foo.bar.example.com"));
1
  EXPECT_FALSE(wildcard_label.matches("fooexample.com"));
1
  EXPECT_FALSE(wildcard_label.matches(""));
1
}
1
TEST_F(CiliumNetworkPolicyTest, OrderedRules) {
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 80
1
    end_port: 8080
1
    rules:
1
    - remote_policies: [ 43 ]
1
      precedence: 0
1
      deny: true
1
  - port: 4040
1
    end_port: 9999
1
    rules:
1
    - remote_policies: [ 43 ]
1
      precedence: 1
1
)EOF"));
1
  std::string expected = R"EOF(ingress:
1
  rules:
1
    [80-4039]:
1
    - rules:
1
      - remotes: [43]
1
        deny: true
1
    [4040-8080]:
1
    - rules:
1
      - remotes: [43]
1
        precedence: 1
1
      - remotes: [43]
1
        deny: true
1
    [8081-9999]:
1
    - rules:
1
      - remotes: [43]
1
        precedence: 1
1
egress:
1
  rules: []
1
)EOF";
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Ingress from 43 is denied to ports 80-4039, but allowed on ports 4040-9999:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 81));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 4039));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4041));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8079));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8081));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 9998));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 9999));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 10000));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
  // Same with policies added in reverse order
1
  EXPECT_NO_THROW(updateFromYaml(R"EOF(version_info: "1"
1
resources:
1
- "@type": type.googleapis.com/cilium.NetworkPolicy
1
  endpoint_ips:
1
  - "10.1.2.3"
1
  endpoint_id: 42
1
  ingress_per_port_policies:
1
  - port: 4040
1
    end_port: 9999
1
    rules:
1
    - remote_policies: [ 43 ]
1
      precedence: 1
1
  - port: 80
1
    end_port: 8080
1
    rules:
1
    - remote_policies: [ 43 ]
1
      precedence: 0
1
      deny: true
1
)EOF"));
1
  EXPECT_TRUE(validate("10.1.2.3", expected));
  // Ingress from 43 is denied to ports 80-4039, but allowed on ports 4040-9999:
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 79));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 80));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 81));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 4039));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4040));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 4041));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8079));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8080));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 8081));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 9998));
1
  EXPECT_TRUE(ingressAllowed("10.1.2.3", 43, 9999));
1
  EXPECT_FALSE(ingressAllowed("10.1.2.3", 43, 10000));
  // No egress is allowed:
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 43, 8080));
1
  EXPECT_FALSE(egressAllowed("10.1.2.3", 44, 8080));
1
}
} // namespace Cilium
} // namespace Envoy