From ef5fedddf10e98b3c4a86bdf0e57b80dace53caf Mon Sep 17 00:00:00 2001 From: Benjamin Lindqvist Date: Mon, 26 Feb 2024 15:41:21 +0100 Subject: [PATCH 1/3] kms: support rest-based kms --- README.md | 24 ++++++++++++--- main.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 97 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index def0b81..01b1c80 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,27 @@ architecture! The barrier of entry has never been lower! Yay! ## Key management integration -Iteration 1 of the proxy only supports the simplest KMS integration possible: -feeding the id/key pairs via a CSV file. Adding additional integrations (Redis, -SQL, etc) is just a matter of extending the `pskLookup()` function (patches more -than welcome). +Iteration 1 of the proxy only supported the simplest KMS integration possible: +feeding the id/key pairs via a CSV file. +Experimental REST support is also available: + +``` +./dtls_proxy ... --psk-rest http://$KMS_SRV:$KMS_PORT/keys +``` + +The KMS service needs to expect a query parameter of the form +`pskId=SOME_STRING`. If it requires additional query parameters (such as API +key), you can piggyback that onto the URL like this: + +``` +--psk-rest http://$KMS_SRV:$KMS_PORT/keys?apiKey=7ad2d94771c9f11f26a51223cb0d0608 +``` + +or whatever -- the final request will include both the `pskId=SOME_STRING` part +and the `apiKey=7ad2d94771c9f11f26a51223cb0d0608` part. The PSK should be +returned in the body as raw binary data (no content-type checking or anything +like that is done by the DTLS proxy). ## DTLS Connection ID diff --git a/main.go b/main.go index 53811f8..8c3b4f2 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,9 @@ import ( "flag" "log" "os" + "net/http" + "strings" + "io" "github.com/pion/dtls/v2" "github.com/pion/dtls/v2/examples/util" @@ -65,7 +68,7 @@ func pipe(conn1 net.Conn, conn2 net.Conn) { } } -func pskLookup(pskId []byte, kms map[string][]byte) []byte { +func pskMapLookup(pskId []byte, kms map[string][]byte) []byte { psk := kms[string(pskId)] if psk == nil { fmt.Printf("Client \"%s\" not found!\n", pskId) @@ -76,6 +79,42 @@ func pskLookup(pskId []byte, kms map[string][]byte) []byte { return psk } +func pskRestLookup(pskId []byte, url string, extraQ string) []byte { + client := &http.Client{} + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + log.Print(err) + return nil + } + + q := req.URL.Query() + q.Add("pskId", string(pskId)) + if len(extraQ) > 0 { + splitExtraQ := strings.Split(extraQ, "=") + q.Add(splitExtraQ[0], splitExtraQ[1]) + } + + req.URL.RawQuery = q.Encode() + + resp, err := client.Do(req) + if err != nil { + fmt.Print(err) + return nil + } + + resBody, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Print(err) + return nil + } + + fmt.Println("http response: ", resBody) + + return resBody +} + + func mapFromCsv(path string) map[string][]byte { f, err := os.Open(path) if err != nil { @@ -104,8 +143,6 @@ func mapFromCsv(path string) map[string][]byte { return m } - - func pskIdFromConn(conn net.Conn) string { var dtlsConn *dtls.Conn = conn.(*dtls.Conn) hint := string(dtlsConn.ConnectionState().IdentityHint) @@ -116,20 +153,18 @@ func pskIdFromConn(conn net.Conn) string { func main() { bindPtr := flag.String("bind", "0.0.0.0:14881", "local ip:port to bind"); upsPtr := flag.String("connect", "kontor.eub.se:14999", "upstream plaintext ip:port") - csvPtr := flag.String("psk-csv", "keys.csv", "id/psk csv file") + csvPtr := flag.String("psk-csv", "", "id/psk csv file") + restPtr := flag.String("psk-rest", "", "id/psk rest looup uri") flag.Parse() fmt.Println("bind:", *bindPtr); fmt.Println("ups:", *upsPtr); - fmt.Println("csv:", *csvPtr); // Map between conns and PSK IDs, used to terminate stale connections var connMap map[string]net.Conn connMap = make(map[string]net.Conn) - kms := mapFromCsv(*csvPtr) - upstreamAddr := *upsPtr; addr, err := net.ResolveUDPAddr("udp", *bindPtr); @@ -146,12 +181,44 @@ func main() { return context.WithTimeout(ctx, 30*time.Second) }, ConnectionIDGenerator: dtls.RandomCIDGenerator(8), - PSK: func(hint []byte) ([]byte, error) { - return pskLookup(hint, kms), nil - }, CipherSuites: []dtls.CipherSuiteID{dtls.TLS_PSK_WITH_AES_128_CCM_8}, } + // If KMS lookup is via local csv, create a map from it + if len(*csvPtr) > 0 { + fmt.Println("csv:", *csvPtr); + kmsMap := mapFromCsv(*csvPtr); + config.PSK = func(hint []byte) ([]byte, error) { + return pskMapLookup(hint, kmsMap), nil + }; + } else if len(*restPtr) > 0 { + fmt.Println("Targeting kms url:", *restPtr); + + // Split into base and query param + var base string; + var xtra string; + split := strings.Split(*restPtr, "?") + if len(split) == 2 { + base = split[0]; + xtra = split[1] + fmt.Println("url: ", base, " and ", xtra); + } else { + base = *restPtr; + xtra = ""; + } + + config.PSK = func(hint []byte) ([]byte, error) { + return pskRestLookup(hint, base, xtra), nil + }; + + } else { + fmt.Println("No KMS lookup method provided!"); + os.Exit(1) + } + + + + listener, err := dtls.Listen("udp", addr, config) util.Check(err) defer func() { From 5b72f51e4cfebabfc116dcd431f586cc1d045a61 Mon Sep 17 00:00:00 2001 From: Benjamin Lindqvist Date: Tue, 14 May 2024 15:09:07 +0200 Subject: [PATCH 2/3] dockerfile added --- Dockerfile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0797c20 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# syntax=docker/dockerfile:1 + +FROM golang:1.17 + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download +COPY *.go ./ + +RUN CGO_ENABLED=0 GOOS=linux go build -o /dtls_proxy + +# These can be overriden via docker run -e foo=bar +ENV PSK_REST_ARG="https://localhost:12345" +ENV CONNECT_ARG="0.0.0.0:5683" +ENV BIND_ARG="0.0.0.0:5684" + +CMD ["/bin/sh", "-c", "/dtls_proxy --connect $CONNECT_ARG --bind $BIND_ARG --psk-rest $PSK_REST_ARG"] From 256b525591eae9a73562f02a01f2a6dada8d2ddb Mon Sep 17 00:00:00 2001 From: Benjamin Lindqvist Date: Wed, 15 May 2024 08:55:13 +0200 Subject: [PATCH 3/3] add gitlab ci docker build --- .gitlab-ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..c70be0d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,19 @@ +variables: + STORAGE_DRIVER: vfs + +container-build: + image: quay.io/buildah/stable:latest + before_script: + - buildah version + - export HOME=$CI_BUILDS_DIR # needed sometimes to avoid conflict with host + - buildah login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - env # tmp + - VERSION=$(git describe --always --abbrev=8 --dirty) + - echo buildah build -t $CI_PROJECT_NAME:$VERSION . + - buildah build -t $CI_PROJECT_NAME:$VERSION . + - echo buildah push $CI_PROJECT_NAME $CI_REGISTRY_IMAGE:$VERSION + - buildah push $CI_PROJECT_NAME $CI_REGISTRY_IMAGE:$VERSION + + after_script: + - buildah logout $CI_REGISTRY