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

Remove global state from tenant ID parsing package #445

Merged
merged 3 commits into from
Dec 19, 2023

Conversation

56quarters
Copy link
Contributor

@56quarters 56quarters commented Nov 29, 2023

What this PR does:

Remove the ability to set a global "default" parser for tenant IDs since this makes uses of this package fragile and bug prone. This also removes the SingleResolver struct which does not support multiple tenant IDs and was previously the default logic.

All code for parsing tenant IDs is now aware of multiple tenant IDs separated by a | character. Consumers that don't want to support multiple tenant IDs at all should use the TenantID() method which returns an error if there are multiple tenant IDs. Consumers that wish to optionally support multiple tenant IDs should validate incoming input to ensure only a single ID is present.

This changes the default behavior of TenantID() and TenantIDs() in two
ways:

  • SingleResolver did not previously enforce a limit on the length of a tenant
    ID. A limit of 150 characters is now enforced. This has always been the
    documented behavior as far back as Cortex, where this code originated. Not
    enforcing it was an oversight.
  • SingleResolver previously allowed tenant IDs to contain the | character.
    This is no longer allowed as part of a tenant ID and instead will be treated
    as a divider between multiple tenant IDs. This has always been the documented
    behavior as far back as Cortex, where this code originated. Not enforcing it
    was an oversight.

Which issue(s) this PR fixes:

Fixes #443

Checklist

  • Tests updated
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]

@56quarters 56quarters force-pushed the 56quarters/rm-tenant-state branch 2 times, most recently from 98ae518 to 1ae07a7 Compare November 29, 2023 21:32
Remove the ability to set a global "default" parser for tenant IDs since
this makes uses of this package fragile and bug prone. This also removes
the `SingleResolver` struct which does not support multiple tenant IDs and
was previously the default logic.

All code for parsing tenant IDs is now aware of multiple tenant IDs separated
by a `|` character. Consumers that don't want to support multiple tenant IDs
at all should use the `TenantID()` method which returns an error if there are
multiple tenant IDs. Consumers that wish to optionally support multiple tenant
IDs should validate incoming input to ensure only a single ID is present.

This changes the default behavior of `TenantID()` and `TenantIDs()` in two
ways:

* `SingleResolver` did not previously enforce a limit on the length of a tenant
  ID. A limit of 150 characters is now enforced. This has always been the
  documented behavior as far back as Cortex, where this code originated. Not
  enforcing it was an oversight.
* `SingleResolver` previously allowed tenant IDs to contain the `|` character.
  This is no longer allowed as part of a tenant ID and instead will be treated
  as a divider between multiple tenant IDs. This has always been the documented
  behavior as far back as Cortex, where this code originated. Not enforcing it
  was an oversight.

Fixes #443

Signed-off-by: Nick Pillitteri <nick.pillitteri@grafana.com>
@56quarters
Copy link
Contributor Author

An example of how multi-tenant queries could be rejected when tenant-federation is not enabled in Mimir: https://github.com/grafana/mimir/pull/6959/files#diff-2a3eea939d04482548f6edf1e004ecc720e1bb218963865cf9e9ad706f5fd5b8

@56quarters 56quarters requested review from a team and slim-bean December 18, 2023 18:16
Copy link
Contributor

@leizor leizor left a comment

Choose a reason for hiding this comment

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

Makes sense to me 👍

Copy link
Contributor

@dimitarvdimitrov dimitarvdimitrov left a comment

Choose a reason for hiding this comment

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

SGTM, not suuper sure of the things that might break with this change.

defaultResolver = r
}
var (
errInvalidTenantID = errors.New("invalid tenant ID")
Copy link
Contributor

Choose a reason for hiding this comment

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

can we add some details about what's invalid ("tenant ID is ., .. or contains / or \")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm realizing now that it doesn't make sense to have containsUnsafePathSegments separate from the logic in ValidTenantID. WDYT about moving the logic from containsUnsafePathSegments to ValidTenantID?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in cb00525 and moved that logic into ValidTenantID()

@56quarters
Copy link
Contributor Author

SGTM, not suuper sure of the things that might break with this change.

  • Anyone using | in a tenant ID and not intending to treat it as the separator between multiple IDs. This doesn't affect Mimir or Loki in Grafana Cloud. It doesn't affect on-prem GEM or GEL since we don't allow | in tenant names. It may affect on-prem installations or Mimir or Loki but | has been documented as not being allowed since Mimir has existed.

  • Anyone with a tenant ID longer than 150 bytes. This doesn't affect Mimir or Loki in Grafana Cloud. It doesn't affect on-prem GEM or GEL since we limit tenant names to 63 characters there. It may affect on-prem installations of Mimir or Loki but again this has been documented as not being allowed since Mimir has existed.

@56quarters 56quarters requested a review from a team December 19, 2023 14:54
@dimitarvdimitrov
Copy link
Contributor

SGTM, not suuper sure of the things that might break with this change.

I was concerned about places that under the SingleResolver used to call TenantID and assume it will be concatenated list tenant IDs. Now effectively we're only using the MultiResolver.

But you said this would have only happened when multi-tenant is disabled and the tenant ID contains |, which as you pointed out is not supported (at least in Mimir and Loki's context). So I'm less concerned now. Even if other clients of dskit hit some problems I think it's better to hit them with a change like this than as bug later on. LGTM

Signed-off-by: Nick Pillitteri <nick.pillitteri@grafana.com>
CHANGELOG.md Outdated Show resolved Hide resolved
@56quarters 56quarters merged commit 2bfd679 into main Dec 19, 2023
3 checks passed
@56quarters 56quarters deleted the 56quarters/rm-tenant-state branch December 19, 2023 16:44
56quarters added a commit to grafana/mimir that referenced this pull request Dec 20, 2023
This change updates dskit to a version that does _not_ rely on global
state for tenant ID parsing. Specifically it pulls in grafana/dskit#445.
As part of this there are a few things changing:

* We use multi-tenant parsing logic everywhere which actually enforces
  limits on the length of tenant IDs and the legal characters in them.
* Instead of relying on single tenant parsing logic when tenant federation
  is disabled to reject multi-tenant queries, we add a query middleware that
  validates the number of expected tenants based on configuration.
* We introduce a new setting to limit the max number of tenant IDs that may be
  included in a multi-tenant query.

This change will result in different behavior in a few cases. However, it
brings the actual behavior of Mimir in line with the documented behavior.
Specifically, the following behavior changes (copied from dskit PR):

* SingleResolver did not previously enforce a limit on the length of a tenant
  ID. A limit of 150 characters is now enforced. This has always been the
  documented behavior as far back as Cortex, where this code originated. Not
  enforcing it was an oversight.
* SingleResolver previously allowed tenant IDs to contain the | character.
  This is no longer allowed as part of a tenant ID and instead will be treated
  as a divider between multiple tenant IDs. This has always been the documented
  behavior as far back as Cortex, where this code originated. Not enforcing it
  was an oversight.

Signed-off-by: Nick Pillitteri <nick.pillitteri@grafana.com>
56quarters added a commit to grafana/mimir that referenced this pull request Dec 21, 2023
This change updates dskit to a version that does _not_ rely on global
state for tenant ID parsing. Specifically it pulls in grafana/dskit#445.
As part of this there are a few things changing:

* We use multi-tenant parsing logic everywhere which actually enforces
  limits on the length of tenant IDs and the legal characters in them.
* Instead of relying on single tenant parsing logic when tenant federation
  is disabled to reject multi-tenant queries, we add a query middleware that
  validates the number of expected tenants based on configuration.
* We introduce a new setting to limit the max number of tenant IDs that may be
  included in a multi-tenant query.

This change will result in different behavior in a few cases. However, it
brings the actual behavior of Mimir in line with the documented behavior.
Specifically, the following behavior changes (copied from dskit PR):

* SingleResolver did not previously enforce a limit on the length of a tenant
  ID. A limit of 150 characters is now enforced. This has always been the
  documented behavior as far back as Cortex, where this code originated. Not
  enforcing it was an oversight.
* SingleResolver previously allowed tenant IDs to contain the | character.
  This is no longer allowed as part of a tenant ID and instead will be treated
  as a divider between multiple tenant IDs. This has always been the documented
  behavior as far back as Cortex, where this code originated. Not enforcing it
  was an oversight.

Signed-off-by: Nick Pillitteri <nick.pillitteri@grafana.com>
56quarters added a commit to grafana/mimir that referenced this pull request Jan 2, 2024
This change updates dskit to a version that does _not_ rely on global
state for tenant ID parsing. Specifically it pulls in grafana/dskit#445.
As part of this there are a few things changing:

* We use multi-tenant parsing logic everywhere which actually enforces
  limits on the length of tenant IDs and the legal characters in them.
* Instead of relying on single tenant parsing logic when tenant federation
  is disabled to reject multi-tenant queries, we add a query middleware that
  validates the number of expected tenants based on configuration.
* We introduce a new setting to limit the max number of tenant IDs that may be
  included in a multi-tenant query.

This change will result in different behavior in a few cases. However, it
brings the actual behavior of Mimir in line with the documented behavior.
Specifically, the following behavior changes (copied from dskit PR):

* SingleResolver did not previously enforce a limit on the length of a tenant
  ID. A limit of 150 characters is now enforced. This has always been the
  documented behavior as far back as Cortex, where this code originated. Not
  enforcing it was an oversight.
* SingleResolver previously allowed tenant IDs to contain the | character.
  This is no longer allowed as part of a tenant ID and instead will be treated
  as a divider between multiple tenant IDs. This has always been the documented
  behavior as far back as Cortex, where this code originated. Not enforcing it
  was an oversight.

See grafana/dskit#445
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tenant package relies on mutable global state
3 participants