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

Globally enforce internal API restriction #193792

Conversation

TinaHeiligers
Copy link
Contributor

@TinaHeiligers TinaHeiligers commented Sep 23, 2024

fix #163654

This PR enforces internal API restrictions in our standard offering.
Internal APIs are subject to rapid change and are intentionally not public. By restricting their access, we protect consumers from these rapid changes.

This PR does not change any public APIs and they remain available for external consumption.

Note to reviewers:

I chose the most practical way of resolving the failures (add the header or disable the restriction).

Details

Requests to internal Kibana APIs will be restricted globally. This allows more flexibility in making breaking changes to internal APIs, without a risk to external consumers.

Why are we doing this?

The restriction is there to help mitigate the risk of breaking external integrations consuming APIs. Internal APIs are subject to frequent changes, necessary for feature development.

What this means to plugin authors :

Kibana core applies the restriction when enabled through HTTP config.

What this means to Kibana consumers:

Explicitly restricting access to internal APIs has advantages for external consumers:

  • Consumers can safely integrate with Kibana's stable, public APIs
  • Consumers are protected from Internal route development, which may involve breaking changes
  • Relevant information in Kibana's external documentation that is user-friendly and complete.

KB article explaining the change (tracked as part of https://github.com/elastic/kibana-team/issues/1044)

Release note

Starting with this release, requests to internal Kibana APIs are globally restricted by default. This change is designed to provide more flexibility in making breaking changes to internal APIs while protecting external consumers from unexpected disruptions.
Key Changes:
Internal API Access: External consumers no longer have access to Kibana’s internal APIs, which are now strictly reserved for internal development and subject to frequent changes. This helps ensure that external integrations only interact with stable, public APIs.
Error Handling: When a request is made to an internal API without the proper internal identifier (header or query parameter), Kibana will respond with a 400 Bad Request error, indicating that the route exists but is not allowed under the current Kibana configuration.

How to test this

Running kibana

  1. Set server.restrictInternalApis: true in kibana.yml
  2. Start es with any license
  3. Start kibana
  4. Make an external request to an internal API:
curl request to get the config for 9.0:
curl --location 'localhost:5601/abc/api/kibana/management/saved_objects/_bulk_get' \
--header 'Content-Type: application/json' \
--header 'kbn-xsrf: kibana' \
--header 'x-elastic-internal-origin: kibana' \
--header 'Authorization: Basic ZWxhc3RpYzpjaGFuZ2VtZQ==' \
--data '[
  {
      "type": "config",
      "id": "9.0.0"
  }
]'

The request should be successful.

  1. Make the same curl request without the internal origin header
curl:
curl --location 'localhost:5601/abc/api/kibana/management/saved_objects/_bulk_get' \
--header 'Content-Type: application/json' \
--header 'kbn-xsrf: kibana' \
--header 'Authorization: Basic ZWxhc3RpYzpjaGFuZ2VtZQ==' \
--data '[
  {
      "type": "config",
      "id": "9.0.0"
  }
]'

The response should be an error similar to:
{"statusCode":400,"error":"Bad Request","message":"uri [/api/kibana/management/saved_objects/_bulk_get] with method [post] exists but is not available with the current configuration"}

  1. Remove server.restrictInternalApis from kibana.yml or set it to false.

  2. Repeat both curl requests above. Both should respond without an error.

Checklist

Delete any items that are not applicable to this PR.

Risk Matrix

Risk Probability Severity Mitigation/Notes
The restriction is knowingly bypassed by end-users adding the required header to use internal APIs Low High Kibana's internal APIs are not documented in the OAS specifications. External consumption will be prevented unless explicitly bypassed.
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

For maintainers

@TinaHeiligers TinaHeiligers added v9.0.0 release_note:breaking Feature:http Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc backport:skip This commit does not require backporting labels Sep 23, 2024
@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@@ -68,7 +68,7 @@ export const createConfigService = ({
shutdownTimeout: moment.duration(30, 'seconds'),
keepaliveTimeout: 120_000,
socketTimeout: 120_000,
restrictInternalApis: false,
restrictInternalApis: false, // disable restriction for Kibana tests
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Leaves the restriction disabled for tests consuming createConfigService.

Copy link
Contributor Author

@TinaHeiligers TinaHeiligers left a comment

Choose a reason for hiding this comment

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

self review.

@TinaHeiligers TinaHeiligers marked this pull request as ready for review September 24, 2024 18:56
@TinaHeiligers TinaHeiligers requested a review from a team as a code owner September 24, 2024 18:56
@elasticmachine
Copy link
Contributor

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

@lukeelmers
Copy link
Member

Before we merge - I think we should investigate two things which I just realized weren't in the rollout plan:

  1. Is it possible to surface a warning for this in UA similar to what we are discussing for Saved Objects APIs? e.g. Show a warning if we detect non-Kibana traffic to an internal API
  2. We should plan to draft an internal KB article due to the widespread impact of this change

Let's also add a bit more detail to our breaking change note. Even though folks shouldn't be using these APIs, we know many are, so again this would be to address the potential wide impact of this change.

@TinaHeiligers TinaHeiligers marked this pull request as draft September 24, 2024 21:38
@TinaHeiligers
Copy link
Contributor Author

@TinaHeiligers
Copy link
Contributor Author

TinaHeiligers commented Sep 24, 2024

we should investigate two things which I just realized weren't in the rollout plan:

TBH, I've also been thinking along these lines because it's the right thing to do.

The tricky part is that restricting access to internal APIs isn't a classic deprecation and we'd need something within the http service to surface external calls in the UA. I'm unsure if that's possible from within the http lifecycle or maybe easier within the router itself. @jloleysens we should discuss our options.

As for the KB, I was going to add one anyway ;-)

Let's also add a bit more detail to our breaking change note

How about rewording something similar to #156935 to highlight how this change helps consumers?

@jloleysens
Copy link
Contributor

...within the http lifecycle or maybe easier within the router itself...

We should be able to piggy-back off work Ahmad is doing. He is creating a core usage counter for HTTP stuff that we can use to make a new route counter. The "internal route usage" counter should be registered during setup time.

As for where we detect/increment this counter, I think we should do it just before returning the 400 here:

That handler will just need the core usage service injected. But for that we are blocked on #193668

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

restrictInternalApis: offeringBasedSchema({
serverless: schema.boolean({ defaultValue: false }),
traditional: schema.boolean({ defaultValue: false }),
serverless: schema.boolean({ defaultValue: 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.

Changing the default also meant updating tests to either disable the restriction or add the header required for internal requests.

@@ -82,6 +83,9 @@ describe('checking all opted-in dynamic config settings', () => {
logging: {
loggers: [{ name: 'root', level: 'info', appenders: ['console'] }],
},
server: {
restrictInternalApis: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's less work to disable the restriction in createTestServers than adding the header/query param to tests.
We disable the restriction by default for ftr tests too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Should/do we have a task for updating these requests in the future or is the plan to leave them unrestricted in tests?

Copy link
Contributor Author

@TinaHeiligers TinaHeiligers Sep 30, 2024

Choose a reason for hiding this comment

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

Should/do we have a task for updating these requests in the future or is the plan to leave them unrestricted in tests

The plan is to update requests if and when we need to, which is consistent with the base config for our FTR tests.

As for this specific test, createRootWithSettings explicitly enables the restriction. Here, we change that in setup, and is an example of how consumers can override the default should they choose to.

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@TinaHeiligers
Copy link
Contributor Author

/ci

@TinaHeiligers
Copy link
Contributor Author

/ci

@TinaHeiligers
Copy link
Contributor Author

TinaHeiligers commented Sep 28, 2024

Let's also add a bit more detail to our breaking change note. Even though folks shouldn't be using these APIs, we know many are, so again this would be to address the potential wide impact of this change.

@lukeelmers I've fleshed out the release note and double-checked that the UA work and KB article are in the meta issue. The plan is to merge the implementation and follow up with the UA hook once that's ready.

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@TinaHeiligers TinaHeiligers marked this pull request as ready for review September 30, 2024 01:31
@TinaHeiligers TinaHeiligers requested review from a team as code owners September 30, 2024 01:31
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.

Great work @TinaHeiligers for chasing down all those test cases. Implementation of new default LGTM. Left some minor comments.

@@ -82,6 +83,9 @@ describe('checking all opted-in dynamic config settings', () => {
logging: {
loggers: [{ name: 'root', level: 'info', appenders: ['console'] }],
},
server: {
restrictInternalApis: false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Should/do we have a task for updating these requests in the future or is the plan to leave them unrestricted in tests?

@SiddharthMantri SiddharthMantri self-requested a review October 1, 2024 13:12
@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

@TinaHeiligers
Copy link
Contributor Author

The FTR test failure is unrelated to this PR: #194425

@rudolf
Copy link
Contributor

rudolf commented Oct 2, 2024

Let's also add a bit more detail to our breaking change note. Even though folks shouldn't be using these APIs, we know many are, so again this would be to address the potential wide impact of this change.

@lukeelmers I've fleshed out the release note and double-checked that the UA work and KB article are in the meta issue. The plan is to merge the implementation and follow up with the UA hook once that's ready.

I've created #194675 to track the work for surfacing internal API usage in the UA.

@TinaHeiligers
Copy link
Contributor Author

@elasticmachine merge upstream

Copy link
Contributor

@SiddharthMantri SiddharthMantri left a comment

Choose a reason for hiding this comment

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

Security changes LGTM.

@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

✅ unchanged

History

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

@TinaHeiligers TinaHeiligers merged commit fe83c0d into elastic:main Oct 2, 2024
22 checks passed
@TinaHeiligers TinaHeiligers deleted the kbn-163654-enable-internalAPIrestriction branch October 2, 2024 17:08
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 Feature:http release_note:breaking Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v9.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Breaking] Restrict internal APIs by default in 9.0
8 participants