This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch refactor-with-go
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git
The following commit(s) were added to refs/heads/refactor-with-go by this push:
new 4927fe21 Update authorization rule (#1061)
4927fe21 is described below
commit 4927fe21ca0a35775016b81fa34b4cb9c90f56ff
Author: Albumen Kevin <[email protected]>
AuthorDate: Sun Mar 26 18:18:10 2023 +0800
Update authorization rule (#1061)
* Update authorization rule
* Update mod
---
deploy/crd.yaml | 16 +
deploy/example-peerauthentication.yaml | 2 +-
go.mod | 2 +-
.../apis/dubbo.apache.org/v1beta1/types.go | 13 +
.../v1beta1/zz_generated.deepcopy.go | 10 +
.../v1beta1/authorizationpolicyspec.go | 9 +
.../v1beta1/authorizationpolicytarget.go | 22 +
pkg/authority/k8s/client.go | 3 +
pkg/authority/k8s/controller.go | 57 +-
pkg/authority/rule/authentication/definition.go | 34 +
pkg/authority/rule/authentication/rule.go | 17 +-
pkg/authority/rule/authorization/definition.go | 192 +++++
.../rule/authorization/definition_test.go | 119 +++
pkg/authority/rule/authorization/rule.go | 201 ++++-
pkg/authority/rule/authorization/rule_test.go | 858 ++++++++++++++++++++-
15 files changed, 1510 insertions(+), 45 deletions(-)
diff --git a/deploy/crd.yaml b/deploy/crd.yaml
index ac792c9b..0228f0a8 100644
--- a/deploy/crd.yaml
+++ b/deploy/crd.yaml
@@ -222,6 +222,16 @@ spec:
type: object
description: "The destination of the traffic to be
matched."
properties:
+ namespaces:
+ type: array
+ description: "The namespaces to match of the
source workload."
+ items:
+ type: string
+ notNamespaces:
+ type: array
+ description: "The namespaces not to match of the
source workload."
+ items:
+ type: string
ipBlocks:
type: array
description: "The IP addresses to match of the
destination workload."
@@ -305,6 +315,12 @@ spec:
minimum: 0
default: 100
maximum: 100
+ order:
+ type: number
+ description: "The order of the rule."
+ minimum: -2147483648
+ default: 0
+ maximum: 2147483647
matchType:
type: string
description: "The match type of the rules."
diff --git a/deploy/example-peerauthentication.yaml
b/deploy/example-peerauthentication.yaml
index fb016fbd..73f07105 100644
--- a/deploy/example-peerauthentication.yaml
+++ b/deploy/example-peerauthentication.yaml
@@ -32,7 +32,7 @@ metadata:
name: default
namespace: dubbo-demo-new
spec:
- action: ALLOW
+ action: DENY
rules:
- from:
namespaces: ["dubbo-demo"]
diff --git a/go.mod b/go.mod
index 2f43008a..0c73e66e 100644
--- a/go.mod
+++ b/go.mod
@@ -38,6 +38,7 @@ require (
k8s.io/api v0.26.1
k8s.io/apimachinery v0.26.1
k8s.io/client-go v0.26.1
+ k8s.io/utils v0.0.0-20221107191617-1a15be271d1d
sigs.k8s.io/structured-merge-diff/v4 v4.2.3
)
@@ -133,7 +134,6 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
- k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
diff --git a/pkg/authority/apis/dubbo.apache.org/v1beta1/types.go
b/pkg/authority/apis/dubbo.apache.org/v1beta1/types.go
index 9b1958b7..1dbe9457 100644
--- a/pkg/authority/apis/dubbo.apache.org/v1beta1/types.go
+++ b/pkg/authority/apis/dubbo.apache.org/v1beta1/types.go
@@ -144,6 +144,13 @@ type AuthorizationPolicySpec struct {
// +kubebuilder:validation:Maximum=100
// +kubebuilder:default=100
Samples float32 `json:"samples,omitempty"`
+ // The order of the rule.
+ // +optional
+ // +kubebuilder:validation:Type=number
+ // +kubebuilder:validation:Minimum=-2147483648
+ // +kubebuilder:validation:Maximum=2147483647
+ // +kubebuilder:default=0
+ Order float32 `json:"order,omitempty"`
// The match type of the rules.
// +optional
// +kubebuilder:validation:Type=string
@@ -191,6 +198,12 @@ type AuthorizationPolicySource struct {
}
type AuthorizationPolicyTarget struct {
+ // The namespaces to match of the source workload.
+ // +optional
+ Namespaces []string `json:"namespaces,omitempty"`
+ // The namespaces not to match of the source workload.
+ // +optional
+ NotNamespaces []string `json:"notNamespaces,omitempty"`
// The IP addresses to match of the destination workload.
// +optional
IpBlocks []string `json:"ipBlocks,omitempty"`
diff --git
a/pkg/authority/apis/dubbo.apache.org/v1beta1/zz_generated.deepcopy.go
b/pkg/authority/apis/dubbo.apache.org/v1beta1/zz_generated.deepcopy.go
index 01dcfe56..a5542bf4 100644
--- a/pkg/authority/apis/dubbo.apache.org/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/authority/apis/dubbo.apache.org/v1beta1/zz_generated.deepcopy.go
@@ -419,6 +419,16 @@ func (in *AuthorizationPolicySpec) DeepCopy()
*AuthorizationPolicySpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
func (in *AuthorizationPolicyTarget) DeepCopyInto(out
*AuthorizationPolicyTarget) {
*out = *in
+ if in.Namespaces != nil {
+ in, out := &in.Namespaces, &out.Namespaces
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.NotNamespaces != nil {
+ in, out := &in.NotNamespaces, &out.NotNamespaces
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
if in.IpBlocks != nil {
in, out := &in.IpBlocks, &out.IpBlocks
*out = make([]string, len(*in))
diff --git
a/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicyspec.go
b/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicyspec.go
index 82de34b5..ccb22ab1 100644
---
a/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicyspec.go
+++
b/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicyspec.go
@@ -23,6 +23,7 @@ type AuthorizationPolicySpecApplyConfiguration struct {
Action *string
`json:"action,omitempty"`
Rules []AuthorizationPolicyRuleApplyConfiguration
`json:"rules,omitempty"`
Samples *float32
`json:"samples,omitempty"`
+ Order *float32
`json:"order,omitempty"`
MatchType *string
`json:"matchType,omitempty"`
}
@@ -61,6 +62,14 @@ func (b *AuthorizationPolicySpecApplyConfiguration)
WithSamples(value float32) *
return b
}
+// WithOrder sets the Order field in the declarative configuration to the
given value
+// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
+// If called multiple times, the Order field is set to the value of the last
call.
+func (b *AuthorizationPolicySpecApplyConfiguration) WithOrder(value float32)
*AuthorizationPolicySpecApplyConfiguration {
+ b.Order = &value
+ return b
+}
+
// WithMatchType sets the MatchType field in the declarative configuration to
the given value
// and returns the receiver, so that objects can be built by chaining "With"
function invocations.
// If called multiple times, the MatchType field is set to the value of the
last call.
diff --git
a/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicytarget.go
b/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicytarget.go
index 474c043d..490b77ab 100644
---
a/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicytarget.go
+++
b/pkg/authority/generated/applyconfiguration/dubbo.apache.org/v1beta1/authorizationpolicytarget.go
@@ -20,6 +20,8 @@ package v1beta1
// AuthorizationPolicyTargetApplyConfiguration represents an declarative
configuration of the AuthorizationPolicyTarget type for use
// with apply.
type AuthorizationPolicyTargetApplyConfiguration struct {
+ Namespaces []string
`json:"namespaces,omitempty"`
+ NotNamespaces []string
`json:"notNamespaces,omitempty"`
IpBlocks []string
`json:"ipBlocks,omitempty"`
NotIpBlocks []string
`json:"notIpBlocks,omitempty"`
Principals []string
`json:"principals,omitempty"`
@@ -34,6 +36,26 @@ func AuthorizationPolicyTarget()
*AuthorizationPolicyTargetApplyConfiguration {
return &AuthorizationPolicyTargetApplyConfiguration{}
}
+// WithNamespaces adds the given value to the Namespaces field in the
declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
+// If called multiple times, values provided by each call will be appended to
the Namespaces field.
+func (b *AuthorizationPolicyTargetApplyConfiguration) WithNamespaces(values
...string) *AuthorizationPolicyTargetApplyConfiguration {
+ for i := range values {
+ b.Namespaces = append(b.Namespaces, values[i])
+ }
+ return b
+}
+
+// WithNotNamespaces adds the given value to the NotNamespaces field in the
declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
+// If called multiple times, values provided by each call will be appended to
the NotNamespaces field.
+func (b *AuthorizationPolicyTargetApplyConfiguration) WithNotNamespaces(values
...string) *AuthorizationPolicyTargetApplyConfiguration {
+ for i := range values {
+ b.NotNamespaces = append(b.NotNamespaces, values[i])
+ }
+ return b
+}
+
// WithIpBlocks adds the given value to the IpBlocks field in the declarative
configuration
// and returns the receiver, so that objects can be build by chaining "With"
function invocations.
// If called multiple times, values provided by each call will be appended to
the IpBlocks field.
diff --git a/pkg/authority/k8s/client.go b/pkg/authority/k8s/client.go
index c58a91a1..5621d5bb 100644
--- a/pkg/authority/k8s/client.go
+++ b/pkg/authority/k8s/client.go
@@ -57,6 +57,7 @@ type Client interface {
}
type ClientImpl struct {
+ options *config.Options
kubeClient *kubernetes.Clientset
informerClient *infoemerclient.Clientset
}
@@ -66,6 +67,7 @@ func NewClient() Client {
}
func (c *ClientImpl) Init(options *config.Options) bool {
+ c.options = options
config, err := rest.InClusterConfig()
options.InPodEnv = err == nil
if err != nil {
@@ -369,6 +371,7 @@ func (c *ClientImpl) InitController(
stopCh := make(chan struct{})
controller := NewController(c.informerClient,
+ c.options.Namespace,
authenticationHandler,
authorizationHandler,
informerFactory.Dubbo().V1beta1().AuthenticationPolicies(),
diff --git a/pkg/authority/k8s/controller.go b/pkg/authority/k8s/controller.go
index 3f65863a..ac0302a0 100644
--- a/pkg/authority/k8s/controller.go
+++ b/pkg/authority/k8s/controller.go
@@ -23,6 +23,7 @@ import (
"github.com/apache/dubbo-admin/pkg/authority/rule/authorization"
"github.com/apache/dubbo-admin/pkg/logger"
"k8s.io/client-go/tools/cache"
+ "k8s.io/utils/strings/slices"
)
type NotificationType int
@@ -40,6 +41,8 @@ const (
type Controller struct {
dubboClientSet clientSet.Interface
+ rootNamespace string
+
authenticationSynced cache.InformerSynced
authorizationSynced cache.InformerSynced
@@ -50,13 +53,16 @@ type Controller struct {
// NewController returns a new sample controller
func NewController(
clientSet clientSet.Interface,
+ rootNamespace string,
authenticationHandler authentication.Handler,
authorizationHandler authorization.Handler,
acInformer informerV1beta1.AuthenticationPolicyInformer,
apInformer informerV1beta1.AuthorizationPolicyInformer,
) *Controller {
controller := &Controller{
- dubboClientSet: clientSet,
+ dubboClientSet: clientSet,
+ rootNamespace: rootNamespace,
+
authenticationSynced: acInformer.Informer().HasSynced,
authorizationSynced: apInformer.Informer().HasSynced,
@@ -118,7 +124,7 @@ func (c *Controller) handleEvent(obj interface{}, eventType
NotificationType) {
switch o := obj.(type) {
case *apiV1beta1.AuthenticationPolicy:
- a := CopyToAuthentication(key, o)
+ a := CopyToAuthentication(key, c.rootNamespace, o)
switch eventType {
case AddNotification:
@@ -130,7 +136,7 @@ func (c *Controller) handleEvent(obj interface{}, eventType
NotificationType) {
}
return
case *apiV1beta1.AuthorizationPolicy:
- a := CopyToAuthorization(key, o)
+ a := CopyToAuthorization(key, c.rootNamespace, o)
switch eventType {
case AddNotification:
@@ -146,7 +152,7 @@ func (c *Controller) handleEvent(obj interface{}, eventType
NotificationType) {
}
}
-func CopyToAuthentication(key string, pa *apiV1beta1.AuthenticationPolicy)
*authentication.Policy {
+func CopyToAuthentication(key, rootNamespace string, pa
*apiV1beta1.AuthenticationPolicy) *authentication.Policy {
a := &authentication.Policy{}
a.Name = key
a.Spec = &authentication.PolicySpec{}
@@ -191,10 +197,27 @@ func CopyToAuthentication(key string, pa
*apiV1beta1.AuthenticationPolicy) *auth
a.Spec.PortLevel = append(a.Spec.PortLevel, r)
}
}
+
+ if rootNamespace == pa.Namespace {
+ return a
+ }
+
+ if len(a.Spec.Selector) == 0 {
+ a.Spec.Selector = append(a.Spec.Selector,
&authentication.Selector{
+ Namespaces: []string{pa.Namespace},
+ })
+ } else {
+ for _, selector := range a.Spec.Selector {
+ if !slices.Contains(selector.Namespaces, pa.Namespace) {
+ selector.Namespaces =
append(selector.Namespaces, pa.Namespace)
+ }
+ }
+ }
+
return a
}
-func CopyToAuthorization(key string, pa *apiV1beta1.AuthorizationPolicy)
*authorization.Policy {
+func CopyToAuthorization(key, rootNamespace string, pa
*apiV1beta1.AuthorizationPolicy) *authorization.Policy {
a := &authorization.Policy{}
a.Name = key
a.Spec = &authorization.PolicySpec{}
@@ -211,6 +234,8 @@ func CopyToAuthorization(key string, pa
*apiV1beta1.AuthorizationPolicy) *author
NotPrincipals: rule.From.NotPrincipals,
},
To: &authorization.Target{
+ Namespaces: rule.To.Namespaces,
+ NotNamespaces: rule.To.NotNamespaces,
IpBlocks: rule.To.IpBlocks,
NotIpBlocks: rule.To.NotIpBlocks,
Principals: rule.To.Principals,
@@ -273,6 +298,28 @@ func CopyToAuthorization(key string, pa
*apiV1beta1.AuthorizationPolicy) *author
}
}
a.Spec.Samples = pa.Spec.Samples
+ a.Spec.Order = pa.Spec.Order
a.Spec.MatchType = pa.Spec.MatchType
+
+ if rootNamespace == pa.Namespace {
+ return a
+ }
+
+ if len(a.Spec.Rules) == 0 {
+ a.Spec.Rules = append(a.Spec.Rules, &authorization.PolicyRule{
+ To: &authorization.Target{
+ Namespaces: []string{pa.Namespace},
+ },
+ })
+ } else {
+ for _, rule := range a.Spec.Rules {
+ if rule.To != nil {
+ rule.To = &authorization.Target{}
+ }
+ if !slices.Contains(rule.To.Namespaces, pa.Namespace) {
+ rule.To.Namespaces = append(rule.To.Namespaces,
pa.Namespace)
+ }
+ }
+ }
return a
}
diff --git a/pkg/authority/rule/authentication/definition.go
b/pkg/authority/rule/authentication/definition.go
index e61176a1..0165c709 100644
--- a/pkg/authority/rule/authentication/definition.go
+++ b/pkg/authority/rule/authentication/definition.go
@@ -21,12 +21,39 @@ type Policy struct {
Spec *PolicySpec `json:"spec"`
}
+func (p *Policy) CopyToClient() *PolicyToClient {
+ toClient := &PolicyToClient{
+ Name: p.Name,
+ }
+
+ if p.Spec != nil {
+ toClient.Spec = p.Spec.CopyToClient()
+ }
+
+ return toClient
+}
+
type PolicySpec struct {
Action string `json:"action"`
Selector []*Selector `json:"selector,omitempty"`
PortLevel []*PortLevel `json:"PortLevel,omitempty"`
}
+func (p *PolicySpec) CopyToClient() *PolicySpecToClient {
+ toClient := &PolicySpecToClient{
+ Action: p.Action,
+ }
+
+ if p.PortLevel != nil {
+ toClient.PortLevel = make([]*PortLevelToClient, 0,
len(p.PortLevel))
+ for _, portLevel := range p.PortLevel {
+ toClient.PortLevel = append(toClient.PortLevel,
portLevel.CopyToClient())
+ }
+ }
+
+ return toClient
+}
+
type Selector struct {
Namespaces []string `json:"namespaces,omitempty"`
NotNamespaces []string `json:"notNamespaces,omitempty"`
@@ -43,6 +70,13 @@ type PortLevel struct {
Action string `json:"action,omitempty"`
}
+func (p *PortLevel) CopyToClient() *PortLevelToClient {
+ return &PortLevelToClient{
+ Port: p.Port,
+ Action: p.Action,
+ }
+}
+
type Extend struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
diff --git a/pkg/authority/rule/authentication/rule.go
b/pkg/authority/rule/authentication/rule.go
index fd67672d..fd9fa3d0 100644
--- a/pkg/authority/rule/authentication/rule.go
+++ b/pkg/authority/rule/authentication/rule.go
@@ -61,8 +61,6 @@ func (o *Origin) Revision() int64 {
func (o *Origin) Exact(endpoint *rule.Endpoint) (rule.ToClient, error) {
matchedRule := make([]*PolicyToClient, 0, len(o.data))
- // TODO match endpoint
-
for _, v := range o.data {
if v.Spec == nil {
continue
@@ -81,20 +79,7 @@ func (o *Origin) Exact(endpoint *rule.Endpoint)
(rule.ToClient, error) {
}
}
- toClient := &PolicyToClient{
- Name: v.Name,
- Spec: &PolicySpecToClient{
- Action: v.Spec.Action,
- },
- }
- if v.Spec.PortLevel != nil {
- for _, p := range v.Spec.PortLevel {
- toClient.Spec.PortLevel =
append(toClient.Spec.PortLevel, &PortLevelToClient{
- Port: p.Port,
- Action: p.Action,
- })
- }
- }
+ toClient := v.CopyToClient()
matchedRule = append(matchedRule, toClient)
}
diff --git a/pkg/authority/rule/authorization/definition.go
b/pkg/authority/rule/authorization/definition.go
index c9a756d1..3670ac4b 100644
--- a/pkg/authority/rule/authorization/definition.go
+++ b/pkg/authority/rule/authorization/definition.go
@@ -21,19 +21,64 @@ type Policy struct {
Spec *PolicySpec `json:"spec"`
}
+func (p *Policy) CopyToClient() *PolicyToClient {
+ toClient := &PolicyToClient{
+ Name: p.Name,
+ }
+
+ if p.Spec != nil {
+ toClient.Spec = p.Spec.CopyToClient()
+ }
+
+ return toClient
+}
+
type PolicySpec struct {
Action string `json:"action,omitempty"`
Rules []*PolicyRule `json:"rules,omitempty"`
Samples float32 `json:"samples,omitempty"`
+ Order float32 `json:"order,omitempty"`
MatchType string `json:"matchType,omitempty"`
}
+func (p *PolicySpec) CopyToClient() *PolicySpecToClient {
+ toClient := &PolicySpecToClient{
+ Action: p.Action,
+ Samples: p.Samples,
+ Order: p.Order,
+ MatchType: p.MatchType,
+ }
+
+ if p.Rules != nil {
+ toClient.Rules = make([]*PolicyRuleToClient, 0, len(p.Rules))
+ for _, rule := range p.Rules {
+ toClient.Rules = append(toClient.Rules,
rule.CopyToClient())
+ }
+ }
+
+ return toClient
+}
+
type PolicyRule struct {
From *Source `json:"from,omitempty"`
To *Target `json:"to,omitempty"`
When *Condition `json:"when,omitempty"`
}
+func (p *PolicyRule) CopyToClient() *PolicyRuleToClient {
+ toClient := &PolicyRuleToClient{}
+
+ if p.From != nil {
+ toClient.From = p.From.CopyToClient()
+ }
+
+ if p.When != nil {
+ toClient.When = p.When.CopyToClient()
+ }
+
+ return toClient
+}
+
type Source struct {
Namespaces []string `json:"namespaces,omitempty"`
NotNamespaces []string `json:"notNamespaces,omitempty"`
@@ -45,7 +90,59 @@ type Source struct {
NotExtends []*Extend `json:"sourceNotExtends,omitempty"`
}
+func (s *Source) CopyToClient() *SourceToClient {
+ toClient := &SourceToClient{}
+
+ if s.Namespaces != nil {
+ toClient.Namespaces = make([]string, len(s.Namespaces))
+ copy(toClient.Namespaces, s.Namespaces)
+ }
+
+ if s.NotNamespaces != nil {
+ toClient.NotNamespaces = make([]string, len(s.NotNamespaces))
+ copy(toClient.NotNamespaces, s.NotNamespaces)
+ }
+
+ if s.IpBlocks != nil {
+ toClient.IpBlocks = make([]string, len(s.IpBlocks))
+ copy(toClient.IpBlocks, s.IpBlocks)
+ }
+
+ if s.NotIpBlocks != nil {
+ toClient.NotIpBlocks = make([]string, len(s.NotIpBlocks))
+ copy(toClient.NotIpBlocks, s.NotIpBlocks)
+ }
+
+ if s.Principals != nil {
+ toClient.Principals = make([]string, len(s.Principals))
+ copy(toClient.Principals, s.Principals)
+ }
+
+ if s.NotPrincipals != nil {
+ toClient.NotPrincipals = make([]string, len(s.NotPrincipals))
+ copy(toClient.NotPrincipals, s.NotPrincipals)
+ }
+
+ if s.Extends != nil {
+ toClient.Extends = make([]*ExtendToClient, len(s.Extends))
+ for i, v := range s.Extends {
+ toClient.Extends[i] = v.CopyToClient()
+ }
+ }
+
+ if s.NotExtends != nil {
+ toClient.NotExtends = make([]*ExtendToClient, len(s.NotExtends))
+ for i, v := range s.NotExtends {
+ toClient.NotExtends[i] = v.CopyToClient()
+ }
+ }
+
+ return toClient
+}
+
type Target struct {
+ Namespaces []string `json:"namespaces,omitempty"`
+ NotNamespaces []string `json:"notNamespaces,omitempty"`
IpBlocks []string `json:"ipBlocks,omitempty"`
NotIpBlocks []string `json:"notIpBlocks,omitempty"`
Principals []string `json:"principals,omitempty"`
@@ -60,12 +157,107 @@ type Condition struct {
NotValues []*Match `json:"notValues,omitempty"`
}
+func (c *Condition) CopyToClient() *ConditionToClient {
+ toClient := &ConditionToClient{
+ Key: c.Key,
+ }
+
+ if c.Values != nil {
+ toClient.Values = make([]*MatchToClient, len(c.Values))
+ for i, v := range c.Values {
+ toClient.Values[i] = v.CopyToClient()
+ }
+ }
+
+ if c.NotValues != nil {
+ toClient.NotValues = make([]*MatchToClient, len(c.NotValues))
+ for i, v := range c.NotValues {
+ toClient.NotValues[i] = v.CopyToClient()
+ }
+ }
+
+ return toClient
+}
+
type Match struct {
Type string `json:"type,omitempty"`
Value string `json:"value,omitempty"`
}
+func (m *Match) CopyToClient() *MatchToClient {
+ return &MatchToClient{
+ Type: m.Type,
+ Value: m.Value,
+ }
+}
+
type Extend struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}
+
+func (e *Extend) CopyToClient() *ExtendToClient {
+ return &ExtendToClient{
+ Key: e.Key,
+ Value: e.Value,
+ }
+}
+
+// To Client Rule
+
+type PolicyToClient struct {
+ Name string `json:"name,omitempty"`
+
+ Spec *PolicySpecToClient `json:"spec"`
+}
+
+type PolicySpecToClient struct {
+ Action string `json:"action,omitempty"`
+ Rules []*PolicyRuleToClient `json:"rules,omitempty"`
+ Samples float32 `json:"samples,omitempty"`
+ Order float32 `json:"order,omitempty"`
+ MatchType string `json:"matchType,omitempty"`
+}
+
+type PolicyRuleToClient struct {
+ From *SourceToClient `json:"from,omitempty"`
+ When *ConditionToClient `json:"when,omitempty"`
+}
+
+type SourceToClient struct {
+ Namespaces []string `json:"namespaces,omitempty"`
+ NotNamespaces []string `json:"notNamespaces,omitempty"`
+ IpBlocks []string `json:"ipBlocks,omitempty"`
+ NotIpBlocks []string `json:"notIpBlocks,omitempty"`
+ Principals []string `json:"principals,omitempty"`
+ NotPrincipals []string `json:"notPrincipals,omitempty"`
+ Extends []*ExtendToClient `json:"sourceExtends,omitempty"`
+ NotExtends []*ExtendToClient `json:"sourceNotExtends,omitempty"`
+}
+
+type TargetToClient struct {
+ Namespaces []string `json:"namespaces,omitempty"`
+ NotNamespaces []string `json:"notNamespaces,omitempty"`
+ IpBlocks []string `json:"ipBlocks,omitempty"`
+ NotIpBlocks []string `json:"notIpBlocks,omitempty"`
+ Principals []string `json:"principals,omitempty"`
+ NotPrincipals []string `json:"notPrincipals,omitempty"`
+ Extends []*ExtendToClient `json:"targetExtends,omitempty"`
+ NotExtends []*ExtendToClient `json:"targetNotExtends,omitempty"`
+}
+
+type ConditionToClient struct {
+ Key string `json:"key,omitempty"`
+ Values []*MatchToClient `json:"values,omitempty"`
+ NotValues []*MatchToClient `json:"notValues,omitempty"`
+}
+
+type MatchToClient struct {
+ Type string `json:"type,omitempty"`
+ Value string `json:"value,omitempty"`
+}
+
+type ExtendToClient struct {
+ Key string `json:"key,omitempty"`
+ Value string `json:"value,omitempty"`
+}
diff --git a/pkg/authority/rule/authorization/definition_test.go
b/pkg/authority/rule/authorization/definition_test.go
new file mode 100644
index 00000000..01396821
--- /dev/null
+++ b/pkg/authority/rule/authorization/definition_test.go
@@ -0,0 +1,119 @@
+// 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 authorization
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCopy(t *testing.T) {
+ policy := &Policy{
+ Name: "test-policy",
+ Spec: &PolicySpec{
+ Action: "test-action",
+ Rules: []*PolicyRule{
+ {
+ From: &Source{
+ Namespaces:
[]string{"test-namespace"},
+ NotNamespaces:
[]string{"test-not-namespace"},
+ IpBlocks:
[]string{"test-ip-block"},
+ NotIpBlocks:
[]string{"test-not-ip-block"},
+ Principals:
[]string{"test-principal"},
+ NotPrincipals:
[]string{"test-not-principal"},
+ Extends: []*Extend{
+ {
+ Key:
"test-key",
+ Value:
"test-value",
+ },
+ },
+ NotExtends: []*Extend{
+ {
+ Key:
"test-not-key",
+ Value:
"test-not-value",
+ },
+ },
+ },
+ To: &Target{
+ Namespaces:
[]string{"test-namespace"},
+ NotNamespaces:
[]string{"test-not-namespace"},
+ IpBlocks:
[]string{"test-ip-block"},
+ NotIpBlocks:
[]string{"test-not-ip-block"},
+ Principals:
[]string{"test-principal"},
+ NotPrincipals:
[]string{"test-not-principal"},
+ Extends: []*Extend{
+ {
+ Key:
"test-key",
+ Value:
"test-value",
+ },
+ },
+ NotExtends: []*Extend{
+ {
+ Key:
"test-not-key",
+ Value:
"test-not-value",
+ },
+ },
+ },
+ When: &Condition{
+ Key: "test-key",
+ Values: []*Match{
+ {
+ Type:
"test-type",
+ Value:
"test-value",
+ },
+ },
+ NotValues: []*Match{
+ {
+ Type:
"test-not-type",
+ Value:
"test-not-value",
+ },
+ },
+ },
+ },
+ },
+ Samples: 0.5,
+ Order: 0.5,
+ MatchType: "test-match-type",
+ },
+ }
+
+ toClient := policy.CopyToClient()
+
+ assert.Equal(t, policy.Name, toClient.Name)
+
+ assert.Equal(t, policy.Spec.Action, toClient.Spec.Action)
+ assert.Equal(t, policy.Spec.Samples, toClient.Spec.Samples)
+ assert.Equal(t, policy.Spec.Order, toClient.Spec.Order)
+ assert.Equal(t, policy.Spec.MatchType, toClient.Spec.MatchType)
+
+ assert.Equal(t, policy.Spec.Rules[0].From.Namespaces,
toClient.Spec.Rules[0].From.Namespaces)
+ assert.Equal(t, policy.Spec.Rules[0].From.NotNamespaces,
toClient.Spec.Rules[0].From.NotNamespaces)
+ assert.Equal(t, policy.Spec.Rules[0].From.IpBlocks,
toClient.Spec.Rules[0].From.IpBlocks)
+ assert.Equal(t, policy.Spec.Rules[0].From.NotIpBlocks,
toClient.Spec.Rules[0].From.NotIpBlocks)
+ assert.Equal(t, policy.Spec.Rules[0].From.Principals,
toClient.Spec.Rules[0].From.Principals)
+ assert.Equal(t, policy.Spec.Rules[0].From.NotPrincipals,
toClient.Spec.Rules[0].From.NotPrincipals)
+ assert.Equal(t, policy.Spec.Rules[0].From.Extends[0].Key,
toClient.Spec.Rules[0].From.Extends[0].Key)
+ assert.Equal(t, policy.Spec.Rules[0].From.Extends[0].Value,
toClient.Spec.Rules[0].From.Extends[0].Value)
+ assert.Equal(t, policy.Spec.Rules[0].From.NotExtends[0].Key,
toClient.Spec.Rules[0].From.NotExtends[0].Key)
+ assert.Equal(t, policy.Spec.Rules[0].From.NotExtends[0].Value,
toClient.Spec.Rules[0].From.NotExtends[0].Value)
+
+ assert.Equal(t, policy.Spec.Rules[0].When.Key,
toClient.Spec.Rules[0].When.Key)
+ assert.Equal(t, policy.Spec.Rules[0].When.Values[0].Type,
toClient.Spec.Rules[0].When.Values[0].Type)
+ assert.Equal(t, policy.Spec.Rules[0].When.Values[0].Value,
toClient.Spec.Rules[0].When.Values[0].Value)
+ assert.Equal(t, policy.Spec.Rules[0].When.NotValues[0].Type,
toClient.Spec.Rules[0].When.NotValues[0].Type)
+ assert.Equal(t, policy.Spec.Rules[0].When.NotValues[0].Value,
toClient.Spec.Rules[0].When.NotValues[0].Value)
+}
diff --git a/pkg/authority/rule/authorization/rule.go
b/pkg/authority/rule/authorization/rule.go
index 92091ea6..ecb7d99c 100644
--- a/pkg/authority/rule/authorization/rule.go
+++ b/pkg/authority/rule/authorization/rule.go
@@ -17,6 +17,11 @@ package authorization
import (
"encoding/json"
+ "net/netip"
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/tidwall/gjson"
"github.com/apache/dubbo-admin/pkg/authority/rule"
)
@@ -53,20 +58,206 @@ func (o *Origin) Revision() int64 {
return o.revision
}
-func (o *Origin) Exact(endpoint *rule.Endpoint) (rule.ToClient, error) {
//nolint:ireturn
- matchedRule := make([]*Policy, 0, len(o.data))
+func (o *Origin) Exact(endpoint *rule.Endpoint) (rule.ToClient, error) {
+ matchedRule := make([]*PolicyToClient, 0, len(o.data))
for _, v := range o.data {
- matchedRule = append(matchedRule, v)
+ if v.Spec == nil {
+ continue
+ }
+
+ if v.Spec.Rules != nil {
+ match := true
+ for _, policyRule := range v.Spec.Rules {
+ if !matchSelector(policyRule.To, endpoint) {
+ match = false
+ break
+ }
+ }
+ if !match {
+ continue
+ }
+ }
+
+ toClient := v.CopyToClient()
+ matchedRule = append(matchedRule, toClient)
}
- allRules, err := json.Marshal(matchedRule)
+ allRule, err := json.Marshal(matchedRule)
if err != nil {
return nil, err
}
return &ToClient{
revision: o.revision,
- data: string(allRules),
+ data: string(allRule),
}, nil
}
+
+func matchSelector(target *Target, endpoint *rule.Endpoint) bool {
+ if endpoint == nil {
+ return true
+ }
+
+ if !matchNamespace(target, endpoint) {
+ return false
+ }
+
+ if !matchNotNamespace(target, endpoint) {
+ return false
+ }
+
+ if !matchIPBlocks(target, endpoint) {
+ return false
+ }
+
+ if !matchNotIPBlocks(target, endpoint) {
+ return false
+ }
+
+ if !matchPrincipals(target, endpoint) {
+ return false
+ }
+
+ if !matchNotPrincipals(target, endpoint) {
+ return false
+ }
+
+ endpointJSON, err := json.Marshal(endpoint)
+ if err != nil {
+ logger.Sugar().Warnf("marshal endpoint failed, %v", err)
+ return false
+ }
+
+ if !matchExtends(target, endpointJSON) {
+ return false
+ }
+
+ return matchNotExtends(target, endpointJSON)
+}
+
+func matchNotExtends(target *Target, endpointJSON []byte) bool {
+ if len(target.NotExtends) == 0 {
+ return true
+ }
+ for _, extend := range target.NotExtends {
+ if gjson.Get(string(endpointJSON), extend.Key).String() ==
extend.Value {
+ return false
+ }
+ }
+ return true
+}
+
+func matchExtends(target *Target, endpointJSON []byte) bool {
+ if len(target.Extends) == 0 {
+ return true
+ }
+ for _, extend := range target.Extends {
+ if gjson.Get(string(endpointJSON), extend.Key).String() ==
extend.Value {
+ return true
+ }
+ }
+ return false
+}
+
+func matchNotPrincipals(target *Target, endpoint *rule.Endpoint) bool {
+ if len(target.NotPrincipals) == 0 {
+ return true
+ }
+ for _, principal := range target.NotPrincipals {
+ if principal == endpoint.SpiffeID {
+ return false
+ }
+ if strings.ReplaceAll(endpoint.SpiffeID, "spiffe://", "") ==
principal {
+ return false
+ }
+ }
+ return true
+}
+
+func matchPrincipals(target *Target, endpoint *rule.Endpoint) bool {
+ if len(target.Principals) == 0 {
+ return true
+ }
+ for _, principal := range target.Principals {
+ if principal == endpoint.SpiffeID {
+ return true
+ }
+ if strings.ReplaceAll(endpoint.SpiffeID, "spiffe://", "") ==
principal {
+ return true
+ }
+ }
+ return false
+}
+
+func matchNotIPBlocks(target *Target, endpoint *rule.Endpoint) bool {
+ if len(target.NotIpBlocks) == 0 {
+ return true
+ }
+ for _, ipBlock := range target.NotIpBlocks {
+ prefix, err := netip.ParsePrefix(ipBlock)
+ if err != nil {
+ logger.Sugar().Warnf("parse ip block %s failed, %v",
ipBlock, err)
+ continue
+ }
+ for _, ip := range endpoint.Ips {
+ addr, err := netip.ParseAddr(ip)
+ if err != nil {
+ logger.Sugar().Warnf("parse ip %s failed, %v",
ip, err)
+ continue
+ }
+ if prefix.Contains(addr) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func matchIPBlocks(target *Target, endpoint *rule.Endpoint) bool {
+ if len(target.IpBlocks) == 0 {
+ return true
+ }
+ for _, ipBlock := range target.IpBlocks {
+ prefix, err := netip.ParsePrefix(ipBlock)
+ if err != nil {
+ logger.Sugar().Warnf("parse ip block %s failed, %v",
ipBlock, err)
+ continue
+ }
+ for _, ip := range endpoint.Ips {
+ addr, err := netip.ParseAddr(ip)
+ if err != nil {
+ logger.Sugar().Warnf("parse ip %s failed, %v",
ip, err)
+ continue
+ }
+ if prefix.Contains(addr) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func matchNotNamespace(target *Target, endpoint *rule.Endpoint) bool {
+ if len(target.NotNamespaces) == 0 {
+ return true
+ }
+ for _, namespace := range target.NotNamespaces {
+ if endpoint.KubernetesEnv != nil && namespace ==
endpoint.KubernetesEnv.Namespace {
+ return false
+ }
+ }
+ return true
+}
+
+func matchNamespace(target *Target, endpoint *rule.Endpoint) bool {
+ if len(target.Namespaces) == 0 {
+ return true
+ }
+ for _, namespace := range target.Namespaces {
+ if endpoint.KubernetesEnv != nil && namespace ==
endpoint.KubernetesEnv.Namespace {
+ return true
+ }
+ }
+ return false
+}
diff --git a/pkg/authority/rule/authorization/rule_test.go
b/pkg/authority/rule/authorization/rule_test.go
index c336b464..17af761d 100644
--- a/pkg/authority/rule/authorization/rule_test.go
+++ b/pkg/authority/rule/authorization/rule_test.go
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package authorization_test
+package authorization
import (
"encoding/json"
@@ -22,7 +22,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/apache/dubbo-admin/pkg/authority/rule"
- "github.com/apache/dubbo-admin/pkg/authority/rule/authorization"
"github.com/apache/dubbo-admin/pkg/authority/rule/connection"
)
@@ -30,17 +29,17 @@ func TestRule(t *testing.T) {
t.Parallel()
storage := connection.NewStorage()
- handler := authorization.NewHandler(storage)
+ handler := NewHandler(storage)
- handler.Add("test", &authorization.Policy{})
+ handler.Add("test", &Policy{})
- originRule := storage.LatestRules[authorization.RuleType]
+ originRule := storage.LatestRules[RuleType]
if originRule == nil {
t.Error("expected origin rule to be added")
}
- if originRule.Type() != authorization.RuleType {
+ if originRule.Type() != RuleType {
t.Error("expected origin rule type to be authorization/v1beta1")
}
@@ -56,7 +55,7 @@ func TestRule(t *testing.T) {
t.Error(err)
}
- if toClient.Type() != authorization.RuleType {
+ if toClient.Type() != RuleType {
t.Error("expected toClient type to be authorization/v1beta1")
}
@@ -64,26 +63,26 @@ func TestRule(t *testing.T) {
t.Error("expected toClient revision to be 1")
}
- if toClient.Data() != `[{"spec":null}]` {
- t.Error("expected toClient data to be [{\"spec\":null}], got "
+ toClient.Data())
+ if toClient.Data() != `[]` {
+ t.Error("expected toClient data to be [], got " +
toClient.Data())
}
- policy := &authorization.Policy{
+ policy := &Policy{
Name: "test2",
- Spec: &authorization.PolicySpec{
+ Spec: &PolicySpec{
Action: "ALLOW",
},
}
handler.Add("test2", policy)
- originRule = storage.LatestRules[authorization.RuleType]
+ originRule = storage.LatestRules[RuleType]
if originRule == nil {
t.Error("expected origin rule to be added")
}
- if originRule.Type() != authorization.RuleType {
+ if originRule.Type() != RuleType {
t.Error("expected origin rule type to be authorization/v1beta1")
}
@@ -100,7 +99,7 @@ func TestRule(t *testing.T) {
t.Error(err)
}
- if toClient.Type() != authorization.RuleType {
+ if toClient.Type() != RuleType {
t.Error("expected toClient type to be authorization/v1beta1")
}
@@ -108,12 +107,837 @@ func TestRule(t *testing.T) {
t.Error("expected toClient revision to be 2")
}
- target := []*authorization.Policy{}
+ target := []*Policy{}
err = json.Unmarshal([]byte(toClient.Data()), &target)
assert.Nil(t, err)
- assert.Equal(t, 2, len(target))
+ assert.Equal(t, 1, len(target))
- assert.Contains(t, target, &authorization.Policy{})
assert.Contains(t, target, policy)
}
+
+func TestRule_Empty(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {},
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ generated, err := origin.Exact(nil)
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+}
+
+func TestRule_Namespace(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ Namespaces:
[]string{"test"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ Namespace: "test",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ Namespace: "test-new",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+}
+
+func TestRule_NotNamespace(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ NotNamespaces:
[]string{"test"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ Namespace: "test-new",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ Namespace: "test",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+}
+
+func TestRule_IPBlocks(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ IpBlocks:
[]string{"127.0.0.1/24"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.0.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.1.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ Ips: []string{"127"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+}
+
+func TestRule_IPBlocks_ErrFmt(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ IpBlocks:
[]string{"127"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // failed
+ generated, err := origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.0.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.1.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+}
+
+func TestRule_NotIPBlocks(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ NotIpBlocks:
[]string{"127.0.0.1/24"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.1.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{
+ Ips: []string{"127"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.0.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+}
+
+func TestRule_NotIPBlocks_ErrFmt(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ NotIpBlocks:
[]string{"127"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.0.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{
+ Ips: []string{"127.0.1.1"},
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+}
+
+func TestRule_Principals(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ Principals:
[]string{"cluster.local/ns/default/sa/default"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ SpiffeID: "cluster.local/ns/default/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{
+ SpiffeID: "spiffe://cluster.local/ns/default/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ SpiffeID: "cluster.local/ns/test/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+}
+
+func TestRule_NotPrincipals(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ NotPrincipals:
[]string{"cluster.local/ns/default/sa/default"},
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ SpiffeID: "cluster.local/ns/test/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{
+ SpiffeID: "spiffe://cluster.local/ns/test/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ SpiffeID: "cluster.local/ns/default/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ SpiffeID: "spiffe://cluster.local/ns/default/sa/default",
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+}
+
+func TestRule_Extends(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ Extends:
[]*Extend{
+ {
+
Key: "kubernetesEnv.podName",
+
Value: "test",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ PodName: "test",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ PodName: "test-new",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+}
+
+func TestRule_NotExtends(t *testing.T) {
+ t.Parallel()
+
+ origin := &Origin{
+ revision: 1,
+ data: map[string]*Policy{
+ "test": {
+ Spec: &PolicySpec{
+ Action: "ALLOW",
+ Rules: []*PolicyRule{
+ {
+ To: &Target{
+ NotExtends:
[]*Extend{
+ {
+
Key: "kubernetesEnv.podName",
+
Value: "test",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "demo": {},
+ },
+ }
+
+ // success
+ generated, err := origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ PodName: "test-new",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ var decoded []*PolicyToClient
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+
+ // failed
+ generated, err = origin.Exact(&rule.Endpoint{
+ KubernetesEnv: &rule.KubernetesEnv{
+ PodName: "test",
+ },
+ })
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 0, len(decoded))
+
+ // success
+ generated, err = origin.Exact(&rule.Endpoint{})
+ assert.Nil(t, err)
+
+ assert.NotNil(t, generated)
+ assert.Equal(t, generated.Type(), RuleType)
+ assert.Equal(t, generated.Revision(), int64(1))
+
+ err = json.Unmarshal([]byte(generated.Data()), &decoded)
+ assert.Nil(t, err)
+
+ assert.Equal(t, 1, len(decoded))
+ assert.Equal(t, "ALLOW", decoded[0].Spec.Action)
+}