tomMoulard / htransformation

A Traefik plugin to change on the fly header's value of a request
MIT License
81 stars 13 forks source link

Set header to generated value or transformed value #44

Open gumbo2k opened 1 year ago

gumbo2k commented 1 year ago

Has there been interest in adding more features to the "Set" header handler?

Something beyond the capability to copy or join values?

I personally would like to have the ability to generate UUID4 or UUID1 values for headers, but apart from generating random header values, I imagine there might be interest in transforming values. Stuff like uppercase, lowercase, hash sum, regex substitution and so on.

There is a very small PR that was rejected from traefik, but might fit very well into the scope of htransformation's "Set" handler: https://github.com/traefik/traefik/pull/6707

TLDR: It adds a value "{uuid}"

If there is interest in this, I would get in touch with the PR's author and ask him to submit it as a PR here, or I would adapt it myself.

Background: There has been a lot of interest in adding the ability to add a "X-Request-ID" or Correlation ID header to traefik before.

But those pull requests have been rejected with a proposed workaround to use jaeger tracing with a 0 sampling frequency to avoid the huge overhead and changing the header name from uber-trace-id to something like X-Request-ID:

            - "--tracing.jaeger.samplingParam=0"
            - "--tracing.jaeger.traceContextHeaderName=X-Request-ID"

This "kind of" works, as is abuses the jaeger tracing to add a generated value to each request but you have no control over the format of the value which is not a UUID (Something like: 17f19df25f472def:65d24975fb779d8d:17f19df25f472def:0 instead of 27155b04-20a6-4b64-87f6-0a458ae33734 )

tomMoulard commented 1 year ago

Hello @gumbo2k,

Thanks for your interest in this Traefik Plugin!

This would even be a nice feature to be able to specify go code that would be interpreted at runtime to modify the headers content. It could look like this:

- Rule: # Header -> X-UUID: X-UUID-27155b04-20a6-4b64-87f6-0a458ae33734
      Name: 'UUID Set'
      Header: 'X-UUID'
      Value: 'X-UUID-{{uuid.New().String()}}'
      Type: 'Setf'

WDYT ?

gumbo2k commented 1 year ago

It sounds fantastic!... But I don't know enough about golang to know if "interpreting" go code in string interpolation is easily implemented. I was under the impression that golang is a statically compiled language. So allowing freeform golang code in string interploation would require us to drag along a go compiler, wouldn't it?

And obviously the security implications of interpreting strings as code ...

tomMoulard commented 1 year ago

We could use Yaegi a Go interpreter to do the heavy lifting for this, but indeed this would open up some security implications. Nonetheless, Traefik Plugins are already interpreted at runtime, idk what it will do to interpret the thing a second time.

gumbo2k commented 1 year ago

It would indeed be great, to have the power to evaluate golang inside those value strings.

I wonder if/how one could make the current headers of the request (or response) accessible, in order to set derived values...

- Rule: 
      Name: 'Set X-Client-IP from first X-Forwarded-For'
      Header: 'X-Client-IP'
      Value: '{{current.header[`x-forwarded-for`].Split(`,`)[0]}}'
      Type: 'Setf'
tomMoulard commented 1 year ago

I tried to do a POC of using Yaegi to do so, but it cannot be imported as Traefik forbids the use of exec inside a plugin.

- Rule: 
     Name: 'Set X-Client-IP from first X-Forwarded-For'
     Header: 'X-Client-IP'
     Value: '{{current.header[`x-forwarded-for`].Split(`,`)[0]}}'
     Type: 'Setf'

But for this use case, you would be better off using/creating a specific plugin for it, and then using this plugin to manipulate headers.