mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add config properties for HTTP security headers (#97158)
This commit is contained in:
parent
b7a9b84af8
commit
978f5eca5a
31 changed files with 501 additions and 86 deletions
|
@ -23,7 +23,7 @@
|
|||
#server.publicBaseUrl: ""
|
||||
|
||||
# The maximum payload size in bytes for incoming server requests.
|
||||
#server.maxPayloadBytes: 1048576
|
||||
#server.maxPayload: 1048576
|
||||
|
||||
# The Kibana server's name. This is used for display purposes.
|
||||
#server.name: "your-hostname"
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CspConfig](./kibana-plugin-core-server.cspconfig.md) > [disableEmbedding](./kibana-plugin-core-server.cspconfig.disableembedding.md)
|
||||
|
||||
## CspConfig.disableEmbedding property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly disableEmbedding: boolean;
|
||||
```
|
|
@ -21,6 +21,7 @@ The constructor for this class is marked as internal. Third-party code should no
|
|||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [DEFAULT](./kibana-plugin-core-server.cspconfig.default.md) | <code>static</code> | <code>CspConfig</code> | |
|
||||
| [disableEmbedding](./kibana-plugin-core-server.cspconfig.disableembedding.md) | | <code>boolean</code> | |
|
||||
| [header](./kibana-plugin-core-server.cspconfig.header.md) | | <code>string</code> | |
|
||||
| [rules](./kibana-plugin-core-server.cspconfig.rules.md) | | <code>string[]</code> | |
|
||||
| [strict](./kibana-plugin-core-server.cspconfig.strict.md) | | <code>boolean</code> | |
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ICspConfig](./kibana-plugin-core-server.icspconfig.md) > [disableEmbedding](./kibana-plugin-core-server.icspconfig.disableembedding.md)
|
||||
|
||||
## ICspConfig.disableEmbedding property
|
||||
|
||||
Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled \*and\* no custom rules have been defined, a restrictive 'frame-ancestors' rule will be added to the default CSP rules.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly disableEmbedding: boolean;
|
||||
```
|
|
@ -16,6 +16,7 @@ export interface ICspConfig
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [disableEmbedding](./kibana-plugin-core-server.icspconfig.disableembedding.md) | <code>boolean</code> | Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled \*and\* no custom rules have been defined, a restrictive 'frame-ancestors' rule will be added to the default CSP rules. |
|
||||
| [header](./kibana-plugin-core-server.icspconfig.header.md) | <code>string</code> | The CSP rules in a formatted directives string for use in a <code>Content-Security-Policy</code> header. |
|
||||
| [rules](./kibana-plugin-core-server.icspconfig.rules.md) | <code>string[]</code> | The CSP rules used for Kibana. |
|
||||
| [strict](./kibana-plugin-core-server.icspconfig.strict.md) | <code>boolean</code> | Specify whether browsers that do not support CSP should be able to use Kibana. Use <code>true</code> to block and <code>false</code> to allow. |
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may cause the server to run out of memory.
|
||||
|
||||
Default value: The one set in the kibana.yml config file under the parameter `server.maxPayloadBytes`<!-- -->.
|
||||
Default value: The one set in the kibana.yml config file under the parameter `server.maxPayload`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export interface RouteConfigOptionsBody
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [accepts](./kibana-plugin-core-server.routeconfigoptionsbody.accepts.md) | <code>RouteContentType | RouteContentType[] | string | string[]</code> | A string or an array of strings with the allowed mime types for the endpoint. Use this settings to limit the set of allowed mime types. Note that allowing additional mime types not listed above will not enable them to be parsed, and if parse is true, the request will result in an error response.<!-- -->Default value: allows parsing of the following mime types: \* application/json \* application/\*+json \* application/octet-stream \* application/x-www-form-urlencoded \* multipart/form-data \* text/\* |
|
||||
| [maxBytes](./kibana-plugin-core-server.routeconfigoptionsbody.maxbytes.md) | <code>number</code> | Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may cause the server to run out of memory.<!-- -->Default value: The one set in the kibana.yml config file under the parameter <code>server.maxPayloadBytes</code>. |
|
||||
| [maxBytes](./kibana-plugin-core-server.routeconfigoptionsbody.maxbytes.md) | <code>number</code> | Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may cause the server to run out of memory.<!-- -->Default value: The one set in the kibana.yml config file under the parameter <code>server.maxPayload</code>. |
|
||||
| [output](./kibana-plugin-core-server.routeconfigoptionsbody.output.md) | <code>typeof validBodyOutput[number]</code> | The processed payload format. The value must be one of: \* 'data' - the incoming payload is read fully into memory. If parse is true, the payload is parsed (JSON, form-decoded, multipart) based on the 'Content-Type' header. If parse is false, a raw Buffer is returned. \* 'stream' - the incoming payload is made available via a Stream.Readable interface. If the payload is 'multipart/form-data' and parse is true, field values are presented as text while files are provided as streams. File streams from a 'multipart/form-data' upload will also have a hapi property containing the filename and headers properties. Note that payload streams for multipart payloads are a synthetic interface created on top of the entire multipart content loaded into memory. To avoid loading large multipart payloads into memory, set parse to false and handle the multipart payload in the handler using a streaming parser (e.g. pez).<!-- -->Default value: 'data', unless no validation.body is provided in the route definition. In that case the default is 'stream' to alleviate memory pressure. |
|
||||
| [parse](./kibana-plugin-core-server.routeconfigoptionsbody.parse.md) | <code>boolean | 'gunzip'</code> | Determines if the incoming payload is processed or presented raw. Available values: \* true - if the request 'Content-Type' matches the allowed mime types set by allow (for the whole payload as well as parts), the payload is converted into an object when possible. If the format is unknown, a Bad Request (400) error response is sent. Any known content encoding is decoded. \* false - the raw payload is returned unmodified. \* 'gunzip' - the raw payload is returned unmodified after any known content encoding is decoded.<!-- -->Default value: true, unless no validation.body is provided in the route definition. In that case the default is false to alleviate memory pressure. |
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ image::maps/images/inspector.png[]
|
|||
** Ensure your geospatial field is searchable and aggregatable.
|
||||
** If your geospatial field type does not match your Elasticsearch mapping, click the *Refresh* button to refresh the field list from Elasticsearch.
|
||||
* Index patterns with thousands of fields can exceed the default maximum payload size.
|
||||
Increase <<settings, `server.maxPayloadBytes`>> for large index patterns.
|
||||
Increase <<settings, `server.maxPayload`>> for large index patterns.
|
||||
|
||||
[float]
|
||||
==== Features are not displayed
|
||||
|
|
|
@ -25,12 +25,12 @@ which may cause a delay before pages start being served.
|
|||
Set to `false` to disable Console. *Default: `true`*
|
||||
|
||||
| `cpu.cgroup.path.override:`
|
||||
| deprecated:[7.10.0,"This setting will no longer be supported as of 8.0."]
|
||||
| deprecated:[7.10.0,"In 8.0 and later, this setting will no longer be supported."]
|
||||
This setting has been renamed to
|
||||
<<ops-cGroupOverrides-cpuPath,`ops.cGroupOverrides.cpuPath`>>.
|
||||
|
||||
| `cpuacct.cgroup.path.override:`
|
||||
| deprecated:[7.10.0,"This setting will no longer be supported as of 8.0."]
|
||||
| deprecated:[7.10.0,"In 8.0 and later, this setting will no longer be supported."]
|
||||
This setting has been renamed to
|
||||
<<ops-cGroupOverrides-cpuAcctPath, `ops.cGroupOverrides.cpuAcctPath`>>.
|
||||
|
||||
|
@ -473,7 +473,7 @@ confident your server can hold this many objects in memory.
|
|||
| The maximum byte size of a saved objects import that the {kib} server will accept.
|
||||
This setting exists to prevent the {kib} server from runnning out of memory when handling
|
||||
a large import payload. Note that this setting overrides the more general
|
||||
<<server-maxPayloadBytes, `server.maxPayloadBytes`>> for saved object imports only.
|
||||
<<server-maxPayload, `server.maxPayload`>> for saved object imports only.
|
||||
*Default: `26214400`*
|
||||
|
||||
|[[server-basePath]] `server.basePath:`
|
||||
|
@ -504,6 +504,55 @@ deprecation warning at startup. This setting cannot end in a slash (`/`).
|
|||
proxy sitting in front of it. This determines whether HTTP compression may be used for responses, based on the request `Referer` header.
|
||||
This setting may not be used when <<server-compression, `server.compression.enabled`>> is set to `false`. *Default: `none`*
|
||||
|
||||
|
||||
a| [[server-securityResponseHeaders-strictTransportSecurity]]
|
||||
----
|
||||
server.securityResponseHeaders:
|
||||
strictTransportSecurity:
|
||||
----
|
||||
| Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security[`Strict-Transport-Security`]
|
||||
header is used in all responses to the client from the {kib} server, and specifies what value is used. Allowed values are any text value or
|
||||
`null`. To disable, set to `null`. *Default:* `null`
|
||||
|
||||
a| [[server-securityResponseHeaders-xContentTypeOptions]]
|
||||
----
|
||||
server.securityResponseHeaders:
|
||||
xContentTypeOptions:
|
||||
----
|
||||
| Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options[`X-Content-Type-Options`] header is
|
||||
used in all responses to the client from the {kib} server, and specifies what value is used. Allowed values are `nosniff` or `null`. To
|
||||
disable, set to `null`. *Default:* `"nosniff"`
|
||||
|
||||
a| [[server-securityResponseHeaders-referrerPolicy]]
|
||||
----
|
||||
server.securityResponseHeaders:
|
||||
referrerPolicy:
|
||||
----
|
||||
| Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy[`Referrer-Policy`] header is used in all
|
||||
responses to the client from the {kib} server, and specifies what value is used. Allowed values are `no-referrer`,
|
||||
`no-referrer-when-downgrade`, `origin`, `origin-when-cross-origin`, `same-origin`, `strict-origin`, `strict-origin-when-cross-origin`,
|
||||
`unsafe-url`, or `null`. To disable, set to `null`. *Default:* `"no-referrer-when-downgrade"`
|
||||
|
||||
a| [[server-securityResponseHeaders-permissionsPolicy]]
|
||||
----
|
||||
server.securityResponseHeaders:
|
||||
permissionsPolicy:
|
||||
----
|
||||
| experimental[] Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy[`Permissions-Policy`] header
|
||||
is used in all responses to the client from the {kib} server, and specifies what value is used. Allowed values are any text value or `null`.
|
||||
To disable, set to `null`. *Default:* `null`
|
||||
|
||||
a| [[server-securityResponseHeaders-disableEmbedding]]
|
||||
----
|
||||
server.securityResponseHeaders:
|
||||
disableEmbedding:
|
||||
----
|
||||
| Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy[`Content-Security-Policy`] and
|
||||
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options[`X-Frame-Options`] headers are configured to disable embedding
|
||||
{kib} in other webpages using iframes. When set to `true`, secure headers are used to disable embedding, which adds the `frame-ancestors:
|
||||
'self'` directive to the `Content-Security-Policy` response header (if you are using the default CSP rules), and adds the `X-Frame-Options:
|
||||
SAMEORIGIN` response header. *Default:* `false`
|
||||
|
||||
| `server.customResponseHeaders:` {ess-icon}
|
||||
| Header names and values to
|
||||
send on all responses to the client from the {kib} server. *Default: `{}`*
|
||||
|
@ -517,6 +566,10 @@ back end server. To allow remote users to connect, set the value to the IP addre
|
|||
the <<server-socketTimeout, `server.socketTimeout`>> counter. *Default: `"120000"`*
|
||||
|
||||
|[[server-maxPayloadBytes]] `server.maxPayloadBytes:`
|
||||
| deprecated:[7.13.0,"In 8.0 and later, this setting will no longer be supported."]
|
||||
This setting has been renamed to <<server-maxPayload,`server.maxPayload`>>.
|
||||
|
||||
|[[server-maxPayload]] `server.maxPayload:`
|
||||
| The maximum payload size in bytes
|
||||
for incoming server requests. *Default: `1048576`*
|
||||
|
||||
|
|
|
@ -95,6 +95,13 @@ const createStartContractMock = () => {
|
|||
supportedProtocols: ['TLSv1.1', 'TLSv1.2'],
|
||||
truststoreConfigured: false,
|
||||
},
|
||||
securityResponseHeaders: {
|
||||
strictTransportSecurity: 'NULL', // `null` values are coalesced to `"NULL"` strings
|
||||
xContentTypeOptions: 'nosniff',
|
||||
referrerPolicy: 'no-referrer-when-downgrade',
|
||||
permissionsPolicyConfigured: false,
|
||||
disableEmbedding: false,
|
||||
},
|
||||
xsrf: {
|
||||
disableProtection: false,
|
||||
allowlistConfigured: false,
|
||||
|
|
|
@ -187,6 +187,13 @@ describe('CoreUsageDataService', () => {
|
|||
"ipAllowlistConfigured": false,
|
||||
},
|
||||
"rewriteBasePath": false,
|
||||
"securityResponseHeaders": Object {
|
||||
"disableEmbedding": false,
|
||||
"permissionsPolicyConfigured": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"strictTransportSecurity": "NULL",
|
||||
"xContentTypeOptions": "nosniff",
|
||||
},
|
||||
"socketTimeout": 120000,
|
||||
"ssl": Object {
|
||||
"certificateAuthoritiesConfigured": false,
|
||||
|
|
|
@ -225,6 +225,16 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
|
|||
keystoreConfigured: isConfigured.record(http.ssl.keystore),
|
||||
truststoreConfigured: isConfigured.record(http.ssl.truststore),
|
||||
},
|
||||
securityResponseHeaders: {
|
||||
// ES does not index `null` and it cannot be searched, so we coalesce these to string values instead
|
||||
strictTransportSecurity: http.securityResponseHeaders.strictTransportSecurity ?? 'NULL',
|
||||
xContentTypeOptions: http.securityResponseHeaders.xContentTypeOptions ?? 'NULL',
|
||||
referrerPolicy: http.securityResponseHeaders.referrerPolicy ?? 'NULL',
|
||||
permissionsPolicyConfigured: isConfigured.string(
|
||||
http.securityResponseHeaders.permissionsPolicy ?? undefined
|
||||
),
|
||||
disableEmbedding: http.securityResponseHeaders.disableEmbedding,
|
||||
},
|
||||
},
|
||||
|
||||
logging: {
|
||||
|
|
|
@ -212,6 +212,13 @@ export interface CoreConfigUsageData {
|
|||
supportedProtocols: string[];
|
||||
clientAuthentication: 'none' | 'optional' | 'required';
|
||||
};
|
||||
securityResponseHeaders: {
|
||||
strictTransportSecurity: string;
|
||||
xContentTypeOptions: string;
|
||||
referrerPolicy: string;
|
||||
permissionsPolicyConfigured: boolean;
|
||||
disableEmbedding: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
logging: {
|
||||
|
|
19
src/core/server/csp/config.test.ts
Normal file
19
src/core/server/csp/config.test.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { config } from './config';
|
||||
|
||||
describe('config.validate()', () => {
|
||||
test(`does not allow "disableEmbedding" to be set to true`, () => {
|
||||
// This is intentionally not editable in the raw CSP config.
|
||||
// Users should set `server.securityResponseHeaders.disableEmbedding` to control this config property.
|
||||
expect(() => config.schema.validate({ disableEmbedding: true })).toThrowError(
|
||||
'[disableEmbedding.0]: expected value to equal [false]'
|
||||
);
|
||||
});
|
||||
});
|
|
@ -27,5 +27,8 @@ export const config = {
|
|||
}),
|
||||
strict: schema.boolean({ defaultValue: true }),
|
||||
warnLegacyBrowsers: schema.boolean({ defaultValue: true }),
|
||||
disableEmbedding: schema.oneOf([schema.literal<boolean>(false)], { defaultValue: false }),
|
||||
}),
|
||||
};
|
||||
|
||||
export const FRAME_ANCESTORS_RULE = `frame-ancestors 'self'`; // only used by CspConfig when embedding is disabled
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CspConfig } from '.';
|
||||
import { CspConfig } from './csp_config';
|
||||
import { FRAME_ANCESTORS_RULE } from './config';
|
||||
|
||||
// CSP rules aren't strictly additive, so any change can potentially expand or
|
||||
// restrict the policy in a way we consider a breaking change. For that reason,
|
||||
|
@ -25,6 +26,7 @@ describe('CspConfig', () => {
|
|||
test('DEFAULT', () => {
|
||||
expect(CspConfig.DEFAULT).toMatchInlineSnapshot(`
|
||||
CspConfig {
|
||||
"disableEmbedding": false,
|
||||
"header": "script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'",
|
||||
"rules": Array [
|
||||
"script-src 'unsafe-eval' 'self'",
|
||||
|
@ -38,49 +40,51 @@ describe('CspConfig', () => {
|
|||
});
|
||||
|
||||
test('defaults from config', () => {
|
||||
expect(new CspConfig()).toMatchInlineSnapshot(`
|
||||
CspConfig {
|
||||
"header": "script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'",
|
||||
"rules": Array [
|
||||
"script-src 'unsafe-eval' 'self'",
|
||||
"worker-src blob: 'self'",
|
||||
"style-src 'unsafe-inline' 'self'",
|
||||
],
|
||||
"strict": true,
|
||||
"warnLegacyBrowsers": true,
|
||||
}
|
||||
`);
|
||||
expect(new CspConfig()).toEqual(CspConfig.DEFAULT);
|
||||
});
|
||||
|
||||
test('creates from partial config', () => {
|
||||
expect(new CspConfig({ strict: false, warnLegacyBrowsers: false })).toMatchInlineSnapshot(`
|
||||
CspConfig {
|
||||
"header": "script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'",
|
||||
"rules": Array [
|
||||
"script-src 'unsafe-eval' 'self'",
|
||||
"worker-src blob: 'self'",
|
||||
"style-src 'unsafe-inline' 'self'",
|
||||
],
|
||||
"strict": false,
|
||||
"warnLegacyBrowsers": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
describe('partial config', () => {
|
||||
test('allows "rules" to be set and changes header', () => {
|
||||
const rules = ['foo', 'bar'];
|
||||
const config = new CspConfig({ rules });
|
||||
expect(config.rules).toEqual(rules);
|
||||
expect(config.header).toMatchInlineSnapshot(`"foo; bar"`);
|
||||
});
|
||||
|
||||
test('computes header from rules', () => {
|
||||
const cspConfig = new CspConfig({ rules: ['alpha', 'beta', 'gamma'] });
|
||||
test('allows "strict" to be set', () => {
|
||||
const config = new CspConfig({ strict: false });
|
||||
expect(config.strict).toEqual(false);
|
||||
expect(config.strict).not.toEqual(CspConfig.DEFAULT.strict);
|
||||
});
|
||||
|
||||
expect(cspConfig).toMatchInlineSnapshot(`
|
||||
CspConfig {
|
||||
"header": "alpha; beta; gamma",
|
||||
"rules": Array [
|
||||
"alpha",
|
||||
"beta",
|
||||
"gamma",
|
||||
],
|
||||
"strict": true,
|
||||
"warnLegacyBrowsers": true,
|
||||
}
|
||||
`);
|
||||
test('allows "warnLegacyBrowsers" to be set', () => {
|
||||
const warnLegacyBrowsers = false;
|
||||
const config = new CspConfig({ warnLegacyBrowsers });
|
||||
expect(config.warnLegacyBrowsers).toEqual(warnLegacyBrowsers);
|
||||
expect(config.warnLegacyBrowsers).not.toEqual(CspConfig.DEFAULT.warnLegacyBrowsers);
|
||||
});
|
||||
|
||||
describe('allows "disableEmbedding" to be set', () => {
|
||||
const disableEmbedding = true;
|
||||
|
||||
test('and changes rules/header if custom rules are not defined', () => {
|
||||
const config = new CspConfig({ disableEmbedding });
|
||||
expect(config.disableEmbedding).toEqual(disableEmbedding);
|
||||
expect(config.disableEmbedding).not.toEqual(CspConfig.DEFAULT.disableEmbedding);
|
||||
expect(config.rules).toEqual(expect.arrayContaining([FRAME_ANCESTORS_RULE]));
|
||||
expect(config.header).toMatchInlineSnapshot(
|
||||
`"script-src 'unsafe-eval' 'self'; worker-src blob: 'self'; style-src 'unsafe-inline' 'self'; frame-ancestors 'self'"`
|
||||
);
|
||||
});
|
||||
|
||||
test('and does not change rules/header if custom rules are defined', () => {
|
||||
const rules = ['foo', 'bar'];
|
||||
const config = new CspConfig({ disableEmbedding, rules });
|
||||
expect(config.disableEmbedding).toEqual(disableEmbedding);
|
||||
expect(config.disableEmbedding).not.toEqual(CspConfig.DEFAULT.disableEmbedding);
|
||||
expect(config.rules).toEqual(rules);
|
||||
expect(config.header).toMatchInlineSnapshot(`"foo; bar"`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { config } from './config';
|
||||
import { config, FRAME_ANCESTORS_RULE } from './config';
|
||||
|
||||
const DEFAULT_CONFIG = Object.freeze(config.schema.validate({}));
|
||||
|
||||
|
@ -32,6 +32,12 @@ export interface ICspConfig {
|
|||
*/
|
||||
readonly warnLegacyBrowsers: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not embedding (using iframes) should be allowed by the CSP. If embedding is disabled *and* no custom rules have been
|
||||
* defined, a restrictive 'frame-ancestors' rule will be added to the default CSP rules.
|
||||
*/
|
||||
readonly disableEmbedding: boolean;
|
||||
|
||||
/**
|
||||
* The CSP rules in a formatted directives string for use
|
||||
* in a `Content-Security-Policy` header.
|
||||
|
@ -49,6 +55,7 @@ export class CspConfig implements ICspConfig {
|
|||
public readonly rules: string[];
|
||||
public readonly strict: boolean;
|
||||
public readonly warnLegacyBrowsers: boolean;
|
||||
public readonly disableEmbedding: boolean;
|
||||
public readonly header: string;
|
||||
|
||||
/**
|
||||
|
@ -58,9 +65,13 @@ export class CspConfig implements ICspConfig {
|
|||
constructor(rawCspConfig: Partial<Omit<ICspConfig, 'header'>> = {}) {
|
||||
const source = { ...DEFAULT_CONFIG, ...rawCspConfig };
|
||||
|
||||
this.rules = source.rules;
|
||||
this.rules = [...source.rules];
|
||||
this.strict = source.strict;
|
||||
this.warnLegacyBrowsers = source.warnLegacyBrowsers;
|
||||
this.header = source.rules.join('; ');
|
||||
this.disableEmbedding = source.disableEmbedding;
|
||||
if (!rawCspConfig.rules?.length && source.disableEmbedding) {
|
||||
this.rules.push(FRAME_ANCESTORS_RULE);
|
||||
}
|
||||
this.header = this.rules.join('; ');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,13 @@ Object {
|
|||
"ipAllowlist": Array [],
|
||||
},
|
||||
"rewriteBasePath": false,
|
||||
"securityResponseHeaders": Object {
|
||||
"disableEmbedding": false,
|
||||
"permissionsPolicy": null,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"strictTransportSecurity": null,
|
||||
"xContentTypeOptions": "nosniff",
|
||||
},
|
||||
"socketTimeout": 120000,
|
||||
"ssl": Object {
|
||||
"cipherSuites": Array [
|
||||
|
|
|
@ -14,6 +14,10 @@ import url from 'url';
|
|||
import { ServiceConfigDescriptor } from '../internal_types';
|
||||
import { CspConfigType, CspConfig, ICspConfig } from '../csp';
|
||||
import { ExternalUrlConfig, IExternalUrlConfig } from '../external_url';
|
||||
import {
|
||||
securityResponseHeadersSchema,
|
||||
parseRawSecurityResponseHeadersConfig,
|
||||
} from './security_response_headers_config';
|
||||
|
||||
const validBasePathRegex = /^\/.*[^\/]$/;
|
||||
const uuidRegexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||
|
@ -53,6 +57,7 @@ const configSchema = schema.object(
|
|||
},
|
||||
}
|
||||
),
|
||||
securityResponseHeaders: securityResponseHeadersSchema,
|
||||
customResponseHeaders: schema.recordOf(schema.string(), schema.any(), {
|
||||
defaultValue: {},
|
||||
}),
|
||||
|
@ -171,6 +176,7 @@ export class HttpConfig implements IHttpConfig {
|
|||
allowCredentials: boolean;
|
||||
allowOrigin: string[];
|
||||
};
|
||||
public securityResponseHeaders: Record<string, string | string[]>;
|
||||
public customResponseHeaders: Record<string, string | string[]>;
|
||||
public maxPayload: ByteSizeValue;
|
||||
public basePath?: string;
|
||||
|
@ -195,6 +201,10 @@ export class HttpConfig implements IHttpConfig {
|
|||
this.host = rawHttpConfig.host;
|
||||
this.port = rawHttpConfig.port;
|
||||
this.cors = rawHttpConfig.cors;
|
||||
const { securityResponseHeaders, disableEmbedding } = parseRawSecurityResponseHeadersConfig(
|
||||
rawHttpConfig.securityResponseHeaders
|
||||
);
|
||||
this.securityResponseHeaders = securityResponseHeaders;
|
||||
this.customResponseHeaders = Object.entries(rawHttpConfig.customResponseHeaders ?? {}).reduce(
|
||||
(headers, [key, value]) => {
|
||||
return {
|
||||
|
@ -213,7 +223,7 @@ export class HttpConfig implements IHttpConfig {
|
|||
this.rewriteBasePath = rawHttpConfig.rewriteBasePath;
|
||||
this.ssl = new SslConfig(rawHttpConfig.ssl || {});
|
||||
this.compression = rawHttpConfig.compression;
|
||||
this.csp = new CspConfig(rawCspConfig);
|
||||
this.csp = new CspConfig({ ...rawCspConfig, disableEmbedding });
|
||||
this.externalUrl = rawExternalUrlConfig;
|
||||
this.xsrf = rawHttpConfig.xsrf;
|
||||
this.requestId = rawHttpConfig.requestId;
|
||||
|
|
|
@ -53,8 +53,16 @@ describe('core lifecycle handlers', () => {
|
|||
},
|
||||
compression: { enabled: true },
|
||||
name: kibanaName,
|
||||
securityResponseHeaders: {
|
||||
// reflects default config
|
||||
strictTransportSecurity: null,
|
||||
xContentTypeOptions: 'nosniff',
|
||||
referrerPolicy: 'strict-origin-when-cross-origin',
|
||||
permissionsPolicy: null,
|
||||
},
|
||||
customResponseHeaders: {
|
||||
'some-header': 'some-value',
|
||||
'referrer-policy': 'strict-origin', // overrides a header that is defined by securityResponseHeaders
|
||||
},
|
||||
xsrf: { disableProtection: false, allowlist: [allowlistedTestPath] },
|
||||
requestId: {
|
||||
|
@ -117,6 +125,13 @@ describe('core lifecycle handlers', () => {
|
|||
const testRoute = '/custom_headers/test/route';
|
||||
const testErrorRoute = '/custom_headers/test/error_route';
|
||||
|
||||
const expectedHeaders = {
|
||||
[nameHeader]: kibanaName,
|
||||
'x-content-type-options': 'nosniff',
|
||||
'referrer-policy': 'strict-origin',
|
||||
'some-header': 'some-value',
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
router.get({ path: testRoute, validate: false }, (context, req, res) => {
|
||||
return res.ok({ body: 'ok' });
|
||||
|
@ -127,36 +142,16 @@ describe('core lifecycle handlers', () => {
|
|||
await server.start();
|
||||
});
|
||||
|
||||
it('adds the kbn-name header', async () => {
|
||||
it('adds the expected headers in case of success', async () => {
|
||||
const result = await supertest(innerServer.listener).get(testRoute).expect(200, 'ok');
|
||||
const headers = result.header as Record<string, string>;
|
||||
expect(headers).toEqual(
|
||||
expect.objectContaining({
|
||||
[nameHeader]: kibanaName,
|
||||
})
|
||||
);
|
||||
expect(headers).toEqual(expect.objectContaining(expectedHeaders));
|
||||
});
|
||||
|
||||
it('adds the kbn-name header in case of error', async () => {
|
||||
it('adds the expected headers in case of error', async () => {
|
||||
const result = await supertest(innerServer.listener).get(testErrorRoute).expect(400);
|
||||
const headers = result.header as Record<string, string>;
|
||||
expect(headers).toEqual(
|
||||
expect.objectContaining({
|
||||
[nameHeader]: kibanaName,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('adds the custom headers', async () => {
|
||||
const result = await supertest(innerServer.listener).get(testRoute).expect(200, 'ok');
|
||||
const headers = result.header as Record<string, string>;
|
||||
expect(headers).toEqual(expect.objectContaining({ 'some-header': 'some-value' }));
|
||||
});
|
||||
|
||||
it('adds the custom headers in case of error', async () => {
|
||||
const result = await supertest(innerServer.listener).get(testErrorRoute).expect(400);
|
||||
const headers = result.header as Record<string, string>;
|
||||
expect(headers).toEqual(expect.objectContaining({ 'some-header': 'some-value' }));
|
||||
expect(headers).toEqual(expect.objectContaining(expectedHeaders));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -241,12 +241,15 @@ describe('customHeaders pre-response handler', () => {
|
|||
expect(toolkit.next).toHaveBeenCalledWith({ headers: { 'kbn-name': 'my-server-name' } });
|
||||
});
|
||||
|
||||
it('adds the custom headers defined in the configuration', () => {
|
||||
it('adds the security headers and custom headers defined in the configuration', () => {
|
||||
const config = createConfig({
|
||||
name: 'my-server-name',
|
||||
customResponseHeaders: {
|
||||
securityResponseHeaders: {
|
||||
headerA: 'value-A',
|
||||
headerB: 'value-B',
|
||||
headerB: 'value-B', // will be overridden by the custom response header below
|
||||
},
|
||||
customResponseHeaders: {
|
||||
headerB: 'x',
|
||||
},
|
||||
});
|
||||
const handler = createCustomHeadersPreResponseHandler(config as HttpConfig);
|
||||
|
@ -258,7 +261,7 @@ describe('customHeaders pre-response handler', () => {
|
|||
headers: {
|
||||
'kbn-name': 'my-server-name',
|
||||
headerA: 'value-A',
|
||||
headerB: 'value-B',
|
||||
headerB: 'x',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -62,12 +62,12 @@ export const createVersionCheckPostAuthHandler = (kibanaVersion: string): OnPost
|
|||
};
|
||||
|
||||
export const createCustomHeadersPreResponseHandler = (config: HttpConfig): OnPreResponseHandler => {
|
||||
const serverName = config.name;
|
||||
const customHeaders = config.customResponseHeaders;
|
||||
const { name: serverName, securityResponseHeaders, customResponseHeaders } = config;
|
||||
|
||||
return (request, response, toolkit) => {
|
||||
const additionalHeaders = {
|
||||
...customHeaders,
|
||||
...securityResponseHeaders,
|
||||
...customResponseHeaders,
|
||||
[KIBANA_NAME_HEADER]: serverName,
|
||||
};
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ export interface RouteConfigOptionsBody {
|
|||
/**
|
||||
* Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may cause the server to run out of memory.
|
||||
*
|
||||
* Default value: The one set in the kibana.yml config file under the parameter `server.maxPayloadBytes`.
|
||||
* Default value: The one set in the kibana.yml config file under the parameter `server.maxPayload`.
|
||||
*/
|
||||
maxBytes?: number;
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
securityResponseHeadersSchema as schema,
|
||||
parseRawSecurityResponseHeadersConfig as parse,
|
||||
} from './security_response_headers_config';
|
||||
|
||||
describe('parseRawSecurityResponseHeadersConfig', () => {
|
||||
it('returns default values', () => {
|
||||
const config = schema.validate({});
|
||||
const result = parse(config);
|
||||
expect(result.disableEmbedding).toBe(false);
|
||||
expect(result.securityResponseHeaders).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"Referrer-Policy": "no-referrer-when-downgrade",
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
describe('strictTransportSecurity', () => {
|
||||
it('a custom value results in the expected Strict-Transport-Security header', () => {
|
||||
const strictTransportSecurity = 'max-age=31536000; includeSubDomains';
|
||||
const config = schema.validate({ strictTransportSecurity });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['Strict-Transport-Security']).toEqual(
|
||||
strictTransportSecurity
|
||||
);
|
||||
});
|
||||
|
||||
it('a null value removes the Strict-Transport-Security header', () => {
|
||||
const config = schema.validate({ strictTransportSecurity: null });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['Strict-Transport-Security']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('xContentTypeOptions', () => {
|
||||
it('a custom value results in the expected X-Content-Type-Options header', () => {
|
||||
const xContentTypeOptions = 'nosniff'; // there is no other valid value to test with
|
||||
const config = schema.validate({ xContentTypeOptions });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['X-Content-Type-Options']).toEqual(xContentTypeOptions);
|
||||
});
|
||||
|
||||
it('a null value removes the X-Content-Type-Options header', () => {
|
||||
const config = schema.validate({ xContentTypeOptions: null });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['X-Content-Type-Options']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('referrerPolicy', () => {
|
||||
it('a custom value results in the expected Referrer-Policy header', () => {
|
||||
const referrerPolicy = 'strict-origin-when-cross-origin';
|
||||
const config = schema.validate({ referrerPolicy });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['Referrer-Policy']).toEqual(referrerPolicy);
|
||||
});
|
||||
|
||||
it('a null value removes the Referrer-Policy header', () => {
|
||||
const config = schema.validate({ referrerPolicy: null });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['Referrer-Policy']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('permissionsPolicy', () => {
|
||||
it('a custom value results in the expected Permissions-Policy header', () => {
|
||||
const permissionsPolicy = 'display-capture=(self)';
|
||||
const config = schema.validate({ permissionsPolicy });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['Permissions-Policy']).toEqual(permissionsPolicy);
|
||||
});
|
||||
|
||||
it('a null value removes the Permissions-Policy header', () => {
|
||||
const config = schema.validate({ permissionsPolicy: null });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['Permissions-Policy']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('disableEmbedding', () => {
|
||||
it('a true value results in the expected X-Frame-Options header and expected disableEmbedding result value', () => {
|
||||
const config = schema.validate({ disableEmbedding: true });
|
||||
const result = parse(config);
|
||||
expect(result.securityResponseHeaders['X-Frame-Options']).toMatchInlineSnapshot(
|
||||
`"SAMEORIGIN"`
|
||||
);
|
||||
expect(result.disableEmbedding).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
72
src/core/server/http/security_response_headers_config.ts
Normal file
72
src/core/server/http/security_response_headers_config.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
|
||||
export const securityResponseHeadersSchema = schema.object({
|
||||
strictTransportSecurity: schema.oneOf([schema.string(), schema.literal(null)], {
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
||||
defaultValue: null,
|
||||
}),
|
||||
xContentTypeOptions: schema.oneOf([schema.literal('nosniff'), schema.literal(null)], {
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
|
||||
defaultValue: 'nosniff',
|
||||
}),
|
||||
referrerPolicy: schema.oneOf(
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
|
||||
[
|
||||
schema.literal('no-referrer'),
|
||||
schema.literal('no-referrer-when-downgrade'),
|
||||
schema.literal('origin'),
|
||||
schema.literal('origin-when-cross-origin'),
|
||||
schema.literal('same-origin'),
|
||||
schema.literal('strict-origin'),
|
||||
schema.literal('strict-origin-when-cross-origin'),
|
||||
schema.literal('unsafe-url'),
|
||||
schema.literal(null),
|
||||
],
|
||||
{ defaultValue: 'no-referrer-when-downgrade' }
|
||||
),
|
||||
permissionsPolicy: schema.oneOf([schema.string(), schema.literal(null)], {
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
|
||||
// Note: Feature-Policy is superseded by Permissions-Policy; the link above is temporary until MDN releases an updated page
|
||||
defaultValue: null,
|
||||
}),
|
||||
disableEmbedding: schema.boolean({ defaultValue: false }), // is used to control X-Frame-Options and CSP headers
|
||||
});
|
||||
|
||||
/**
|
||||
* Parses raw security header config info, returning an object with the appropriate header keys and values.
|
||||
*
|
||||
* @param raw
|
||||
* @internal
|
||||
*/
|
||||
export function parseRawSecurityResponseHeadersConfig(
|
||||
raw: TypeOf<typeof securityResponseHeadersSchema>
|
||||
) {
|
||||
const securityResponseHeaders: Record<string, string | string[]> = {};
|
||||
const { disableEmbedding } = raw;
|
||||
|
||||
if (raw.strictTransportSecurity) {
|
||||
securityResponseHeaders['Strict-Transport-Security'] = raw.strictTransportSecurity;
|
||||
}
|
||||
if (raw.xContentTypeOptions) {
|
||||
securityResponseHeaders['X-Content-Type-Options'] = raw.xContentTypeOptions;
|
||||
}
|
||||
if (raw.referrerPolicy) {
|
||||
securityResponseHeaders['Referrer-Policy'] = raw.referrerPolicy;
|
||||
}
|
||||
if (raw.permissionsPolicy) {
|
||||
securityResponseHeaders['Permissions-Policy'] = raw.permissionsPolicy;
|
||||
}
|
||||
if (disableEmbedding) {
|
||||
securityResponseHeaders['X-Frame-Options'] = 'SAMEORIGIN';
|
||||
}
|
||||
|
||||
return { securityResponseHeaders, disableEmbedding };
|
||||
}
|
|
@ -38,6 +38,7 @@ configService.atPath.mockImplementation((path) => {
|
|||
disableProtection: true,
|
||||
allowlist: [],
|
||||
},
|
||||
securityResponseHeaders: {},
|
||||
customResponseHeaders: {},
|
||||
requestId: {
|
||||
allowFromAnyIp: true,
|
||||
|
|
|
@ -442,6 +442,13 @@ export interface CoreConfigUsageData {
|
|||
supportedProtocols: string[];
|
||||
clientAuthentication: 'none' | 'optional' | 'required';
|
||||
};
|
||||
securityResponseHeaders: {
|
||||
strictTransportSecurity: string;
|
||||
xContentTypeOptions: string;
|
||||
referrerPolicy: string;
|
||||
permissionsPolicyConfigured: boolean;
|
||||
disableEmbedding: boolean;
|
||||
};
|
||||
};
|
||||
// (undocumented)
|
||||
logging: {
|
||||
|
@ -757,6 +764,8 @@ export class CspConfig implements ICspConfig {
|
|||
// (undocumented)
|
||||
static readonly DEFAULT: CspConfig;
|
||||
// (undocumented)
|
||||
readonly disableEmbedding: boolean;
|
||||
// (undocumented)
|
||||
readonly header: string;
|
||||
// (undocumented)
|
||||
readonly rules: string[];
|
||||
|
@ -1113,6 +1122,7 @@ export type IContextProvider<Context extends RequestHandlerContext, ContextName
|
|||
|
||||
// @public
|
||||
export interface ICspConfig {
|
||||
readonly disableEmbedding: boolean;
|
||||
readonly header: string;
|
||||
readonly rules: string[];
|
||||
readonly strict: boolean;
|
||||
|
|
|
@ -116,12 +116,17 @@ kibana_vars=(
|
|||
server.compression.referrerWhitelist
|
||||
server.cors
|
||||
server.cors.origin
|
||||
server.customResponseHeaders
|
||||
server.securityResponseHeaders.strictTransportSecurity
|
||||
server.securityResponseHeaders.xContentTypeOptions
|
||||
server.securityResponseHeaders.referrerPolicy
|
||||
server.securityResponseHeaders.permissionsPolicy
|
||||
server.securityResponseHeaders.disableEmbedding
|
||||
server.customResponseHeaders
|
||||
server.defaultRoute
|
||||
server.host
|
||||
server.keepAliveTimeout
|
||||
server.maxPayloadBytes
|
||||
server.maxPayload
|
||||
server.name
|
||||
server.port
|
||||
server.rewriteBasePath
|
||||
|
|
|
@ -238,6 +238,38 @@ export function getCoreUsageCollector(
|
|||
},
|
||||
},
|
||||
},
|
||||
securityResponseHeaders: {
|
||||
strictTransportSecurity: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'The strictTransportSecurity response header, "NULL" if disabled.',
|
||||
},
|
||||
},
|
||||
xContentTypeOptions: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'The xContentTypeOptions response header, "NULL" if disabled.',
|
||||
},
|
||||
},
|
||||
referrerPolicy: {
|
||||
type: 'keyword',
|
||||
_meta: { description: 'The referrerPolicy response header, "NULL" if disabled.' },
|
||||
},
|
||||
permissionsPolicyConfigured: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
description:
|
||||
'Indicates if the permissionsPolicy response header has been configured.',
|
||||
},
|
||||
},
|
||||
disableEmbedding: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
description:
|
||||
'Indicates if security headers to disable embedding have been configured.',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
logging: {
|
||||
|
|
|
@ -6742,6 +6742,40 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityResponseHeaders": {
|
||||
"properties": {
|
||||
"strictTransportSecurity": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "The strictTransportSecurity response header, \"NULL\" if disabled."
|
||||
}
|
||||
},
|
||||
"xContentTypeOptions": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "The xContentTypeOptions response header, \"NULL\" if disabled."
|
||||
}
|
||||
},
|
||||
"referrerPolicy": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "The referrerPolicy response header, \"NULL\" if disabled."
|
||||
}
|
||||
},
|
||||
"permissionsPolicyConfigured": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "Indicates if the permissionsPolicy response header has been configured."
|
||||
}
|
||||
},
|
||||
"disableEmbedding": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "Indicates if security headers to disable embedding have been configured."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -50,7 +50,7 @@ export default function () {
|
|||
// These are *very* important to have them pointing to staging
|
||||
'--telemetry.url=https://telemetry-staging.elastic.co/xpack/v2/send',
|
||||
'--telemetry.optInStatusUrl=https://telemetry-staging.elastic.co/opt_in_status/v2/send',
|
||||
`--server.maxPayloadBytes=1679958`,
|
||||
`--server.maxPayload=1679958`,
|
||||
// newsfeed mock service
|
||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'newsfeed')}`,
|
||||
`--newsfeed.service.urlRoot=${servers.kibana.protocol}://${servers.kibana.hostname}:${servers.kibana.port}`,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue