forked from alibaba/higress
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: wasm support opa (Open Policy Agent) (alibaba#760)
- Loading branch information
Showing
16 changed files
with
717 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# 功能说明 | ||
|
||
该插件实现了 `OPA` 策略控制 | ||
|
||
# 该教程使用k8s,[k8s配置文件](../../../../test/e2e/conformance/tests/go-wasm-opa.yaml) | ||
|
||
支持client `k8s,nacos,ip,route` 策略去访问 | ||
|
||
## 配置字段 | ||
|
||
| 字段 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
|---------------|--------|------|-----|--------------------------------------| | ||
| policy | string | 必填 | - | opa 策略 | | ||
| timeout | string | 必填 | - | 访问超时时间设置 | | ||
| serviceSource | string | 必填 | - | k8s,nacos,ip,route | | ||
| host | string | 非必填 | - | 服务主机(serviceSource为`ip`必填) | | ||
| serviceName | string | 非必填 | - | 服务名称(serviceSource为`k8s,nacos,ip`必填) | | ||
| servicePort | string | 非必填 | - | 服务端口(serviceSource为`k8s,nacos,ip`必填) | | ||
| namespace | string | 非必填 | - | 服务端口(serviceSource为`k8s,nacos`必填) | | ||
|
||
这是一个用于OPA认证配置的表格,确保在提供所有必要的信息时遵循上述指导。 | ||
|
||
## 配置示例 | ||
|
||
```yaml | ||
serviceSource: k8s | ||
serviceName: opa | ||
servicePort: 8181 | ||
namespace: higress-backend | ||
policy: example1 | ||
timeout: 5s | ||
``` | ||
# 在宿主机上执行OPA的流程 | ||
## 启动opa服务 | ||
```shell | ||
docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s | ||
``` | ||
|
||
## 创建opa策略 | ||
|
||
```shell | ||
curl -X PUT '127.0.0.1:8181/v1/policies/example1' \ | ||
-H 'Content-Type: text/plain' \ | ||
-d 'package example1 | ||
import input.request | ||
default allow = false | ||
allow { | ||
# HTTP method must GET | ||
request.method == "GET" | ||
}' | ||
``` | ||
|
||
## 查询策略 | ||
|
||
```shell | ||
curl -X POST '127.0.0.1:8181/v1/data/example1/allow' \ | ||
-H 'Content-Type: application/json' \ | ||
-d '{"input":{"request":{"method":"GET"}}}' | ||
``` | ||
|
||
# 测试插件 | ||
|
||
## 打包 WASM 插件 | ||
|
||
> 在 `wasm-go` 目录下把Dockerfile文件改成`PLUGIN_NAME=opa`,然后执行以下命令 | ||
```shell | ||
docker build -t build-wasm-opa --build-arg GOPROXY=https://goproxy.cn,direct --platform=linux/amd64 . | ||
``` | ||
|
||
## 拷贝插件 | ||
|
||
> 在当前的目录执行以下命令,将插件拷贝当前的目录 | ||
```shell | ||
docker cp wasm-opa:/plugin.wasm . | ||
``` | ||
|
||
## 运行插件 | ||
|
||
> 运行前修改envoy.yaml 这两个字段 `OPA_SERVER` `OPA_PORT` 替换宿主机上的IP和端口 | ||
```shell | ||
docker compose up | ||
``` | ||
|
||
## 使用curl测试插件 | ||
|
||
```shell | ||
curl http://127.0.0.1:10000/get -X GET -v | ||
``` | ||
|
||
```shell | ||
curl http://127.0.0.1:10000/get -X POST -v | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright (c) 2022 Alibaba Group Holding Ltd. | ||
// | ||
// Licensed 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 main | ||
|
||
import ( | ||
"errors" | ||
"strings" | ||
|
||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" | ||
"github.com/tidwall/gjson" | ||
) | ||
|
||
type OpaConfig struct { | ||
policy string | ||
timeout uint32 | ||
|
||
client wrapper.HttpClient | ||
} | ||
|
||
func Client(json gjson.Result) (wrapper.HttpClient, error) { | ||
serviceSource := strings.TrimSpace(json.Get("serviceSource").String()) | ||
serviceName := strings.TrimSpace(json.Get("serviceName").String()) | ||
servicePort := json.Get("servicePort").Int() | ||
|
||
host := strings.TrimSpace(json.Get("host").String()) | ||
if host == "" { | ||
if serviceName == "" || servicePort == 0 { | ||
return nil, errors.New("invalid service config") | ||
} | ||
} | ||
|
||
var namespace string | ||
if serviceSource == "k8s" || serviceSource == "nacos" { | ||
if namespace = strings.TrimSpace(json.Get("namespace").String()); namespace == "" { | ||
return nil, errors.New("namespace not allow empty") | ||
} | ||
} | ||
|
||
switch serviceSource { | ||
case "k8s": | ||
return wrapper.NewClusterClient(wrapper.K8sCluster{ | ||
ServiceName: serviceName, | ||
Namespace: namespace, | ||
Port: servicePort, | ||
}), nil | ||
case "nacos": | ||
return wrapper.NewClusterClient(wrapper.NacosCluster{ | ||
ServiceName: serviceName, | ||
NamespaceID: namespace, | ||
Port: servicePort, | ||
}), nil | ||
case "ip": | ||
return wrapper.NewClusterClient(wrapper.StaticIpCluster{ | ||
ServiceName: serviceName, | ||
Host: host, | ||
Port: servicePort, | ||
}), nil | ||
case "dns": | ||
return wrapper.NewClusterClient(wrapper.DnsCluster{ | ||
ServiceName: serviceName, | ||
Port: servicePort, | ||
Domain: json.Get("domain").String(), | ||
}), nil | ||
case "route": | ||
return wrapper.NewClusterClient(wrapper.RouteCluster{ | ||
Host: host, | ||
}), nil | ||
} | ||
return nil, errors.New("unknown service source: " + serviceSource) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright (c) 2022 Alibaba Group Holding Ltd. | ||
// | ||
// Licensed 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 main | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/tidwall/gjson" | ||
) | ||
|
||
func TestConfig(t *testing.T) { | ||
json := gjson.Result{Type: gjson.JSON, Raw: `{"serviceSource": "k8s","serviceName": "opa","servicePort": 8181,"namespace": "example1","policy": "example1","timeout": "5s"}`} | ||
config := &OpaConfig{} | ||
assert.NoError(t, parseConfig(json, config, wrapper.Log{})) | ||
assert.Equal(t, config.policy, "example1") | ||
assert.Equal(t, config.timeout, uint32(5000)) | ||
assert.NotNil(t, config.client) | ||
|
||
type tt struct { | ||
raw string | ||
result bool | ||
} | ||
|
||
tests := []tt{ | ||
{raw: `{}`, result: false}, | ||
{raw: `{"policy": "example1","timeout": "5s"}`, result: false}, | ||
{raw: `{"serviceSource": "route","host": "example.com","policy": "example1","timeout": "5s"}`, result: true}, | ||
{raw: `{"serviceSource": "nacos","serviceName": "opa","servicePort": 8181,"policy": "example1","timeout": "5s"}`, result: false}, | ||
{raw: `{"serviceSource": "nacos","serviceName": "opa","servicePort": 8181,"namespace": "example1","policy": "example1","timeout": "5s"}`, result: true}, | ||
} | ||
|
||
for _, test := range tests { | ||
json = gjson.Result{Type: gjson.JSON, Raw: test.raw} | ||
assert.Equal(t, parseConfig(json, config, wrapper.Log{}) == nil, test.result) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
version: '3.7' | ||
services: | ||
envoy: | ||
image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/gateway:1.3.1 | ||
entrypoint: /usr/local/bin/envoy | ||
command: -c /etc/envoy/envoy.yaml --component-log-level wasm:debug | ||
networks: | ||
- wasmtest | ||
ports: | ||
- "10000:10000" | ||
volumes: | ||
- ./envoy.yaml:/etc/envoy/envoy.yaml | ||
- ./plugin.wasm:/etc/envoy/plugin.wasm | ||
|
||
networks: | ||
wasmtest: { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
admin: | ||
address: | ||
socket_address: | ||
protocol: TCP | ||
address: 0.0.0.0 | ||
port_value: 9901 | ||
static_resources: | ||
listeners: | ||
- name: listener_0 | ||
address: | ||
socket_address: | ||
protocol: TCP | ||
address: 0.0.0.0 | ||
port_value: 10000 | ||
filter_chains: | ||
- filters: | ||
- name: envoy.filters.network.http_connection_manager | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager | ||
stat_prefix: ingress_http | ||
route_config: | ||
name: local_route | ||
virtual_hosts: | ||
- name: local_service | ||
domains: [ "*" ] | ||
routes: | ||
- match: | ||
prefix: "/" | ||
route: | ||
cluster: opa-server | ||
http_filters: | ||
- name: wasmdemo | ||
typed_config: | ||
"@type": type.googleapis.com/udpa.type.v1.TypedStruct | ||
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm | ||
value: | ||
config: | ||
name: wasmdemo | ||
vm_config: | ||
runtime: envoy.wasm.runtime.v8 | ||
code: | ||
local: | ||
filename: /etc/envoy/plugin.wasm | ||
configuration: | ||
"@type": "type.googleapis.com/google.protobuf.StringValue" | ||
value: | | ||
{ | ||
"serviceSource": "route", | ||
"host": "OPA_SERVER:OPA_PORT", | ||
"policy": "example1", | ||
"timeout": "5s" | ||
} | ||
- name: envoy.filters.http.router | ||
clusters: | ||
- name: opa-server | ||
connect_timeout: 0.5s | ||
type: STRICT_DNS | ||
lb_policy: ROUND_ROBIN | ||
dns_refresh_rate: 5s | ||
dns_lookup_family: V4_ONLY | ||
load_assignment: | ||
cluster_name: opa-server | ||
endpoints: | ||
- lb_endpoints: | ||
- endpoint: | ||
address: | ||
socket_address: | ||
address: OPA_SERVER # opa server Host IP | ||
port_value: OPA_PORT # opa server Host PORT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module github.com/alibaba/higress/plugins/wasm-go/extensions/opa | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/alibaba/higress/plugins/wasm-go v0.0.0 | ||
github.com/stretchr/testify v1.8.4 | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 | ||
github.com/tidwall/gjson v1.14.4 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/google/uuid v1.5.0 // indirect | ||
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect | ||
github.com/magefile/mage v1.14.0 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/tidwall/match v1.1.1 // indirect | ||
github.com/tidwall/pretty v1.2.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) | ||
|
||
replace github.com/alibaba/higress/plugins/wasm-go => ../.. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= | ||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA= | ||
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew= | ||
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= | ||
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 h1:kS7BvMKN+FiptV4pfwiNX8e3q14evxAWkhYbxt8EI1M= | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0/go.mod h1:qkW5MBz2jch2u8bS59wws65WC+Gtx3x0aPUX5JL7CXI= | ||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= | ||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | ||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= | ||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= | ||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= | ||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Oops, something went wrong.