From fca775dd5f881139556d266a7a7090ccd946957c Mon Sep 17 00:00:00 2001 From: Jonas Kaninda Date: Fri, 15 Nov 2024 07:56:37 +0100 Subject: [PATCH] chore: add skip SSL certificate verification --- .github/workflows/lint.yml | 23 +++++ .github/workflows/{go.yml => test.yml} | 0 docs/quickstart/route.md | 1 + examples/goma.yml | 1 + internal/cors_type.go | 37 ++++++++ internal/gateway_type.go | 57 +++++++++++ internal/handler.go | 3 +- internal/healthCheck.go | 9 +- internal/helpers.go | 18 ++-- internal/middleware_type.go | 31 ++++++ internal/route_type.go | 58 ++++++++++++ internal/types.go | 125 ++----------------------- 12 files changed, 234 insertions(+), 129 deletions(-) create mode 100644 .github/workflows/lint.yml rename .github/workflows/{go.yml => test.yml} (100%) create mode 100644 internal/cors_type.go create mode 100644 internal/gateway_type.go create mode 100644 internal/middleware_type.go create mode 100644 internal/route_type.go diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..f40d365 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + pull_request: + +jobs: + lint: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '~1.22' + + - name: Run linter + uses: golangci/golangci-lint-action@v6 + with: + version: v1.61 diff --git a/.github/workflows/go.yml b/.github/workflows/test.yml similarity index 100% rename from .github/workflows/go.yml rename to .github/workflows/test.yml diff --git a/docs/quickstart/route.md b/docs/quickstart/route.md index 92dda32..a0836ea 100644 --- a/docs/quickstart/route.md +++ b/docs/quickstart/route.md @@ -135,6 +135,7 @@ gateway: - https://example.com - https://example2.com - https://example4.com + insecureSkipVerify: true methods: [] healthCheck: path: "/health/live" diff --git a/examples/goma.yml b/examples/goma.yml index abf3181..ab41911 100644 --- a/examples/goma.yml +++ b/examples/goma.yml @@ -87,6 +87,7 @@ gateway: backends: - https://example.com - https://example2.com + insecureSkipVerify: true methods: - GET # Route healthcheck diff --git a/internal/cors_type.go b/internal/cors_type.go new file mode 100644 index 0000000..717cf43 --- /dev/null +++ b/internal/cors_type.go @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * 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 + * + * http://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 pkg + +type Cors struct { + // Cors Allowed origins, + //e.g: + // + // - http://localhost:80 + // + // - https://example.com + Origins []string `yaml:"origins"` + // + //e.g: + // + //Access-Control-Allow-Origin: '*' + // + // Access-Control-Allow-Methods: 'GET, POST, PUT, DELETE, OPTIONS' + // + // Access-Control-Allow-Cors: 'Content-Type, Authorization' + Headers map[string]string `yaml:"headers"` +} diff --git a/internal/gateway_type.go b/internal/gateway_type.go new file mode 100644 index 0000000..23467c5 --- /dev/null +++ b/internal/gateway_type.go @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * 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 + * + * http://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 pkg + +// Gateway contains Goma Proxy Gateway's configs +type Gateway struct { + // SSLCertFile SSL Certificate file + SSLCertFile string `yaml:"sslCertFile" env:"GOMA_SSL_CERT_FILE, overwrite"` + // SSLKeyFile SSL Private key file + SSLKeyFile string `yaml:"sslKeyFile" env:"GOMA_SSL_KEY_FILE, overwrite"` + // Redis contains redis database details + Redis Redis `yaml:"redis"` + // WriteTimeout defines proxy write timeout + WriteTimeout int `yaml:"writeTimeout" env:"GOMA_WRITE_TIMEOUT, overwrite"` + // ReadTimeout defines proxy read timeout + ReadTimeout int `yaml:"readTimeout" env:"GOMA_READ_TIMEOUT, overwrite"` + // IdleTimeout defines proxy idle timeout + IdleTimeout int `yaml:"idleTimeout" env:"GOMA_IDLE_TIMEOUT, overwrite"` + // RateLimit Defines the number of request peer minutes + RateLimit int `yaml:"rateLimit" env:"GOMA_RATE_LIMIT, overwrite"` + // BlockCommonExploits enable, disable block common exploits + BlockCommonExploits bool `yaml:"blockCommonExploits"` + AccessLog string `yaml:"accessLog" env:"GOMA_ACCESS_LOG, overwrite"` + ErrorLog string `yaml:"errorLog" env:"GOMA_ERROR_LOG=, overwrite"` + LogLevel string `yaml:"logLevel" env:"GOMA_LOG_LEVEL, overwrite"` + // DisableHealthCheckStatus enable and disable routes health check + DisableHealthCheckStatus bool `yaml:"disableHealthCheckStatus"` + // DisableRouteHealthCheckError allows enabling and disabling backend healthcheck errors + DisableRouteHealthCheckError bool `yaml:"disableRouteHealthCheckError"` + //Disable allows enabling and disabling displaying routes on start + DisableDisplayRouteOnStart bool `yaml:"disableDisplayRouteOnStart"` + // DisableKeepAlive allows enabling and disabling KeepALive server + DisableKeepAlive bool `yaml:"disableKeepAlive"` + EnableMetrics bool `yaml:"enableMetrics"` + // InterceptErrors holds the status codes to intercept the error from backend + InterceptErrors []int `yaml:"interceptErrors"` + // Cors holds proxy global cors + Cors Cors `yaml:"cors"` + + // Routes holds proxy routes + Routes []Route `yaml:"routes"` +} diff --git a/internal/handler.go b/internal/handler.go index 4036850..1bbe058 100644 --- a/internal/handler.go +++ b/internal/handler.go @@ -18,6 +18,7 @@ limitations under the License. import ( "context" "encoding/json" + "fmt" "github.com/gorilla/mux" "github.com/jkaninda/goma-gateway/pkg/logger" "net/http" @@ -56,7 +57,7 @@ func CORSHandler(cors Cors) mux.MiddlewareFunc { func ProxyErrorHandler(w http.ResponseWriter, r *http.Request, err error) { logger.Error("Proxy error: %v", err) w.WriteHeader(http.StatusBadGateway) - _, err = w.Write([]byte("Bad Gateway")) + _, err = w.Write([]byte(fmt.Sprintf("%d %s ", http.StatusBadGateway, http.StatusText(http.StatusBadGateway)))) if err != nil { return } diff --git a/internal/healthCheck.go b/internal/healthCheck.go index 012c518..90b9652 100644 --- a/internal/healthCheck.go +++ b/internal/healthCheck.go @@ -16,6 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import ( + "crypto/tls" "fmt" "github.com/jkaninda/goma-gateway/pkg/logger" "github.com/jkaninda/goma-gateway/util" @@ -36,8 +37,14 @@ func (health Health) Check() error { if err != nil { return fmt.Errorf("error route %s: creating HealthCheck request: %v ", health.Name, err) } + // Create custom transport with TLS configuration + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: health.InsecureSkipVerify, // Skip SSL certificate verification + }, + } // Perform the request to the route's healthcheck - client := &http.Client{Timeout: health.TimeOut} + client := &http.Client{Transport: transport, Timeout: health.TimeOut} healthResp, err := client.Do(healthReq) if err != nil { logger.Debug("Error route %s: performing HealthCheck request: %v ", health.Name, err) diff --git a/internal/helpers.go b/internal/helpers.go index 7c47ecb..1b02d34 100644 --- a/internal/helpers.go +++ b/internal/helpers.go @@ -118,20 +118,22 @@ func healthCheckRoutes(routes []Route) []Health { if len(route.Backends) > 0 { for index, backend := range route.Backends { health := Health{ - Name: fmt.Sprintf("%s - [%d]", route.Name, index), - URL: backend + route.HealthCheck.Path, - TimeOut: timeout, - HealthyStatuses: route.HealthCheck.HealthyStatuses, + Name: fmt.Sprintf("%s - [%d]", route.Name, index), + URL: backend + route.HealthCheck.Path, + TimeOut: timeout, + HealthyStatuses: route.HealthCheck.HealthyStatuses, + InsecureSkipVerify: route.InsecureSkipVerify, } healthRoutes = append(healthRoutes, health) } } else { health := Health{ - Name: route.Name, - URL: route.Destination + route.HealthCheck.Path, - TimeOut: timeout, - HealthyStatuses: route.HealthCheck.HealthyStatuses, + Name: route.Name, + URL: route.Destination + route.HealthCheck.Path, + TimeOut: timeout, + HealthyStatuses: route.HealthCheck.HealthyStatuses, + InsecureSkipVerify: route.InsecureSkipVerify, } healthRoutes = append(healthRoutes, health) } diff --git a/internal/middleware_type.go b/internal/middleware_type.go new file mode 100644 index 0000000..acd33a3 --- /dev/null +++ b/internal/middleware_type.go @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * 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 + * + * http://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 pkg + +// Middleware defined the route middleware +type Middleware struct { + //Path contains the name of middleware and must be unique + Name string `yaml:"name"` + // Type contains authentication types + // + // basic, jwt, auth0, rateLimit, access + Type string `yaml:"type"` // Middleware type [basic, jwt, auth0, rateLimit, access] + Paths []string `yaml:"paths"` // Protected paths + // Rule contains rule type of + Rule interface{} `yaml:"rule"` // Middleware rule +} diff --git a/internal/route_type.go b/internal/route_type.go new file mode 100644 index 0000000..11bd21e --- /dev/null +++ b/internal/route_type.go @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * 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 + * + * http://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 pkg + +// Route defines gateway route +type Route struct { + // Path defines route path + Path string `yaml:"path"` + // Name defines route name + Name string `yaml:"name"` + //Host Domain/host based request routing + //Host string `yaml:"host"` + //Hosts Domains/hosts based request routing + Hosts []string `yaml:"hosts"` + // Rewrite rewrites route path to desired path + // + // E.g. /cart to / => It will rewrite /cart path to / + Rewrite string `yaml:"rewrite"` + // + // Methods allowed method + Methods []string `yaml:"methods"` + // Destination Defines backend URL + Destination string `yaml:"destination"` + Backends []string `yaml:"backends"` + InsecureSkipVerify bool `yaml:"insecureSkipVerify"` + // HealthCheck Defines the backend is health + HealthCheck RouteHealthCheck `yaml:"healthCheck"` + // Cors contains the route cors headers + Cors Cors `yaml:"cors"` + RateLimit int `yaml:"rateLimit"` + // DisableHostFording Disable X-forwarded header. + // + // [X-Forwarded-Host, X-Forwarded-For, Host, Scheme ] + // + // It will not match the backend route + DisableHostFording bool `yaml:"disableHostFording"` + // InterceptErrors holds the status codes to intercept the error from backend + InterceptErrors []int `yaml:"interceptErrors"` + // BlockCommonExploits enable, disable block common exploits + BlockCommonExploits bool `yaml:"blockCommonExploits"` + // Middlewares Defines route middleware from Middleware names + Middlewares []string `yaml:"middlewares"` +} diff --git a/internal/types.go b/internal/types.go index 91a4df8..56caff7 100644 --- a/internal/types.go +++ b/internal/types.go @@ -31,25 +31,6 @@ type BasicRuleMiddleware struct { Password string `yaml:"password"` } -type Cors struct { - // Cors Allowed origins, - //e.g: - // - // - http://localhost:80 - // - // - https://example.com - Origins []string `yaml:"origins"` - // - //e.g: - // - //Access-Control-Allow-Origin: '*' - // - // Access-Control-Allow-Methods: 'GET, POST, PUT, DELETE, OPTIONS' - // - // Access-Control-Allow-Cors: 'Content-Type, Authorization' - Headers map[string]string `yaml:"headers"` -} - // JWTRuleMiddleware authentication using HTTP GET method // // JWTRuleMiddleware contains the authentication details @@ -114,101 +95,6 @@ type AccessRuleMiddleware struct { ResponseCode int `yaml:"responseCode"` // HTTP Response code } -// Middleware defined the route middleware -type Middleware struct { - //Path contains the name of middleware and must be unique - Name string `yaml:"name"` - // Type contains authentication types - // - // basic, jwt, auth0, rateLimit, access - Type string `yaml:"type"` // Middleware type [basic, jwt, auth0, rateLimit, access] - Paths []string `yaml:"paths"` // Protected paths - // Rule contains rule type of - Rule interface{} `yaml:"rule"` // Middleware rule -} -type MiddlewareName struct { - name string `yaml:"name"` -} - -// Route defines gateway route -type Route struct { - // Path defines route path - Path string `yaml:"path"` - // Name defines route name - Name string `yaml:"name"` - //Host Domain/host based request routing - //Host string `yaml:"host"` - //Hosts Domains/hosts based request routing - Hosts []string `yaml:"hosts"` - // Rewrite rewrites route path to desired path - // - // E.g. /cart to / => It will rewrite /cart path to / - Rewrite string `yaml:"rewrite"` - // - // Methods allowed method - Methods []string `yaml:"methods"` - // Destination Defines backend URL - Destination string `yaml:"destination"` - Backends []string `yaml:"backends"` - InsecureSkipVerify bool `yaml:"insecureSkipVerify"` - // HealthCheck Defines the backend is health - HealthCheck RouteHealthCheck `yaml:"healthCheck"` - // Cors contains the route cors headers - Cors Cors `yaml:"cors"` - RateLimit int `yaml:"rateLimit"` - // DisableHostFording Disable X-forwarded header. - // - // [X-Forwarded-Host, X-Forwarded-For, Host, Scheme ] - // - // It will not match the backend route - DisableHostFording bool `yaml:"disableHostFording"` - // InterceptErrors holds the status codes to intercept the error from backend - InterceptErrors []int `yaml:"interceptErrors"` - // BlockCommonExploits enable, disable block common exploits - BlockCommonExploits bool `yaml:"blockCommonExploits"` - // Middlewares Defines route middleware from Middleware names - Middlewares []string `yaml:"middlewares"` -} - -// Gateway contains Goma Proxy Gateway's configs -type Gateway struct { - // SSLCertFile SSL Certificate file - SSLCertFile string `yaml:"sslCertFile" env:"GOMA_SSL_CERT_FILE, overwrite"` - // SSLKeyFile SSL Private key file - SSLKeyFile string `yaml:"sslKeyFile" env:"GOMA_SSL_KEY_FILE, overwrite"` - // Redis contains redis database details - Redis Redis `yaml:"redis"` - // WriteTimeout defines proxy write timeout - WriteTimeout int `yaml:"writeTimeout" env:"GOMA_WRITE_TIMEOUT, overwrite"` - // ReadTimeout defines proxy read timeout - ReadTimeout int `yaml:"readTimeout" env:"GOMA_READ_TIMEOUT, overwrite"` - // IdleTimeout defines proxy idle timeout - IdleTimeout int `yaml:"idleTimeout" env:"GOMA_IDLE_TIMEOUT, overwrite"` - // RateLimit Defines the number of request peer minutes - RateLimit int `yaml:"rateLimit" env:"GOMA_RATE_LIMIT, overwrite"` - // BlockCommonExploits enable, disable block common exploits - BlockCommonExploits bool `yaml:"blockCommonExploits"` - AccessLog string `yaml:"accessLog" env:"GOMA_ACCESS_LOG, overwrite"` - ErrorLog string `yaml:"errorLog" env:"GOMA_ERROR_LOG=, overwrite"` - LogLevel string `yaml:"logLevel" env:"GOMA_LOG_LEVEL, overwrite"` - // DisableHealthCheckStatus enable and disable routes health check - DisableHealthCheckStatus bool `yaml:"disableHealthCheckStatus"` - // DisableRouteHealthCheckError allows enabling and disabling backend healthcheck errors - DisableRouteHealthCheckError bool `yaml:"disableRouteHealthCheckError"` - //Disable allows enabling and disabling displaying routes on start - DisableDisplayRouteOnStart bool `yaml:"disableDisplayRouteOnStart"` - // DisableKeepAlive allows enabling and disabling KeepALive server - DisableKeepAlive bool `yaml:"disableKeepAlive"` - EnableMetrics bool `yaml:"enableMetrics"` - // InterceptErrors holds the status codes to intercept the error from backend - InterceptErrors []int `yaml:"interceptErrors"` - // Cors holds proxy global cors - Cors Cors `yaml:"cors"` - - // Routes holds proxy routes - Routes []Route `yaml:"routes"` -} - type RouteHealthCheck struct { Path string `yaml:"path"` Interval string `yaml:"interval"` @@ -282,11 +168,12 @@ type JWTSecret struct { // Health represents the health check content for a route type Health struct { - Name string - URL string - TimeOut time.Duration - Interval string - HealthyStatuses []int + Name string + URL string + TimeOut time.Duration + Interval string + HealthyStatuses []int + InsecureSkipVerify bool } type Redis struct { // Addr redis hostname and port number :