t33m / k8s-secure-proxy

Simple proxy for k8s API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

k8s-secure-proxy


Simple proxy for k8s API.

features:

  • path filtering
  • request logging
  • multiple backends support

example usage

package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"

	"github.com/t33m/k8s-secure-proxy/pkg/proxy"
)

func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		log.Printf(
			"client-ip: %s, user-agent: %s, host: %s, method: %s, path: %s",
			req.RemoteAddr, req.UserAgent(), req.Host, req.Method, req.URL.Path,
		)
		next.ServeHTTP(w, req)
	})
}


func runProxy(listen, virtualHost, apiEndpoint, caCertPath, keyPath, certPath string) error {
	caPool, err := x509.SystemCertPool()
	if err != nil {
		return err
	}
	if caCertPath != "" {
		caCert, err := ioutil.ReadFile(caCertPath)
		if err != nil {
			return err
		}
		caPool.AppendCertsFromPEM(caCert)
	}

	keyBytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return err
	}

	certBytes, err := ioutil.ReadFile(certPath)
	if err != nil {
		return err
	}

	cert, err := tls.X509KeyPair(certBytes, keyBytes)
	if err != nil {
		return err
	}

	vHosts := proxy.VirtualHosts{}
	if vHosts[virtualHost], err = url.Parse(apiEndpoint); err != nil {
		return err
	}

	filterTransport, err := proxy.NewFilterTransport(
		proxy.DefaultPathRejectRE, proxy.DefaultPathAcceptRE, &tls.Config{
			MinVersion: tls.VersionTLS13,
			RootCAs:    caPool,
		},
	)
	if err != nil {
		return err
	}

	tr := proxy.NewBackendTransport(filterTransport, vHosts)
	server := &http.Server{
		Addr:     listen,
		Handler:  loggingMiddleware(proxy.NewProxyHandler(tr)),
	}

	server.TLSConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
	defer func(){
		_ = server.Shutdown(context.Background())
	}()

	done := make(chan struct{}, 1)
	go func() {
		_ = server.ListenAndServeTLS("", "")
		close(done)
	}()

	log.Printf("listening on %s", listen)

	<-done
	return nil
}

func main() {
	flag.Usage = func() {
		_, _  = fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
	}

	var listen, virtualHost, apiEndpoint, caCertPath, keyPath, certPath string

	flag.StringVar(&listen, "listen", "127.0.0.1:8443", "proxy listen address")
	flag.StringVar(&virtualHost, "virtual-host", "127.0.0.1", "virtual host")
	flag.StringVar(&apiEndpoint, "api-endpoint", "", "endpoint of k8s api node")
	flag.StringVar(&caCertPath, "ca", "", "path to CA certificate for verify k8s api node")
	flag.StringVar(&keyPath, "key", "", "path to key for proxy listener")
	flag.StringVar(&certPath, "cert", "", "path to certificate for proxy listener")

	flag.Parse()

	if err := runProxy(listen, virtualHost, apiEndpoint, caCertPath, keyPath, certPath); err != nil {
		_ , _ = fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

About

Simple proxy for k8s API


Languages

Language:Go 100.0%