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

OIDC Auth for Funnel, k8s state support #1

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft

Conversation

lstoll
Copy link
Collaborator

@lstoll lstoll commented Mar 29, 2024

This adds OIDC auth for funnel usage. By default all funnel requests will require this, unless explicitly overridden.

Because this makes the config more complex, move to just using a file for it.

Add support for persisting state in a k8s secret too.

Add CI build, with docker image.

TODO

  • Update README
  • Resolve local tailscale daemon usage

Going to get more complex with k8s config + OIDC, make it a file.
Want to run it in k8s, add a backend that uses a secret to store the data.
While tailscale has one in their codebase, it's not suitable for our usage so
we just add a simple one.
Want a dedicated listener, so we can selectively apply auth etc. So just add a
new listener/server for that.

Redirect to https for internal requests on funnel fqdn's, to keep URLs
consistent.

Rework startup/shutdown a little to be more graceful.
Adds OIDC auth to funnel endpoints, setting user header consistently.

Optionally paths can be specified to be authless.
When running in a container, tailscale doesn't already exist so we can't talk
to it.

Just use a local listener, need to think about this more.
@lstoll
Copy link
Collaborator Author

lstoll commented Mar 29, 2024

Need to think about the local tailscale daemon usage - it's there to figure out where to bind the discovery and metrics endpoints, but this doesn't work when it's running in a container.

Might make a config option (ugh, checkboxes) for metrics listen - either set it to a fixed ip/port, or fallback to daemon discovery. But will think on it more

@@ -0,0 +1,117 @@
package main
Copy link
Owner

Choose a reason for hiding this comment

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

@@ -205,98 +163,210 @@ func tsproxy(ctx context.Context) error {
}
}

for i, upstream := range upstreams {
// https://go.dev/doc/faq#closures_and_goroutines
i := i
Copy link
Owner

Choose a reason for hiding this comment

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

hehe nice

// OIDCClientID sets the OIDC client ID
OIDCClientID string `json:"oidcClientID"`
// OIDCClientSecret sets the OIDC client secret
OIDCClientSecret string `json:"oidcClientSecret"`
Copy link
Owner

Choose a reason for hiding this comment

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

be cool to support a file too, play nice with systemd-creds. For flags I usually do this:

	if _, path, ok := strings.Cut(*cliSecret, "file://"); ok {
		b, err := os.ReadFile(path)
		if err != nil {
			return err
		}
		s := strings.TrimSpace(string(b))
		cliSecret = &s
	}

but doesn't really work w/ a config file. Maybe oidcClientSecretFile?

Copy link
Owner

@sr sr Mar 29, 2024

Choose a reason for hiding this comment

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

also wondering if this should be on the root config struct, or do you plan on using a different issuer for some upstream(s)?

StateDir string `json:"stateDir"`
// Kubernetes configures the proxy to run in a kubernetes cluster. In this
// case the StateDir is ignored, and state managed in a secret.
Kubernetes kubernetesConfig `json:"kubernetes"`
Copy link
Owner

Choose a reason for hiding this comment

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

*kubernetesConfig? then can drop the enabled field.

}
listeners = append(listeners, ln)
}*/
ln, err := net.Listen("tcp", "0.0.0.0:"+p)
Copy link
Owner

Choose a reason for hiding this comment

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

I use http://nuc10i5/sd in my prom config, I guess I could make tsproxy.service listen on the node's tailscale IP using some ansible: {{ ansible_facts.tailscale0.ipv4.address }

alternatively could you check for the presence of a local socket? will think about it too.

// Proxy requests from non-funnel tagged nodes as is.
//
// TODO(lstoll) figure out why - and if end-user nodes would be tagged?
if whois.Node.IsTagged() && !isFunnel {
Copy link
Owner

Choose a reason for hiding this comment

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

yeah I guess a config w/ a list of tags, or maybe node id to consider as end-users??

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.

2 participants