-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Query Frontend: forward tenant information downstream #6595
Query Frontend: forward tenant information downstream #6595
Conversation
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
* Add tenant forwarding based on tenant cert. * Fix bugs in the header management. Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
cmd/thanos/query_frontend.go
Outdated
@@ -217,6 +223,13 @@ func runQueryFrontend( | |||
cfg *queryFrontendConfig, | |||
comp component.Component, | |||
) error { | |||
cfg.ForwardHeaders = append(cfg.ForwardHeaders, tenancy.DefaultTenantHeader) | |||
cfg.orgIdHeaders = append(cfg.orgIdHeaders, tenancy.DefaultTenantHeader) | |||
if cfg.TenantHeader != "" && cfg.TenantHeader != tenancy.DefaultTenantHeader { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be an if else
? or is it a case that we always want to forward the default tenant header since it is appended above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to use only if
with a good initialization instead of if else
. Makes it easier to read: "we always forward the default tenant header and if there's a custom one, we forward it too".
Buuuut, I think I can remove cfg.ForwardHeaders = append(cfg.ForwardHeaders, cfg.TenantHeader)
, as a custom tenant header doesn't need to be forwarded as-is downstream. It'll be converted to the internal one (the default), before being forwarded.
But I still have to add it to the list of orgIdHeaders
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, don't disagree, was just wondering if it was a case of always passing on the default but that answers it.
tenant = r.Header.Get(DefaultTenantHeader) | ||
if tenant == "" { | ||
tenant = defaultTenantID | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you think its worth logging down below if we end up overwriting based on the cert? or maybe we could just handle this on startup with a log or an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be too spammy. We had similar logs when parsing the tenant information from the request in the Store GW and they were removed: 510c054
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
We should always and only forward the default (internal) one. Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
cmd/thanos/query_frontend.go
Outdated
@@ -146,6 +147,10 @@ func registerQueryFrontend(app *extkingpin.App) { | |||
|
|||
cmd.Flag("query-frontend.forward-header", "List of headers forwarded by the query-frontend to downstream queriers, default is empty").PlaceHolder("<http-header-name>").StringsVar(&cfg.ForwardHeaders) | |||
|
|||
cmd.Flag("query-frontend.tenant-header", "HTTP header to determine tenant").Default(tenancy.DefaultTenantHeader).Hidden().StringVar(&cfg.TenantHeader) | |||
cmd.Flag("query-frontend.default-tenant", "Default tenant to use if tenant header is not present").Default(tenancy.DefaultTenant).Hidden().StringVar(&cfg.DefaultTenant) | |||
cmd.Flag("query-frontend.tenant-certificate-field", "Use TLS client's certificate field to determine tenant for requests. Must be one of "+tenancy.CertificateFieldOrganization+", "+tenancy.CertificateFieldOrganizationalUnit+" or "+tenancy.CertificateFieldCommonName+". This setting will cause the query-frontend.tenant-header flag value to be ignored.").Default("").EnumVar(&cfg.TenantCertField, "", tenancy.CertificateFieldOrganization, tenancy.CertificateFieldOrganizationalUnit, tenancy.CertificateFieldCommonName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one should probably be hidden as the other two, until this functionality is ready.
@@ -146,6 +147,10 @@ func registerQueryFrontend(app *extkingpin.App) { | |||
|
|||
cmd.Flag("query-frontend.forward-header", "List of headers forwarded by the query-frontend to downstream queriers, default is empty").PlaceHolder("<http-header-name>").StringsVar(&cfg.ForwardHeaders) | |||
|
|||
cmd.Flag("query-frontend.tenant-header", "HTTP header to determine tenant").Default(tenancy.DefaultTenantHeader).Hidden().StringVar(&cfg.TenantHeader) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is the right place to discuss this, but the query frontend also has a query-frontend.org-id-header
arg. Thanos side, I believe this is only used when logging slow queries, but probably has some more use for Cortex.
Do we want to keep both the org-id-header
and the tenant-header
long term ? Could perhaps be nice to unify that into one cmd line arg if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long term we should indeed converge on only one to avoid confusion for users and ourselves, and for consistency.
As part of the migration process, I can mark the query-frontend.org-id-header
as deprecated for now, mention the new one, and store the configured org-id-header
in the tenant header config. This way someone already using this will have a warning about the change and can easily adapt to the new CLI arg, allowing us to completely drop the org ID config in a future breaking change.
Internally and more technically speaking, I am copying the tenant header field's value to the Org ID one because of some middlewares we are importing/reusing from Cortex, but I think over time we can adapt them to avoid this and clean things up.
What do you think, @jacobbaungard?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a good plan to me. What would happen if one define both, can we error out in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jacobbaungard we could error out or print out a warning & give priority to the tenant header config, similar to what happens if you configure the header and the cert field in Receive. I personally have no preference. Will update to error out when both are provided. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think the orgID
was introduced only as a method of identifying sources of slow queries and passing that information to Cortex. It's also a repeatable flag, with significance in how headers are ordered, afaiu reading original issue/PR.
Thus I don't think it is mutually exclusive with this tenant
header, and both have different semantics as well, as you can have multiple orgID
headers, but only a single tenant
one. So let's not error or warn the user, and keep it for now.
cc: @yeya24 in case he has some other thoughts on this! 🙂
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
cmd/thanos/query_frontend.go
Outdated
@@ -217,6 +224,19 @@ func runQueryFrontend( | |||
cfg *queryFrontendConfig, | |||
comp component.Component, | |||
) error { | |||
if len(cfg.orgIdHeaders) != 0 && cfg.TenantHeader != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, won't this always evaluate true when setting the orgIdHeader
, as the TenantHeader
has a non-empty default value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hummmm, true. I'm starting to think it will be much simpler to output a warning and give priority to the tenant header configuration. 🤔
Let me see what I can do!
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, looks good to me!
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
cc: @yeya24 as a reviewer with some cortex knowledge :) |
pkg/queryfrontend/roundtrip.go
Outdated
queriesCount *prometheus.CounterVec | ||
queriesCount *prometheus.CounterVec | ||
tenantHeader string | ||
defaultTenant string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are the two new fields used in the roundTripper
struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch, @yeya24. I think they are some leftovers of previous approaches I tried. I'm removing them.
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
@yeya24 took care of the comment and rebased, please have another look when you have some time. Thanks! 🙇 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the great work! Generally LGTM, but cc: @yeya24 on the point of orgID and tenant headers.
@@ -146,6 +147,10 @@ func registerQueryFrontend(app *extkingpin.App) { | |||
|
|||
cmd.Flag("query-frontend.forward-header", "List of headers forwarded by the query-frontend to downstream queriers, default is empty").PlaceHolder("<http-header-name>").StringsVar(&cfg.ForwardHeaders) | |||
|
|||
cmd.Flag("query-frontend.tenant-header", "HTTP header to determine tenant").Default(tenancy.DefaultTenantHeader).Hidden().StringVar(&cfg.TenantHeader) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think the orgID
was introduced only as a method of identifying sources of slow queries and passing that information to Cortex. It's also a repeatable flag, with significance in how headers are ordered, afaiu reading original issue/PR.
Thus I don't think it is mutually exclusive with this tenant
header, and both have different semantics as well, as you can have multiple orgID
headers, but only a single tenant
one. So let's not error or warn the user, and keep it for now.
cc: @yeya24 in case he has some other thoughts on this! 🙂
@saswatamcode from the Thanos perspective, the headers do the same thing. In theory, you can send multiple values for any HTTP header (internally in the stdlib they are HTTP headers ordering is not a concern we need to have, stdlib takes care of this. I could have completely removed Note that nothing here makes Thanos incompatible with Cortex and vice-versa. On this context. the only change is the rename of the cli arg from |
Even added this in the feature's e2e test to ensure the OrgID header keeps being passed downstream: https://github.com/thanos-io/thanos/pull/6595/files#diff-e84e75cb190ebf54e47774afa03e68ed6cbc3f03e6216ae31e79c58509b0acbeR984-R985 |
…enant Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! I think this is good to go.
For the orgID
stuff, I believe it's there as a separate header due to certain cortex feature, but we can make it more in-line with Thanos tenancy model or remove it completely as Thanos has its own slow query log. 🙂
* Make query frontend forward tenant info downstream Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add TODO for client certificate Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Finish qfe tenant forward features * Add tenant forwarding based on tenant cert. * Fix bugs in the header management. Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Test more scenarios Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Goimports files Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun CI Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun goimports without any line breaks Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Resort imports in groups (std, 3rd-party, local) Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * No need to forward a custom tenant header downstream We should always and only forward the default (internal) one. Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Make query frontend tenant cert config hidden Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Error out when org ig and tenant header are provided at the same time Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Fix typo Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Update docs Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Improve comments around forward and org id headers for tenancy Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add some test comments Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Improve logic for detecting tenant and org id headers were provided Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Fix order of check for org id headers Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add some TODO comments for the future Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun CI Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Make default tenant flag in qfe match receive's Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Remove unnecessary struct fields Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add instant query to tenant forward tests Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun build Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> --------- Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
* Make query frontend forward tenant info downstream Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add TODO for client certificate Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Finish qfe tenant forward features * Add tenant forwarding based on tenant cert. * Fix bugs in the header management. Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Test more scenarios Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Goimports files Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun CI Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun goimports without any line breaks Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Resort imports in groups (std, 3rd-party, local) Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * No need to forward a custom tenant header downstream We should always and only forward the default (internal) one. Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Make query frontend tenant cert config hidden Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Error out when org ig and tenant header are provided at the same time Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Fix typo Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Update docs Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Improve comments around forward and org id headers for tenancy Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add some test comments Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Improve logic for detecting tenant and org id headers were provided Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Fix order of check for org id headers Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add some TODO comments for the future Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun CI Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Make default tenant flag in qfe match receive's Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Remove unnecessary struct fields Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Add instant query to tenant forward tests Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> * Rerun build Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com> --------- Signed-off-by: Douglas Camata <159076+douglascamata@users.noreply.github.com>
It's not relevant to end users (yet) because it has no impact, just like #6530.
Changes
This PR continues the work from #6530, which started to forward tenant information down from Querier to Store API endpoints.
Here the tenant information is propagated from the Query Frontend to the Queriers. These are the change done by this PR:
query-frontend.tenant-header
: indicates name of the tenant header, defaults toTHANOS-TENANT
.When this option is provided at the same time as
query-frontend.org-id-header
: an error is thrown, the Query Frontend won't start, the user will then be warned to stop using the org id header configuration and migrate to the tenant header one.query-frontend.default-tenant-id
: indicates the default tenant ID, defaults todefault-tenant
. This is the tenant that will be used when the request doesn't specify one.query-frontend.tenant-certificate-field
: use the TLS client's certificate field to identify the tenant.THANOS-TENANT
).tenancy.GetTenantFromHTTP
helper has been updated to match this behavior.X-Scope-Orgid
header from Cortex is kept for compatibility with request middlewares and tripperwares imported from Cortex'queryfrontend
package. If and/or when Cortex allows the org id header name to be customized, the duplication can be removed in favor of properly configuring Cortex.Verification
Added e2e tests and did manual tests.