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/12/12 14:25:24 UTC
[apisix-ingress-controller] branch master updated: feat: support secret plugin config (#1486)
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 0009b5d6 feat: support secret plugin config (#1486)
0009b5d6 is described below
commit 0009b5d6951c89d2b67e0a440d4a75952fb3154c
Author: dongjunduo <an...@gmail.com>
AuthorDate: Mon Dec 12 22:25:18 2022 +0800
feat: support secret plugin config (#1486)
---
docs/en/latest/concepts/apisix_route.md | 47 +++++++++++
pkg/kube/apisix/apis/config/v2/types.go | 2 +
.../apisix/translation/apisix_pluginconfig.go | 15 ++++
pkg/providers/apisix/translation/apisix_route.go | 30 +++++++
samples/deploy/crd/v1/ApisixPluginConfig.yaml | 2 +
samples/deploy/crd/v1/ApisixRoute.yaml | 4 +
.../suite-plugins-general/secret_ref.go | 93 ++++++++++++++++++++++
7 files changed, 193 insertions(+)
diff --git a/docs/en/latest/concepts/apisix_route.md b/docs/en/latest/concepts/apisix_route.md
index c04860b2..79b0946b 100644
--- a/docs/en/latest/concepts/apisix_route.md
+++ b/docs/en/latest/concepts/apisix_route.md
@@ -201,6 +201,53 @@ spec:
enable: true
```
+### Config with secretRef
+
+Plugins are supported to be configured from kubernetes secret with `secretRef`.
+
+The priority is `plugins.secretRef > plugins.config`. That is, the duplicated key in `plugins.config` are replaced by `plugins.secretRef`.
+
+Example below configures echo plugin. The final values of `before_body`, `body` and `after_body` are "This is the replaced preface", "my custom body" and "This is the epilogue", respectively.
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: echo
+data:
+ # content is "This is the replaced preface"
+ before_body: IlRoaXMgaXMgdGhlIHJlcGxhY2VkIHByZWZhY2Ui
+ # content is "my custom body"
+ body: Im15IGN1c3RvbSBib2R5Ig==
+---
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+ name: httpbin-route
+spec:
+ http:
+ - name: rule1
+ match:
+ hosts:
+ - httpbin.org
+ paths:
+ - /ip
+ backends:
+ - serviceName: %s
+ servicePort: %d
+ weight: 10
+ plugins:
+ - name: echo
+ enable: true
+ config:
+ before_body: "This is the preface"
+ after_body: "This is the epilogue"
+ headers:
+ X-Foo: v1
+ X-Foo2: v2
+ secretRef: echo
+```
+
## Websocket proxy
You can route requests to [WebSocket](https://en.wikipedia.org/wiki/WebSocket#:~:text=WebSocket%20is%20a%20computer%20communications,WebSocket%20is%20distinct%20from%20HTTP.) services by setting the `websocket` attribute to `true` as shown below:
diff --git a/pkg/kube/apisix/apis/config/v2/types.go b/pkg/kube/apisix/apis/config/v2/types.go
index da481997..d87a8a56 100644
--- a/pkg/kube/apisix/apis/config/v2/types.go
+++ b/pkg/kube/apisix/apis/config/v2/types.go
@@ -170,6 +170,8 @@ type ApisixRoutePlugin struct {
Enable bool `json:"enable" yaml:"enable"`
// Plugin configuration.
Config ApisixRoutePluginConfig `json:"config" yaml:"config"`
+ // Plugin configuration secretRef.
+ SecretRef string `json:"secretRef" yaml:"secretRef"`
}
// ApisixRoutePluginConfig is the configuration for
diff --git a/pkg/providers/apisix/translation/apisix_pluginconfig.go b/pkg/providers/apisix/translation/apisix_pluginconfig.go
index 1812e8c2..732d0ba7 100644
--- a/pkg/providers/apisix/translation/apisix_pluginconfig.go
+++ b/pkg/providers/apisix/translation/apisix_pluginconfig.go
@@ -82,6 +82,21 @@ func (t *translator) TranslatePluginConfigV2(config *configv2.ApisixPluginConfig
zap.Any("new", plugin.Config),
)
}
+ if plugin.SecretRef != "" {
+ sec, err := t.SecretLister.Secrets(config.Namespace).Get(plugin.SecretRef)
+ if err != nil {
+ log.Errorw("The config secretRef is invalid",
+ zap.Any("plugin", plugin.Name),
+ zap.String("secretRef", plugin.SecretRef))
+ break
+ }
+ log.Debugw("Add new items, then override items with the same plugin key",
+ zap.Any("plugin", plugin.Name),
+ zap.String("secretRef", plugin.SecretRef))
+ for key, value := range sec.Data {
+ plugin.Config[key] = string(value)
+ }
+ }
pluginMap[plugin.Name] = plugin.Config
} else {
pluginMap[plugin.Name] = make(map[string]interface{})
diff --git a/pkg/providers/apisix/translation/apisix_route.go b/pkg/providers/apisix/translation/apisix_route.go
index 2d1d032b..76f01fdd 100644
--- a/pkg/providers/apisix/translation/apisix_route.go
+++ b/pkg/providers/apisix/translation/apisix_route.go
@@ -251,6 +251,21 @@ func (t *translator) translateHTTPRouteV2(ctx *translation.TranslateContext, ar
continue
}
if plugin.Config != nil {
+ if plugin.SecretRef != "" {
+ sec, err := t.SecretLister.Secrets(ar.Namespace).Get(plugin.SecretRef)
+ if err != nil {
+ log.Errorw("The config secretRef is invalid",
+ zap.Any("plugin", plugin.Name),
+ zap.String("secretRef", plugin.SecretRef))
+ break
+ }
+ log.Debugw("Add new items, then override items with the same plugin key",
+ zap.Any("plugin", plugin.Name),
+ zap.String("secretRef", plugin.SecretRef))
+ for key, value := range sec.Data {
+ plugin.Config[key] = string(value)
+ }
+ }
pluginMap[plugin.Name] = plugin.Config
} else {
pluginMap[plugin.Name] = make(map[string]interface{})
@@ -753,6 +768,21 @@ func (t *translator) translateStreamRouteV2(ctx *translation.TranslateContext, a
continue
}
if plugin.Config != nil {
+ if plugin.SecretRef != "" {
+ sec, err := t.SecretLister.Secrets(ar.Namespace).Get(plugin.SecretRef)
+ if err != nil {
+ log.Errorw("The config secretRef is invalid",
+ zap.Any("plugin", plugin.Name),
+ zap.String("secretRef", plugin.SecretRef))
+ break
+ }
+ log.Debugw("Add new items, then override items with the same plugin key",
+ zap.Any("plugin", plugin.Name),
+ zap.String("secretRef", plugin.SecretRef))
+ for key, value := range sec.Data {
+ plugin.Config[key] = string(value)
+ }
+ }
pluginMap[plugin.Name] = plugin.Config
} else {
pluginMap[plugin.Name] = make(map[string]interface{})
diff --git a/samples/deploy/crd/v1/ApisixPluginConfig.yaml b/samples/deploy/crd/v1/ApisixPluginConfig.yaml
index 4a79a61b..c49b27bf 100644
--- a/samples/deploy/crd/v1/ApisixPluginConfig.yaml
+++ b/samples/deploy/crd/v1/ApisixPluginConfig.yaml
@@ -114,6 +114,8 @@ spec:
config:
type: object
x-kubernetes-preserve-unknown-fields: true # we have to enable it since plugin config
+ secretRef:
+ type: string
required:
- name
- enable
diff --git a/samples/deploy/crd/v1/ApisixRoute.yaml b/samples/deploy/crd/v1/ApisixRoute.yaml
index 89dac1de..e241bd5a 100644
--- a/samples/deploy/crd/v1/ApisixRoute.yaml
+++ b/samples/deploy/crd/v1/ApisixRoute.yaml
@@ -504,6 +504,8 @@ spec:
config:
type: object
x-kubernetes-preserve-unknown-fields: true # we have to enable it since plugin config
+ secretRef:
+ type: string
required:
- name
- enable
@@ -592,6 +594,8 @@ spec:
config:
type: object
x-kubernetes-preserve-unknown-fields: true # we have to enable it since plugin config
+ secretRef:
+ type: string
required:
- name
- enable
diff --git a/test/e2e/suite-plugins/suite-plugins-general/secret_ref.go b/test/e2e/suite-plugins/suite-plugins-general/secret_ref.go
new file mode 100644
index 00000000..7fa16bc2
--- /dev/null
+++ b/test/e2e/suite-plugins/suite-plugins-general/secret_ref.go
@@ -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 (
+ "fmt"
+ ginkgo "github.com/onsi/ginkgo/v2"
+ "github.com/stretchr/testify/assert"
+ "net/http"
+
+ "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("suite-plugins-general: config plugin with secretRef", func() {
+ suites := func(scaffoldFunc func() *scaffold.Scaffold) {
+ s := scaffoldFunc()
+ ginkgo.It("suite-plugins-general: echo plugin config with secretRef", func() {
+ backendSvc, backendPorts := s.DefaultHTTPBackend()
+ secret := `
+apiVersion: v1
+kind: Secret
+metadata:
+ name: echo
+data:
+ # content is "This is the replaced preface"
+ before_body: IlRoaXMgaXMgdGhlIHJlcGxhY2VkIHByZWZhY2Ui
+ # content is "my custom body"
+ body: Im15IGN1c3RvbSBib2R5Ig==
+
+`
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(secret), "creating echo secret for ApisixRoute")
+ ar := fmt.Sprintf(`
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+ name: httpbin-route
+spec:
+ http:
+ - name: rule1
+ match:
+ hosts:
+ - httpbin.org
+ paths:
+ - /ip
+ backends:
+ - serviceName: %s
+ servicePort: %d
+ weight: 10
+ plugins:
+ - name: echo
+ enable: true
+ config:
+ before_body: "This is the preface"
+ after_body: "This is the epilogue"
+ headers:
+ X-Foo: v1
+ X-Foo2: v2
+ secretRef: echo
+
+`, backendSvc, backendPorts[0])
+
+ assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar))
+
+ err := s.EnsureNumApisixUpstreamsCreated(1)
+ assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")
+ err = s.EnsureNumApisixRoutesCreated(1)
+ assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes")
+
+ resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+ resp.Status(http.StatusOK)
+ resp.Header("X-Foo").Equal("v1")
+ resp.Header("X-Foo2").Equal("v2")
+ resp.Body().Contains("This is the replaced preface")
+ resp.Body().Contains("This is the epilogue")
+ resp.Body().Contains("my custom body")
+ })
+ }
+ ginkgo.Describe("suite-plugins-general: scaffold v2", func() {
+ suites(scaffold.NewDefaultV2Scaffold)
+ })
+})