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

Secure socks proxy: Allow the env variables to be overriden #716

Merged
merged 6 commits into from
Jul 17, 2023

Conversation

stephaniehingtgen
Copy link
Contributor

@stephaniehingtgen stephaniehingtgen commented Jul 14, 2023

What this PR does / why we need it:
This PR adds functionality for environment variables to be overriden by a config. This allows us to use the plugin sdk within Grafana and reduce code redundancy.

A draft Grafana PR is up now on how this will be used

Which issue(s) this PR fixes:

Related to https://github.com/grafana/hosted-grafana/issues/3754

Special notes for your reviewer:

@stephaniehingtgen stephaniehingtgen requested a review from a team as a code owner July 14, 2023 00:03
@stephaniehingtgen stephaniehingtgen requested review from wbrowne and xnyo and removed request for a team July 14, 2023 00:03
Comment on lines 163 to 169
// SetSecureSocksProxyConfig overrides the default proxy configuration set by the Grafana env variables
func SetSecureSocksProxyConfig(cfg *SecureSocksProxyConfig) {
proxyConfig = cfg
}

// proxyConfig is automatically set through the env variables added to plugin contexts by grafana
var proxyConfig = getConfigFromEnv()
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this approach is deterministic enough. We should not keep global state. For example, calling SecureSocksProxyEnabled would return different values depening on when it's called.

The desired approach would be to make all the exposed methods as part of an interface and then instantiate a secureSocksProxy based either on env vars or a config.

I understand that is a breaking change (since now something needs to be initialized before accessing the exposed functions) and if that's something we cannot break, I would suggest to keep exposing those functions but falling back to use environment variables (since that's the current behavior). Something like:

func SecureSocksProxyEnabled(opts *Options) bool {
  return NewSecureSocksProxyFromEnv().SecureSocksProxyEnabled(opts *Options)
}

If we are fine with the breaking change, we can skip that.

Is what I propose possible?

Copy link
Member

Choose a reason for hiding this comment

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

Also in the interests of multitenancy, having any plugin state that could potentially be shared amongst tenants would be best avoided. I realize this isn't how things are working now, but ideally we move in a direction where we can build more confidence 🙏

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 made some updates, but this is definitely something to be revisited when a solution for the environment variables is determined.

To make it consistent, I used similar logic to the Logger, where the Default Logger is available for plugins, but then Grafana overrides the default logger internally. For the proxy.Cli, I also have a default of the environment variables, but override that default in the grafana core server based on the config.

I would prefer to wait to add a breaking change until we have the environment variables figured out, otherwise we'll have to update 15+ plugins twice (once to initialize the environment variables to initialize the client, and then go back through when the env variables are removed). But let me know if this is a blocking concern

I tested these changes out with various core datasources and MongoDB and things are looking good.

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 also updated the Grafana PR to include the changes for this

Copy link
Contributor

Choose a reason for hiding this comment

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

I am sorry, I completely missed this message and the related line of code. Now, reviewing your other PR I noticed the change. Unfortunately this is not something we want to move forward with. The Default Logger you point out is an (ugly) workaround that we had to implement so core plugins could behave as external plugins. We are currently working on removing differences between core and external plugins and having different behavior calling the same SDK functions is not something we want to promote.

I would prefer to wait to add a breaking change

This was a breaking change anyway since all the plugins would need to change the call from, for example, proxy.SecureSocksProxyEnabled to proxy.Cli.SecureSocksProxyEnabled. Which I guess is more convenient than having to pass down a client but still a breaking change.

and then go back through when the env variables are removed

We don't know how that would look like so better not to base current code on unknowns.

But let me know if this is a blocking concern

Sorry again, this should have been blocked, my bad.

Copy link
Contributor

Choose a reason for hiding this comment

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

After a conversation with @stephaniehingtgen offline discussing the issue. This is my summary:

  • The end goal of this is to automatically set the secure proxy when creating a new http client.
  • All data sources have access to data source settings when creating the client but not to Grafana config. The required information to set up the client is in the Grafana config, not in the data source config.
  • External plugins using the SDK obtain that configuration through environment variables.

The goal is to use the same SDK functions both for core plugins and external plugins but those two access to Grafana config differently. We have the following options:

  • The current one. Grafana core changes the SDK implementation to create a default client from the config that it has, not environment variables.
  • Manually modify the clients generated in Grafana for its core plugins. This has been discarded because it adds boilerplate code and adds to the differences between core plugins code and external ones.
  • Set the required config in Grafana as environment variables. That way the SDK would have access to that info as environment variables in any case. This option has been discarded as well by @marefr.

Since there is no better option, we concluded to continue with the code as it is. Thanks for the context @stephaniehingtgen

Copy link
Contributor

Choose a reason for hiding this comment

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

To clarify, this invalidates the possibility to use a multi tenant instance as @wbrowne highlightes but it may be fine since people using secure proxied connections will likely run on a standalone instance.

Copy link
Contributor

@andresmgot andresmgot left a comment

Choose a reason for hiding this comment

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

Code wise LGTM. Make sure to add a notice about the breaking change when releasing.

backend/proxy/secure_socks_proxy.go Outdated Show resolved Hide resolved
@stephaniehingtgen stephaniehingtgen merged commit 30591d3 into main Jul 17, 2023
2 checks passed
@stephaniehingtgen stephaniehingtgen deleted the secure-socks-proxy-allow-overrides branch July 17, 2023 19:20
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.

None yet

3 participants