Skip to content

Commit d8f4343

Browse files
committed
Add xds credentials tests
1 parent 1ce0143 commit d8f4343

File tree

7 files changed

+182
-2
lines changed

7 files changed

+182
-2
lines changed

packages/grpc-js-xds/gulpfile.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import * as mocha from 'gulp-mocha';
2121
import * as path from 'path';
2222
import * as execa from 'execa';
2323
import * as semver from 'semver';
24+
import { ncp } from 'ncp';
25+
import { promisify } from 'util';
26+
27+
const ncpP = promisify(ncp);
2428

2529
Error.stackTraceLimit = Infinity;
2630

@@ -60,6 +64,10 @@ const cleanAll = gulp.parallel(clean);
6064
*/
6165
const compile = checkTask(() => execNpmCommand('compile'));
6266

67+
const copyTestFixtures = checkTask(() =>
68+
ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`)
69+
);
70+
6371
const runTests = checkTask(() => {
6472
process.env.GRPC_EXPERIMENTAL_XDS_FEDERATION = 'true';
6573
process.env.GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG = 'true';
@@ -71,7 +79,7 @@ const runTests = checkTask(() => {
7179
require: ['ts-node/register']}));
7280
});
7381

74-
const test = gulp.series(install, runTests);
82+
const test = gulp.series(install, copyTestFixtures, runTests);
7583

7684
export {
7785
install,

packages/grpc-js-xds/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@types/yargs": "^15.0.5",
4242
"find-free-ports": "^3.1.1",
4343
"gts": "^5.0.1",
44+
"ncp": "^2.0.0",
4445
"typescript": "^5.1.3",
4546
"yargs": "^15.4.1"
4647
},
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
3+
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
4+
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
5+
Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
6+
YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
7+
BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
8+
+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
9+
g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
10+
Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
11+
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
12+
sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
13+
oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
14+
Dfcog5wrJytaQ6UA0wE=
15+
-----END CERTIFICATE-----
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
3+
M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
4+
3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
5+
AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
6+
V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
7+
tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
8+
dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
9+
K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
10+
81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
11+
DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
12+
aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
13+
ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
14+
XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
15+
F98XJ7tIFfJq
16+
-----END PRIVATE KEY-----
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
3+
MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
4+
dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
5+
MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
6+
BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
7+
ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
8+
LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
9+
zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
10+
9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
11+
CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
12+
em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
13+
CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
14+
hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
15+
y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
16+
-----END CERTIFICATE-----
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2024 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+
18+
import * as assert from 'assert';
19+
import { createBackends } from './backend';
20+
import { FakeEdsCluster, FakeRouteGroup, FakeServerRoute } from './framework';
21+
import { ControlPlaneServer } from './xds-server';
22+
import { XdsTestClient } from './client';
23+
import { XdsServerCredentials } from '../src';
24+
import { credentials, ServerCredentials } from '@grpc/grpc-js';
25+
import { readFileSync } from 'fs';
26+
import * as path from 'path';
27+
import { Listener } from '../src/generated/envoy/config/listener/v3/Listener';
28+
import { DownstreamTlsContext } from '../src/generated/envoy/extensions/transport_sockets/tls/v3/DownstreamTlsContext';
29+
import { AnyExtension } from '@grpc/proto-loader';
30+
import { DOWNSTREAM_TLS_CONTEXT_TYPE_URL } from '../src/resources';
31+
32+
const ca = readFileSync(path.join(__dirname, 'fixtures', 'ca.pem'));
33+
const key = readFileSync(path.join(__dirname, 'fixtures', 'server1.key'));
34+
const cert = readFileSync(path.join(__dirname, 'fixtures', 'server1.pem'));
35+
36+
describe('Server xDS Credentials', () => {
37+
let xdsServer: ControlPlaneServer;
38+
let client: XdsTestClient;
39+
beforeEach(done => {
40+
xdsServer = new ControlPlaneServer();
41+
xdsServer.startServer(error => {
42+
done(error);
43+
});
44+
});
45+
afterEach(() => {
46+
client?.close();
47+
xdsServer?.shutdownServer();
48+
});
49+
it('Should use fallback credentials when certificate providers are not configured', async () => {
50+
const [backend] = await createBackends(1, true, new XdsServerCredentials(ServerCredentials.createInsecure()));
51+
const serverRoute = new FakeServerRoute(backend.getPort(), 'serverRoute');
52+
xdsServer.setRdsResource(serverRoute.getRouteConfiguration());
53+
xdsServer.setLdsResource(serverRoute.getListener());
54+
xdsServer.addResponseListener((typeUrl, responseState) => {
55+
if (responseState.state === 'NACKED') {
56+
client?.stopCalls();
57+
assert.fail(`Client NACKED ${typeUrl} resource with message ${responseState.errorMessage}`);
58+
}
59+
});
60+
const cluster = new FakeEdsCluster('cluster1', 'endpoint1', [{backends: [backend], locality:{region: 'region1'}}]);
61+
const routeGroup = new FakeRouteGroup('listener1', 'route1', [{cluster: cluster}]);
62+
await routeGroup.startAllBackends(xdsServer);
63+
xdsServer.setEdsResource(cluster.getEndpointConfig());
64+
xdsServer.setCdsResource(cluster.getClusterConfig());
65+
xdsServer.setRdsResource(routeGroup.getRouteConfiguration());
66+
xdsServer.setLdsResource(routeGroup.getListener());
67+
client = XdsTestClient.createFromServer('listener1', xdsServer, credentials.createInsecure());
68+
const error = await client.sendOneCallAsync();
69+
assert.strictEqual(error, null);
70+
});
71+
it('Should use the identity certificate when configured', async () => {
72+
const [backend] = await createBackends(1, true, new XdsServerCredentials(ServerCredentials.createInsecure()));
73+
const downstreamTlsContext: DownstreamTlsContext & AnyExtension = {
74+
'@type': DOWNSTREAM_TLS_CONTEXT_TYPE_URL,
75+
common_tls_context: {
76+
tls_certificate_provider_instance: {
77+
instance_name: 'test_certificates'
78+
}
79+
}
80+
}
81+
const baseServerListener: Listener = {
82+
default_filter_chain: {
83+
filter_chain_match: {
84+
source_type: 'SAME_IP_OR_LOOPBACK'
85+
},
86+
transport_socket: {
87+
name: 'envoy.transport_sockets.tls',
88+
typed_config: downstreamTlsContext
89+
}
90+
}
91+
}
92+
const serverRoute = new FakeServerRoute(backend.getPort(), 'serverRoute', baseServerListener);
93+
xdsServer.setRdsResource(serverRoute.getRouteConfiguration());
94+
xdsServer.setLdsResource(serverRoute.getListener());
95+
xdsServer.addResponseListener((typeUrl, responseState) => {
96+
if (responseState.state === 'NACKED') {
97+
client?.stopCalls();
98+
assert.fail(`Client NACKED ${typeUrl} resource with message ${responseState.errorMessage}`);
99+
}
100+
});
101+
const cluster = new FakeEdsCluster('cluster1', 'endpoint1', [{backends: [backend], locality:{region: 'region1'}}]);
102+
const routeGroup = new FakeRouteGroup('listener1', 'route1', [{cluster: cluster}]);
103+
await routeGroup.startAllBackends(xdsServer);
104+
xdsServer.setEdsResource(cluster.getEndpointConfig());
105+
xdsServer.setCdsResource(cluster.getClusterConfig());
106+
xdsServer.setRdsResource(routeGroup.getRouteConfiguration());
107+
xdsServer.setLdsResource(routeGroup.getListener());
108+
client = XdsTestClient.createFromServer('listener1', xdsServer, credentials.createSsl(ca));
109+
const error = await client.sendOneCallAsync();
110+
assert.strictEqual(error, null);
111+
});
112+
});

packages/grpc-js-xds/test/xds-server.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import * as adsTypes from '../src/generated/ads';
3131
import * as lrsTypes from '../src/generated/lrs';
3232
import { LoadStatsRequest__Output } from "../src/generated/envoy/service/load_stats/v3/LoadStatsRequest";
3333
import { LoadStatsResponse } from "../src/generated/envoy/service/load_stats/v3/LoadStatsResponse";
34+
import * as path from 'path';
3435

3536
const TRACER_NAME = 'control_plane_server';
3637

@@ -367,7 +368,18 @@ export class ControlPlaneServer {
367368
id: 'test',
368369
locality: {}
369370
},
370-
server_listener_resource_name_template: '%s'
371+
server_listener_resource_name_template: '%s',
372+
certificate_providers: {
373+
test_certificates: {
374+
plugin_name: 'file_watcher',
375+
config: {
376+
certificate_file: path.join(__dirname, 'fixtures', 'server1.pem'),
377+
private_key_file: path.join(__dirname, 'fixtures', 'server1.key'),
378+
ca_certificate_file: path.join(__dirname, 'fixtures', 'ca.pem'),
379+
refresh_interval: '60s'
380+
}
381+
}
382+
}
371383
}
372384
return JSON.stringify(bootstrapInfo);
373385
}

0 commit comments

Comments
 (0)