From e1c95dbdffbbabe94c91bb895ec7d143f4e6466b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=9D=B0=E9=B2=81?= Date: Thu, 24 Feb 2022 14:19:27 +0800 Subject: [PATCH 1/3] test: add cli test --- api/conf/conf.yaml | 8 ++++++++ api/internal/conf/conf.go | 35 +++++++++++++++++++++++++++++++++++ api/internal/filter/cors.go | 32 +++++++++++++++++++++++++++----- api/test/shell/cli_test.sh | 26 ++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/api/conf/conf.yaml b/api/conf/conf.yaml index 30901946a5..747bfc14c1 100644 --- a/api/conf/conf.yaml +++ b/api/conf/conf.yaml @@ -60,6 +60,14 @@ conf: # such as absolute path on Windows: winfile:///C:\access.log # log example: 2020-12-09T16:38:09.039+0800 INFO filter/logging.go:46 /apisix/admin/routes/r1 {"status": 401, "host": "127.0.0.1:9000", "query": "asdfsafd=adf&a=a", "requestId": "3d50ecb8-758c-46d1-af5b-cd9d1c820156", "latency": 0, "remoteIP": "127.0.0.1", "method": "PUT", "errs": []} max_cpu: 0 # supports tweaking with the number of OS threads are going to be used for parallelism. Default value: 0 [will use max number of available cpu cores considering hyperthreading (if any)]. If the value is negative, is will not touch the existing parallelism profile. + # security: + # access_control_allow_origin: "http:httpbin.org" + # access_control_allow_credentials: true # support user custom cors configration + # access_control_allow_headers: "Authorization" + # access_control-allow_methods: "*" + # x_frame_options: "deny" + # content_security_policy: ""default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"" + authentication: secret: diff --git a/api/internal/conf/conf.go b/api/internal/conf/conf.go index b0a7328e75..5087edf77d 100644 --- a/api/internal/conf/conf.go +++ b/api/internal/conf/conf.go @@ -61,6 +61,7 @@ var ( ImportSizeLimit = 10 * 1024 * 1024 AllowList []string Plugins = map[string]bool{} + SecurityConf Security ) type MTLS struct { @@ -110,6 +111,7 @@ type Conf struct { Log Log AllowList []string `mapstructure:"allow_list"` MaxCpu int `mapstructure:"max_cpu"` + Security Security } type User struct { @@ -129,6 +131,15 @@ type Config struct { Plugins []string } +type Security struct { + AllowCredentials string `mapstructure:"access_control_allow_credentials"` + AllowOrigin string `mapstructure:"access_control_allow_origin"` + AllowMethods string `mapstructure:"access_control-allow_methods"` + AllowHeaders string `mapstructure:"access_control_allow_headers"` + XFrameOptions string `mapstructure:"x_frame_options"` + ContentSecurityPolicy string `mapstructure:"content_security_policy"` +} + // TODO: we should no longer use init() function after remove all handler's integration tests // ENV=test is for integration tests only, other ENV should call "InitConf" explicitly func init() { @@ -246,6 +257,9 @@ func setupConfig() { // set plugin initPlugins(config.Plugins) + + // security configuration + initSecurity(config.Conf.Security) } func setupEnv() { @@ -316,3 +330,24 @@ func initParallelism(choiceCores int) { } runtime.GOMAXPROCS(choiceCores) } + +// initialize security settings +func initSecurity(conf Security) { + var se Security + // if conf == se, then conf is empty, we should use default value + if conf != se { + SecurityConf = conf + if conf.ContentSecurityPolicy == "" { + SecurityConf.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'" + } + if conf.XFrameOptions == "" { + SecurityConf.XFrameOptions = "deny" + } + return + } + + SecurityConf = Security{ + XFrameOptions: "deny", + ContentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'", + } +} diff --git a/api/internal/filter/cors.go b/api/internal/filter/cors.go index b33c62b94f..3c72e1afba 100644 --- a/api/internal/filter/cors.go +++ b/api/internal/filter/cors.go @@ -16,14 +16,36 @@ */ package filter -import "github.com/gin-gonic/gin" +import ( + "github.com/apisix/manager-api/internal/conf" + "github.com/gin-gonic/gin" +) func CORS() gin.HandlerFunc { return func(c *gin.Context) { - c.Writer.Header().Set("Access-Control-Allow-Origin", "*") - c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - c.Writer.Header().Set("Access-Control-Allow-Headers", "Authorization") - c.Writer.Header().Set("Access-Control-Allow-Methods", "*") + if conf.SecurityConf.AllowOrigin != "" { + c.Writer.Header().Set("Access-Control-Allow-Origin", conf.SecurityConf.AllowOrigin) + } + + if conf.SecurityConf.AllowHeaders != "" { + c.Writer.Header().Set("Access-Control-Allow-Headers", conf.SecurityConf.AllowHeaders) + } + + if conf.SecurityConf.AllowMethods != "" { + c.Writer.Header().Set("Access-Control-Allow-Methods", conf.SecurityConf.AllowMethods) + } + + if conf.SecurityConf.AllowCredentials != "" { + c.Writer.Header().Set("Access-Control-Allow-Credentials", conf.SecurityConf.AllowCredentials) + } + + if conf.SecurityConf.XFrameOptions != "" { + c.Writer.Header().Set("X-Frame-Options", conf.SecurityConf.XFrameOptions) + } + + if conf.SecurityConf.ContentSecurityPolicy != "" { + c.Writer.Header().Set("Content-Security-Policy", conf.SecurityConf.ContentSecurityPolicy) + } if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return diff --git a/api/test/shell/cli_test.sh b/api/test/shell/cli_test.sh index be1d3a834c..da866a411a 100755 --- a/api/test/shell/cli_test.sh +++ b/api/test/shell/cli_test.sh @@ -454,6 +454,32 @@ stop_dashboard() { recover_service_file } +#15 +@test "Check Security configuration" { + recover_conf + + start_dashboard 3 + + # check response header without custom header + run curl -i http://127.0.0.1:9000 + + [ $(echo "$output" | grep -c "X-Frame-Options: deny") -eq '1' ] + + stop_dashboard 6 + + sed -i 's@# security:@security:@' ${CONF_FILE} + sed -i 's@# x_frame_options: "deny"@ x_frame_options: "test"@' ${CONF_FILE} + + start_dashboard 3 + + # check response header with custom header + run curl -i http://127.0.0.1:9000 + +[ $(echo "$output" | grep -c "X-Frame-Options: test") -eq '1' ] + + stop_dashboard 6 +} + #post @test "Clean test environment" { # kill etcd From 81e9de604eafd3fa48b53e2eb4719c9100270e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=9D=B0=E9=B2=81?= Date: Wed, 9 Mar 2022 11:41:31 +0800 Subject: [PATCH 2/3] fix: lint error --- api/test/shell/cli_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/test/shell/cli_test.sh b/api/test/shell/cli_test.sh index da866a411a..d41f270570 100755 --- a/api/test/shell/cli_test.sh +++ b/api/test/shell/cli_test.sh @@ -462,7 +462,7 @@ stop_dashboard() { # check response header without custom header run curl -i http://127.0.0.1:9000 - + [ $(echo "$output" | grep -c "X-Frame-Options: deny") -eq '1' ] stop_dashboard 6 From 9a1dab9b92a15f6f96718e499bbd964a11a3eeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=9D=B0=E9=B2=81?= Date: Fri, 11 Mar 2022 09:33:08 +0800 Subject: [PATCH 3/3] fix: style --- api/conf/conf.yaml | 4 ++-- api/internal/filter/cors.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/api/conf/conf.yaml b/api/conf/conf.yaml index 747bfc14c1..84e1f3aba7 100644 --- a/api/conf/conf.yaml +++ b/api/conf/conf.yaml @@ -61,8 +61,8 @@ conf: # log example: 2020-12-09T16:38:09.039+0800 INFO filter/logging.go:46 /apisix/admin/routes/r1 {"status": 401, "host": "127.0.0.1:9000", "query": "asdfsafd=adf&a=a", "requestId": "3d50ecb8-758c-46d1-af5b-cd9d1c820156", "latency": 0, "remoteIP": "127.0.0.1", "method": "PUT", "errs": []} max_cpu: 0 # supports tweaking with the number of OS threads are going to be used for parallelism. Default value: 0 [will use max number of available cpu cores considering hyperthreading (if any)]. If the value is negative, is will not touch the existing parallelism profile. # security: - # access_control_allow_origin: "http:httpbin.org" - # access_control_allow_credentials: true # support user custom cors configration + # access_control_allow_origin: "http://httpbin.org" + # access_control_allow_credentials: true # support using custom cors configration # access_control_allow_headers: "Authorization" # access_control-allow_methods: "*" # x_frame_options: "deny" diff --git a/api/internal/filter/cors.go b/api/internal/filter/cors.go index 3c72e1afba..28ca331625 100644 --- a/api/internal/filter/cors.go +++ b/api/internal/filter/cors.go @@ -17,8 +17,9 @@ package filter import ( - "github.com/apisix/manager-api/internal/conf" "github.com/gin-gonic/gin" + + "github.com/apisix/manager-api/internal/conf" ) func CORS() gin.HandlerFunc {