Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lib/metrics/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const {
View
} = require('@opentelemetry/sdk-metrics')

const { getDynatraceMetadata, getCredsForDTAsUPS, getCredsForCLSAsUPS, augmentCLCreds, _require } = require('../utils')
const { getDynatraceMetadata, getCredsForDTAsUPS, getCredsForCLSAsUPS, getCredsForCaaS, augmentCLCreds, augmentCaaSCreds, _require } = require('../utils')

const _protocol2module = {
grpc: '@opentelemetry/exporter-metrics-otlp-grpc',
Expand Down Expand Up @@ -70,6 +70,13 @@ function _getExporter() {
config.credentials ??= credentials.credentials
}

if (kind.match(/to-caas$/)) {
if (!credentials) credentials = getCredsForCaaS()
if (!credentials) throw new Error('No CaaS credentials found.')
augmentCaaSCreds(credentials)
config.url ??= credentials.url
}

// default to DELTA
config.temporalityPreference ??= AggregationTemporality.DELTA

Expand Down
9 changes: 9 additions & 0 deletions lib/tracing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ const {
getDynatraceMetadata,
getCredsForDTAsUPS,
getCredsForCLSAsUPS,
getCredsForCaaS,
augmentCLCreds,
augmentCaaSCreds,
hasDependency,
_require
} = require('../utils')
Expand Down Expand Up @@ -125,6 +127,13 @@ function _getExporter() {
config.credentials ??= credentials.credentials
}

if (kind.match(/to-caas$/)) {
if (!credentials) credentials = getCredsForCaaS()
if (!credentials) throw new Error('No CaaS credentials found')
Comment thread
vkozyura marked this conversation as resolved.
Outdated
augmentCaaSCreds(credentials)
config.url ??= credentials.url
}

const exporter = new tracingExporterModule[tracingExporter.class](config)
LOG._debug && LOG.debug('Using trace exporter:', exporter)

Expand Down
94 changes: 94 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,97 @@
}
}

function getCredsForCaaS() {
if (!process.env.VCAP_SERVICES) return
const vcap = JSON.parse(process.env.VCAP_SERVICES)

// look for caas-service binding
const caas = vcap['caas-service']?.[0]
if (caas) return caas.credentials
}

function getCredsForCertService() {
if (!process.env.VCAP_SERVICES) return
const vcap = JSON.parse(process.env.VCAP_SERVICES)
const certSvc = vcap['certificate-service']?.[0]
if (certSvc) return certSvc.credentials
}

function getCredsForCaaSMtls() {
if (!process.env.VCAP_SERVICES) return
const vcap = JSON.parse(process.env.VCAP_SERVICES)
// Look for user-provided service with name containing 'caas-mtls' or 'caas-cert'
const mtlsCreds = vcap['user-provided']?.find(b => b.name.match(/caas-mtls|caas-cert/i))
if (mtlsCreds) return mtlsCreds.credentials
}

function augmentCaaSCreds(credentials) {
if (credentials._augmented) return
credentials._augmented = true

// check for otlp endpoints
if (!credentials.otlp?.http && !credentials.otlp?.grpc) {
throw new Error('No OTLP endpoints found in CaaS binding. Make sure the CaaS instance is properly configured.')
}

// use http endpoint by default (proto exporter)
credentials.url = credentials.otlp.http
Comment thread
vkozyura marked this conversation as resolved.

// Check for mTLS credentials (cert + key) in user-provided service
const mtlsCreds = getCredsForCaaSMtls()
if (mtlsCreds && mtlsCreds.cert && mtlsCreds.key) {
LOG._info && LOG.info('Found CaaS mTLS credentials, configuring HTTPS agent')
try {
const https = require('https')
const cert = Buffer.from(mtlsCreds.cert, 'base64').toString('utf-8')
const key = Buffer.from(mtlsCreds.key, 'base64').toString('utf-8')

// Override the global https agent to use client certificates
// This is needed because OTLP HTTP exporter doesn't support passing certs directly
const originalAgent = https.globalAgent
const customAgent = new https.Agent({
cert: cert,
key: key,
keepAlive: true
})

// Store original agent for potential restoration
credentials._originalAgent = originalAgent

// Monkey-patch https.request to use our agent for CaaS endpoints
const originalRequest = https.request
https.request = function(options, callback) {
if (typeof options === 'string' || options instanceof URL) {
const url = new URL(options)
if (url.hostname.includes('caas.shoot.live.k8s-hana.ondemand.com')) {

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High

'
caas.shoot.live.k8s-hana.ondemand.com
' can be anywhere in the URL, and arbitrary hosts may come before or after it.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
options = { ...options }
options.agent = customAgent
}
} else if (options && options.hostname && options.hostname.includes('caas.shoot.live.k8s-hana.ondemand.com')) {

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High

'
caas.shoot.live.k8s-hana.ondemand.com
' can be anywhere in the URL, and arbitrary hosts may come before or after it.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
options = { ...options, agent: customAgent }
} else if (options && options.host && options.host.includes('caas.shoot.live.k8s-hana.ondemand.com')) {

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization High

'
caas.shoot.live.k8s-hana.ondemand.com
' can be anywhere in the URL, and arbitrary hosts may come before or after it.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
options = { ...options, agent: customAgent }
}
return originalRequest.call(this, options, callback)
}

LOG._info && LOG.info('CaaS mTLS configured successfully')
} catch (err) {
LOG._error && LOG.error('Failed to configure CaaS mTLS:', err.message)
}
Comment thread
vkozyura marked this conversation as resolved.
} else {
// Check for certificate-service binding (manual enrollment needed)
const certServiceCreds = getCredsForCertService()
if (certServiceCreds) {
LOG._warn && LOG.warn('Found certificate-service binding but no caas-mtls-creds.')
LOG._warn && LOG.warn('Run the certificate enrollment script and create caas-mtls-creds service.')
} else {
LOG._warn && LOG.warn('CaaS requires mTLS authentication. No mTLS credentials found.')
LOG._warn && LOG.warn('Bind a caas-mtls-creds user-provided service with cert and key.')
}
}
}
Comment thread
vkozyura marked this conversation as resolved.

function augmentCLCreds(credentials) {
if (credentials._augmented) return
credentials._augmented = true
Expand Down Expand Up @@ -194,7 +285,10 @@
getDynatraceMetadata,
getCredsForDTAsUPS,
getCredsForCLSAsUPS,
getCredsForCaaS,
getCredsForCertService,
augmentCLCreds,
augmentCaaSCreds,
hasDependency,
_hrnow,
_require
Expand Down
Loading