diff --git a/.vscode/launch.json b/.vscode/launch.json index 4f5f245..e0172a5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,12 @@ "type": "go", "request": "launch", "mode": "auto", - "program": "${workspaceFolder}/cmd/jarl/main.go" + "program": "${workspaceFolder}/cmd/jarl/main.go", + "coreFilePath": "${workspaceFolder}", + "args": [ + "-c", + "${workspaceFolder}/cmd" + ] } ] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..76f2e3c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +# use a builder image for building cloudflare +ARG TARGET_GOOS=linux +ARG TARGET_GOARCH=amd64 +FROM golang:1.22.2 as builder +ENV GO111MODULE=on \ + CGO_ENABLED=0 \ + TARGET_GOOS=${TARGET_GOOS} \ + TARGET_GOARCH=${TARGET_GOARCH} + +WORKDIR /go/src/github.com/fredjeck/jarl/ + +# install dependancies +COPY go.mod go.sum ./ +RUN go mod download && go mod verify + +# copy our sources into the builder image +COPY . . + +# build +RUN go build -o /go/src/github.com/fredjeck/jarl/bin/jarl ./cmd/jarl +# create a default directory for the configuration in order to copy it to the runtime image as mkdir is not available on distroless +RUN mkdir -p /var/run/jarl/configuration + +# use a distroless base image with glibc +FROM gcr.io/distroless/base-debian12:nonroot + +LABEL org.opencontainers.image.source="hhttps://github.com/fredjeck/jarl" + +# copy our compiled binary +COPY --from=builder --chown=nonroot /go/src/github.com/fredjeck/jarl/bin/jarl /usr/local/bin/ +COPY --from=builder --chown=nonroot /var/run/jarl/configuration /var/run/jarl/configuration + +# run as non-privileged user +USER nonroot + +ARG PORT_GRPC=9000 +ARG PORT_HTTP=8000 +ARG AUTHZ_HEADER=x-forwarded-sub +ARG CONFIGURATION=/var/run/jarl/configuration +ENV CONFIGURATION=${CONFIGURATION} + +# command / entrypoint of container +ENTRYPOINT ["jarl"] +#,"-h","$PORT_HTTP","-g","$PORT_HTTP","-a","$AUTHZ_HEADER","-c",$CONFIGURATION] + +EXPOSE $PORT_GRPC +EXPOSE $PORT_HTTP \ No newline at end of file diff --git a/authz/authorizations.go b/authz/authorizations.go index 7e27c9d..a599d70 100644 --- a/authz/authorizations.go +++ b/authz/authorizations.go @@ -33,6 +33,11 @@ func (a *Authorizations) Add(auth *Authorization) error { // IsAllowed ensures the provided clientID is configured for accessing the provided path with the given method func (a *Authorizations) IsAllowed(clientID string, path string, method HTTPMethod) (bool, error) { + + if len(a.authorizations) == 0 { + return true, nil // No configuration found we allow a passthrough + } + reason := "" allowed := true @@ -92,5 +97,9 @@ func LoadAll(dir string) (*Authorizations, error) { slog.Error(fmt.Sprintf("an error occured while load authorization files from '%s' see details for errors", dir), slog.Any("error", err)) } + if len(authz.authorizations) == 0 { + slog.Warn(fmt.Sprintf("no configuration files could be loaded from '%s' jar will accept all requests", dir)) + } + return authz, nil } diff --git a/cmd/jarl/main.go b/cmd/jarl/main.go index ccf0feb..dbfdd9f 100644 --- a/cmd/jarl/main.go +++ b/cmd/jarl/main.go @@ -29,10 +29,10 @@ import ( ) var ( - httpPort = flag.String("http", "8000", "HTTP server port") - grpcPort = flag.String("grpc", "9000", "gRPC server port") - header = flag.String("header", "x-forwarded-sub", "HTTP Header key identifying the connected client") - configuration = flag.String("clients", "/var/run/jarl/clients", "Folder containing the clients configurations") + httpPort = flag.String("h", "8000", "HTTP server port") + grpcPort = flag.String("g", "9000", "gRPC server port") + header = flag.String("a", "x-forwarded-sub", "HTTP Header key identifying the connected client") + configuration = flag.String("c", "/var/run/jarl/configuration", "Folder containing the clients configurations") ) func main() { diff --git a/main b/main new file mode 100755 index 0000000..129d703 Binary files /dev/null and b/main differ diff --git a/server/grpc.go b/server/grpc.go index ea37c4b..a35af90 100644 --- a/server/grpc.go +++ b/server/grpc.go @@ -54,7 +54,13 @@ func (srv *GRPCAuthzServer) Start(wg *sync.WaitGroup) { authv2.RegisterAuthorizationServer(srv.grpcServer, &GRPCAuthzServerV2{AuthzHeader: srv.configuration.HTTPAuthZHeader, Authorizations: srv.configuration.Authorizations}) authv3.RegisterAuthorizationServer(srv.grpcServer, &GRPCAuthzServerV3{AuthzHeader: srv.configuration.HTTPAuthZHeader, Authorizations: srv.configuration.Authorizations}) grpc_health_v1.RegisterHealthServer(srv.grpcServer, health.NewServer()) - srv.ready <- true + + select { + case srv.ready <- true: + fmt.Println("Notified test cases") + default: + fmt.Println("No test cases running") + } srv.state = Serving slog.Info(fmt.Sprintf("starting jarl GRPC authz server at '%s", listener.Addr())) diff --git a/server/http.go b/server/http.go index b069077..3d6f08b 100644 --- a/server/http.go +++ b/server/http.go @@ -50,7 +50,12 @@ func (srv *HTTPAuthzServer) Start(wg *sync.WaitGroup, healthFunc func() (bool, s mux.HandleFunc("/healtz", handleHealth(healthFunc)) srv.httpServer = &http.Server{Handler: mux} - srv.ready <- true // for testing + select { + case srv.ready <- true: + fmt.Println("Notified test cases") + default: + fmt.Println("No test cases running") + } srv.state = Serving slog.Info(fmt.Sprintf("starting jarl http authz server at '%s", listener.Addr())) diff --git a/server/server_test.go b/server/server_test.go index 3dee021..8182f12 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -29,7 +29,7 @@ import ( "google.golang.org/grpc/credentials/insecure" ) -const checkHeader = "x-ext-authz" +const checkHeader = "x-forwarded-sub" const clientA = ` clientID: clientA @@ -130,7 +130,7 @@ func TestExtAuthz(t *testing.T) { // Prepare the gRPC request. _ = <-server.grpcServer.ready - conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", server.grpcServer.port), grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", 9000), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { t.Fatalf(err.Error()) }