cmd/hbone/hbone.go (83 lines of code) (raw):

//Copyright 2021 Google LLC // //Licensed under the Apache License, Version 2.0 (the "License"); //you may not use this file except in compliance with the License. //You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // //Unless required by applicable law or agreed to in writing, software //distributed under the License is distributed on an "AS IS" BASIS, //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //See the License for the specific language governing permissions and //limitations under the License. package main import ( "context" "flag" "fmt" "io" "log" "net" "os" "strings" "time" "github.com/GoogleCloudPlatform/cloud-run-mesh/pkg/gcp" "github.com/GoogleCloudPlatform/cloud-run-mesh/pkg/hbone" "github.com/GoogleCloudPlatform/cloud-run-mesh/pkg/mesh" "github.com/GoogleCloudPlatform/cloud-run-mesh/pkg/sts" ) var ( localForward = flag.String("L", "", "Local port, if set connections to this port will be forwarded to the mesh service") ) // Create a HBONE tunnel. // // Will attempt to discover an east-west gateway and get credentials using KUBE_CONFIG or google credentials. // // For example: // // ssh -o ProxyCommand='hbone %h:22' root@fortio-cr.fortio // // If the server doesn't have persistent SSH key, add to the ssh parameters: // -F /dev/null -o StrictHostKeyChecking=no -o "UserKnownHostsFile /dev/null" // func main() { // WIP - multiple ports //flag.Var(&localForwards, "LocalForward", "SSH-style local forward") flag.Parse() kr := mesh.New() ctx, cf := context.WithTimeout(context.Background(), 10000*time.Second) defer cf() gcp.InitGCP(ctx, kr) // Use kubeconfig or gcp to find the cluster err := kr.LoadConfig(ctx) if err != nil { log.Fatal("Failed to connect to K8S ", time.Since(kr.StartTime), kr, os.Environ(), err) } // Not calling RefreshAndSaveTokens - hbone is not creating files, jwts and certs in memory only. // Also not initializing pilot-agent or envoy - this is just using k8s to configure the hbone tunnel tokenProvider, err := sts.NewSTS(kr) if kr.MeshConnectorAddr == "" { log.Fatal("Failed to find in-cluster, missing 'hgate' service in mesh env") } kr.XDSAddr = kr.MeshConnectorAddr + ":15012" hb := hbone.New() tcache := sts.NewTokenCache(kr, tokenProvider) hb.TokenCallback = tcache.Token if *localForward != "" { go localForwardPort(hb, kr.MeshConnectorAddr) } if len(flag.Args()) == 0 && *localForward == "" { flag.Usage() os.Exit(1) } if len(flag.Args()) > 0 { dest := flag.Arg(0) err := forward(dest, hb, kr.MeshConnectorAddr, os.Stdin, os.Stdout) if err != nil { fmt.Fprintln(os.Stderr, "Error forwarding ", err) log.Fatal(err) } } else { select {} } } func forward(dest string, hb *hbone.HBone, hg string, in io.Reader, out io.WriteCloser) error { // TODO: k8s discovery for hgate // TODO: -R to register to the gate, reverse proxy // TODO: get certs hc := hb.NewEndpoint(dest) err := hc.Proxy(context.Background(), in, out) if err != nil { return err } return nil } func localForwardPort(hb *hbone.HBone, hg string) { parts := strings.SplitN(*localForward, ":", 2) if len(parts) != 2 { log.Fatal("Expecting 2 parts", *localForward) } dest := parts[1] l, err := net.Listen("tcp", "127.0.0.1:"+parts[0]) if err != nil { panic(err) } for { a, err := l.Accept() if err != nil { panic(err) } go func() { forward(dest, hb, hg, a, a) }() } }