You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by kv...@apache.org on 2020/12/17 08:32:36 UTC

[apisix-ingress-controller] branch master updated: feat: support TLS (#95)

This is an automated email from the ASF dual-hosted git repository.

kvn 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 04ab348  feat: support TLS (#95)
04ab348 is described below

commit 04ab348eb343485f01837fe1da456156e5131deb
Author: kv <gx...@163.com>
AuthorDate: Thu Dec 17 16:32:29 2020 +0800

    feat: support TLS (#95)
    
    * feat: add tls
    
    * add comment
    
    * feat: support ssl in seven
    
    * fix: fail to  delete tls && add doc
    
    * add test case
    
    * fix: conf path & apache header
    
    * fix: move log object
    
    * fix: unexpected error
    
    * change: ApisixTLS instead of ApisixTls
    
    * modify the comment
    
    * order the import libs
    
    * remove glog
---
 cmd/ingress/ingress.go                             |   2 +
 go.mod                                             |  12 +-
 go.sum                                             |  13 ++
 pkg/ingress/apisix/tls.go                          |  68 ++++++++
 pkg/ingress/apisix/tls_test.go                     | 115 +++++++++++++
 pkg/ingress/controller/apisix_tls.go               | 186 +++++++++++++++++++++
 pkg/ingress/controller/controller.go               |   8 +
 .../v1beta1/{kustomization.yaml => ApisixTls.yaml} |  21 ++-
 samples/deploy/crd/v1beta1/kustomization.yaml      |   1 +
 samples/deploy/rbac/apisix_view_clusterrole.yaml   |   1 +
 10 files changed, 417 insertions(+), 10 deletions(-)

diff --git a/cmd/ingress/ingress.go b/cmd/ingress/ingress.go
index 679accc..a59f648 100644
--- a/cmd/ingress/ingress.go
+++ b/cmd/ingress/ingress.go
@@ -114,6 +114,8 @@ func NewIngressCommand() *cobra.Command {
 			c.ApisixUpstream()
 			// ApisixService
 			c.ApisixService()
+			// ApisixTLS
+			c.ApisixTLS()
 
 			go func() {
 				time.Sleep(time.Duration(10) * time.Second)
diff --git a/go.mod b/go.mod
index 40660d1..4c8541c 100644
--- a/go.mod
+++ b/go.mod
@@ -6,10 +6,10 @@ require (
 	github.com/gin-gonic/gin v1.6.3
 	github.com/gogo/protobuf v1.3.1 // indirect
 	github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
-	github.com/gxthrj/apisix-ingress-types v0.1.2
-	github.com/gxthrj/apisix-types v0.1.0
-	github.com/gxthrj/seven v0.1.9
-	github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
+	github.com/gxthrj/apisix-ingress-types v0.1.3
+	github.com/gxthrj/apisix-types v0.1.3
+	github.com/gxthrj/seven v0.2.4
+	github.com/julienschmidt/httprouter v1.3.0
 	github.com/spf13/cobra v1.1.1
 	github.com/stretchr/testify v1.4.0
 	go.uber.org/zap v1.13.0
@@ -19,6 +19,6 @@ require (
 	k8s.io/client-go v0.0.0-20190819141724-e14f31a72a77
 )
 
-replace github.com/gxthrj/apisix-ingress-types v0.1.2 => github.com/api7/ingress-types v0.1.2
+replace github.com/gxthrj/apisix-ingress-types v0.1.3 => github.com/api7/ingress-types v0.1.3
 
-replace github.com/gxthrj/apisix-types v0.1.0 => github.com/api7/types v0.1.0
+replace github.com/gxthrj/apisix-types v0.1.2 => github.com/api7/types v0.1.2
diff --git a/go.sum b/go.sum
index 65077f1..af23442 100644
--- a/go.sum
+++ b/go.sum
@@ -20,8 +20,12 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/api7/ingress-types v0.1.2 h1:K8GxVKSvPi89CHozico/oLbcy6mZOdeOk+VfJRCLXrE=
 github.com/api7/ingress-types v0.1.2/go.mod h1:xWuHLSHGN4/JZjz9b0ftKgtE3yZ7NehkJAiTyZ+KoPA=
+github.com/api7/ingress-types v0.1.3 h1:euvLySusNeOjzOjnpZl+J3Ve5ZcWoby/lm3lPmH4xTI=
+github.com/api7/ingress-types v0.1.3/go.mod h1:xWuHLSHGN4/JZjz9b0ftKgtE3yZ7NehkJAiTyZ+KoPA=
 github.com/api7/types v0.1.0 h1:x8nOUY9yjNCCpxlODqXpp5MrEjp9W4grNyGsgxxLq1Y=
 github.com/api7/types v0.1.0/go.mod h1:STdHATWxqIeJhUEXt6dZTd6z0To0qO70K/1mnfBtlC0=
+github.com/api7/types v0.1.1/go.mod h1:STdHATWxqIeJhUEXt6dZTd6z0To0qO70K/1mnfBtlC0=
+github.com/api7/types v0.1.2/go.mod h1:STdHATWxqIeJhUEXt6dZTd6z0To0qO70K/1mnfBtlC0=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@@ -113,8 +117,16 @@ github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:Fecb
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/gxthrj/apisix-ingress-types v0.1.3/go.mod h1:xWuHLSHGN4/JZjz9b0ftKgtE3yZ7NehkJAiTyZ+KoPA=
+github.com/gxthrj/apisix-types v0.1.0/go.mod h1:STdHATWxqIeJhUEXt6dZTd6z0To0qO70K/1mnfBtlC0=
+github.com/gxthrj/apisix-types v0.1.1/go.mod h1:STdHATWxqIeJhUEXt6dZTd6z0To0qO70K/1mnfBtlC0=
+github.com/gxthrj/apisix-types v0.1.3 h1:H8TqK6uIcG+rM2o+wq33gSh4KKZI+197j9lcy8aZ0Iw=
+github.com/gxthrj/apisix-types v0.1.3/go.mod h1:STdHATWxqIeJhUEXt6dZTd6z0To0qO70K/1mnfBtlC0=
 github.com/gxthrj/seven v0.1.9 h1:EccFVE5PIqZXyt91laXxGu9tydCjg31EXn/Q4aFfwD4=
 github.com/gxthrj/seven v0.1.9/go.mod h1:epDVCYT1ibfV6fgaeM918QAer9u0/M2LXW6OcIRdfQc=
+github.com/gxthrj/seven v0.2.0 h1:S85ZI2TzVQILsiI9BE+Sa0VqrkU3kzNYJFOOh4+5Vu8=
+github.com/gxthrj/seven v0.2.0/go.mod h1:Uf0JHSRmhZyV3tPLV1oVzq/Dw19ya9rXFsECiLKrgVk=
+github.com/gxthrj/seven v0.2.4/go.mod h1:SYs/veqEMdwRF5BL3nf/nxfypoDMO2E6Odgp17m+J9U=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -157,6 +169,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
diff --git a/pkg/ingress/apisix/tls.go b/pkg/ingress/apisix/tls.go
new file mode 100644
index 0000000..fc8b2de
--- /dev/null
+++ b/pkg/ingress/apisix/tls.go
@@ -0,0 +1,68 @@
+// 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 apisix
+
+import (
+	ingressConf "github.com/api7/ingress-controller/pkg/kube"
+	ingress "github.com/gxthrj/apisix-ingress-types/pkg/apis/config/v1"
+	apisix "github.com/gxthrj/apisix-types/pkg/apis/apisix/v1"
+	"k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const (
+	ApisixTls = "ApisixTls"
+)
+
+type ApisixTlsCRD ingress.ApisixTls
+
+// Convert convert to  apisix.Ssl from ingress.ApisixTls CRD
+func (as *ApisixTlsCRD) Convert(sc Secreter) (*apisix.Ssl, error) {
+	name := as.Name
+	namespace := as.Namespace
+	id := namespace + "_" + name
+	secretName := as.Spec.Secret.Name
+	secretNamespace := as.Spec.Secret.Namespace
+	secret, err := sc.FindByName(secretNamespace, secretName)
+	if err != nil {
+		return nil, err
+	}
+	cert := string(secret.Data["cert"])
+	key := string(secret.Data["key"])
+	status := 1
+	snis := make([]*string, 0)
+	for _, host := range as.Spec.Hosts {
+		snis = append(snis, &host)
+	}
+	ssl := &apisix.Ssl{
+		ID:     &id,
+		Snis:   snis,
+		Cert:   &cert,
+		Key:    &key,
+		Status: &status,
+	}
+	return ssl, nil
+}
+
+type Secreter interface {
+	FindByName(namespace, name string) (*v1.Secret, error)
+}
+
+type SecretClient struct{}
+
+func (sc *SecretClient) FindByName(namespace, name string) (*v1.Secret, error) {
+	clientSet := ingressConf.GetKubeClient()
+	return clientSet.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{})
+}
diff --git a/pkg/ingress/apisix/tls_test.go b/pkg/ingress/apisix/tls_test.go
new file mode 100644
index 0000000..68d9262
--- /dev/null
+++ b/pkg/ingress/apisix/tls_test.go
@@ -0,0 +1,115 @@
+// 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 apisix
+
+import (
+	"encoding/json"
+	"fmt"
+	"testing"
+
+	a6Type "github.com/gxthrj/apisix-types/pkg/apis/apisix/v1"
+	"github.com/stretchr/testify/assert"
+	"gopkg.in/yaml.v2"
+	"k8s.io/api/core/v1"
+)
+
+func TestConvert(t *testing.T) {
+	atlsStr := `
+apiVersion: apisix.apache.org/v1
+kind: ApisixTls
+metadata:
+  name: foo
+  namespace: helm
+spec:
+  hosts:
+  - api6.com
+  secret:
+    name: test-atls
+    namespace: helm
+`
+	id := "helm_foo"
+	host := "api6.com"
+	snis := []*string{&host}
+	status := int(1)
+	cert := "root"
+	key := "123456"
+	sslExpect := &a6Type.Ssl{
+		ID:     &id,
+		Snis:   snis,
+		Cert:   &cert,
+		Key:    &key,
+		Status: &status,
+	}
+	atlsCRD := &ApisixTlsCRD{}
+	err := yaml.Unmarshal([]byte(atlsStr), atlsCRD)
+	assert.Nil(t, err, "yaml decode failed")
+	sc := &SecretClientMock{}
+	ssl, err := atlsCRD.Convert(sc)
+	assert.EqualValues(t, sslExpect.Key, ssl.Key, "ssl convert error")
+	assert.EqualValues(t, sslExpect.ID, ssl.ID, "ssl convert error")
+	assert.EqualValues(t, sslExpect.Cert, ssl.Cert, "ssl convert error")
+	assert.EqualValues(t, sslExpect.Snis, ssl.Snis, "ssl convert error")
+}
+
+func TestConvert_Error(t *testing.T) {
+	atlsStr := `
+apiVersion: apisix.apache.org/v1
+kind: ApisixTls
+metadata:
+  name: foo
+  namespace: helm
+spec:
+  secret:
+    name: test-atls
+    namespace: helm
+`
+	atlsCRD := &ApisixTlsCRD{}
+	err := yaml.Unmarshal([]byte(atlsStr), atlsCRD)
+	assert.Nil(t, err, "yaml decode failed")
+	sc := &SecretClientErrorMock{}
+	ssl, err := atlsCRD.Convert(sc)
+	assert.Nil(t, ssl)
+	assert.NotNil(t, err)
+}
+
+type SecretClientMock struct{}
+
+func (sc *SecretClientMock) FindByName(namespace, name string) (*v1.Secret, error) {
+	secretStr := `
+{
+  "apiVersion": "v1",
+  "kind": "Secret",
+  "metadata": {
+    "name": "test-atls",
+    "namespace": "helm"
+  },
+  "data": {
+    "cert": "cm9vdA==",
+    "key": "MTIzNDU2"
+  }
+}
+`
+	secret := &v1.Secret{}
+	if err := json.Unmarshal([]byte(secretStr), secret); err != nil {
+		fmt.Errorf(err.Error())
+	}
+	return secret, nil
+}
+
+type SecretClientErrorMock struct{}
+
+func (sc *SecretClientErrorMock) FindByName(namespace, name string) (*v1.Secret, error) {
+	return nil, fmt.Errorf("NOT FOUND")
+}
diff --git a/pkg/ingress/controller/apisix_tls.go b/pkg/ingress/controller/apisix_tls.go
new file mode 100644
index 0000000..fe2a144
--- /dev/null
+++ b/pkg/ingress/controller/apisix_tls.go
@@ -0,0 +1,186 @@
+// 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 controller
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/api7/ingress-controller/pkg/ingress/apisix"
+	"github.com/api7/ingress-controller/pkg/log"
+	apisixV1 "github.com/gxthrj/apisix-ingress-types/pkg/apis/config/v1"
+	clientSet "github.com/gxthrj/apisix-ingress-types/pkg/client/clientset/versioned"
+	apisixScheme "github.com/gxthrj/apisix-ingress-types/pkg/client/clientset/versioned/scheme"
+	informers "github.com/gxthrj/apisix-ingress-types/pkg/client/informers/externalversions/config/v1"
+	"github.com/gxthrj/apisix-ingress-types/pkg/client/listers/config/v1"
+	"github.com/gxthrj/seven/state"
+	"k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/util/runtime"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/kubernetes/scheme"
+	"k8s.io/client-go/tools/cache"
+	"k8s.io/client-go/util/workqueue"
+)
+
+type ApisixTlsController struct {
+	kubeclientset   kubernetes.Interface
+	apisixClientset clientSet.Interface
+	apisixTlsList   v1.ApisixTlsLister
+	apisixTlsSynced cache.InformerSynced
+	workqueue       workqueue.RateLimitingInterface
+}
+
+type TlsQueueObj struct {
+	Key    string              `json:"key"`
+	OldObj *apisixV1.ApisixTls `json:"old_obj"`
+	Ope    string              `json:"ope"` // add / update / delete
+}
+
+func BuildApisixTlsController(
+	kubeclientset kubernetes.Interface,
+	apisixTlsClientset clientSet.Interface,
+	apisixTlsInformer informers.ApisixTlsInformer) *ApisixTlsController {
+
+	runtime.Must(apisixScheme.AddToScheme(scheme.Scheme))
+	controller := &ApisixTlsController{
+		kubeclientset:   kubeclientset,
+		apisixClientset: apisixTlsClientset,
+		apisixTlsList:   apisixTlsInformer.Lister(),
+		apisixTlsSynced: apisixTlsInformer.Informer().HasSynced,
+		workqueue:       workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "ApisixTlses"),
+	}
+	apisixTlsInformer.Informer().AddEventHandler(
+		cache.ResourceEventHandlerFuncs{
+			AddFunc:    controller.addFunc,
+			UpdateFunc: controller.updateFunc,
+			DeleteFunc: controller.deleteFunc,
+		})
+	return controller
+}
+
+func (c *ApisixTlsController) Run(stop <-chan struct{}) error {
+	if ok := cache.WaitForCacheSync(stop); !ok {
+		log.Errorf("sync ApisixService cache failed")
+		return fmt.Errorf("failed to wait for caches to sync")
+	}
+	go wait.Until(c.runWorker, time.Second, stop)
+	return nil
+}
+
+func (c *ApisixTlsController) runWorker() {
+	for c.processNextWorkItem() {
+	}
+}
+
+func (c *ApisixTlsController) processNextWorkItem() bool {
+	defer recoverException()
+	obj, shutdown := c.workqueue.Get()
+	if shutdown {
+		return false
+	}
+	err := func(obj interface{}) error {
+		defer c.workqueue.Done(obj)
+		var key string
+		var ok bool
+
+		var tqo *TlsQueueObj
+		if tqo, ok = obj.(*TlsQueueObj); !ok {
+			c.workqueue.Forget(obj)
+			return fmt.Errorf("expected TlsQueueObj in workqueue but got %#v", obj)
+		}
+		if err := c.syncHandler(tqo); err != nil {
+			return fmt.Errorf("error syncing '%s': %s", key, err.Error())
+		}
+
+		c.workqueue.Forget(obj)
+		return nil
+	}(obj)
+	if err != nil {
+		runtime.HandleError(err)
+	}
+	return true
+}
+
+func (c *ApisixTlsController) syncHandler(tqo *TlsQueueObj) error {
+	namespace, name, err := cache.SplitMetaNamespaceKey(tqo.Key)
+	if err != nil {
+		log.Errorf("invalid resource key: %s", tqo.Key)
+		return fmt.Errorf("invalid resource key: %s", tqo.Key)
+	}
+	apisixTlsYaml := tqo.OldObj
+	if tqo.Ope != state.Delete {
+		apisixTlsYaml, err = c.apisixTlsList.ApisixTlses(namespace).Get(name)
+		if err != nil {
+			if errors.IsNotFound(err) {
+				log.Infof("apisixTls %s is removed", tqo.Key)
+				return nil
+			}
+			runtime.HandleError(fmt.Errorf("failed to list apisixTls %s/%s", tqo.Key, err.Error()))
+			return err
+		}
+	}
+	apisixTls := apisix.ApisixTlsCRD(*apisixTlsYaml)
+	sc := &apisix.SecretClient{}
+	if tls, err := apisixTls.Convert(sc); err != nil {
+		return err
+	} else {
+		// sync to apisix
+		log.Debug(tls)
+		log.Debug(tqo)
+		state.SyncSsl(tls, tqo.Ope)
+	}
+	return err
+}
+
+func (c *ApisixTlsController) addFunc(obj interface{}) {
+	var key string
+	var err error
+	if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
+		runtime.HandleError(err)
+		return
+	}
+	rqo := &TlsQueueObj{Key: key, OldObj: nil, Ope: state.Create}
+	c.workqueue.AddRateLimited(rqo)
+}
+
+func (c *ApisixTlsController) updateFunc(oldObj, newObj interface{}) {
+	oldTls := oldObj.(*apisixV1.ApisixTls)
+	newTls := newObj.(*apisixV1.ApisixTls)
+	if oldTls.ResourceVersion == newTls.ResourceVersion {
+		return
+	}
+	var key string
+	var err error
+	if key, err = cache.MetaNamespaceKeyFunc(newObj); err != nil {
+		runtime.HandleError(err)
+		return
+	}
+	rqo := &TlsQueueObj{Key: key, OldObj: oldTls, Ope: state.Update}
+	c.workqueue.AddRateLimited(rqo)
+}
+
+func (c *ApisixTlsController) deleteFunc(obj interface{}) {
+	oldTls := obj.(cache.DeletedFinalStateUnknown).Obj.(*apisixV1.ApisixTls)
+	var key string
+	var err error
+	key, err = cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
+	if err != nil {
+		runtime.HandleError(err)
+		return
+	}
+	rqo := &TlsQueueObj{Key: key, OldObj: oldTls, Ope: state.Delete}
+	c.workqueue.AddRateLimited(rqo)
+}
diff --git a/pkg/ingress/controller/controller.go b/pkg/ingress/controller/controller.go
index 11ddaa4..34fb9f8 100644
--- a/pkg/ingress/controller/controller.go
+++ b/pkg/ingress/controller/controller.go
@@ -62,6 +62,14 @@ func (api6 *Api6Controller) ApisixService() {
 	auc.Run(api6.Stop)
 }
 
+func (api6 *Api6Controller) ApisixTLS() {
+	auc := BuildApisixTlsController(
+		api6.KubeClientSet,
+		api6.Api6ClientSet,
+		api6.SharedInformerFactory.Apisix().V1().ApisixTlses())
+	auc.Run(api6.Stop)
+}
+
 func (api6 *Api6Controller) Endpoint() {
 	auc := BuildEndpointController(api6.KubeClientSet)
 	//conf.EndpointsInformer)
diff --git a/samples/deploy/crd/v1beta1/kustomization.yaml b/samples/deploy/crd/v1beta1/ApisixTls.yaml
similarity index 69%
copy from samples/deploy/crd/v1beta1/kustomization.yaml
copy to samples/deploy/crd/v1beta1/ApisixTls.yaml
index 5186cb8..9a828dd 100644
--- a/samples/deploy/crd/v1beta1/kustomization.yaml
+++ b/samples/deploy/crd/v1beta1/ApisixTls.yaml
@@ -15,7 +15,20 @@
 # limitations under the License.
 #
 
-resources:
-  - ./ApisixRoute.yaml
-  - ./ApisixUpstream.yaml
-  - ./ApisixService.yaml
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: apisixtlses.apisix.apache.org
+spec:
+  group: apisix.apache.org
+  versions:
+    - name: v1
+      served: true
+      storage: true
+  scope: Namespaced
+  names:
+    plural: apisixtlses
+    singular: apisixtls
+    kind: ApisixTls
+    shortNames:
+    - atls
diff --git a/samples/deploy/crd/v1beta1/kustomization.yaml b/samples/deploy/crd/v1beta1/kustomization.yaml
index 5186cb8..4d22446 100644
--- a/samples/deploy/crd/v1beta1/kustomization.yaml
+++ b/samples/deploy/crd/v1beta1/kustomization.yaml
@@ -19,3 +19,4 @@ resources:
   - ./ApisixRoute.yaml
   - ./ApisixUpstream.yaml
   - ./ApisixService.yaml
+  - ./ApisixTls.yaml
diff --git a/samples/deploy/rbac/apisix_view_clusterrole.yaml b/samples/deploy/rbac/apisix_view_clusterrole.yaml
index 4a92260..756f415 100644
--- a/samples/deploy/rbac/apisix_view_clusterrole.yaml
+++ b/samples/deploy/rbac/apisix_view_clusterrole.yaml
@@ -137,6 +137,7 @@ rules:
   - apisixroutes
   - apisixupstreams
   - apisixservices
+  - apisixtlses
   verbs:
   - get
   - list