private sharing; caddy (#392); sdk refactor

This commit is contained in:
Michael Quigley 2023-08-30 13:46:51 -04:00
parent d3c43c340e
commit 7bc8976951
No known key found for this signature in database
GPG Key ID: 9B60314A9DD20A62
4 changed files with 90 additions and 112 deletions

View File

@ -3,24 +3,18 @@ package main
import ( import (
"fmt" "fmt"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints" "github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel" "github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/endpoints/udpTunnel" "github.com/openziti/zrok/endpoints/udpTunnel"
"github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment"
"github.com/openziti/zrok/rest_client_zrok" "github.com/openziti/zrok/environment/env_core"
"github.com/openziti/zrok/rest_client_zrok/share"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/sdk" "github.com/openziti/zrok/sdk"
"github.com/openziti/zrok/tui" "github.com/openziti/zrok/tui"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"os" "os"
"os/signal" "os/signal"
"strings"
"syscall" "syscall"
) )
@ -44,7 +38,7 @@ func newSharePrivateCommand() *sharePrivateCommand {
} }
command := &sharePrivateCommand{cmd: cmd} command := &sharePrivateCommand{cmd: cmd}
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...") cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...")
cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel}") cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy}")
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless") cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>") cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>")
cmd.Run = command.run cmd.Run = command.run
@ -74,11 +68,14 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
case "udpTunnel": case "udpTunnel":
target = args[0] target = args[0]
case "caddy":
target = args[0]
default: default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel}", cmd.backendMode), nil) tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel}", cmd.backendMode), nil)
} }
env, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to load environment", err) tui.Error("unable to load environment", err)
@ -86,11 +83,11 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
panic(err) panic(err)
} }
if !env.IsEnabled() { if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil) tui.Error("unable to load environment; did you 'zrok enable'?", nil)
} }
zif, err := env.ZitiIdentityNamed(env.EnvironmentIdentityName()) zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName())
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to load ziti identity configuration", err) tui.Error("unable to load ziti identity configuration", err)
@ -98,36 +95,13 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
panic(err) panic(err)
} }
zrok, err := env.Client() req := &sdk.ShareRequest{
if err != nil { BackendMode: sdk.BackendMode(cmd.backendMode),
if !panicInstead { ShareMode: sdk.PrivateShareMode,
tui.Error("unable to create zrok client", err) Auth: cmd.basicAuth,
Target: target,
} }
panic(err) shr, err := sdk.CreateShare(root, req)
}
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Environment().Token)
req := share.NewShareParams()
req.Body = &rest_model_zrok.ShareRequest{
EnvZID: env.Environment().ZitiIdentity,
ShareMode: string(sdk.PrivateShareMode),
BackendMode: cmd.backendMode,
BackendProxyEndpoint: target,
AuthScheme: string(sdk.None),
}
if len(cmd.basicAuth) > 0 {
logrus.Infof("configuring basic auth")
req.Body.AuthScheme = string(sdk.Basic)
for _, pair := range cmd.basicAuth {
tokens := strings.Split(pair, ":")
if len(tokens) == 2 {
req.Body.AuthUsers = append(req.Body.AuthUsers, &rest_model_zrok.AuthUser{Username: strings.TrimSpace(tokens[0]), Password: strings.TrimSpace(tokens[1])})
} else {
panic(errors.Errorf("invalid username:password pair '%v'", pair))
}
}
}
resp, err := zrok.Share.Share(req, auth)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to create share", err) tui.Error("unable to create share", err)
@ -135,8 +109,8 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
panic(err) panic(err)
} }
shareDescription := fmt.Sprintf("access your share with: %v", tui.Code.Render(fmt.Sprintf("zrok access private %v", resp.Payload.ShrToken))) shareDescription := fmt.Sprintf("access your share with: %v", tui.Code.Render(fmt.Sprintf("zrok access private %v", shr.Token)))
mdl := newShareModel(resp.Payload.ShrToken, []string{shareDescription}, sdk.PrivateShareMode, sdk.BackendMode(cmd.backendMode)) mdl := newShareModel(shr.Token, []string{shareDescription}, sdk.PrivateShareMode, sdk.BackendMode(cmd.backendMode))
if !cmd.headless { if !cmd.headless {
proxy.SetCaddyLoggingWriter(mdl) proxy.SetCaddyLoggingWriter(mdl)
} }
@ -145,36 +119,45 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() { go func() {
<-c <-c
cmd.destroy(env.Environment().ZitiIdentity, resp.Payload.ShrToken, zrok, auth) cmd.shutdown(root, shr)
os.Exit(0) os.Exit(0)
}() }()
requestsChan := make(chan *endpoints.Request, 1024) requests := make(chan *endpoints.Request, 1024)
switch cmd.backendMode { switch cmd.backendMode {
case "proxy": case "proxy":
cfg := &proxy.BackendConfig{ cfg := &proxy.BackendConfig{
IdentityPath: zif, IdentityPath: zif,
EndpointAddress: target, EndpointAddress: target,
ShrToken: resp.Payload.ShrToken, ShrToken: shr.Token,
Insecure: cmd.insecure, Insecure: cmd.insecure,
RequestsChan: requestsChan, Requests: requests,
} }
_, err = cmd.proxyBackendMode(cfg)
be, err := proxy.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to create proxy backend handler", err) tui.Error("error creating proxy backend", err)
} }
panic(err) panic(err)
} }
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running http proxy backend: %v", err)
}
}()
case "web": case "web":
cfg := &proxy.CaddyWebBackendConfig{ cfg := &proxy.CaddyWebBackendConfig{
IdentityPath: zif, IdentityPath: zif,
WebRoot: target, WebRoot: target,
ShrToken: resp.Payload.ShrToken, ShrToken: shr.Token,
Requests: requestsChan, Requests: requests,
} }
_, err = cmd.webBackendMode(cfg)
be, err := proxy.NewCaddyWebBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to create web backend handler", err) tui.Error("unable to create web backend handler", err)
@ -182,13 +165,20 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
panic(err) panic(err)
} }
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running http web backend: %v", err)
}
}()
case "tcpTunnel": case "tcpTunnel":
cfg := &tcpTunnel.BackendConfig{ cfg := &tcpTunnel.BackendConfig{
IdentityPath: zif, IdentityPath: zif,
EndpointAddress: target, EndpointAddress: target,
ShrToken: resp.Payload.ShrToken, ShrToken: shr.Token,
RequestsChan: requestsChan, RequestsChan: requests,
} }
be, err := tcpTunnel.NewBackend(cfg) be, err := tcpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
@ -196,6 +186,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
} }
panic(err) panic(err)
} }
go func() { go func() {
if err := be.Run(); err != nil { if err := be.Run(); err != nil {
logrus.Errorf("error running tcpTunnel backend: %v", err) logrus.Errorf("error running tcpTunnel backend: %v", err)
@ -206,9 +197,10 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
cfg := &udpTunnel.BackendConfig{ cfg := &udpTunnel.BackendConfig{
IdentityPath: zif, IdentityPath: zif,
EndpointAddress: target, EndpointAddress: target,
ShrToken: resp.Payload.ShrToken, ShrToken: shr.Token,
RequestsChan: requestsChan, RequestsChan: requests,
} }
be, err := udpTunnel.NewBackend(cfg) be, err := udpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
@ -216,21 +208,43 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
} }
panic(err) panic(err)
} }
go func() { go func() {
if err := be.Run(); err != nil { if err := be.Run(); err != nil {
logrus.Errorf("error running udpTunnel backend: %v", err) logrus.Errorf("error running udpTunnel backend: %v", err)
} }
}() }()
case "caddy":
cfg := &proxy.CaddyfileBackendConfig{
CaddyfilePath: target,
Shr: shr,
Requests: requests,
}
be, err := proxy.NewCaddyfileBackend(cfg)
if err != nil {
if !panicInstead {
tui.Error("unable to create caddy backend", err)
}
panic(err)
}
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running caddy backend: %v", err)
}
}()
default: default:
tui.Error("invalid backend mode", nil) tui.Error("invalid backend mode", nil)
} }
if cmd.headless { if cmd.headless {
logrus.Infof("allow other to access your share with the following command:\nzrok access private %v", resp.Payload.ShrToken) logrus.Infof("allow other to access your share with the following command:\nzrok access private %v", shr.Token)
for { for {
select { select {
case req := <-requestsChan: case req := <-requests:
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path) logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
} }
} }
@ -243,7 +257,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
go func() { go func() {
for { for {
select { select {
case req := <-requestsChan: case req := <-requests:
prg.Send(req) prg.Send(req)
} }
} }
@ -253,51 +267,15 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
tui.Error("An error occurred", err) tui.Error("An error occurred", err)
} }
close(requestsChan) close(requests)
cmd.destroy(env.Environment().ZitiIdentity, resp.Payload.ShrToken, zrok, auth) cmd.shutdown(root, shr)
} }
} }
func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxy.BackendConfig) (endpoints.RequestHandler, error) { func (cmd *sharePrivateCommand) shutdown(root env_core.Root, shr *sdk.Share) {
be, err := proxy.NewBackend(cfg) logrus.Debugf("shutting down '%v'", shr.Token)
if err != nil { if err := sdk.DeleteShare(root, shr); err != nil {
return nil, errors.Wrap(err, "error creating http proxy backend") logrus.Errorf("error shutting down '%v': %v", shr.Token, err)
} }
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running http proxy backend: %v", err)
}
}()
return be, nil
}
func (cmd *sharePrivateCommand) webBackendMode(cfg *proxy.CaddyWebBackendConfig) (endpoints.RequestHandler, error) {
be, err := proxy.NewCaddyWebBackend(cfg)
if err != nil {
return nil, errors.Wrap(err, "error creating http web backend")
}
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running http web backend: %v", err)
}
}()
return be, nil
}
func (cmd *sharePrivateCommand) destroy(id string, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
logrus.Debugf("shutting down '%v'", shrToken)
req := share.NewUnshareParams()
req.Body = &rest_model_zrok.UnshareRequest{
EnvZID: id,
ShrToken: shrToken,
}
if _, err := zrok.Share.Unshare(req, auth); err == nil {
logrus.Debugf("shutdown complete") logrus.Debugf("shutdown complete")
} else {
logrus.Errorf("error shutting down: %v", err)
}
} }

View File

@ -71,7 +71,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil) tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
} }
env, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to load environment", err) tui.Error("unable to load environment", err)
@ -79,11 +79,11 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
panic(err) panic(err)
} }
if !env.IsEnabled() { if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil) tui.Error("unable to load environment; did you 'zrok enable'?", nil)
} }
zif, err := env.ZitiIdentityNamed(env.EnvironmentIdentityName()) zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName())
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to access ziti identity file", err) tui.Error("unable to access ziti identity file", err)
@ -98,7 +98,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
Auth: cmd.basicAuth, Auth: cmd.basicAuth,
Target: target, Target: target,
} }
shr, err := sdk.CreateShare(env, req) shr, err := sdk.CreateShare(root, req)
if err != nil { if err != nil {
if !panicInstead { if !panicInstead {
tui.Error("unable to create share", err) tui.Error("unable to create share", err)
@ -115,7 +115,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() { go func() {
<-c <-c
cmd.shutdown(env, shr) cmd.shutdown(root, shr)
os.Exit(0) os.Exit(0)
}() }()
@ -128,7 +128,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
EndpointAddress: target, EndpointAddress: target,
ShrToken: shr.Token, ShrToken: shr.Token,
Insecure: cmd.insecure, Insecure: cmd.insecure,
RequestsChan: requests, Requests: requests,
} }
be, err := proxy.NewBackend(cfg) be, err := proxy.NewBackend(cfg)
@ -220,7 +220,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
} }
close(requests) close(requests)
cmd.shutdown(env, shr) cmd.shutdown(root, shr)
} }
} }

View File

@ -127,7 +127,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
EndpointAddress: target, EndpointAddress: target,
ShrToken: shrToken, ShrToken: shrToken,
Insecure: cmd.insecure, Insecure: cmd.insecure,
RequestsChan: requestsChan, Requests: requestsChan,
} }
_, err := cmd.proxyBackendMode(cfg) _, err := cmd.proxyBackendMode(cfg)
if err != nil { if err != nil {

View File

@ -20,7 +20,7 @@ type BackendConfig struct {
EndpointAddress string EndpointAddress string
ShrToken string ShrToken string
Insecure bool Insecure bool
RequestsChan chan *endpoints.Request Requests chan *endpoints.Request
} }
type Backend struct { type Backend struct {
@ -88,8 +88,8 @@ func newReverseProxy(cfg *BackendConfig) (*httputil.ReverseProxy, error) {
proxy.Transport = tpt proxy.Transport = tpt
director := proxy.Director director := proxy.Director
proxy.Director = func(req *http.Request) { proxy.Director = func(req *http.Request) {
if cfg.RequestsChan != nil { if cfg.Requests != nil {
cfg.RequestsChan <- &endpoints.Request{ cfg.Requests <- &endpoints.Request{
Stamp: time.Now(), Stamp: time.Now(),
RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]), RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]),
Method: req.Method, Method: req.Method,