Skip to content

Commit

Permalink
feat: add control http method using kubernetes ingress by annotations (
Browse files Browse the repository at this point in the history
  • Loading branch information
incubator4 committed Dec 2, 2022
1 parent bccf762 commit 8e39e71
Show file tree
Hide file tree
Showing 12 changed files with 498 additions and 7 deletions.
25 changes: 25 additions & 0 deletions docs/en/latest/concepts/annotations.md
Expand Up @@ -99,6 +99,31 @@ k8s.apisix.apache.org/blocklist-source-range: "127.0.0.1,172.17.0.0/16"

The default value is empty which means no IP addresses are blocked.

## Customized http methods

> `http-allow-methods` and `http-block-methods` are mutually exclusive.
> If they're both set, only `http-allow-methods` works
### Allow http methods

This annotation can be used to specify which http method are allowed. Multiple methods can also be specified by separating them with commas.

```yaml
k8s.apisix.apache.org/http-allow-methods: "GET,POST"
```

The default value is empty which means all methods are allowed.

### Block http methods

This annotation can be used to specify which http method are blocked. Multiple methods can also be specified by separating them with commas.

```yaml
k8s.apisix.apache.org/http-block-method: "PUT,DELETE"
```

The default value is empty which means no methods are blocked.

## Rewrite target

These annotations are used to rewrite requests.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -7,6 +7,7 @@ require (
github.com/hashicorp/go-memdb v1.3.4
github.com/hashicorp/go-multierror v1.1.1
github.com/imdario/mergo v0.3.13
github.com/incubator4/go-resty-expr v0.1.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.14.0
github.com/prometheus/client_model v0.3.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -205,6 +205,8 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/incubator4/go-resty-expr v0.1.1 h1:9ur1M+p0wDzL1bprdGzHugGkfK0Yd3Ba/ijcgvL+a1k=
github.com/incubator4/go-resty-expr v0.1.1/go.mod h1:w9YQkQLUs1cArOb4O7SGJwJL/L8kuAo6y5CVS2o9eag=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
Expand Down
@@ -0,0 +1,64 @@
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 plugins

import (
"net/http"

"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"

"github.com/incubator4/go-resty-expr/expr"
)

type HttpMethod struct{}

// NewHttpHandler creates a handler to convert annotations about
// HttpMethod to APISIX cors plugin.
func NewHttpMethodHandler() PluginAnnotationsHandler {
return &HttpMethod{}
}

func (h HttpMethod) PluginName() string {
return "response-rewrite"
}

func (h HttpMethod) Handle(e annotations.Extractor) (interface{}, error) {
var plugin apisixv1.ResponseRewriteConfig

allowMethods := e.GetStringsAnnotation(annotations.AnnotationsHttpAllowMethods)
blockMethods := e.GetStringsAnnotation(annotations.AnnotationsHttpBlockMethods)

plugin.StatusCode = http.StatusMethodNotAllowed

if len(allowMethods) > 0 {
plugin.LuaRestyExpr = []expr.Expr{
expr.StringExpr("request_method").Not().In(
expr.ArrayExpr(expr.ExprArrayFromStrings(allowMethods)...),
),
}

} else if len(blockMethods) > 0 {
plugin.LuaRestyExpr = []expr.Expr{
expr.StringExpr("request_method").In(
expr.ArrayExpr(expr.ExprArrayFromStrings(blockMethods)...),
),
}

} else {
return nil, nil
}
return &plugin, nil
}
@@ -0,0 +1,93 @@
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 plugins

import (
"net/http"
"testing"

"github.com/stretchr/testify/assert"

"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"

"github.com/incubator4/go-resty-expr/expr"
)

// annotations:
//
// k8s.apisix.apache.org/allow-http-methods: GET,POST
func TestAnnotationsHttpAllowMethod(t *testing.T) {
anno := map[string]string{
annotations.AnnotationsHttpAllowMethods: "GET,POST",
}
p := NewHttpMethodHandler()
out, err := p.Handle(annotations.NewExtractor(anno))
assert.Nil(t, err, "checking given error")
config := out.(*apisixv1.ResponseRewriteConfig)

assert.Equal(t, http.StatusMethodNotAllowed, config.StatusCode)
assert.Equal(t, []expr.Expr{
expr.StringExpr("request_method").Not().In(expr.ArrayExpr(
expr.StringExpr("GET"),
expr.StringExpr("POST"),
)),
}, config.LuaRestyExpr)
}

// annotations:
//
// k8s.apisix.apache.org/block-http-methods: GET,PUT
func TestAnnotationsHttpBlockMethod(t *testing.T) {
anno := map[string]string{
annotations.AnnotationsHttpBlockMethods: "GET,PUT",
}
p := NewHttpMethodHandler()
out, err := p.Handle(annotations.NewExtractor(anno))
assert.Nil(t, err, "checking given error")
config := out.(*apisixv1.ResponseRewriteConfig)

assert.Equal(t, 405, config.StatusCode)
assert.Equal(t, []expr.Expr{
expr.StringExpr("request_method").In(expr.ArrayExpr(
expr.StringExpr("GET"),
expr.StringExpr("PUT"),
)),
}, config.LuaRestyExpr)
}

// annotations:
//
// k8s.apisix.apache.org/allow-http-methods: GET
// k8s.apisix.apache.org/block-http-methods: POST,PUT
//
// Only allow methods would be accepted, block methods would be ignored.
func TestAnnotationsHttpBothMethod(t *testing.T) {
anno := map[string]string{
annotations.AnnotationsHttpAllowMethods: "GET",
annotations.AnnotationsHttpBlockMethods: "POST,PUT",
}
p := NewHttpMethodHandler()
out, err := p.Handle(annotations.NewExtractor(anno))
assert.Nil(t, err, "checking given error")
config := out.(*apisixv1.ResponseRewriteConfig)

assert.Equal(t, http.StatusMethodNotAllowed, config.StatusCode)
assert.Equal(t, []expr.Expr{
expr.StringExpr("request_method").Not().In(expr.ArrayExpr(
expr.StringExpr("GET"),
)),
}, config.LuaRestyExpr)
}
Expand Up @@ -43,6 +43,7 @@ var (
NewBasicAuthHandler(),
NewKeyAuthHandler(),
NewCSRFHandler(),
NewHttpMethodHandler(),
}
)

Expand Down
4 changes: 4 additions & 0 deletions pkg/providers/ingress/translation/annotations/types.go
Expand Up @@ -62,6 +62,10 @@ const (
AnnotationsAllowlistSourceRange = AnnotationsPrefix + "allowlist-source-range"
AnnotationsBlocklistSourceRange = AnnotationsPrefix + "blocklist-source-range"

// http-method plugin
AnnotationsHttpAllowMethods = AnnotationsPrefix + "http-allow-methods"
AnnotationsHttpBlockMethods = AnnotationsPrefix + "http-block-methods"

// key-auth plugin and basic-auth plugin
// auth-type: keyAuth | basicAuth
AnnotationsAuthType = AnnotationsPrefix + "auth-type"
Expand Down
17 changes: 16 additions & 1 deletion pkg/types/apisix/v1/plugin_types.go
Expand Up @@ -14,7 +14,11 @@
// limitations under the License.
package v1

import "encoding/json"
import (
"encoding/json"

"github.com/incubator4/go-resty-expr/expr"
)

// TrafficSplitConfig is the config of traffic-split plugin.
// +k8s:deepcopy-gen=true
Expand Down Expand Up @@ -128,6 +132,17 @@ type RewriteConfig struct {
Headers Headers `json:"headers,omitempty"`
}

// ResponseRewriteConfig is the rule config for response-rewrite plugin.
// +k8s:deepcopy-gen=true
type ResponseRewriteConfig struct {
StatusCode int `json:"status_code,omitempty"`
Body string `json:"body,omitempty"`
BodyBase64 bool `json:"body_base64,omitempty"`
Headers Headers `json:"headers,omitempty"`
LuaRestyExpr []expr.Expr `json:"vars,omitempty"`
Filters []map[string]string `json:"filters,omitempty"`
}

// RedirectConfig is the rule config for redirect plugin.
// +k8s:deepcopy-gen=true
type RedirectConfig struct {
Expand Down
41 changes: 41 additions & 0 deletions pkg/types/apisix/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/e2e/go.mod
Expand Up @@ -58,6 +58,7 @@ require (
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/imkira/go-interpol v1.1.0 // indirect
github.com/incubator4/go-resty-expr v0.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
Expand Down
8 changes: 2 additions & 6 deletions test/e2e/go.sum
Expand Up @@ -262,12 +262,9 @@ github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRa
github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE=
github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-memdb v1.3.3 h1:oGfEWrFuxtIUF3W2q/Jzt6G85TrMk9ey6XfYLvVe1Wo=
github.com/hashicorp/go-memdb v1.3.3/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c=
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
Expand All @@ -286,6 +283,8 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/incubator4/go-resty-expr v0.1.1 h1:9ur1M+p0wDzL1bprdGzHugGkfK0Yd3Ba/ijcgvL+a1k=
github.com/incubator4/go-resty-expr v0.1.1/go.mod h1:w9YQkQLUs1cArOb4O7SGJwJL/L8kuAo6y5CVS2o9eag=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
Expand Down Expand Up @@ -388,14 +387,11 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
Expand Down

0 comments on commit 8e39e71

Please sign in to comment.