Skip to content

Commit

Permalink
feat: sticky-sessions and fips support
Browse files Browse the repository at this point in the history
This will add sticky-sessions by adding session ID Mechanism \n \n
FIPS 140-2 support based on boringSSL
  • Loading branch information
Sean Connole committed Oct 17, 2024
1 parent dda4613 commit c814271
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 10 deletions.
17 changes: 13 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
FROM debian
ARG GO_VER=1.22
FROM golang:${GO_VER} AS build

RUN apt update && apt install -y ca-certificates curl
RUN mkdir -p /go/src/github.com/contentsquare/chproxy
WORKDIR /go/src/github.com/contentsquare/chproxy
COPY . ./
ARG EXT_BUILD_TAG
ENV EXT_BUILD_TAG=${EXT_BUILD_TAG}
RUN make release-build
RUN ls -al /go/src/github.com/contentsquare/chproxy

COPY chproxy /
FROM alpine
RUN apk add --no-cache curl ca-certificates
COPY --from=build /go/src/github.com/contentsquare/chproxy/chproxy* /

EXPOSE 9090

ENTRYPOINT ["/chproxy"]
ENTRYPOINT [ "/chproxy" ]
CMD [ "--help" ]
44 changes: 44 additions & 0 deletions Dockerfile_boringcrypto
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
ARG UBUNTU_IMAGE=ubuntu:20.04
FROM ${UBUNTU_IMAGE} AS build

ENV GOPATH=/gocode
ENV PATH=$PATH:$GOPATH/bin
ENV GOVERSION=1.22

RUN mkdir /scr
WORKDIR /src

# golang
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
apt-utils \
software-properties-common \
gcc \
libc-dev \
&& add-apt-repository -y ppa:longsleep/golang-backports \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
golang-$GOVERSION-go \
golang-golang-x-tools \
&& apt-get autoremove -y \
&& apt-get remove -y \
apt-utils \
software-properties-common

# Create symbolic link
RUN ln -s /usr/lib/go-$GOVERSION /gocode

# tools
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
git \
make \
tzdata \
curl \
ca-certificates

FROM build

# Build chproxy
COPY . ./
ARG EXT_BUILD_TAG
ENV GOEXPERIMENT=boringcrypto
RUN make release-build
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ run: build

lint:
go vet $(pkgs)
golangci-lint run
go list ./... | grep -v /vendor/ | xargs -n1 golint

tidy:
go mod tidy
Expand All @@ -48,8 +48,8 @@ clean:
release-build:
@echo "Ver: $(BUILD_TAG), OPTS: $(BUILD_OPTS)"
GOOS=linux GOARCH=amd64 go build $(BUILD_OPTS)
rm chproxy-linux-amd64-*.tar.gz || true
tar czf chproxy-linux-amd64-$(BUILD_TAG).tar.gz chproxy
rm chproxy-linux-amd64-*.tar.gz

release: format lint test clean release-build
@echo "Ver: $(BUILD_TAG), OPTS: $(BUILD_OPTS)"
Expand All @@ -58,4 +58,9 @@ release: format lint test clean release-build
release-build-docker:
@echo "Ver: $(BUILD_TAG)"
@DOCKER_BUILDKIT=1 docker build --target build --build-arg EXT_BUILD_TAG=$(BUILD_TAG) --progress plain -t chproxy-build .
@docker run --rm --entrypoint "/bin/sh" -v $(CURDIR):/host chproxy-build -c "/bin/cp /go/src/github.com/contentsquare/chproxy/*.tar.gz /host"
@docker run --rm --entrypoint "/bin/sh" -v $(CURDIR):/host chproxy-build -c "/bin/cp chproxy-linux-*-*.tar.gz /host"

release-build-docker-fips:
@echo "Ver: $(BUILD_TAG)"
@DOCKER_BUILDKIT=1 docker build -f Dockerfile_boringcrypto --build-arg EXT_BUILD_TAG=$(BUILD_TAG)-fips --build-arg EXT_BUILD_OPTS="-tags fips" --progress plain -t chproxy-build .
@docker run --rm --entrypoint "/bin/sh" -v $(CURDIR):/host chproxy-build -c "/bin/cp /src/chproxy-*.tar.gz /host"
8 changes: 8 additions & 0 deletions docs/src/content/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ Chproxy is an HTTP proxy and load balancer for [ClickHouse](https://ClickHouse.y
- Exposes various useful [metrics](/configuration/metrics) in [Prometheus text format](https://prometheus.io/docs/instrumenting/exposition_formats/).
- Configuration may be updated without restart - just send `SIGHUP` signal to `chproxy` process.
- Easy to manage and run - just pass config file path to a single `chproxy` binary.
- Facilitates session affinity through `session_id` mapping, guaranteeing requests from the same user session are routed to the same upstream server (It is useful if one application server performs an initial processing step and stores the results in a temporary table; other servers can efficiently access and utilize that data by reaching the same server where the data is.)
- Service can be built to use only cryptographic algorithms approved by the Federal Information Processing Standard (FIPS) 140-2, making it suitable for processing sensitive government data.
```bash
-- to build regular artifact
make release-build-docker
-- to build artifact with FIPS support relying on Borring Crypto Module
make release-build-docker-fips:
```
- Easy to [configure](https://github.com/contentsquare/chproxy/blob/master/config/examples/simple.yml):
```yml
server:
Expand Down
5 changes: 5 additions & 0 deletions fips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build fips

package main

import _ "crypto/tls/fipsonly"
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bsm/ginkgo/v2 v2.5.0 h1:aOAnND1T40wEdAtkGSkvSICWeQ8L3UASX7YVCqQx+eQ=
github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/gomega v1.20.0 h1:JhAwLmtRzXFTx2AkALSLa8ijZafntmhSoU63Ok18Uq8=
github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
Expand Down
20 changes: 17 additions & 3 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,21 +443,35 @@ func TestServe(t *testing.T) {
startHTTP,
},
{
"http POST request with session id",
"http POST request with session_id and session_timeout",
"testdata/http-session-id.yml",
func(t *testing.T) {
sessionName := "name"
sessionTimeout := 900
req, err := http.NewRequest("POST",
"http://127.0.0.1:9090/?query_id=45395792-a432-4b92-8cc9-536c14e1e1a9&extremes=0&session_id=default-session-id233",
"http://127.0.0.1:9090/?query_id=45395792-a432-4b92-8cc9-536c14e1e1a9&extremes=0&session_id="+sessionName+"&session_timeout="+strconv.Itoa(sessionTimeout),
bytes.NewBufferString("SELECT * FROM system.numbers LIMIT 10"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;") // This makes it work

checkErr(t, err)
resp, err := http.DefaultClient.Do(req)
checkErr(t, err)

if resp.StatusCode != http.StatusOK || resp.StatusCode != http.StatusOK && resp.Header.Get("X-Clickhouse-Server-Session-Id") == "" {
if resp.StatusCode != http.StatusOK {
t.Fatalf("unexpected status code: %d; expected: %d", resp.StatusCode, http.StatusOK)
}

// verify correctness of session_id
_sessionName := resp.Header.Get("X-Clickhouse-Server-Session-Id")
if _sessionName != sessionName {
t.Fatalf("unexpected value of X-Clickhouse-Server-Session-Id: %s; expected: %s", _sessionName, sessionName)
}

// verify correctness of session_id
_sessionTimeout, _ := strconv.Atoi(resp.Header.Get("X-Clickhouse-Server-Session-Timeout"))
if _sessionTimeout != sessionTimeout {
t.Fatalf("unexpected value of X-Clickhouse-Server-Session-Timeout: %d; expected: %d", _sessionTimeout, sessionTimeout)
}
resp.Body.Close()
},
startHTTP,
Expand Down
5 changes: 5 additions & 0 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ func (rp *reverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("X-ClickHouse-Server-Session-Id", s.sessionId)
}

// publish session_timeout if needed
if s.sessionId != "" {
rw.Header().Set("X-ClickHouse-Server-Session-Timeout", strconv.Itoa(s.sessionTimeout))
}

q, shouldReturnFromCache, err := shouldRespondFromCache(s, origParams, req)
if err != nil {
respondWith(srw, err, http.StatusBadRequest)
Expand Down

0 comments on commit c814271

Please sign in to comment.