Skip to content

Commit 80bdc25

Browse files
committed
CLDSRV-851: Read TLS info from proxy headers in access logs
When cloudserver sits behind a TLS-terminating proxy (e.g. nginx), cipherSuite and tlsVersion are null because the socket is not encrypted. Fall back to x-ssl-cipher and x-ssl-protocol headers set by the proxy.
1 parent f1d9d12 commit 80bdc25

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

lib/utilities/serverAccessLogger.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,10 +484,14 @@ function buildLogEntry(req, params, options) {
484484
userAgent: options.userAgent ?? undefined,
485485
versionId: options.versionId ?? undefined,
486486
signatureVersion: authInfo?.getAuthVersion() ?? undefined,
487-
cipherSuite: req.socket?.encrypted ? req.socket.getCipher()['standardName'] : undefined,
487+
cipherSuite: req.socket?.encrypted
488+
? req.socket.getCipher()['standardName']
489+
: req.headers?.['x-ssl-cipher'] ?? undefined,
488490
authenticationType: authInfo?.getAuthType() ?? undefined,
489491
hostHeader: req.headers?.host ?? undefined,
490-
tlsVersion: req.socket?.encrypted ? req.socket.getCipher()['version'] : undefined,
492+
tlsVersion: req.socket?.encrypted
493+
? req.socket.getCipher()['version']
494+
: req.headers?.['x-ssl-protocol'] ?? undefined,
491495
aclRequired: options.aclRequired ?? undefined, // TODO: CLDSRV-774
492496
// hostID: undefined, // NOT IMPLEMENTED
493497
// accessPointARN: undefined, // NOT IMPLEMENTED

tests/unit/utils/serverAccessLogger.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,57 @@ describe('serverAccessLogger utility functions', () => {
979979
assert.strictEqual('tlsVersion' in loggedData, false);
980980
});
981981

982+
it('should read TLS info from proxy headers when socket is not encrypted', () => {
983+
setServerAccessLogger(mockLogger);
984+
const req = {
985+
serverAccessLog: {},
986+
headers: {
987+
'x-ssl-cipher': 'ECDHE-RSA-AES256-GCM-SHA384',
988+
'x-ssl-protocol': 'TLSv1.3',
989+
},
990+
socket: {
991+
encrypted: false,
992+
},
993+
};
994+
const res = {
995+
serverAccessLog: {},
996+
getHeader: () => null,
997+
};
998+
999+
logServerAccess(req, res);
1000+
1001+
assert.strictEqual(mockLogger.write.callCount, 1);
1002+
const loggedData = JSON.parse(mockLogger.write.firstCall.args[0].trim());
1003+
assert.strictEqual(loggedData.cipherSuite, 'ECDHE-RSA-AES256-GCM-SHA384');
1004+
assert.strictEqual(loggedData.tlsVersion, 'TLSv1.3');
1005+
});
1006+
1007+
it('should prefer socket TLS info over proxy headers when encrypted', () => {
1008+
setServerAccessLogger(mockLogger);
1009+
const req = {
1010+
serverAccessLog: {},
1011+
headers: {
1012+
'x-ssl-cipher': 'PROXY-CIPHER',
1013+
'x-ssl-protocol': 'TLSv1.2',
1014+
},
1015+
socket: {
1016+
encrypted: true,
1017+
getCipher: () => ({ standardName: 'TLS_AES_128_GCM_SHA256', version: 'TLSv1.3' }),
1018+
},
1019+
};
1020+
const res = {
1021+
serverAccessLog: {},
1022+
getHeader: () => null,
1023+
};
1024+
1025+
logServerAccess(req, res);
1026+
1027+
assert.strictEqual(mockLogger.write.callCount, 1);
1028+
const loggedData = JSON.parse(mockLogger.write.firstCall.args[0].trim());
1029+
assert.strictEqual(loggedData.cipherSuite, 'TLS_AES_128_GCM_SHA256');
1030+
assert.strictEqual(loggedData.tlsVersion, 'TLSv1.3');
1031+
});
1032+
9821033
it('should handle missing query parameters', () => {
9831034
setServerAccessLogger(mockLogger);
9841035
const req = {

0 commit comments

Comments
 (0)