Skip to content

Commit

Permalink
[Backport 8.11] Bump transport to 8.4.0 (#2096)
Browse files Browse the repository at this point in the history
* Support for transport 8.4.0 redaction functionality

* Docs for `redaction` options

(cherry picked from commit c2c417a)

Co-authored-by: Josh Mock <[email protected]>
  • Loading branch information
github-actions[bot] and JoshMock authored Dec 12, 2023
1 parent dda20a4 commit d00cc52
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 6 deletions.
88 changes: 88 additions & 0 deletions docs/advanced-config.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,94 @@ const client = new Client({
})
----

[discrete]
==== Redaction of potentially sensitive data

When the client raises an `Error` that originated at the HTTP layer, like a `ConnectionError` or `TimeoutError`, a `meta` object is often attached to the error object that includes metadata useful for debugging, like request and response information. Because this can include potentially sensitive data, like authentication secrets in an `Authorization` header, the client takes measures to redact common sources of sensitive data when this metadata is attached and serialized.

If your configuration requires extra headers or other configurations that may include sensitive data, you may want to adjust these settings to account for that.

By default, the `redaction` option is set to `{ type: 'replace' }`, which recursively searches for sensitive key names, case insensitive, and replaces their values with the string `[redacted]`.

[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({
cloud: { id: '<cloud-id>' },
auth: { apiKey: 'base64EncodedKey' },
})
try {
await client.indices.create({ index: 'my_index' })
} catch (err) {
console.log(err.meta.meta.request.options.headers.authorization) // prints "[redacted]"
}
----

If you would like to redact additional properties, you can include additional key names to search and replace:

[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({
cloud: { id: '<cloud-id>' },
auth: { apiKey: 'base64EncodedKey' },
headers: { 'X-My-Secret-Password': 'shhh it's a secret!' },
redaction: {
type: "replace",
additionalKeys: ["x-my-secret-password"]
}
})
try {
await client.indices.create({ index: 'my_index' })
} catch (err) {
console.log(err.meta.meta.request.options.headers['X-My-Secret-Password']) // prints "[redacted]"
}
----

Alternatively, if you know you're not going to use the metadata at all, setting the redaction type to `remove` will remove all optional sources of potentially sensitive data entirely, or replacing them with `null` for required properties.

[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({
cloud: { id: '<cloud-id>' },
auth: { apiKey: 'base64EncodedKey' },
redaction: { type: "remove" }
})
try {
await client.indices.create({ index: 'my_index' })
} catch (err) {
console.log(err.meta.meta.request.options.headers) // undefined
}
----

Finally, if you prefer to turn off redaction altogether, perhaps while debugging on a local developer environment, you can set the redaction type to `off`. This will revert the client to pre-8.11.0 behavior, where basic redaction is only performed during common serialization methods like `console.log` and `JSON.stringify`.

WARNING: Setting `redaction.type` to `off` is not recommended in production environments.

[source,js]
----
const { Client } = require('@elastic/elasticsearch')
const client = new Client({
cloud: { id: '<cloud-id>' },
auth: { apiKey: 'base64EncodedKey' },
redaction: { type: "off" }
})
try {
await client.indices.create({ index: 'my_index' })
} catch (err) {
console.log(err.meta.meta.request.options.headers.authorization) // the actual header value will be logged
}
----

[discrete]
==== Migrate to v8

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"zx": "^7.2.2"
},
"dependencies": {
"@elastic/transport": "^8.3.4",
"@elastic/transport": "^8.4.0",
"tslib": "^2.4.0"
},
"tap": {
Expand Down
11 changes: 9 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
BearerAuth,
Context
} from '@elastic/transport/lib/types'
import { RedactionOptions } from '@elastic/transport/lib/Transport'
import BaseConnection, { prepareHeaders } from '@elastic/transport/lib/connection/BaseConnection'
import SniffingTransport from './sniffingTransport'
import Helpers from './helpers'
Expand Down Expand Up @@ -113,6 +114,7 @@ export interface ClientOptions {
caFingerprint?: string
maxResponseSize?: number
maxCompressedResponseSize?: number
redaction?: RedactionOptions
}

export default class Client extends API {
Expand Down Expand Up @@ -186,7 +188,11 @@ export default class Client extends API {
proxy: null,
enableMetaHeader: true,
maxResponseSize: null,
maxCompressedResponseSize: null
maxCompressedResponseSize: null,
redaction: {
type: 'replace',
additionalKeys: []
}
}, opts)

if (options.caFingerprint != null && isHttpConnection(opts.node ?? opts.nodes)) {
Expand Down Expand Up @@ -259,7 +265,8 @@ export default class Client extends API {
jsonContentType: 'application/vnd.elasticsearch+json; compatible-with=8',
ndjsonContentType: 'application/vnd.elasticsearch+x-ndjson; compatible-with=8',
accept: 'application/vnd.elasticsearch+json; compatible-with=8,text/plain'
}
},
redaction: options.redaction
})

this.helpers = new Helpers({
Expand Down
12 changes: 9 additions & 3 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,11 @@ export default class Helpers {
await sleep(wait)
}
assert(response !== undefined, 'The response is undefined, please file a bug report')

const { redaction = { type: 'replace' } } = options
const errorOptions = { redaction }
if (response.statusCode === 429) {
throw new ResponseError(response)
throw new ResponseError(response, errorOptions)
}

let scroll_id = response.body._scroll_id
Expand Down Expand Up @@ -237,7 +240,7 @@ export default class Helpers {
await sleep(wait)
}
if (response.statusCode === 429) {
throw new ResponseError(response)
throw new ResponseError(response, errorOptions)
}
}

Expand Down Expand Up @@ -289,6 +292,9 @@ export default class Helpers {
} = options
reqOptions.meta = true

const { redaction = { type: 'replace' } } = reqOptions
const errorOptions = { redaction }

let stopReading = false
let stopError: Error | null = null
let timeoutRef = null
Expand Down Expand Up @@ -502,7 +508,7 @@ export default class Helpers {
// @ts-expect-error
addDocumentsGetter(result)
if (response.status != null && response.status >= 400) {
callbacks[i](new ResponseError(result), result)
callbacks[i](new ResponseError(result, errorOptions), result)
} else {
callbacks[i](null, result)
}
Expand Down

0 comments on commit d00cc52

Please sign in to comment.