From 58b573acea8ea469979a3fd03ed0ece6568cca40 Mon Sep 17 00:00:00 2001 From: Paul Lorenz Date: Wed, 10 Mar 2021 20:56:39 -0500 Subject: [PATCH] Updates for converged router/tunneller --- CHANGELOG.md | 120 +++++++++++++++++- etc/ctrl.with.edge.yml | 17 +-- etc/tmpl/edge.router.yml | 1 + go.mod | 2 +- go.sum | 4 +- ziti-router/subcmd/run.go | 17 ++- ziti-tunnel/cmd/ziti-tunnel/subcmd/proxy.go | 39 +----- .../cmd/edge_controller/create_edge_router.go | 7 +- .../cmd/edge_controller/update_edge_router.go | 11 +- 9 files changed, 157 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2770fe4f9..e80b8f177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,108 @@ +# Release 0.19.8 + +## What's New + +* Converged Tunneler/Router + +## Converged Tunneler/Router + +ziti-router can now run with the tunneler embedded. It has the same capabilities as ziti-tunnel. As +ziti-tunnel gains new features, the combined ziti-router/tunnel should maintain feature parity. + +### Supported configurations + +Current only `ziti-tunneler-server.v1` and `ziti-tunneler-client.v1` are supported. Support +for `host.v1`, `intercept.v1` and the upcoming `host.v2` will be added in a follow-up release. + +### Router Identities + +When an edge router is marked as being tunneler enabled, a matching identity will be created, of +type Router, as well as an edge router policy. The edge router policy ensures that the identity +always has access to the edge router. The identity allows the router to be included in service +policies, to configure which services will intercepted/hosted. + +1. The identity will have the same id and name as the edge router +1. If an identity with the same name as the router already exists, the router create/update will + fail +1. When the router name is changed, the identity name will be updated as well. +1. The identity name and type cannot be changed directly. The type may not be changed at all and the + name may only be changed by changing the name of the router. +1. The identity may not be deleted except by deleting the router or disabling tunneler support for + the identity. +1. When the router is deleted, the accompanying identity and edge router policy will also be deleted +1. If tunneler support is disabled in the router, the accompanying identity and edge router policy + will also be deleted. +1. The edge router policy will have the same id as the router and have a name of the + form `edge-router--system`, where `` is replaced by the id of the + edge router. +1. The edge router policy is considered a `system` entity, and cannot be updated and cannot deleted + except by the system when the associated router is deleted. + +### Tunneler Prerequisites + +In order for a router instance to host a tunneler, it must meet the following criteria: + +1. It must be represented in the model by an edge router +2. The edge router field `isTunnelerEnabled` must be set to true +3. Edge functionality in the router must be enabled, which means the `edge:` config section must be + present. NOTE: The edge listener does **not** need to be enabled. +4. The tunnel listener must be enabled. + +### Making an Edge Router Tunneler enabled + +The ziti CLI can be used to enable/disable tunneler support on edge routers. When creating an edge +router, the `-t` flag can be passed in to enable running the tunneler. + +```shell +ziti edge create edge-router myEdgeRouter --tunneler-enabled +``` + +or + +```shell +ziti edge create edge-router myEdgeRouter -t +``` + +An existing edge router can be marked as tunneler enabled as follows: + +```shell +ziti edge update edge-router myEdgeRouter --tunneler-enabled +``` + +or + +```shell +ziti edge update edge-router myEdgeRouter -t +``` + +An existing edge router can be marked as not supporting the tunneler as follows: + +```shell +ziti edge update edge-router myEdgeRouter -t=false +``` + +or + +```shell +ziti edge update edge-router myEdgeRouter --tunneler-enabled=false +``` + +### Tunnel listener configuration + +```yaml + +listeners: + - binding: tunnel + options: + mode: tproxy # mode to run in. Valid values [tproxy, host, proxy]. Default: tproxy + svcPollRate: 15s # How often to poll for service changes. Default: 15s + resolver: udp://127.0.0.1:53 # DNS resolve. Default: udp://127.0.0.1:53 for tproxy, blank for others + dnsSvcIpRange: 100.64.0.1/10 # cidr to use when assigning IPs to unresolvable intercept hostnames (default "100.64.0.1/10") + services: # services to intercept in proxy mode. Default: none + - echo:1977 + lanIf: tun1 # if specified, INPUT rules for intercepted service addresses are assigned to this interface. Defaults to unspecified. +``` + # Release 0.19.7 ## What's New @@ -90,17 +195,19 @@ Example Output: ### Heartbeat Collection And Batching -In previous versions heartbeats from REST API usage and discrete Edge Router connection would all cause writes -for the same API Session as they were encountered. In situations where one or more REST API requests were issues and/or one or more -Edge Router connections were held by a ZitI Application, multiple simultaneous heartbeats could occur for no apparent benefit -and consume disk write I/O. +In previous versions heartbeats from REST API usage and discrete Edge Router connection would all +cause writes for the same API Session as they were encountered. In situations where one or more REST +API requests were issues and/or one or more Edge Router connections were held by a ZitI Application, +multiple simultaneous heartbeats could occur for no apparent benefit and consume disk write I/O. -Heartbeats are now aggregated over a window of time in a cache and written to disk on an interval. The write interval defaults to 90s -and the batch size (for write transactions) to 250. Additionally, all heartbeats are flush to disk when the controller is properly shut down. +Heartbeats are now aggregated over a window of time in a cache and written to disk on an interval. +The write interval defaults to 90s and the batch size (for write transactions) to 250. Additionally, +all heartbeats are flush to disk when the controller is properly shut down. These settings can be defined in the `edge.api` section for the Ziti Controller configuration. Example: + ``` edge: api: @@ -112,7 +219,6 @@ edge: ... ``` - ### Add Service Request Failures for Posture Checks When a Ziti Identity (endpoint) requests a service that is provided via a Service Policy with diff --git a/etc/ctrl.with.edge.yml b/etc/ctrl.with.edge.yml index 9bd715d29..0a4667dce 100644 --- a/etc/ctrl.with.edge.yml +++ b/etc/ctrl.with.edge.yml @@ -52,10 +52,10 @@ metrics: #url: http://localhost:8086 #database: ziti -# events: -# jsonLogger: -# subscriptions: -# - type: fabric.terminators +events: + jsonLogger: + subscriptions: + - type: fabric.terminators # - type: metrics # sourceFilter: .* # metricFilter: .*egress.*m1_rate* @@ -66,10 +66,11 @@ metrics: # include: # - created # - type: fabric.usage -# handler: -# type: file -# format: json -# path: /tmp/ziti-events.log + - type: services + handler: + type: file + format: json + path: /tmp/ziti-events.log terminator: validators: diff --git a/etc/tmpl/edge.router.yml b/etc/tmpl/edge.router.yml index e6f1fe7b1..0ea063459 100644 --- a/etc/tmpl/edge.router.yml +++ b/etc/tmpl/edge.router.yml @@ -80,6 +80,7 @@ dialers: - binding: transport listeners: + - binding: tunnel - binding: edge address: tls:0.0.0.0:${ZITI_EDGE_PORT} options: diff --git a/go.mod b/go.mod index d751ded19..30acde55f 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 github.com/michaelquigley/pfxlog v0.3.7 - github.com/openziti/edge v0.19.42 + github.com/openziti/edge v0.19.44 github.com/openziti/fabric v0.16.34 github.com/openziti/foundation v0.15.38 github.com/openziti/sdk-golang v0.15.25 diff --git a/go.sum b/go.sum index 6a2a3b028..47885c86f 100644 --- a/go.sum +++ b/go.sum @@ -620,8 +620,8 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e h1:ST9+54UtCr96S5+Wa7LQtpGS6/xK7Z+KQXvOAtYgJlA= github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -github.com/openziti/edge v0.19.42 h1:N/AJpNlWWuTe9T3Xm+yKvZtn3s5AuPF3yiwB4hc78IE= -github.com/openziti/edge v0.19.42/go.mod h1:f4RGk64cNx+SfENoz/SQb9vqj4zhGfJETVCeDWACOTU= +github.com/openziti/edge v0.19.44 h1:eh/9LkVVp86t6Zsbd3WTHGCTMFQae3NAmOpd+0TVD3Y= +github.com/openziti/edge v0.19.44/go.mod h1:f4RGk64cNx+SfENoz/SQb9vqj4zhGfJETVCeDWACOTU= github.com/openziti/fabric v0.16.34 h1:WmznP2xp6KkevPIPis9EgRM9F3nHz4F4XAAeZTe2jbc= github.com/openziti/fabric v0.16.34/go.mod h1:VJeX6WbHMVsUiYuiAVRnChAGTM4fN2DL01M7ibD09a4= github.com/openziti/foundation v0.15.38 h1:Cy6LkIhROI0k2tHbuEDWUu4aouNZrv4DZ5fIXOOkIBA= diff --git a/ziti-router/subcmd/run.go b/ziti-router/subcmd/run.go index 8e71084d8..92e63a7bb 100644 --- a/ziti-router/subcmd/run.go +++ b/ziti-router/subcmd/run.go @@ -18,8 +18,11 @@ package subcmd import ( "github.com/michaelquigley/pfxlog" + "github.com/openziti/edge/edge_common" + "github.com/openziti/edge/router/fabric" "github.com/openziti/edge/router/xgress_edge" "github.com/openziti/edge/router/xgress_edge_transport" + "github.com/openziti/edge/router/xgress_edge_tunnel" "github.com/openziti/fabric/router" "github.com/openziti/fabric/router/xgress" "github.com/openziti/foundation/agent" @@ -69,15 +72,23 @@ func run(cmd *cobra.Command, args []string) { config.SetFlags(getFlags(cmd)) - xgressEdgeFactory := xgress_edge.NewFactory(config, version.GetCmdBuildInfo()) - xgress.GlobalRegistry().Register("edge", xgressEdgeFactory) + stateManager := fabric.NewStateManager() + + xgressEdgeFactory := xgress_edge.NewFactory(config, version.GetCmdBuildInfo(), stateManager) + xgress.GlobalRegistry().Register(edge_common.EdgeBinding, xgressEdgeFactory) if err := r.RegisterXctrl(xgressEdgeFactory); err != nil { logrus.Panicf("error registering edge in framework (%v)", err) } - xgressEdgeTransportFactory := xgress_edge_transport.NewFactory(config.Id, r) + xgressEdgeTransportFactory := xgress_edge_transport.NewFactory(r) xgress.GlobalRegistry().Register(xgress_edge_transport.BindingName, xgressEdgeTransportFactory) + xgressEdgeTunnelFactory := xgress_edge_tunnel.NewFactory(config, stateManager) + xgress.GlobalRegistry().Register(edge_common.TunnelBinding, xgressEdgeTunnelFactory) + if err := r.RegisterXctrl(xgressEdgeTunnelFactory); err != nil { + logrus.Panicf("error registering edge tunnel in framework (%v)", err) + } + if err := r.Run(); err != nil { logrus.WithError(err).Fatal("error starting") } diff --git a/ziti-tunnel/cmd/ziti-tunnel/subcmd/proxy.go b/ziti-tunnel/cmd/ziti-tunnel/subcmd/proxy.go index 72c143758..be36a5ab8 100644 --- a/ziti-tunnel/cmd/ziti-tunnel/subcmd/proxy.go +++ b/ziti-tunnel/cmd/ziti-tunnel/subcmd/proxy.go @@ -17,14 +17,12 @@ package subcmd import ( - "fmt" - "github.com/openziti/edge/tunnel/intercept" "github.com/openziti/edge/tunnel/intercept/proxy" + "github.com/pkg/errors" "github.com/spf13/cobra" "math" "net" "strconv" - "strings" ) var runProxyCmd = &cobra.Command{ @@ -41,36 +39,6 @@ func init() { } func runProxy(_ *cobra.Command, args []string) error { - services := make(map[string]*proxy.Service, len(args)) - - for _, arg := range args { - parts := strings.Split(arg, ":") - if len(parts) < 2 || len(parts) > 3 { - return fmt.Errorf("invalid argument '%s'", arg) - } - - port, err := strconv.Atoi(parts[1]) - if err != nil { - return fmt.Errorf("invalid port specified in '%s'", arg) - } - - service := &proxy.Service{ - Name: parts[0], - Port: port, - Protocol: intercept.TCP, - } - - if len(parts) == 3 { - protocol := parts[2] - if protocol == "udp" { - service.Protocol = intercept.UDP - } else if protocol != "tcp" { - return fmt.Errorf("invalid protocol specified in '%s', must be tcp or udp", arg) - } - } - services[parts[0]] = service - } - // Fiddle with the poll rate and resolver settings if the user didn't wan't anything special. if !root.Flag(svcPollRateFlag).Changed { _ = root.PersistentFlags().Set(svcPollRateFlag, strconv.FormatUint(math.MaxUint32, 10)) @@ -79,9 +47,8 @@ func runProxy(_ *cobra.Command, args []string) error { _ = root.PersistentFlags().Set(resolverCfgFlag, "") } var err error - interceptor, err = proxy.New(net.IPv4zero, services) - if err != nil { - return fmt.Errorf("failed to initialize proxy interceptor: %v", err) + if interceptor, err = proxy.New(net.IPv4zero, args); err != nil { + return errors.Wrap(err, "failed to initialize proxy interceptor") } return nil } diff --git a/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go b/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go index af7643173..f440525b7 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go +++ b/ziti/cmd/ziti/cmd/edge_controller/create_edge_router.go @@ -30,8 +30,9 @@ import ( type createEdgeRouterOptions struct { edgeOptions - roleAttributes []string - jwtOutputFile string + isTunnelerEnabled bool + roleAttributes []string + jwtOutputFile string } func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { @@ -59,6 +60,7 @@ func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) // allow interspersing positional args and flags cmd.Flags().SetInterspersed(true) cmd.Flags().StringSliceVarP(&options.roleAttributes, "role-attributes", "a", nil, "Role attributes of the new edge router") + cmd.Flags().BoolVarP(&options.isTunnelerEnabled, "tunneler-enabled", "t", false, "Can this edge router be used as a tunneler") cmd.Flags().StringVarP(&options.jwtOutputFile, "jwt-output-file", "o", "", "File to which to output the JWT used for enrolling the edge router") options.AddCommonFlags(cmd) @@ -69,6 +71,7 @@ func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) func runCreateEdgeRouter(o *createEdgeRouterOptions) error { routerData := gabs.New() setJSONValue(routerData, o.Args[0], "name") + setJSONValue(routerData, o.isTunnelerEnabled, "isTunnelerEnabled") setJSONValue(routerData, o.roleAttributes, "roleAttributes") result, err := createEntityOfType("edge-routers", routerData.String(), &o.edgeOptions) diff --git a/ziti/cmd/ziti/cmd/edge_controller/update_edge_router.go b/ziti/cmd/ziti/cmd/edge_controller/update_edge_router.go index 46f06d131..9e61b499d 100644 --- a/ziti/cmd/ziti/cmd/edge_controller/update_edge_router.go +++ b/ziti/cmd/ziti/cmd/edge_controller/update_edge_router.go @@ -31,8 +31,9 @@ import ( type updateEdgeRouterOptions struct { edgeOptions - name string - roleAttributes []string + name string + isTunnelerEnabled bool + roleAttributes []string } func newUpdateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { @@ -59,6 +60,7 @@ func newUpdateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) // allow interspersing positional args and flags cmd.Flags().SetInterspersed(true) cmd.Flags().StringVarP(&options.name, "name", "n", "", "Set the name of the edge router") + cmd.Flags().BoolVarP(&options.isTunnelerEnabled, "tunneler-enabled", "t", false, "Can this edge router be used as a tunneler") cmd.Flags().StringSliceVarP(&options.roleAttributes, "role-attributes", "a", nil, "Set role attributes of the edge router. Use --role-attributes '' to set an empty list") options.AddCommonFlags(cmd) @@ -80,6 +82,11 @@ func runUpdateEdgeRouter(o *updateEdgeRouterOptions) error { change = true } + if o.Cmd.Flags().Changed("tunneler-enabled") { + setJSONValue(entityData, o.isTunnelerEnabled, "isTunnelerEnabled") + change = true + } + if o.Cmd.Flags().Changed("role-attributes") { setJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true