Skip to content

Commit

Permalink
feat: blocklist-source-range annotation (#446)
Browse files Browse the repository at this point in the history
  • Loading branch information
tokers committed May 14, 2021
1 parent 8824bbd commit 5d479ae
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 15 deletions.
10 changes: 8 additions & 2 deletions docs/en/latest/concepts/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,11 @@ Default is `"*"`, which means all HTTP methods are accepted.
Allowlist Source Range
-----------------------

You can specify the allowed client IP addresses or nets by the annotation `k8s.apisix.apache.org/allowlist-source-range`, multiple IP adddresses or nets join together with `,`,
for instance, `k8s.apisix.apache.org/allowlist-source-range: 10.0.5.0/16,127.0.0.1,192.168.3.98`. Default value is *empty*, which means the sources are unlimited.
You can specify the allowed client IP addresses or nets by the annotation `k8s.apisix.apache.org/allowlist-source-range`, multiple IP addresses or nets join together with `,`,
for instance, `k8s.apisix.apache.org/allowlist-source-range: 10.0.5.0/16,127.0.0.1,192.168.3.98`. Default value is *empty*, which means the sources are not limited.

Blocklist Source Range
----------------------

You can specify the denied client IP addresses or nets by the annotation `k8s.apisix.apache.org/blocklist-source-range`, multiple IP addresses or nets join together with `,`,
for instance, `k8s.apisix.apache.org/blocklist-source-range: 127.0.0.1,172.17.0.0/16`. Default value is *empty*, which means the sources are not limited.
151 changes: 151 additions & 0 deletions go.sum

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/kube/translation/annotations/cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
type cors struct{}

// NewCorsHandler creates a handler to convert annotations about
// cors to APISIX cors plugin.
// CORS to APISIX cors plugin.
func NewCorsHandler() Handler {
return &cors{}
}
Expand Down
13 changes: 8 additions & 5 deletions pkg/kube/translation/annotations/iprestriction.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

const (
_allowlistSourceRange = "k8s.apisix.apache.org/allowlist-source-range"
_blocklistSourceRange = "k8s.apisix.apache.org/blocklist-source-range"
)

type ipRestriction struct{}
Expand All @@ -36,10 +37,12 @@ func (i *ipRestriction) PluginName() string {

func (i *ipRestriction) Handle(e Extractor) (interface{}, error) {
var plugin apisixv1.IPRestrictConfig
if allowlist := e.GetStringsAnnotation(_allowlistSourceRange); len(allowlist) > 0 {
plugin.Whitelist = allowlist
} else {
return nil, nil
allowlist := e.GetStringsAnnotation(_allowlistSourceRange)
blocklist := e.GetStringsAnnotation(_blocklistSourceRange)
if allowlist != nil || blocklist != nil {
plugin.Allowlist = allowlist
plugin.Blocklist = blocklist
return &plugin, nil
}
return &plugin, nil
return nil, nil
}
19 changes: 15 additions & 4 deletions pkg/kube/translation/annotations/iprestriction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,24 @@ func TestIPRestrictionHandler(t *testing.T) {
out, err := p.Handle(NewExtractor(annotations))
assert.Nil(t, err, "checking given error")
config := out.(*apisixv1.IPRestrictConfig)
assert.Len(t, config.Whitelist, 2, "checking size of white list")
assert.Equal(t, config.Whitelist[0], "10.2.2.2")
assert.Equal(t, config.Whitelist[1], "192.168.0.0/16")

assert.Len(t, config.Allowlist, 2, "checking size of white list")
assert.Equal(t, config.Allowlist[0], "10.2.2.2")
assert.Equal(t, config.Allowlist[1], "192.168.0.0/16")
assert.Equal(t, p.PluginName(), "ip-restriction")

annotations[_blocklistSourceRange] = "172.17.0.0/16,127.0.0.1"
out, err = p.Handle(NewExtractor(annotations))
assert.Nil(t, err, "checking given error")
config = out.(*apisixv1.IPRestrictConfig)
assert.Len(t, config.Allowlist, 2, "checking size of white list")
assert.Equal(t, config.Allowlist[0], "10.2.2.2")
assert.Equal(t, config.Allowlist[1], "192.168.0.0/16")
assert.Len(t, config.Blocklist, 2, "checking size of black list")
assert.Equal(t, config.Blocklist[0], "172.17.0.0/16")
assert.Equal(t, config.Blocklist[1], "127.0.0.1")

delete(annotations, _allowlistSourceRange)
delete(annotations, _blocklistSourceRange)
out, err = p.Handle(NewExtractor(annotations))
assert.Nil(t, err, "checking given error")
assert.Nil(t, out, "checking the given ip-restrction plugin config")
Expand Down
3 changes: 2 additions & 1 deletion pkg/types/apisix/v1/plugin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ type TrafficSplitConfigRuleWeightedUpstream struct {
// IPRestrictConfig is the rule config for ip-restriction plugin.
// +k8s:deepcopy-gen=true
type IPRestrictConfig struct {
Whitelist []string `json:"whitelist,omitempty"`
Allowlist []string `json:"whitelist,omitempty"`
Blocklist []string `json:"blacklist,omitempty"`
}

// CorsConfig is the rule config for cors plugin.
Expand Down
9 changes: 7 additions & 2 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.

93 changes: 93 additions & 0 deletions test/e2e/annotations/iprestriction.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,96 @@ spec:
resp.Status(http.StatusForbidden)
})
})

var _ = ginkgo.Describe("blocklist-source-range annotations", func() {
s := scaffold.NewDefaultScaffold()

ginkgo.It("enable in ingress networking/v1", func() {
backendSvc, backendPort := s.DefaultHTTPBackend()
ing := fmt.Sprintf(`
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: apisix
k8s.apisix.apache.org/blocklist-source-range: "127.0.0.1"
name: ingress-v1
spec:
rules:
- host: httpbin.org
http:
paths:
- path: /ip
pathType: Exact
backend:
service:
name: %s
port:
number: %d
`, backendSvc, backendPort[0])
err := s.CreateResourceFromString(ing)
assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
time.Sleep(5 * time.Second)

resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
resp.Status(http.StatusForbidden)
})

ginkgo.It("enable in ingress networking/v1beta1", func() {
backendSvc, backendPort := s.DefaultHTTPBackend()
ing := fmt.Sprintf(`
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: apisix
k8s.apisix.apache.org/blocklist-source-range: "127.0.0.1"
name: ingress-v1beta1
spec:
rules:
- host: httpbin.org
http:
paths:
- path: /ip
pathType: Exact
backend:
serviceName: %s
servicePort: %d
`, backendSvc, backendPort[0])
err := s.CreateResourceFromString(ing)
assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
time.Sleep(5 * time.Second)

resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
resp.Status(http.StatusForbidden)
})

ginkgo.It("enable in ingress extensions/v1beta1", func() {
backendSvc, backendPort := s.DefaultHTTPBackend()
ing := fmt.Sprintf(`
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: apisix
k8s.apisix.apache.org/blocklist-source-range: "127.0.0.1"
name: ingress-extensions-v1beta1
spec:
rules:
- host: httpbin.org
http:
paths:
- path: /ip
pathType: Exact
backend:
serviceName: %s
servicePort: %d
`, backendSvc, backendPort[0])
err := s.CreateResourceFromString(ing)
assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
time.Sleep(5 * time.Second)

resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
resp.Status(http.StatusForbidden)
})
})

0 comments on commit 5d479ae

Please sign in to comment.