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

feat(lambda-promtail): Add possibility to set additional HTTP headers for promtail-client requests #11883

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

trc-ikeskin
Copy link

What this PR does / why we need it:

This PR adds the ability to set additional, custom HTTP headers for requests made by the promtail client in the lambda-promtail tool. Additional headers can be passed to the AWS Lambda function via the environment variable EXTRA_HTTP_HEADERS in the form <HTTP header 1 key>,<HTTP header 1 value>,<HTTP header 2 key>,<HTTP header 2 value>, ....

This functionality is needed when for example requests pass a AWS Web Application Firewall that expects a certain custom header to be set on every request passed to a load balancer. If this load balancer must be traversed to access the Loki gateway push endpoint, then there is currently no easy way to achieve this.

Special notes for your reviewer:

Simple header key validation was implemented using regex, but there is currently no validation for header values.

@trc-ikeskin trc-ikeskin requested a review from a team as a code owner February 6, 2024 19:40
@CLAassistant
Copy link

CLAassistant commented Feb 6, 2024

CLA assistant check
All committers have signed the CLA.

@trc-ikeskin
Copy link
Author

@cstyan would you be able to review this PR?

skipTlsVerify bool
printLogLine bool
extraHeaders map[string]string
httpHeaderKeyRegex = regexp.MustCompile("([A-Za-z0-9-])+")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the set of characters that are valid for HTTP header keys is much more than this, is it not?

Copy link
Author

Choose a reason for hiding this comment

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

You seem to be right about this from an RFC perspective, since AFAICS there is no real specification for the format of a valid HTTP header field name. Nevertheless some services still impose such restrictions - especially the ones stated by AWS ELB led me to idea to implement this:

tools/lambda-promtail/lambda-promtail/main.go Outdated Show resolved Hide resolved
Copy link
Contributor

@cstyan cstyan left a 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 the regex for the header values is correct, or necessary?

We should also have some tests, see the other tests in main_test.go for examples, such as TestLambdaPromtail_ExtraLabels*

@trc-ikeskin trc-ikeskin requested a review from cstyan February 16, 2024 13:04
Comment on lines +68 to +96
func TestLambdaPromtail_ExtraHeadersValid(t *testing.T) {
extraHeaders, err := parseExtraHeaders("X-Custom-Header,This!sATota\\yCu$t0mHe4der,My-Server_WantsThis,What_ever could go here?,Expected4Entry,yLKc+QSB5VF/Gp3VPN7oOxa98yxWMxeHOAo+CW6trow=")
require.Nil(t, err)
require.Len(t, extraHeaders, 3)
require.Equal(t, extraHeaders["X-Custom-Header"], "This!sATota\\yCu$t0mHe4der")
require.Equal(t, extraHeaders["My-Server_WantsThis"], "What_ever could go here?")
require.Equal(t, extraHeaders["Expected4Entry"], "yLKc+QSB5VF/Gp3VPN7oOxa98yxWMxeHOAo+CW6trow=")
}

func TestLambdaPromtail_ExtraHeadersInvalidHeaderKey(t *testing.T) {
extraHeaders, err := parseExtraHeaders("Th.s_Shou|d-Fa!l,a")
require.Nil(t, extraHeaders)
require.ErrorContains(t, err, "HTTP header key is invalid:")
extraHeaders, err = parseExtraHeaders("Also Not Valid ,b")
require.Nil(t, extraHeaders)
require.ErrorContains(t, err, "HTTP header key is invalid:")
}

func TestLambdaPromtail_ExtraHeadersMissingValue(t *testing.T) {
extraHeaders, err := parseExtraHeaders("A,a,B,b,C,c,D")
require.Nil(t, extraHeaders)
require.Errorf(t, err, invalidExtraHeadersError)
}

func TestLambdaPromtail_TestParseHeadersNoneProvided(t *testing.T) {
extraLabels, err := parseExtraHeaders("")
require.Len(t, extraLabels, 0)
require.Nil(t, err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

lets simplify a bit and make this a table driven test

Copy link
Author

Choose a reason for hiding this comment

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

I am not really sure how a table driven test simplifies my test, but I am also not too experience with this kind of testing. Maybe you could give me a hint and what you had in mind here?

Copy link
Contributor

Choose a reason for hiding this comment

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

rather than declaring 4 new tests, one for each of these success or failure scenarios, we would have one test with an array of input/expected output, see here https://go.dev/wiki/TableDrivenTests

Comment on lines 201 to 206
if len(extraHeaders) > 0 {
for key, value := range extraHeaders {
req.Header.Set(key, value)
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm am wondering if, to avoid any potential unexpected issues, we should include some validation here. For example, not allowing overwriting of the headers we set earlier in this function, and logging if we overwrite an existing header value (such as someone not noticing that in their configured extra headers they're setting SOME-EXTRA-HEADER=a, ... , SOME-EXTRA-HEADER=b.

Copy link
Author

Choose a reason for hiding this comment

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

I implemented a simple check to see if a key has already been set and added a warning for the user to check its env vars: 6a8a19d

Not sure about the logging part since I could not really find a clear way the logging is implemented in the code. Maybe you could have a closer look at that.

Copy link
Contributor

Choose a reason for hiding this comment

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

@trc-ikeskin thanks! this is exactly what I had in mind. Logging in this context just meant fmt.Println or using the logger which you've done.

I still think we should guard against people overwriting the headers that are set earlier in this same function, such as Authorization or X-Scope-OrgID. We can do that here or in a follow up PR. Up to you.

@cstyan cstyan changed the title (feat) lambda-promtail: Add possibility to set additional HTTP headers for promtail-client requests feat(lambda-promtail): Add possibility to set additional HTTP headers for promtail-client requests Apr 22, 2024
@cstyan
Copy link
Contributor

cstyan commented Apr 22, 2024

@trc-ikeskin IMO there's still some minor changes we should make here

@@ -25,19 +26,23 @@ const (

maxErrMsgLen = 1024

invalidExtraLabelsError = "invalid value for environment variable EXTRA_LABELS. Expected a comma separated list with an even number of entries. "
invalidExtraLabelsError = "invalid value for environment variable EXTRA_LABELS. Expected a comma separated list with an even number of entries. "
invalidEvenExtraHeadersError = "invalid value for environment variable EXTRA_HTTP_HEADERS. Expected a comma separated list with an even number of entries."
Copy link
Contributor

Choose a reason for hiding this comment

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

hey @trc-ikeskin either the name here or on line 89 of the tests needs to change, I think invalidExtraHeadersError is enough

@cstyan
Copy link
Contributor

cstyan commented Jul 16, 2024

@trc-ikeskin did you still want to proceed with this PR?

@trc-ikeskin
Copy link
Author

@trc-ikeskin did you still want to proceed with this PR?

@cstyan I still want to continue eventually but I cannot find the time right now - sorry.

@cstyan
Copy link
Contributor

cstyan commented Jul 17, 2024

@trc-ikeskin did you still want to proceed with this PR?

@cstyan I still want to continue eventually but I cannot find the time right now - sorry.

👍 no worries

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants