• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19524

25 Oct 2024 09:06AM UTC coverage: 84.61% (-0.007%) from 84.617%
#19524

push

github

web-flow
Xds: Implement using system root trust CA for TLS server authentication (#11470)

Allow using system root certs for server cert validation rather than CA root certs provided by the control plane when the validation context provided by the control plane specifies so.

33855 of 40013 relevant lines covered (84.61%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.94
/../xds/src/main/java/io/grpc/xds/EnvoyServerProtoData.java
1
/*
2
 * Copyright 2020 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.auto.value.AutoValue;
22
import com.google.common.annotations.VisibleForTesting;
23
import com.google.common.collect.ImmutableList;
24
import com.google.protobuf.util.Durations;
25
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
26
import io.grpc.Internal;
27
import io.grpc.xds.client.EnvoyProtoData;
28
import io.grpc.xds.internal.security.SslContextProviderSupplier;
29
import java.net.InetAddress;
30
import java.net.UnknownHostException;
31
import java.util.Objects;
32
import javax.annotation.Nullable;
33

34
/**
35
 * Defines gRPC data types for Envoy protobuf messages used in xDS protocol on the server side,
36
 * similar to how {@link EnvoyProtoData} defines it for the client side.
37
 */
38
@Internal
39
public final class EnvoyServerProtoData {
40

41
  // Prevent instantiation.
42
  private EnvoyServerProtoData() {
43
  }
44

45
  public abstract static class BaseTlsContext {
46
    protected final CommonTlsContext commonTlsContext;
47

48
    protected BaseTlsContext(CommonTlsContext commonTlsContext) {
1✔
49
      this.commonTlsContext = checkNotNull(commonTlsContext, "commonTlsContext cannot be null.");
1✔
50
    }
1✔
51

52
    public CommonTlsContext getCommonTlsContext() {
53
      return commonTlsContext;
1✔
54
    }
55

56
    @Override
57
    public boolean equals(Object o) {
58
      if (this == o) {
1✔
59
        return true;
×
60
      }
61
      if (!(o instanceof BaseTlsContext)) {
1✔
62
        return false;
1✔
63
      }
64
      BaseTlsContext that = (BaseTlsContext) o;
1✔
65
      return Objects.equals(commonTlsContext, that.commonTlsContext);
1✔
66
    }
67

68
    @Override
69
    public int hashCode() {
70
      return Objects.hashCode(commonTlsContext);
1✔
71
    }
72
  }
73

74
  public static final class UpstreamTlsContext extends BaseTlsContext {
75

76
    @VisibleForTesting
77
    public UpstreamTlsContext(CommonTlsContext commonTlsContext) {
78
      super(commonTlsContext);
1✔
79
    }
1✔
80

81
    public static UpstreamTlsContext fromEnvoyProtoUpstreamTlsContext(
82
        io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
83
            upstreamTlsContext) {
84
      return new UpstreamTlsContext(upstreamTlsContext.getCommonTlsContext());
1✔
85
    }
86

87
    @Override
88
    public String toString() {
89
      return "UpstreamTlsContext{" + "commonTlsContext=" + commonTlsContext + '}';
1✔
90
    }
91
  }
92

93
  public static final class DownstreamTlsContext extends BaseTlsContext {
94

95
    private final boolean requireClientCertificate;
96

97
    @VisibleForTesting
98
    public DownstreamTlsContext(
99
        CommonTlsContext commonTlsContext, boolean requireClientCertificate) {
100
      super(commonTlsContext);
1✔
101
      this.requireClientCertificate = requireClientCertificate;
1✔
102
    }
1✔
103

104
    public static DownstreamTlsContext fromEnvoyProtoDownstreamTlsContext(
105
        io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
106
            downstreamTlsContext) {
107
      return new DownstreamTlsContext(downstreamTlsContext.getCommonTlsContext(),
1✔
108
        downstreamTlsContext.hasRequireClientCertificate());
1✔
109
    }
110

111
    public boolean isRequireClientCertificate() {
112
      return requireClientCertificate;
1✔
113
    }
114

115
    @Override
116
    public String toString() {
117
      return "DownstreamTlsContext{"
×
118
          + "commonTlsContext="
119
          + commonTlsContext
120
          + ", requireClientCertificate="
121
          + requireClientCertificate
122
          + '}';
123
    }
124

125
    @Override
126
    public boolean equals(Object o) {
127
      if (this == o) {
1✔
128
        return true;
×
129
      }
130
      if (o == null || getClass() != o.getClass()) {
1✔
131
        return false;
×
132
      }
133
      if (!super.equals(o)) {
1✔
134
        return false;
1✔
135
      }
136
      DownstreamTlsContext that = (DownstreamTlsContext) o;
1✔
137
      return requireClientCertificate == that.requireClientCertificate;
1✔
138
    }
139

140
    @Override
141
    public int hashCode() {
142
      return Objects.hash(super.hashCode(), requireClientCertificate);
1✔
143
    }
144
  }
145

146
  @AutoValue
147
  abstract static class CidrRange {
1✔
148

149
    abstract InetAddress addressPrefix();
150

151
    abstract int prefixLen();
152

153
    static CidrRange create(String addressPrefix, int prefixLen) throws UnknownHostException {
154
      return new AutoValue_EnvoyServerProtoData_CidrRange(
1✔
155
          InetAddress.getByName(addressPrefix), prefixLen);
1✔
156
    }
157
  }
158

159
  enum ConnectionSourceType {
1✔
160
    // Any connection source matches.
161
    ANY,
1✔
162

163
    // Match a connection originating from the same host.
164
    SAME_IP_OR_LOOPBACK,
1✔
165

166
    // Match a connection originating from a different host.
167
    EXTERNAL
1✔
168
  }
169

170
  /**
171
   * Corresponds to Envoy proto message
172
   * {@link io.envoyproxy.envoy.config.listener.v3.FilterChainMatch}.
173
   */
174
  @AutoValue
175
  abstract static class FilterChainMatch {
1✔
176

177
    abstract int destinationPort();
178

179
    abstract ImmutableList<CidrRange> prefixRanges();
180

181
    abstract ImmutableList<String> applicationProtocols();
182

183
    abstract ImmutableList<CidrRange> sourcePrefixRanges();
184

185
    abstract ConnectionSourceType connectionSourceType();
186

187
    abstract ImmutableList<Integer> sourcePorts();
188

189
    abstract ImmutableList<String> serverNames();
190

191
    abstract String transportProtocol();
192

193
    public static FilterChainMatch create(int destinationPort,
194
        ImmutableList<CidrRange> prefixRanges,
195
        ImmutableList<String> applicationProtocols, ImmutableList<CidrRange> sourcePrefixRanges,
196
        ConnectionSourceType connectionSourceType, ImmutableList<Integer> sourcePorts,
197
        ImmutableList<String> serverNames, String transportProtocol) {
198
      return new AutoValue_EnvoyServerProtoData_FilterChainMatch(
1✔
199
          destinationPort, prefixRanges, applicationProtocols, sourcePrefixRanges,
200
          connectionSourceType, sourcePorts, serverNames, transportProtocol);
201
    }
202
  }
203

204
  /**
205
   * Corresponds to Envoy proto message {@link io.envoyproxy.envoy.config.listener.v3.FilterChain}.
206
   */
207
  @AutoValue
208
  abstract static class FilterChain {
1✔
209

210
    // possibly empty
211
    abstract String name();
212

213
    // TODO(sanjaypujare): flatten structure by moving FilterChainMatch class members here.
214
    abstract FilterChainMatch filterChainMatch();
215

216
    abstract HttpConnectionManager httpConnectionManager();
217

218
    @Nullable
219
    abstract SslContextProviderSupplier sslContextProviderSupplier();
220

221
    static FilterChain create(
222
        String name,
223
        FilterChainMatch filterChainMatch,
224
        HttpConnectionManager httpConnectionManager,
225
        @Nullable DownstreamTlsContext downstreamTlsContext,
226
        TlsContextManager tlsContextManager) {
227
      SslContextProviderSupplier sslContextProviderSupplier =
228
          downstreamTlsContext == null
1✔
229
              ? null : new SslContextProviderSupplier(downstreamTlsContext, tlsContextManager);
1✔
230
      return new AutoValue_EnvoyServerProtoData_FilterChain(
1✔
231
          name, filterChainMatch, httpConnectionManager, sslContextProviderSupplier);
232
    }
233
  }
234

235
  /**
236
   * Corresponds to Envoy proto message {@link io.envoyproxy.envoy.config.listener.v3.Listener} and
237
   * related classes.
238
   */
239
  @AutoValue
240
  abstract static class Listener {
1✔
241

242
    abstract String name();
243

244
    @Nullable
245
    abstract String address();
246

247
    abstract ImmutableList<FilterChain> filterChains();
248

249
    @Nullable
250
    abstract FilterChain defaultFilterChain();
251

252
    static Listener create(
253
        String name,
254
        @Nullable String address,
255
        ImmutableList<FilterChain> filterChains,
256
        @Nullable FilterChain defaultFilterChain) {
257
      return new AutoValue_EnvoyServerProtoData_Listener(name, address, filterChains,
1✔
258
          defaultFilterChain);
259
    }
260
  }
261

262
  /**
263
   * Corresponds to Envoy proto message {@link
264
   * io.envoyproxy.envoy.config.cluster.v3.OutlierDetection}. Only the fields supported by gRPC are
265
   * included.
266
   *
267
   * <p>Protobuf Duration fields are represented in their string format (e.g. "10s").
268
   */
269
  @AutoValue
270
  abstract static class OutlierDetection {
1✔
271

272
    @Nullable
273
    abstract Long intervalNanos();
274

275
    @Nullable
276
    abstract Long baseEjectionTimeNanos();
277

278
    @Nullable
279
    abstract Long maxEjectionTimeNanos();
280

281
    @Nullable
282
    abstract Integer maxEjectionPercent();
283

284
    @Nullable
285
    abstract SuccessRateEjection successRateEjection();
286

287
    @Nullable
288
    abstract FailurePercentageEjection failurePercentageEjection();
289

290
    static OutlierDetection create(
291
        @Nullable Long intervalNanos,
292
        @Nullable Long baseEjectionTimeNanos,
293
        @Nullable Long maxEjectionTimeNanos,
294
        @Nullable Integer maxEjectionPercentage,
295
        @Nullable SuccessRateEjection successRateEjection,
296
        @Nullable FailurePercentageEjection failurePercentageEjection) {
297
      return new AutoValue_EnvoyServerProtoData_OutlierDetection(intervalNanos,
1✔
298
          baseEjectionTimeNanos, maxEjectionTimeNanos, maxEjectionPercentage, successRateEjection,
299
          failurePercentageEjection);
300
    }
301

302
    static OutlierDetection fromEnvoyOutlierDetection(
303
        io.envoyproxy.envoy.config.cluster.v3.OutlierDetection envoyOutlierDetection) {
304

305
      Long intervalNanos = envoyOutlierDetection.hasInterval()
1✔
306
          ? Durations.toNanos(envoyOutlierDetection.getInterval()) : null;
1✔
307
      Long baseEjectionTimeNanos = envoyOutlierDetection.hasBaseEjectionTime()
1✔
308
          ? Durations.toNanos(envoyOutlierDetection.getBaseEjectionTime()) : null;
1✔
309
      Long maxEjectionTimeNanos = envoyOutlierDetection.hasMaxEjectionTime()
1✔
310
          ? Durations.toNanos(envoyOutlierDetection.getMaxEjectionTime()) : null;
1✔
311
      Integer maxEjectionPercentage = envoyOutlierDetection.hasMaxEjectionPercent()
1✔
312
          ? envoyOutlierDetection.getMaxEjectionPercent().getValue() : null;
1✔
313

314
      SuccessRateEjection successRateEjection;
315
      // If success rate enforcement has been turned completely off, don't configure this ejection.
316
      if (envoyOutlierDetection.hasEnforcingSuccessRate()
1✔
317
          && envoyOutlierDetection.getEnforcingSuccessRate().getValue() == 0) {
1✔
318
        successRateEjection = null;
×
319
      } else {
320
        Integer stdevFactor = envoyOutlierDetection.hasSuccessRateStdevFactor()
1✔
321
            ? envoyOutlierDetection.getSuccessRateStdevFactor().getValue() : null;
1✔
322
        Integer enforcementPercentage = envoyOutlierDetection.hasEnforcingSuccessRate()
1✔
323
            ? envoyOutlierDetection.getEnforcingSuccessRate().getValue() : null;
1✔
324
        Integer minimumHosts = envoyOutlierDetection.hasSuccessRateMinimumHosts()
1✔
325
            ? envoyOutlierDetection.getSuccessRateMinimumHosts().getValue() : null;
1✔
326
        Integer requestVolume = envoyOutlierDetection.hasSuccessRateRequestVolume()
1✔
327
            ? envoyOutlierDetection.getSuccessRateMinimumHosts().getValue() : null;
1✔
328

329
        successRateEjection = SuccessRateEjection.create(stdevFactor, enforcementPercentage,
1✔
330
            minimumHosts, requestVolume);
331
      }
332

333
      FailurePercentageEjection failurePercentageEjection;
334
      if (envoyOutlierDetection.hasEnforcingFailurePercentage()
1✔
335
          && envoyOutlierDetection.getEnforcingFailurePercentage().getValue() == 0) {
1✔
336
        failurePercentageEjection = null;
×
337
      } else {
338
        Integer threshold = envoyOutlierDetection.hasFailurePercentageThreshold()
1✔
339
            ? envoyOutlierDetection.getFailurePercentageThreshold().getValue() : null;
1✔
340
        Integer enforcementPercentage = envoyOutlierDetection.hasEnforcingFailurePercentage()
1✔
341
            ? envoyOutlierDetection.getEnforcingFailurePercentage().getValue() : null;
1✔
342
        Integer minimumHosts = envoyOutlierDetection.hasFailurePercentageMinimumHosts()
1✔
343
            ? envoyOutlierDetection.getFailurePercentageMinimumHosts().getValue() : null;
1✔
344
        Integer requestVolume = envoyOutlierDetection.hasFailurePercentageRequestVolume()
1✔
345
            ? envoyOutlierDetection.getFailurePercentageRequestVolume().getValue() : null;
1✔
346

347
        failurePercentageEjection = FailurePercentageEjection.create(threshold,
1✔
348
            enforcementPercentage, minimumHosts, requestVolume);
349
      }
350

351
      return create(intervalNanos, baseEjectionTimeNanos, maxEjectionTimeNanos,
1✔
352
          maxEjectionPercentage, successRateEjection, failurePercentageEjection);
353
    }
354
  }
355

356
  @AutoValue
357
  abstract static class SuccessRateEjection {
1✔
358

359
    @Nullable
360
    abstract Integer stdevFactor();
361

362
    @Nullable
363
    abstract Integer enforcementPercentage();
364

365
    @Nullable
366
    abstract Integer minimumHosts();
367

368
    @Nullable
369
    abstract Integer requestVolume();
370

371
    static SuccessRateEjection create(
372
        @Nullable Integer stdevFactor,
373
        @Nullable Integer enforcementPercentage,
374
        @Nullable Integer minimumHosts,
375
        @Nullable Integer requestVolume) {
376
      return new AutoValue_EnvoyServerProtoData_SuccessRateEjection(stdevFactor,
1✔
377
          enforcementPercentage, minimumHosts, requestVolume);
378
    }
379
  }
380

381
  @AutoValue
382
  abstract static class FailurePercentageEjection {
1✔
383

384
    @Nullable
385
    abstract Integer threshold();
386

387
    @Nullable
388
    abstract Integer enforcementPercentage();
389

390
    @Nullable
391
    abstract Integer minimumHosts();
392

393
    @Nullable
394
    abstract Integer requestVolume();
395

396
    static FailurePercentageEjection create(
397
        @Nullable Integer threshold,
398
        @Nullable Integer enforcementPercentage,
399
        @Nullable Integer minimumHosts,
400
        @Nullable Integer requestVolume) {
401
      return new AutoValue_EnvoyServerProtoData_FailurePercentageEjection(threshold,
1✔
402
          enforcementPercentage, minimumHosts, requestVolume);
403
    }
404
  }
405
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc