Skip to content

Commit

Permalink
api: ACL API design
Browse files Browse the repository at this point in the history
Signed-off-by: Jesse Haka <haka.jesse@gmail.com>
  • Loading branch information
zetaab committed Feb 19, 2024
1 parent a5125bf commit 6416777
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 5 deletions.
24 changes: 24 additions & 0 deletions api/v1alpha1/acl_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package v1alpha1

// +kubebuilder:validation:XValidation:rule="(has(self.allow) || has(self.deny))",message="one of allow or deny must be specified"
//
// ACL defines the IP deny/allow configuration.
type ACL struct {
// Allow specifies the list of IPBlocks that are allowed to access the service.
// Other cidrs are denied.
Allow []IPBlock `json:"allow,omitempty"`
// Deny specifies the list of IPBlocks that are denied to access the service.
Deny []IPBlock `json:"deny,omitempty"`
}

// IPBlock defines policy on a particular IPBlock.
type IPBlock struct {
// cidr is a string representing the IPBlock
// Valid examples are "192.168.1.0/24" or "2001:db8::/64"
CIDR string `json:"cidr,omitempty"`
}
5 changes: 5 additions & 0 deletions api/v1alpha1/securitypolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ type SecurityPolicySpec struct {
//
// +optional
ExtAuth *ExtAuth `json:"extAuth,omitempty"`

// ACL defines the IP deny/allow configuration.
//
// +optional
ACL *ACL `json:"acl,omitempty"`
}

// SecurityPolicyStatus defines the state of SecurityPolicy
Expand Down
30 changes: 28 additions & 2 deletions api/v1alpha1/validation/securitypolicy_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package validation
import (
"errors"
"fmt"
"net"
"net/mail"
"net/url"

Expand All @@ -24,7 +25,7 @@ func ValidateSecurityPolicy(policy *egv1a1.SecurityPolicy) error {
return errors.New("policy is nil")
}
if err := validateSecurityPolicySpec(&policy.Spec); err != nil {
errs = append(errs, errors.New("policy is nil"))
errs = append(errs, err)
}

return utilerrors.NewAggregate(errs)
Expand All @@ -42,6 +43,8 @@ func validateSecurityPolicySpec(spec *egv1a1.SecurityPolicySpec) error {
sum++
case spec.JWT != nil:
sum++
case spec.ACL != nil:
sum++
}
if sum == 0 {
errs = append(errs, errors.New("no security policy is specified"))
Expand All @@ -52,13 +55,36 @@ func validateSecurityPolicySpec(spec *egv1a1.SecurityPolicySpec) error {
return utilerrors.NewAggregate(errs)
}

if err := ValidateJWTProvider(spec.JWT.Providers); err != nil {
if spec.JWT != nil {
if err := ValidateJWTProvider(spec.JWT.Providers); err != nil {
errs = append(errs, err)
}
}

if err := ValidateACL(spec.ACL); err != nil {
errs = append(errs, err)
}

return utilerrors.NewAggregate(errs)
}

// ValidateACL validates the provided ACL configuration.
func ValidateACL(acl *egv1a1.ACL) error {
var errs []error
if acl == nil {
return nil
}

for _, ipBlock := range append(acl.Allow, acl.Deny...) {
_, _, err := net.ParseCIDR(ipBlock.CIDR)
if err != nil {
errs = append(errs, fmt.Errorf("invalid CIDR: %s", ipBlock.CIDR))
}
}

return utilerrors.NewAggregate(errs)
}

// ValidateJWTProvider validates the provided JWT authentication configuration.
func ValidateJWTProvider(providers []egv1a1.JWTProvider) error {
var errs []error
Expand Down
82 changes: 79 additions & 3 deletions api/v1alpha1/validation/securitypolicy_validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package validation
import (
"testing"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
Expand Down Expand Up @@ -463,16 +463,92 @@ func TestValidateSecurityPolicy(t *testing.T) {
},
expected: true,
},
{
name: "acl with valid ipv4 cidr",
policy: &egv1a1.SecurityPolicy{
TypeMeta: metav1.TypeMeta{
Kind: egv1a1.KindSecurityPolicy,
APIVersion: egv1a1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egv1a1.SecurityPolicySpec{
ACL: &egv1a1.ACL{
Allow: []egv1a1.IPBlock{{CIDR: "192.168.1.0/24"}},
},
},
},
expected: true,
},
{
name: "acl with valid ipv6 cidr",
policy: &egv1a1.SecurityPolicy{
TypeMeta: metav1.TypeMeta{
Kind: egv1a1.KindSecurityPolicy,
APIVersion: egv1a1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egv1a1.SecurityPolicySpec{
ACL: &egv1a1.ACL{
Allow: []egv1a1.IPBlock{{CIDR: "2001:db8::/64"}},
},
},
},
expected: true,
},
{
name: "acl with invalid ipv4 cidr",
policy: &egv1a1.SecurityPolicy{
TypeMeta: metav1.TypeMeta{
Kind: egv1a1.KindSecurityPolicy,
APIVersion: egv1a1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egv1a1.SecurityPolicySpec{
ACL: &egv1a1.ACL{
Allow: []egv1a1.IPBlock{{CIDR: "inva2.4.1.3/foo"}},
},
},
},
expected: false,
},
{
name: "acl with invalid ipv6 cidr",
policy: &egv1a1.SecurityPolicy{
TypeMeta: metav1.TypeMeta{
Kind: egv1a1.KindSecurityPolicy,
APIVersion: egv1a1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "test",
Name: "test",
},
Spec: egv1a1.SecurityPolicySpec{
ACL: &egv1a1.ACL{
Allow: []egv1a1.IPBlock{{CIDR: "20.db8::/64"}},
},
},
},
expected: false,
},
}

for i := range testCases {
tc := testCases[i]
t.Run(tc.name, func(t *testing.T) {
err := ValidateSecurityPolicy(tc.policy)
if tc.expected {
require.NoError(t, err)
assert.NoError(t, err)
} else {
require.Error(t, err)
assert.Error(t, err)
}
})
}
Expand Down
45 changes: 45 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,37 @@ spec:
spec:
description: Spec defines the desired state of SecurityPolicy.
properties:
acl:
description: ACL defines the IP deny/allow configuration.
properties:
allow:
description: Allow specifies the list of IPBlocks that are allowed
to access the service. Other cidrs are denied.
items:
description: IPBlock defines policy on a particular IPBlock.
properties:
cidr:
description: cidr is a string representing the IPBlock Valid
examples are "192.168.1.0/24" or "2001:db8::/64"
type: string
type: object
type: array
deny:
description: Deny specifies the list of IPBlocks that are denied
to access the service.
items:
description: IPBlock defines policy on a particular IPBlock.
properties:
cidr:
description: cidr is a string representing the IPBlock Valid
examples are "192.168.1.0/24" or "2001:db8::/64"
type: string
type: object
type: array
type: object
x-kubernetes-validations:
- message: one of allow or deny must be specified
rule: (has(self.allow) || has(self.deny))
basicAuth:
description: BasicAuth defines the configuration for the HTTP Basic
Authentication.
Expand Down
30 changes: 30 additions & 0 deletions site/content/en/latest/api/extension_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ API group.



#### ACL



ACL defines the IP deny/allow configuration.

_Appears in:_
- [SecurityPolicySpec](#securitypolicyspec)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `allow` | _[IPBlock](#ipblock) array_ | true | Allow specifies the list of IPBlocks that are allowed to access the service. Other cidrs are denied. |
| `deny` | _[IPBlock](#ipblock) array_ | true | Deny specifies the list of IPBlocks that are denied to access the service. |


#### ALPNProtocol

_Underlying type:_ _string_
Expand Down Expand Up @@ -1229,6 +1244,20 @@ _Appears in:_
| `passive` | _[PassiveHealthCheck](#passivehealthcheck)_ | false | Passive passive check configuration |


#### IPBlock



IPBlock defines policy on a particular IPBlock.

_Appears in:_
- [ACL](#acl)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `cidr` | _string_ | true | cidr is a string representing the IPBlock Valid examples are "192.168.1.0/24" or "2001:db8::/64" |


#### InfrastructureProviderType

_Underlying type:_ _string_
Expand Down Expand Up @@ -2154,6 +2183,7 @@ _Appears in:_
| `jwt` | _[JWT](#jwt)_ | false | JWT defines the configuration for JSON Web Token (JWT) authentication. |
| `oidc` | _[OIDC](#oidc)_ | false | OIDC defines the configuration for the OpenID Connect (OIDC) authentication. |
| `extAuth` | _[ExtAuth](#extauth)_ | false | ExtAuth defines the configuration for External Authorization. |
| `acl` | _[ACL](#acl)_ | false | ACL defines the IP deny/allow configuration. |



Expand Down

0 comments on commit 6416777

Please sign in to comment.