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 <[email protected]>
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)
+ })
+})