Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable API protection in serverless #162149

Merged
merged 12 commits into from
Aug 4, 2023
Merged

Enable API protection in serverless #162149

merged 12 commits into from
Aug 4, 2023

Conversation

TinaHeiligers
Copy link
Contributor

@TinaHeiligers TinaHeiligers commented Jul 18, 2023

fix #162117
restrictInternalApis set to true enforces the restriction to internal API's. The restriction is only enabled in serverless.

What this means to plugin authors and stack components :

Access to internal Kibana HTTP API endpoints is restricted in serverless and calls to these endpoints will respond with 400 when the request doesn't include an x-elastic-internal-origin header.

The header is automatically included when using core's browser-side HTTP service (e.g. core.http.fetch('....'))

where the restriction is not applied:

  • Public APIs do not have the restriction. Any request made to an endpoint defined as access: public remains open.
  • The restriction is not enabled in our current offerings.

For more details, see #152404

Risk

Risk Probability Severity Mitigation/Notes
The restriction is knowingly bypassed by end-users adding the required header to use internal APIs Low High Serverless: Kibana's internal APIs are not publically documented. If we do see violations, we tell the user to stop. Current offerings: internal public documentation on internal APIs must have the experimental warning and clearly state that internal APIs are subject to frequent changes
Upstream services don't include the header and requests to internal APIs fail Medium Medium The Core team needs to ensure intra-stack components are updated too

`restrictInternalApis` set to `true` enforces the restriction to `internal` API's. The restriction is only enabled in serverless.
@TinaHeiligers TinaHeiligers added Feature:http Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc Project:Serverless Work as part of the Serverless project for its initial release v8.10.0 labels Jul 18, 2023
@TinaHeiligers TinaHeiligers marked this pull request as ready for review July 18, 2023 13:53
@TinaHeiligers TinaHeiligers requested a review from a team as a code owner July 18, 2023 13:53
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-core (Team:Core)

@TinaHeiligers TinaHeiligers added the release_note:skip Skip the PR/issue when compiling release notes label Jul 18, 2023
@TinaHeiligers TinaHeiligers added the Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! label Jul 18, 2023
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-security (Team:Security)

@TinaHeiligers
Copy link
Contributor Author

TinaHeiligers commented Jul 18, 2023

Tests against api/spaces/space fail because they're public and missing the required and now enforced x-elastic-internal-origin header. The requests are expected to fail but for different reasons. Adding the header will fix the error message we expect to see.
@elastic/kibana-security is looking into that.

Update: Clarifying above:

When the access tag for a route definition is not explicitly set by API owners, the default was to interpret access from the route path:

  • Route paths with a prefix of "internal" (e.g. path = '/internal/my_app/....") end up with `access: 'internal'.
  • Route paths with a prefix of "api" (e.g. path = '/api/my_app/....") have access: 'public'.
  • All other routes that don't have either of those two prefixes also become public by default.

#161672 changes the default to internal, meaning that API owners have to explicitly set access: public to pass the API protection restriction.

api/spaces/space used to be 'public', and not restricted but now it's seen as internal.

@@ -48,7 +48,7 @@ data.search.sessions.enabled: false
advanced_settings.enabled: false

# Enforce restring access to internal APIs see https://github.com/elastic/kibana/issues/151940
# server.restrictInternalApis: true
server.restrictInternalApis: true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested to do something else in https://github.com/elastic/kibana/pull/161733/files#r1262308667 because the purpose of the linked PR was to enabled restricted API mode for tests, and enabling it globally wasn't the best way of doing so.

If your PR intends to enabled the restriction in production, then uncommenting the value in the serverless config file makes sense.

@azasypkin
Copy link
Member

azasypkin commented Jul 19, 2023

restrictInternalApis set to true enforces the restriction to internal API's. The restriction is only enabled in serverless.

What does it mean in practice? Does it affect internal routes defined with httpResources.register (e.g. '/internal/security/capture-url' - user is being redirected to this URL and it's not possible to set any request headers)?

Tests against api/spaces/space fail because they're public and missing the required and now enforced x-elastic-internal-origin header.

If API is public, does it require x-elastic-internal-origin? What about public APIs used by external integrations that cannot set these headers (e.g. /api/security/saml/callback)?

@jloleysens
Copy link
Contributor

Hey @azasypkin !

In practice it means that all routes that match request.route.options.access === 'internal' will require setting x-elastic-internal-origin.

We are going to be doing an analysis of affected systems first before merging this PR (like resource bundles, login etc). Will likely take a while longer before this is ready.

If API is public, does it require x-elastic-internal-origin

No it will not require the header to use the endpoint.

Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking pending further analysis of affected systems

@azasypkin
Copy link
Member

We are going to be doing an analysis of affected systems first before merging this PR (like resource bundles, login etc). Will likely take a while longer before this is ready.

👍

No it will not require the header to use the endpoint.

Great, thanks for confirming!

@jloleysens jloleysens changed the title enable API protection in serverless Enable API protection in serverless Jul 25, 2023
jloleysens added a commit that referenced this pull request Jul 26, 2023
…forced (#162258)

## Summary

When turning on `server.restrictInternalApis` a number of issues
surfaced due to defaulting to internal resulting in `400`s for:

* HTTP resources
* Static assets via `registerStaticDir`
* Use of `res.render(Html|Js|Css)` outside of HTTP resources

This PR:

* defaults our HTTP resources service to register routes by default
`public`, same for static dirs.
* Did an audit of all renderX usages, if outside of HTTP resources I
added an explicit `access: public`
* ...what else?

### Set `access: 'public'` for known set of "system" routes

Method | Path | Comment
-- | -- | --
GET | /api/status
GET | /api/stats
GET | /translations/{locale}.json
GET | /api/fleet/agent_policies
GET | /api/task_manager/_background_task_utilization
GET | /internal/task_manager/_background_task_utilization
GET | /internal/detection_engine/health/_cluster
POST | /internal/detection_engine/health/_cluster
GET | /internal/detection_engine/health/_space
POST | /internal/detection_engine/health/_space
POST | /internal/detection_engine/health/_rule
POST | /internal/detection_engine/health/_setup
GET	| /bootstrap.js
GET	| /bootstrap-anonymous.js
GET	| \*\*/bundles/\* | Core's routes for serving JS & CSS bundles



## How to test

Run this PR with `kibana.dev.yml` containing
`server.restrictInternalApis: true` and navigate around Kibana UI
checking that there are no `400`s in the network resources tab due to
access restrictions.

## Notes

* Either left a comment about why `access` was set public or a simple
unit test to check that we are setting access for a given route

## To do

- [x] Manually test Kibana
- [x] Manually test with `interactiveSetup` plugin
- [ ] Add integration and e2e test (will do in a follow up PR) 

Related: #162149

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
jeramysoucy added a commit that referenced this pull request Jul 26, 2023
Subset of #161337
Unblocks #162149

## Summary

This PR uses the access 'public' option when registering the `GET
/api/security/logout` and `POST /api/security/saml/callback` APIs. This
will ensure they have public access in serverless, while all other APIs
will default to internal. PR #161672 changes default access of
registered endpoints to 'internal', meaning that API owners have to
explicitly set access: public to pass the API protection restriction.

This PR also adds internal headers to the existing serverless Spaces API
tests. This unblocks the PR to enable API protection in serverless
(#162149).

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's wait 1 week from today to merge this -- we should address failing tests though.

FWIW #162258 has been merged.

rshen91 pushed a commit to rshen91/kibana that referenced this pull request Jul 26, 2023
…forced (elastic#162258)

## Summary

When turning on `server.restrictInternalApis` a number of issues
surfaced due to defaulting to internal resulting in `400`s for:

* HTTP resources
* Static assets via `registerStaticDir`
* Use of `res.render(Html|Js|Css)` outside of HTTP resources

This PR:

* defaults our HTTP resources service to register routes by default
`public`, same for static dirs.
* Did an audit of all renderX usages, if outside of HTTP resources I
added an explicit `access: public`
* ...what else?

### Set `access: 'public'` for known set of "system" routes

Method | Path | Comment
-- | -- | --
GET | /api/status
GET | /api/stats
GET | /translations/{locale}.json
GET | /api/fleet/agent_policies
GET | /api/task_manager/_background_task_utilization
GET | /internal/task_manager/_background_task_utilization
GET | /internal/detection_engine/health/_cluster
POST | /internal/detection_engine/health/_cluster
GET | /internal/detection_engine/health/_space
POST | /internal/detection_engine/health/_space
POST | /internal/detection_engine/health/_rule
POST | /internal/detection_engine/health/_setup
GET	| /bootstrap.js
GET	| /bootstrap-anonymous.js
GET	| \*\*/bundles/\* | Core's routes for serving JS & CSS bundles



## How to test

Run this PR with `kibana.dev.yml` containing
`server.restrictInternalApis: true` and navigate around Kibana UI
checking that there are no `400`s in the network resources tab due to
access restrictions.

## Notes

* Either left a comment about why `access` was set public or a simple
unit test to check that we are setting access for a given route

## To do

- [x] Manually test Kibana
- [x] Manually test with `interactiveSetup` plugin
- [ ] Add integration and e2e test (will do in a follow up PR) 

Related: elastic#162149

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@TinaHeiligers
Copy link
Contributor Author

Now that we merged #162636 I think we should just do a simple smoke test of running this PR against ES project, then merge tomorrow. WDYT

@jloleysens The smoke test failed miserably 😞 . There's an issue security solution cypress tests.

@TinaHeiligers
Copy link
Contributor Author

@elastic/security-solution your serverless cyprus test fail with API protection enabled.

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@TinaHeiligers
Copy link
Contributor Author

TinaHeiligers commented Aug 2, 2023

@paul-tavares oh dear, it looks like we need to do more work around cypress.
sendApiLoginRequest is missing the required header in the request to the internal API '/internal/security/login',

const sendApiLoginRequest = (
username: string,
password: string
): Cypress.Chainable<{ username: string; password: string }> => {
const url = new URL(Cypress.config().baseUrl ?? '');
url.pathname = '/internal/security/login';
cy.log(`Authenticating [${username}] via ${url.toString()}`);
return request({
headers: { 'kbn-xsrf': 'cypress-creds-via-env' },
method: 'POST',
url: url.toString(),
body: {
providerType: 'basic',
providerName: isLocalhost(url.hostname) ? 'basic' : 'cloud-basic',
currentURL: '/',
params: {
username,
password,
},
},
}).then(() => {
return {
username,
password,
};
});
};

There might be a few others too

@patrykkopycinski
Copy link
Contributor

added label to make sure we run all Kibana's Cypress tests

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@jloleysens
Copy link
Contributor

@elasticmachine merge upstream

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

  • Buildkite Build
  • Commit: 6334d7b
  • Kibana Serverless Image: docker.elastic.co/kibana-ci/kibana-serverless:pr-162149-6334d7b8821b

Failed CI Steps

Test Failures

  • [job] [logs] Threat Intelligence Cypress Tests #1 / Empty Page should render the empty page with link to docs and integrations, and navigate to integrations page

Metrics [docs]

✅ unchanged

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@TinaHeiligers TinaHeiligers merged commit f2e23d7 into main Aug 4, 2023
@TinaHeiligers TinaHeiligers deleted the TinaHeiligers-patch-3 branch August 4, 2023 20:35
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Aug 4, 2023
@TinaHeiligers
Copy link
Contributor Author

@paul-tavares one of the cypress test failed but didn't block the build.
Could you please watch that tests and let me know if it stays flaky?
Thanks!

@paul-tavares
Copy link
Contributor

I just took a look and its not one of the tests we worked on. It came from x-pack/plugins/threat_intelligence/cypress/e2e/empty_page.cy.ts which ran on this PR because of the label that @patrykkopycinski added. I don't think it has anything to do with serverless

nchaulet added a commit that referenced this pull request Aug 7, 2023
nchaulet added a commit to nchaulet/kibana that referenced this pull request Aug 7, 2023
crespocarlos pushed a commit to crespocarlos/kibana that referenced this pull request Aug 8, 2023
bryce-b pushed a commit to bryce-b/kibana that referenced this pull request Aug 9, 2023
azasypkin added a commit that referenced this pull request Aug 23, 2023
Closes #161337

## Summary

Uses build flavor(see #161930) to disable specific Kibana security,
spaces, and encrypted saved objects HTTP API routes in serverless (see
details in #161337). HTTP APIs that will be public in serverless have
been handled in #162523.

**IMPORTANT: This PR leaves login, user, and role routes enabled. The
primary reason for this is due to several testing mechanisms that rely
on basic authentication and custom roles (UI, Cypress). These tests will
be modified to use SAML authentication and serverless roles in the
immediate future. Once this occurs, we will disable these routes.**

### Testing
This PR also implements testing API access in serverless.
- The testing strategy for disabled routes in serverless is to verify a
`404 not found `response.
- The testing strategy for internal access routes in serverless is to
verify that without the internal request header
(`x-elastic-internal-origin`), a `400 bad request response` is received,
then verify that with the internal request header, a `200 ok response`
is received.
- The strategy for public routes in serverless is to verify a `200 ok`
or `203 redirect` is received.

~~blocked by #161930~~
~~blocked by #162149 for test implementation~~

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting blocked ci:all-cypress-suites ci:build-serverless-image Feature:http Project:Serverless Work as part of the Serverless project for its initial release release_note:skip Skip the PR/issue when compiling release notes Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! v8.10.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Turn on the restrictInternalApis in our serverless.yml
9 participants