diff --git a/README.md b/README.md index 0f1d8596..78dbad8b 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ to be aware of. from OIDC/oAuth/etc.) to authenticate with OpenZIti - [`reflect`](example/reflect) - a low level network "echo" client and server example - [`simple-server`](example/simple-server) - a bare-bones HTTP server side only example + - [`udp-offload`](example/udp-offload) - an example demonstrating how to work with an OpenZiti client and a UDP server - [`zcat`](example/zcat) - wrapping existing network tooling (netcat) to work over OpenZiti - [`zping`](example/zping) - wrapping existing network tooling (ping) to work over OpenZiti diff --git a/RELEASING.md b/RELEASING.md index 0599413e..bf54b66e 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,6 +2,8 @@ As part of your PR, do the following: +* Install `ziti-ci` + * `go install github.com/openziti/ziti-ci@v0.5.125` (or latest) * Make sure the buildinfo is up to date using: * `ziti-ci update-sdk-build-info` * This will update the version number in the code diff --git a/example/udp-offload/README.md b/example/udp-offload/README.md new file mode 100644 index 00000000..97ed04e3 --- /dev/null +++ b/example/udp-offload/README.md @@ -0,0 +1,95 @@ +# Overview +This example illustrates how to send data to, and receive data from a UDP server via OpenZiti. +You will configure an OpenZiti overlay network and run a UDP server that will respond with whatever text it was sent. +The response from the server will be read written to the console. + +This example demonstrates a hybrid approach ZTAA --> ZTHA: +* Dialing a service +* Binding a service using a tunneler + +## Requirements +* OpenZiti CLI to create services and identities on the OpenZiti Network +* an OpenZiti network. If you have one you'd like to use, great. The guide is written using the + `ziti edge quickstart` command. +* All commands are executed relative to the `example` folder + +## Build the examples +Refer to the [example README](../README.md) to build the SDK examples + +## Run and Configure OpenZiti +The README assumes the `ziti` CLI on your path. If not, supply the full path to the `ziti` executable. This command +will start a ziti overlay network on ports 1280/3022 for use with the rest of the README. The default values will +also be used for username and password. The router from the quickstart is the identity which will offload the OpenZiti +traffic toward the UDP server + +In a new terminal run the following command: +``` +ziti edge quickstart +``` + +To configure the overlay, you will need another terminal with `ziti` on the path. Now, add a service for the UDP +server to be offloaded from the OpenZiti overlay as well as create the identity this example will use: +``` +svc_name="udp.relay.example" +edge_router_name="quickstart-router" +ziti edge login localhost:1280 -u admin -p admin -y +ziti edge create config ${svc_name}.hostv1 host.v1 '{"protocol":"udp", "address":"127.0.0.1","port":10001}' +ziti edge create service ${svc_name} --configs "${svc_name}.hostv1" +ziti edge create service-policy ${svc_name}.dial Dial --identity-roles "#${svc_name}.dialers" --service-roles "@${svc_name}" +ziti edge create service-policy ${svc_name}.bind Bind --identity-roles "#${svc_name}.binders" --service-roles "@${svc_name}" + +ziti edge create identity ${svc_name}.client -a ${svc_name}.dialers -o ${svc_name}.client.jwt +ziti edge enroll --jwt ${svc_name}.client.jwt + +ziti edge update identity ${edge_router_name} -a "${svc_name}.binders" +ziti edge policy-advisor services -q +``` + +## Run the UDP Server +In the terminal from where you configured the OpenZiti overlay start the UDP server. Make sure you're in the +`example` folder and run: +``` +./build/udp-server +``` + +You should now have a UDP server that is listening on port 10001 and will respond to UDP messages sent to it. +``` +$ ./build/udp-server +Listening on :10001 +``` + +## Run the Example +Make sure the router (or identity) hosting the service establishes a terminator. Issue the following command and verify +a terminator is listed as shown: +``` +ziti edge list terminators 'service.name="udp.relay.example"' +``` + +example output: +``` +$ ziti edge list terminators 'service.name="udp.relay.example"' +╭───────────────────────┬───────────────────┬───────────────────┬─────────┬───────────────────────┬──────────┬──────┬────────────┬──────────────╮ +│ ID │ SERVICE │ ROUTER │ BINDING │ ADDRESS │ IDENTITY │ COST │ PRECEDENCE │ DYNAMIC COST │ +├───────────────────────┼───────────────────┼───────────────────┼─────────┼───────────────────────┼──────────┼──────┼────────────┼──────────────┤ +│ sNVBPDKuI6q5I0f2PrEc6 │ udp.relay.example │ quickstart-router │ tunnel │ sNVBPDKuI6q5I0f2PrEc6 │ │ 0 │ default │ 0 │ +╰───────────────────────┴───────────────────┴───────────────────┴─────────┴───────────────────────┴──────────┴──────┴────────────┴──────────────╯ +results: 1-1 of 1 +``` + +With the terminator in place, run the sample +``` +./build/udp-offload-client ./udp.relay.example.client.json +``` + +example output: +``` +$ ./build/udp-offload-client ./udp.relay.example.client.json +INFO[0000] found service named: udp.relay.example +INFO[0000] Connected to udp.relay.example successfully. +INFO[0000] You may now type a line to be sent to the server (press enter to send) +INFO[0000] The line will be sent to the reflect server and returned +this is the udp example +wrote 24 bytes +Sent :this is the udp example +Received: udp server echo: this is the udp example +``` \ No newline at end of file diff --git a/example/udp-offload/udp-offload-client/main.go b/example/udp-offload/udp-offload-client/main.go new file mode 100644 index 00000000..31d093a7 --- /dev/null +++ b/example/udp-offload/udp-offload-client/main.go @@ -0,0 +1,83 @@ +package main + +import ( + "bufio" + "fmt" + "github.com/michaelquigley/pfxlog" + "github.com/openziti/sdk-golang/ziti" + "io" + "os" +) + +var log = pfxlog.Logger() + +func main() { + serviceName := "udp.relay.example" + + zitiCfg, err := ziti.NewConfigFromFile(os.Args[1]) + if err != nil { + log.Fatalf("failed to load ziti configuration file: %v", err) + } + zitiCfg.ConfigTypes = []string{ + "ziti-tunneler-client.v1", + } + + ctx, err := ziti.NewContext(zitiCfg) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + foundSvc, ok := ctx.GetService(serviceName) + if !ok { + fmt.Println("error when retrieving all the services for the provided config") + os.Exit(1) + } + log.Infof("found service named: %s", *foundSvc.Name) + + svc, err := ctx.Dial(serviceName) //dial the service using the given name + if err != nil { + fmt.Println(fmt.Sprintf("error when dialing service name %s. %v", serviceName, err)) + os.Exit(1) + } + + go ReadFromZiti(svc) + log.Infof("Connected to %s successfully.", serviceName) + log.Info("You may now type a line to be sent to the server (press enter to send)") + log.Info("The line will be sent to the reflect server and returned") + ReadFromConsole(svc) +} + +func ReadFromConsole(writer io.Writer) { + conWrite := bufio.NewWriter(writer) + reader := bufio.NewReader(os.Stdin) + for { + text, err := reader.ReadString('\n') //read a line from input + if err != nil { + fmt.Println(err) + os.Exit(1) + } + bytesRead, err := conWrite.WriteString(text) + _ = conWrite.Flush() + if err != nil { + fmt.Println(err) + os.Exit(1) + } else { + fmt.Println("wrote", bytesRead, "bytes") + } + fmt.Print("Sent :", text) + } +} + +func ReadFromZiti(reader io.Reader) { + conRead := bufio.NewReader(reader) + for { + read, err := conRead.ReadString('\n') + if err != nil { + fmt.Println(err) + os.Exit(1) + } else { + fmt.Print("Received: ", read) + } + } +} diff --git a/example/udp-offload/udp-server/udp-server.go b/example/udp-offload/udp-server/udp-server.go new file mode 100644 index 00000000..2ee97581 --- /dev/null +++ b/example/udp-offload/udp-server/udp-server.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "net" + "os" +) + +func main() { + addr := ":10001" + conn, err := net.ListenPacket("udp", addr) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + defer conn.Close() + fmt.Printf("Listening on %s\n", addr) + + buf := make([]byte, 1024) + for { + n, remoteAddr, err := conn.ReadFrom(buf) + if err != nil { + fmt.Println("Error reading:", err) + continue + } + + fmt.Printf("%s sent: %s\n", remoteAddr, string(buf[:n-1])) + + _, err = conn.WriteTo([]byte("udp server echo: "), remoteAddr) + if err != nil { + fmt.Println("Error writing:", err) + } + _, err = conn.WriteTo(buf[:n], remoteAddr) + if err != nil { + fmt.Println("Error writing:", err) + } + } +} diff --git a/example/zping/README.md b/example/zping/README.md index a8580e25..5387fe9c 100644 --- a/example/zping/README.md +++ b/example/zping/README.md @@ -1,123 +1,137 @@ -# Intro: +# zping -What is zping? zping replaces the function of icmp ping tool in a ziti network. +`zping` provides equivalent functionality for an OpenZiti overlay network as the similarly named underlay function +`ping`. Being a zero trust overlay network, classic underlay tooling like `ping` won't function properly. -It provides an end to end latency measurement between any two ziti identities in a ziti network and like icmp ping will provide the following metrics upon completion of the ping session: +`zping` provides end to end latency measurements between any two identities in an OpenZiti network. Like `icmp`, `zping` +will provide the following metrics upon completion of the ping session: -min, max and mean latency and standard deviation. +* min +* max +* mean latency +* standard deviation. -zping uses the addressable terminator function of ziti to direct ping requests to specific identities. +`zping` uses addressable terminators to direct ping requests to specific identities. -# Get the code : +## Build the Example +Refer to the [example README](../README.md) to build the SDK examples -Compile from source: +## Setup and Configure the Example -Install golang for your platform follow instructions at https://golang.org -and ensure you set you gopath properly for your platform. i.e -Ubuntu linux: - -``` -export GOPATH=$HOME/go -``` -``` -export PATH=$PATH:$GOROOT/bin:$GOPATH/bin -``` - -Linux: - - Create a dir -``` - mkdir zitiapps -``` -``` - $ cd zitiapps -``` -``` - $ git clone https://github.com/openziti/sdk-golang.git -``` -``` - $ cd sdk-golang/example/zping -``` -``` - $ go install zping -``` - -# Setup the Network and the Ziti Service : +This README will use the `ziti edge quickstart` command for its example. You'll need the `ziti` CLI on your path to run +the commands shown. If you have an OpenZiti overlay network already, some commands will not be necessary. The +commands all use bash and expect you're running on a version of *nix as `/tmp` is referenced. Adapt accordingly if +you're using Windows. The example expects the binary to be put into the build directory as specified by the "Build +the Example" section above. ![Diagram](network.png) -1. Create or use an existing ziti network with at least one edge router. - -2. Create at least two ziti identities and give them a common identity role i.e. #ping - - e.g. zitiendpoint1, zitiendpoint2 - -3. Create a simple sdk service named “ziti-ping” this is the default service zping looks for but can be - - overridden with the -s command line flag. - -4. Create a bind policy with identityRoles set to [#ping] and serviceroles set to [@ziti-ping]. - -5. Create a dial service policy with identityRoles set to [#ping] and serviceroles set to [@ziti-ping]. - -6. Ensure that you have created appropriate edge-router and service-edge-router policies allowing the identities access - edge-router(s) and the edge-routers access to the service. - -7. Create an AppWAN and enter @ziti-ping in the service attributes and #ping in the “Endpoint Attributes” - -8. Download the zpingendpoint1.jwt, zpingendpoint2.jwt - -9. Distribute the zping binary to the endpoint(s) you wish to run on - -10. Enroll the endpoints with the zping binary i.e. -``` - $ zping enroll -j zitiendpoint1.jwt - - INFO[0000] generating 4096 bit RSA key - - INFO[0002] enrolled successfully. identity file written to: zpingendpoint1.json -``` -``` - $ zping enroll -j zpingendpoint2.jwt - - INFO[0000] generating 4096 bit RSA key - - INFO[0002] enrolled successfully. identity file written to: zpingendpoint2.json -``` -11. On each machine in run either in background or a separate window in server mode -``` - $ zping server -c zpingendpoint1.json & - [1] 4123 - INFO[0000] binding service ziti-ping - - zpingendpoint1 now serving - - INFO[0000] connection to edge router using token 1de2f02e-62fe-44fb-bebb-e2d21a82d13f -``` -``` - $ zping server -c zpingendpoint2.json & - [1] 5176 - INFO[0000] binding service ziti-ping - - zpingendpoint2 now serving - - INFO[0000] connection to edge router using token d472f74c-97af-426a-a07f-7ecd907a2013 -``` -12. Send 5 zpings from zpingclient2 to zpingclient1 -``` - $ zping client -c zitiendpoint2.json -i zitiendpoint1 -n 5 - INFO[0000] connection to edge router using token b78cab88-fa22-4d49-906f-ddf101b63b88 - INFO[0566] new connection - - Sending 100 byte pings to zpingendpoint1: - - 100 bytes from zpingendpoint1: ziti_seq=1 time=76.558ms - 100 bytes from zpingendpoint1: ziti_seq=2 time=75.597ms - 100 bytes from zpingendpoint1: ziti_seq=3 time=76.209ms - 100 bytes from zpingendpoint1: ziti_seq=4 time=76.332ms - 100 bytes from zpingendpoint1: ziti_seq=5 time=76.849ms - - --- zpingendpoint1 ping statistics --- - 5 packets transmitted and 5 packets received, 0.00% packet loss - round-trip min/max/avg/stddev 75.597/76.849/76.309/0.417 ms -``` +1. Create or use an existing ziti network with at least one edge router. This can be accomplished easily by running + ``` + ziti edge quickstart + ``` + + after the quickstart runs, you'll have an ephemeral network usable for testing. + +1. Create at least two ziti identities and give them a common identity role i.e. #zping + ``` + ziti edge create identity client -o client.jwt -a "zping" + ziti edge create identity server -o server.jwt -a "zping" + ziti edge enroll client.jwt + ziti edge enroll server.jwt + ``` + +1. Create a simple sdk service named "ziti-ping". This is the default service name `zping` looks for. You can + override the service by using the `-s` flag. + ``` + ziti edge create service ziti-ping + ``` + +1. Create a bind policy with identityRoles set to [#zping] and serviceroles set to [@ziti-ping]. + ``` + ziti edge create service-policy zping.bind Bind --identity-roles "#zping" --service-roles "@ziti-ping" + ``` + +1. Create a dial service policy with identityRoles set to [#zping] and serviceroles set to [@ziti-ping]. + ``` + ziti edge create service-policy zping.dial Dial --identity-roles "#zping" --service-roles "@ziti-ping" + ``` + +1. Ensure that you have created appropriate edge-router and service-edge-router policies allowing the identities access + edge-router(s) and the edge-routers access to the service. Verify by running policy-advisor. Both identities + should be able to dial **and** bind zping: + + ``` + $ ziti edge policy-advisor identities -q + ERROR: Default Admin + - Identity does not have access to any services. Adjust service policies. + + OKAY : client (1) -> ziti-ping (1) Common Routers: (1/1) Dial: Y Bind: N + + OKAY : server (1) -> ziti-ping (1) Common Routers: (1/1) Dial: Y Bind: N + + ERROR: quickstart-router + - Identity does not have access to any services. Adjust service policies. + ``` + +1. In one window run the server + ``` + build/zping server -c server.json + ``` + + example: + ``` + $ build/zping server -c server.json + INFO[0000] binding service ziti-ping + + 0xc00040d660 now serving + + INFO[0000] new service session session token=52e059d2-f166-4561-b5a4-b42056bcd787 + INFO[0041] new connection + ``` + +1. In another window run the client + ``` + build/zping client -c client.json -i server + ``` + + example: + ``` + $ build/zping client -c client.json -i server + + Sending 100 byte pings to server: + + 100 bytes from server: ziti_seq=1 time=0.609ms + 100 bytes from server: ziti_seq=2 time=0.670ms + 100 bytes from server: ziti_seq=3 time=0.381ms + 100 bytes from server: ziti_seq=4 time=0.387ms + 100 bytes from server: ziti_seq=5 time=0.564ms + 100 bytes from server: ziti_seq=6 time=0.455ms + 100 bytes from server: ziti_seq=7 time=0.446ms + 100 bytes from server: ziti_seq=8 time=0.377ms + 100 bytes from server: ziti_seq=9 time=0.455ms + 100 bytes from server: ziti_seq=10 time=0.502ms + 100 bytes from server: ziti_seq=11 time=0.977ms + 100 bytes from server: ziti_seq=12 time=0.487ms + ^C + --- server ping statistics --- + 12 packets transmitted and 12 packets received, 0.00% packet loss + round-trip min/max/avg/stddev 0.377/0.977/0.526/0.162 ms + ``` + +1. Send 5 zpings from the client to the server using `-n 5` + ``` + $ build/zping client -c client.json -i server -n 5 + + Sending 100 byte pings to server: + + 100 bytes from server: ziti_seq=1 time=0.349ms + 100 bytes from server: ziti_seq=2 time=0.690ms + 100 bytes from server: ziti_seq=3 time=0.590ms + 100 bytes from server: ziti_seq=4 time=0.429ms + 100 bytes from server: ziti_seq=5 time=0.480ms + + --- server ping statistics --- + 5 packets transmitted and 5 packets received, 0.00% packet loss + round-trip min/max/avg/stddev 0.349/0.690/0.508/0.120 ms + ``` diff --git a/ziti/sdkinfo/build_info.go b/ziti/sdkinfo/build_info.go index b1729094..fd5df8ad 100644 --- a/ziti/sdkinfo/build_info.go +++ b/ziti/sdkinfo/build_info.go @@ -20,5 +20,5 @@ package sdkinfo const ( - Version = "v0.23.44" + Version = "v0.23.45" )