Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(hepa): fix key-auth for mse and nginx check for kong #5976

Merged
merged 1 commit into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const (
MseDefaultConsumerCredential = "2bda943c-ba2b-11ec-ba07-00163e1250b5"
MseDefaultConsumerKey = "2bda943c-ba2b-11ec-ba07-00163e1250b5"
MseDefaultConsumerSecret = "2bda943c-ba2b-11ec-ba07-00163e1250b5"
MseDefaultKeyAuthConfig = "# 配置必须字段的校验,如下例所示,要求插件配置必须存在 \"consumers\"、\"_rules_\" 字段\nconsumers: \n- key: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n secret: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n name: consumer-erda-default\nkeys:\n - appKey\n - x-app-key\nin_query: true\nin_header: true\n# 使用 _rules_ 字段进行细粒度规则配置\n_rules_:\n# 按路由名称匹配生效\n- _match_route_:\n - route-erda-default\n allow:\n - consumer-erda-default"
MseDefaultKeyAuthConfig = "# 配置必须字段的校验,如下例所示,要求插件配置必须存在 \"consumers\"、\"_rules_\" 字段\nconsumers: \n- key: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n secret: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n name: consumer-erda-default\n credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5\nkeys:\n - appKey\n - x-app-key\nin_query: true\nin_header: true\n# 使用 _rules_ 字段进行细粒度规则配置\n_rules_:\n# 按路由名称匹配生效\n- _match_route_:\n - route-erda-default\n allow:\n - consumer-erda-default"
MseDefaultHmacAuthConfig = "# 配置必须字段的校验,如下例所示,要求插件配置必须存在 \"consumers\"、\"_rules_\" 字段\nconsumers: \n- key: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n secret: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n name: consumer-erda-default\n# 使用 _rules_ 字段进行细粒度规则配置\n_rules_:\n# 按路由名称匹配生效\n- _match_route_:\n - route-erda-default\n allow:\n - consumer-erda-default"
MseDefaultParaSignAuthConfig = "# 配置必须字段的校验,如下例所示,要求插件配置必须存在 \"_rules_\" 字段\n_rules_:\n- _match_route_:\n - route-erda-default\n request_body_size_limit: 10485760\n date_offset: 600\n consumers:\n - name: consumer-erda-default\n key: 2bda943c-ba2b-11ec-ba07-00163e1250b5\n secret: 2bda943c-ba2b-11ec-ba07-00163e1250b5"
MseDefaultErdaIPConfig = "# 配置必须字段的校验,如下例所示,要求插件配置必须存在 \"_rules_\"、\"_match_route_\"、“ip_source”、\"ip_acl_type\" 字段\n_rules_:\n- _match_route_:\n - route-erda-default\n ip_source: \"x-forwarded-for\"\n ip_acl_type: \"black\"\n ip_acl_list:\n - 10.10.10.10\n - 10.12.13.0/24"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (s *upstreamService) Register(ctx context.Context, req *pb.RegisterRequest)
err = erdaErr.NewInvalidParameterError(vars.TODO_PARAM, "invalid request")
return
}
logrus.Infof("Call /api/gateway/register_async with Req: %+v\n", *(req.GetUpstream()))
logrus.Infof("Call /api/gateway/register_async enter Register with Req: %+v\n", *(req.GetUpstream()))
if req.GetUpstream().GetRuntimeId() == "" || req.GetUpstream().GetOnlyRuntimePath() {
return s.register(ctx, req)
}
Expand Down Expand Up @@ -94,6 +94,7 @@ func (s *upstreamService) AsyncRegister(ctx context.Context, req *pb.AsyncRegist
ctx = context1.WithLoggerIfWithout(ctx, logrus.StandardLogger())
l := ctx.(*context1.LogContext).Entry()
l.WithError(nil).Infof("Call /api/gateway/register_async with Req: %+v\n", *(req.GetUpstream()))
logrus.Infof("Call /api/gateway/register_async with Req: %+v\n", *(req.GetUpstream()))

if req.Upstream == nil {
err = erdaErr.NewInvalidParameterError(vars.TODO_PARAM, "invalid request")
Expand Down
30 changes: 20 additions & 10 deletions internal/tools/orchestrator/hepa/services/api_policy/impl/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ const (

var azMutex []*sync.Mutex

// Nginx 配置 llocations 部分,more_set_headers、proxy_set_header、set、limit_req、limit_conn、error_page、deny、allow、return 等允许多次设置
var skipKeys = map[string]bool{
"more_set_headers": true,
"proxy_set_header": true,
"set": true,
"limit_req": true,
"limit_conn": true,
"error_page": true,
"deny": true,
"allow": true,
"return": true,
}

func init() {
for i := 0; i < mutexBucketSize; i++ {
azMutex = append(azMutex, &sync.Mutex{})
Expand Down Expand Up @@ -1385,7 +1398,10 @@ func hasDuplicatedConfig(p1, p2 apipolicy.PolicyConfig) (string, error) {

for k := range p1_Nginx {
if val, ok := p2_Nginx[k]; ok {
return k + fmt.Sprintf("=%s", val), nil
// more_set_headers、proxy_set_header、set、limit_req、limit_conn、error_page、deny、allow、return 等允许多次设置
if !skipKeys[k] {
return k + fmt.Sprintf("=%s", val), nil
}
wangzhuzhen marked this conversation as resolved.
Show resolved Hide resolved
}
}
return "", nil
Expand All @@ -1404,9 +1420,7 @@ func getNginxConfFromPolicyConfig(p apipolicy.PolicyConfig) (map[string]string,
key := strings.ReplaceAll(keys[l-1], "-", "_")
if _, ok := ret[key]; ok {
// more_set_headers、proxy_set_header、set、limit_req、limit_conn、error_page、deny、allow、return 等允许多次设置
if key != "more_set_headers" && key != "proxy_set_header" &&
key != "set" && key != "limit_req" && key != "limit_conn" &&
key != "error_page" && key != "deny" && key != "allow" && key != "return" {
if !skipKeys[key] {
return ret, errors.Errorf("Annotation nginx conf %s duplicated", key)
}
}
Expand All @@ -1432,9 +1446,7 @@ func getNginxConfFromPolicyConfig(p apipolicy.PolicyConfig) (map[string]string,
key := strings.ReplaceAll(k, "-", "_")
if _, ok := ret[key]; ok {
// more_set_headers、proxy_set_header、set、limit_req、limit_conn、error_page、deny、allow、return 等允许多次设置
if key != "more_set_headers" && key != "proxy_set_header" &&
key != "set" && key != "limit_req" && key != "limit_conn" &&
key != "error_page" && key != "deny" && key != "allow" && key != "return" {
if !skipKeys[key] {
return ret, errors.Errorf("ConfigOption nginx conf %s duplicated", key)
}
}
Expand Down Expand Up @@ -1486,9 +1498,7 @@ func extractConfigFromString(kind, src string, ret map[string]string) error {
key := strings.ReplaceAll(kv[0], "-", "_")
if _, ok := ret[key]; ok {
// more_set_headers、proxy_set_header、set、limit_req、limit_conn、error_page、deny、allow、return 等允许多次设置
if key != "more_set_headers" && key != "proxy_set_header" &&
key != "set" && key != "limit_req" && key != "limit_conn" &&
key != "error_page" && key != "deny" && key != "allow" && key != "return" {
if !skipKeys[key] {
return errors.Errorf("%s nginx conf %s duplicated", kind, key)
}
}
Expand Down
83 changes: 58 additions & 25 deletions internal/tools/orchestrator/hepa/services/endpoint_api/impl/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2056,32 +2056,8 @@ func (impl GatewayOpenapiServiceImpl) TouchPackageApiZone(info endpoint_api.Pack
if err != nil {
return "", err
}
svc, err := impl.touchServiceForExternalService(info, *z)
if err != nil {
return "", err
}

// 转发地址为内部地址,相当于此做一个内部 Service 的 Spec 拷贝
if strings.Contains(svc.Spec.ExternalName, K8S_SVC_CLUSTER_DOMAIN) {
svcNameAndNamespace := strings.Split(strings.TrimSuffix(svc.Spec.ExternalName, K8S_SVC_CLUSTER_DOMAIN), ".")
if len(svcNameAndNamespace) <= 1 {
return "", errors.Errorf("get svc name and namespace from inner addr %s failed\n", svc.Spec.ExternalName)
}
svcNamespace := svcNameAndNamespace[1]
svcName := svcNameAndNamespace[0]
innerSvc, err := k8sAdapter.GetServiceByName(svcNamespace, svcName)
if err != nil {
logrus.Errorf("GetServiceByName failed:%v\n", err)
return "", err
}
svc.Spec.ExternalName = ""
svc.Spec.Ports = innerSvc.Spec.Ports
svc.Spec.Type = innerSvc.Spec.Type
svc.Spec.Selector = innerSvc.Spec.Selector
svc.Spec.SessionAffinity = innerSvc.Spec.SessionAffinity
}

externalSvc, err = k8sAdapter.CreateOrUpdateService(svc)
externalSvc, err = impl.createOrUpdateService(k8sAdapter, info, *z)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -2129,6 +2105,22 @@ func (impl GatewayOpenapiServiceImpl) TouchPackageApiZone(info endpoint_api.Pack
}
transSucc = true
return z.Id, nil
} else {
// 对于 MSE 需要更新单独创建的 Service
if !useKong && info.RedirectType == gw.RT_URL {
k8sAdapter, err = k8s.NewAdapter(info.Az)
if err != nil {
return "", err
}
z, err := (*impl.zoneBiz).GetZone(info.ZoneId, session...)
if err != nil {
return "", err
}
externalSvc, err = impl.createOrUpdateService(k8sAdapter, info, *z)
if err != nil {
return "", err
}
}
}

//update zone route
Expand All @@ -2149,6 +2141,47 @@ func (impl GatewayOpenapiServiceImpl) TouchPackageApiZone(info endpoint_api.Pack
return info.ZoneId, nil
}

func (impl GatewayOpenapiServiceImpl) createOrUpdateService(k8sAdapter k8s.K8SAdapter, info endpoint_api.PackageApiInfo, z orm.GatewayZone) (*corev1.Service, error) {
svc, err := impl.touchServiceForExternalService(info, z)
if err != nil {
return nil, err
}

// 转发地址为内部地址,相当于此做一个内部 Service 的 Spec 拷贝
if strings.Contains(svc.Spec.ExternalName, K8S_SVC_CLUSTER_DOMAIN) {
err = copyService(svc, k8sAdapter)
if err != nil {
return nil, err
}
}

externalSvc, err := k8sAdapter.CreateOrUpdateService(svc)
if err != nil {
return nil, err
}
return externalSvc, nil
}

func copyService(svc *corev1.Service, k8sAdapter k8s.K8SAdapter) error {
svcNameAndNamespace := strings.Split(strings.TrimSuffix(svc.Spec.ExternalName, K8S_SVC_CLUSTER_DOMAIN), ".")
if len(svcNameAndNamespace) <= 1 {
return errors.Errorf("get svc name and namespace from inner addr %s failed\n", svc.Spec.ExternalName)
}
svcNamespace := svcNameAndNamespace[1]
svcName := svcNameAndNamespace[0]
innerSvc, err := k8sAdapter.GetServiceByName(svcNamespace, svcName)
if err != nil {
logrus.Errorf("GetServiceByName failed:%v\n", err)
return err
}
svc.Spec.ExternalName = ""
svc.Spec.Ports = innerSvc.Spec.Ports
svc.Spec.Type = innerSvc.Spec.Type
svc.Spec.Selector = innerSvc.Spec.Selector
svc.Spec.SessionAffinity = innerSvc.Spec.SessionAffinity
return nil
}

func (impl GatewayOpenapiServiceImpl) CreatePackageApi(id string, dto *gw.OpenapiDto) (apiId string, exist bool, err error) {
var helper *db.SessionHelper
defer func() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"

mseDto "github.com/erda-project/erda/internal/tools/orchestrator/hepa/gateway-providers/mse/dto"
"github.com/erda-project/erda/internal/tools/orchestrator/hepa/k8s"
"github.com/erda-project/erda/internal/tools/orchestrator/hepa/repository/orm"
"github.com/erda-project/erda/internal/tools/orchestrator/hepa/repository/service"
"github.com/erda-project/erda/internal/tools/orchestrator/hepa/services/api_policy"
Expand Down Expand Up @@ -397,3 +398,74 @@ func TestGatewayOpenapiServiceImpl_mseConsumerConfig(t *testing.T) {
})
}
}

func Test_copyService(t *testing.T) {
type args struct {
svc *corev1.Service
k8sAdapter k8s.K8SAdapter
}

ports := make([]corev1.ServicePort, 0)
ports = append(ports, corev1.ServicePort{
Name: "tcp-0",
Protocol: "TCP",
Port: 80,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
IntVal: 80,
},
NodePort: 0,
})

selectors := make(map[string]string)
selectors["app"] = "bbb"

tests := []struct {
name string
args args
wantErr bool
}{
{
name: "Test_01",
args: args{
svc: &corev1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "dice-test-2-api-d777be56b33944ff8d22db0cf136ce24-bfdc2e",
Namespace: "project-2-test",
ClusterName: "test",
},
Spec: corev1.ServiceSpec{
ExternalName: "demo.project-1.svc.cluster.local",
},
},
k8sAdapter: &k8s.K8SAdapterImpl{},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
monkey.PatchInstanceMethod(reflect.TypeOf(tt.args.k8sAdapter), "GetServiceByName", func(_ *k8s.K8SAdapterImpl, _, _ string) (*corev1.Service, error) {
return &corev1.Service{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: corev1.ServiceSpec{
Ports: ports,
Selector: selectors,
Type: "ClusterIP",
SessionAffinity: "None",
},
}, nil
})

defer monkey.UnpatchAll()
if err := copyService(tt.args.svc, tt.args.k8sAdapter); (err != nil) != tt.wantErr {
t.Errorf("copyService() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}