You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by zh...@apache.org on 2022/05/11 03:26:15 UTC
[apisix-ingress-controller] branch master updated: feat:add authorization-annotation the ingress resource (#985)
This is an automated email from the ASF dual-hosted git repository.
zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
The following commit(s) were added to refs/heads/master by this push:
new 670d671d feat:add authorization-annotation the ingress resource (#985)
670d671d is described below
commit 670d671d436701ec8083248c6b23713a50ec0c4c
Author: Xin Rong <79...@users.noreply.github.com>
AuthorDate: Wed May 11 11:26:11 2022 +0800
feat:add authorization-annotation the ingress resource (#985)
---
pkg/kube/translation/annotations.go | 2 +
pkg/kube/translation/annotations/authorization.go | 64 +++++
pkg/types/apisix/v1/plugin_types.go | 10 +
pkg/types/apisix/v1/zz_generated.deepcopy.go | 32 +++
test/e2e/scaffold/consumer.go | 26 +-
test/e2e/suite-annotations/authorization.go | 310 ++++++++++++++++++++++
6 files changed, 441 insertions(+), 3 deletions(-)
diff --git a/pkg/kube/translation/annotations.go b/pkg/kube/translation/annotations.go
index 767f7da0..3f06b813 100644
--- a/pkg/kube/translation/annotations.go
+++ b/pkg/kube/translation/annotations.go
@@ -29,6 +29,8 @@ var (
annotations.NewRewriteHandler(),
annotations.NewRedirectHandler(),
annotations.NewForwardAuthHandler(),
+ annotations.NewBasicAuthHandler(),
+ annotations.NewKeyAuthHandler(),
}
)
diff --git a/pkg/kube/translation/annotations/authorization.go b/pkg/kube/translation/annotations/authorization.go
new file mode 100644
index 00000000..c97567a4
--- /dev/null
+++ b/pkg/kube/translation/annotations/authorization.go
@@ -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 annotations
+
+import (
+ apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+const (
+ // auth-type: keyAuth | basicAuth
+ _authType = AnnotationsPrefix + "auth-type"
+)
+
+type basicAuth struct{}
+
+// NewkeyBasicHandler creates a handler to convert
+// annotations about basicAuth control to APISIX basic-auth plugin.
+func NewBasicAuthHandler() Handler {
+ return &basicAuth{}
+}
+
+func (b *basicAuth) PluginName() string {
+ return "basic-auth"
+}
+
+func (b *basicAuth) Handle(e Extractor) (interface{}, error) {
+ if e.GetStringAnnotation(_authType) != "basicAuth" {
+ return nil, nil
+ }
+ plugin := apisixv1.BasicAuthConfig{}
+ return &plugin, nil
+}
+
+type keyAuth struct{}
+
+// NewkeyAuthHandler creates a handler to convert
+// annotations about keyAuth control to APISIX key-auth plugin.
+func NewKeyAuthHandler() Handler {
+ return &keyAuth{}
+}
+
+func (k *keyAuth) PluginName() string {
+ return "key-auth"
+}
+
+func (k *keyAuth) Handle(e Extractor) (interface{}, error) {
+ if e.GetStringAnnotation(_authType) != "keyAuth" {
+ return nil, nil
+ }
+ plugin := apisixv1.KeyAuthConfig{}
+ return &plugin, nil
+}
diff --git a/pkg/types/apisix/v1/plugin_types.go b/pkg/types/apisix/v1/plugin_types.go
index 51346b78..b0f927c9 100644
--- a/pkg/types/apisix/v1/plugin_types.go
+++ b/pkg/types/apisix/v1/plugin_types.go
@@ -99,3 +99,13 @@ type ForwardAuthConfig struct {
UpstreamHeaders []string `json:"upstream_headers,omitempty"`
ClientHeaders []string `json:"client_headers,omitempty"`
}
+
+// BasicAuthConfig is the rule config for basic-auth plugin.
+// +k8s:deepcopy-gen=true
+type BasicAuthConfig struct {
+}
+
+// KeyAuthConfig is the rule config for key-auth plugin.
+// +k8s:deepcopy-gen=true
+type KeyAuthConfig struct {
+}
diff --git a/pkg/types/apisix/v1/zz_generated.deepcopy.go b/pkg/types/apisix/v1/zz_generated.deepcopy.go
index eabfe8b9..4016a713 100644
--- a/pkg/types/apisix/v1/zz_generated.deepcopy.go
+++ b/pkg/types/apisix/v1/zz_generated.deepcopy.go
@@ -19,6 +19,22 @@
package v1
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BasicAuthConfig) DeepCopyInto(out *BasicAuthConfig) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BasicAuthConfig.
+func (in *BasicAuthConfig) DeepCopy() *BasicAuthConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(BasicAuthConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BasicAuthConsumerConfig) DeepCopyInto(out *BasicAuthConsumerConfig) {
*out = *in
@@ -165,6 +181,22 @@ func (in *IPRestrictConfig) DeepCopy() *IPRestrictConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *KeyAuthConfig) DeepCopyInto(out *KeyAuthConfig) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyAuthConfig.
+func (in *KeyAuthConfig) DeepCopy() *KeyAuthConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(KeyAuthConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KeyAuthConsumerConfig) DeepCopyInto(out *KeyAuthConsumerConfig) {
*out = *in
diff --git a/test/e2e/scaffold/consumer.go b/test/e2e/scaffold/consumer.go
index 3c44a7c7..5cee9b24 100644
--- a/test/e2e/scaffold/consumer.go
+++ b/test/e2e/scaffold/consumer.go
@@ -16,8 +16,8 @@ package scaffold
import "fmt"
-func (s *Scaffold) ApisixConsumerBasicAuthCreated(name, username, password string) error {
- ac := fmt.Sprintf(`
+var (
+ _apisixConsumerBasicAuth = `
apiVersion: apisix.apache.org/v2beta3
kind: ApisixConsumer
metadata:
@@ -28,6 +28,26 @@ spec:
value:
username: %s
password: %s
-`, name, username, password)
+`
+ _apisixConsumerKeyAuth = `
+ apiVersion: apisix.apache.org/v2beta3
+ kind: ApisixConsumer
+ metadata:
+ name: %s
+ spec:
+ authParameter:
+ keyAuth:
+ value:
+ key: %s
+ `
+)
+
+func (s *Scaffold) ApisixConsumerBasicAuthCreated(name, username, password string) error {
+ ac := fmt.Sprintf(_apisixConsumerBasicAuth, name, username, password)
+ return s.CreateResourceFromString(ac)
+}
+
+func (s *Scaffold) ApisixConsumerKeyAuthCreated(name, key string) error {
+ ac := fmt.Sprintf(_apisixConsumerKeyAuth, name, key)
return s.CreateResourceFromString(ac)
}
diff --git a/test/e2e/suite-annotations/authorization.go b/test/e2e/suite-annotations/authorization.go
new file mode 100644
index 00000000..d1818651
--- /dev/null
+++ b/test/e2e/suite-annotations/authorization.go
@@ -0,0 +1,310 @@
+// 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 annotations
+
+import (
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/onsi/ginkgo"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("suite-annotations: authorization annotations", func() {
+ s := scaffold.NewDefaultScaffold()
+
+ ginkgo.It("enable keyAuth in ingress networking/v1", func() {
+ err := s.ApisixConsumerKeyAuthCreated("foo", "bar")
+ assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth ApisixConsumer")
+
+ // Wait until the ApisixConsumer create event was delivered.
+ time.Sleep(6 * time.Second)
+
+ 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/auth-type: "keyAuth"
+ 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)
+
+ msg401 := s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ Expect().
+ Status(http.StatusUnauthorized).
+ Body().
+ Raw()
+ assert.Contains(ginkgo.GinkgoT(), msg401, "Missing API key found in request")
+
+ _ = s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ WithHeader("apikey", "bar").
+ Expect().
+ Status(http.StatusOK)
+ })
+
+ ginkgo.It("enable keyAuth in ingress networking/v1beta1", func() {
+ err := s.ApisixConsumerKeyAuthCreated("foo", "bar")
+ assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth ApisixConsumer")
+
+ // Wait until the ApisixConsumer create event was delivered.
+ time.Sleep(6 * time.Second)
+
+ 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/auth-type: "keyAuth"
+ 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)
+
+ msg401 := s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ Expect().
+ Status(http.StatusUnauthorized).
+ Body().
+ Raw()
+ assert.Contains(ginkgo.GinkgoT(), msg401, "Missing API key found in request")
+
+ _ = s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ WithHeader("apikey", "bar").
+ Expect().
+ Status(http.StatusOK)
+ })
+
+ ginkgo.It("enable keyAuth in ingress extensions/v1beta1", func() {
+ err := s.ApisixConsumerKeyAuthCreated("foo", "bar")
+ assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth ApisixConsumer")
+
+ // Wait until the ApisixConsumer create event was delivered.
+ time.Sleep(6 * time.Second)
+
+ backendSvc, backendPort := s.DefaultHTTPBackend()
+ ing := fmt.Sprintf(`
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ annotations:
+ kubernetes.io/ingress.class: apisix
+ k8s.apisix.apache.org/auth-type: "keyAuth"
+ 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)
+
+ msg401 := s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ Expect().
+ Status(http.StatusUnauthorized).
+ Body().
+ Raw()
+ assert.Contains(ginkgo.GinkgoT(), msg401, "Missing API key found in request")
+
+ _ = s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ WithHeader("apikey", "bar").
+ Expect().
+ Status(http.StatusOK)
+ })
+
+ ginkgo.It("enable basicAuth in ingress networking/v1", func() {
+ err := s.ApisixConsumerBasicAuthCreated("jack1", "jack1-username", "jack1-password")
+ assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth ApisixConsumer")
+
+ // Wait until the ApisixConsumer create event was delivered.
+ time.Sleep(6 * time.Second)
+
+ 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/auth-type: "basicAuth"
+ 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)
+
+ msg401 := s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ Expect().
+ Status(http.StatusUnauthorized).
+ Body().
+ Raw()
+ assert.Contains(ginkgo.GinkgoT(), msg401, "Missing authorization in request")
+
+ _ = s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ WithHeader("Authorization", "Basic amFjazEtdXNlcm5hbWU6amFjazEtcGFzc3dvcmQ=").
+ Expect().
+ Status(http.StatusOK)
+ })
+
+ ginkgo.It("enable basicAuth in ingress networking/v1beta1", func() {
+ err := s.ApisixConsumerBasicAuthCreated("jack1", "jack1-username", "jack1-password")
+ assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth ApisixConsumer")
+
+ // Wait until the ApisixConsumer create event was delivered.
+ time.Sleep(6 * time.Second)
+
+ 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/auth-type: "basicAuth"
+ 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)
+
+ msg401 := s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ Expect().
+ Status(http.StatusUnauthorized).
+ Body().
+ Raw()
+ assert.Contains(ginkgo.GinkgoT(), msg401, "Missing authorization in request")
+
+ _ = s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ WithHeader("Authorization", "Basic amFjazEtdXNlcm5hbWU6amFjazEtcGFzc3dvcmQ=").
+ Expect().
+ Status(http.StatusOK)
+ })
+
+ ginkgo.It("enable basicAuth in ingress networking/v1beta1", func() {
+ err := s.ApisixConsumerBasicAuthCreated("jack1", "jack1-username", "jack1-password")
+ assert.Nil(ginkgo.GinkgoT(), err, "creating keyAuth ApisixConsumer")
+
+ // Wait until the ApisixConsumer create event was delivered.
+ time.Sleep(6 * time.Second)
+
+ backendSvc, backendPort := s.DefaultHTTPBackend()
+ ing := fmt.Sprintf(`
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ annotations:
+ kubernetes.io/ingress.class: apisix
+ k8s.apisix.apache.org/auth-type: "basicAuth"
+ 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)
+
+ msg401 := s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ Expect().
+ Status(http.StatusUnauthorized).
+ Body().
+ Raw()
+ assert.Contains(ginkgo.GinkgoT(), msg401, "Missing authorization in request")
+
+ _ = s.NewAPISIXClient().GET("/ip").
+ WithHeader("Host", "httpbin.org").
+ WithHeader("Authorization", "Basic amFjazEtdXNlcm5hbWU6amFjazEtcGFzc3dvcmQ=").
+ Expect().
+ Status(http.StatusOK)
+ })
+})