policy-engine/inmemory_test.go
Denis Kirillov 63ecf63a08
All checks were successful
Tests and linters / Tests (1.21) (pull_request) Successful in 1m39s
Tests and linters / Tests (1.20) (pull_request) Successful in 2m11s
DCO action / DCO (pull_request) Successful in 2m31s
Tests and linters / Staticcheck (pull_request) Successful in 2m27s
Tests and linters / Tests with -race (pull_request) Successful in 2m35s
Tests and linters / Lint (pull_request) Successful in 3m55s
[#11] iam: Support 'NotPrincipal', 'NotAction', 'NotResource'
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2023-11-02 14:55:48 +03:00

193 lines
5.9 KiB
Go

package policyengine
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestInmemory(t *testing.T) {
const (
object = "native::object::abc/xyz"
container = "native::object::abc/*"
namespace = "Tenant1"
namespace2 = "Tenant2"
actor1 = "owner1"
actor2 = "owner2"
)
s := NewInMemory()
// Object which was put via S3.
res := newResource(object, map[string]string{"FromS3": "true"})
// Request initiating from the trusted subnet and actor.
reqGood := newRequest("native::object::put", res, map[string]string{
"SourceIP": "10.1.1.12",
"Actor": actor1,
})
status, ok := s.IsAllowed(Ingress, namespace, reqGood)
require.Equal(t, NoRuleFound, status)
require.False(t, ok)
s.AddNameSpaceChain(Ingress, namespace, &Chain{
Rules: []Rule{
{ // Restrict to remove ANY object from the namespace.
Status: AccessDenied,
Actions: Actions{Names: []string{"native::object::delete"}},
Resources: Resources{Names: []string{"native::object::*"}},
},
{ // Allow to put object only from the trusted subnet AND trusted actor, deny otherwise.
Status: AccessDenied,
Actions: Actions{Names: []string{"native::object::put"}},
Resources: Resources{Names: []string{"native::object::*"}},
Any: true,
Condition: []Condition{
{
Op: CondStringNotLike,
Object: ObjectRequest,
Key: "SourceIP",
Value: "10.1.1.*",
},
{
Op: CondStringNotEquals,
Object: ObjectRequest,
Key: "Actor",
Value: actor1,
},
},
},
},
})
s.AddNameSpaceChain(Ingress, namespace2, &Chain{
Rules: []Rule{
{ // Deny all expect "native::object::get" for all objects expect "native::object::abc/xyz".
Status: AccessDenied,
Actions: Actions{Inverted: true, Names: []string{"native::object::get"}},
Resources: Resources{Inverted: true, Names: []string{object}},
},
},
})
s.AddResourceChain(Ingress, container, &Chain{
Rules: []Rule{
{ // Allow to actor2 to get objects from the specific container only if they have `Department=HR` attribute.
Status: Allow,
Actions: Actions{Names: []string{"native::object::get"}},
Resources: Resources{Names: []string{"native::object::abc/*"}},
Condition: []Condition{
{
Op: CondStringEquals,
Object: ObjectResource,
Key: "Department",
Value: "HR",
},
{
Op: CondStringEquals,
Object: ObjectRequest,
Key: "Actor",
Value: actor2,
},
},
},
},
})
t.Run("bad subnet, namespace deny", func(t *testing.T) {
// Request initiating from the untrusted subnet.
reqBadIP := newRequest("native::object::put", res, map[string]string{
"SourceIP": "10.122.1.20",
"Actor": actor1,
})
status, ok := s.IsAllowed(Ingress, namespace, reqBadIP)
require.Equal(t, AccessDenied, status)
require.True(t, ok)
})
t.Run("bad actor, namespace deny", func(t *testing.T) {
// Request initiating from the untrusted actor.
reqBadActor := newRequest("native::object::put", res, map[string]string{
"SourceIP": "10.1.1.13",
"Actor": actor2,
})
status, ok := s.IsAllowed(Ingress, namespace, reqBadActor)
require.Equal(t, AccessDenied, status)
require.True(t, ok)
})
t.Run("bad object, container deny", func(t *testing.T) {
objGood := newResource("native::object::abc/id1", map[string]string{"Department": "HR"})
objBadAttr := newResource("native::object::abc/id2", map[string]string{"Department": "Support"})
status, ok := s.IsAllowed(Ingress, namespace, newRequest("native::object::get", objGood, map[string]string{
"SourceIP": "10.1.1.14",
"Actor": actor2,
}))
require.Equal(t, Allow, status)
require.True(t, ok)
status, ok = s.IsAllowed(Ingress, namespace, newRequest("native::object::get", objBadAttr, map[string]string{
"SourceIP": "10.1.1.14",
"Actor": actor2,
}))
require.Equal(t, NoRuleFound, status)
require.False(t, ok)
})
t.Run("bad operation, namespace deny", func(t *testing.T) {
// Request with the forbidden operation.
reqBadOperation := newRequest("native::object::delete", res, map[string]string{
"SourceIP": "10.1.1.12",
"Actor": actor1,
})
status, ok := s.IsAllowed(Ingress, namespace, reqBadOperation)
require.Equal(t, AccessDenied, status)
require.True(t, ok)
})
t.Run("inverted rules", func(t *testing.T) {
req := newRequest("native::object::put", newResource(object, nil), nil)
status, ok = s.IsAllowed(Ingress, namespace2, req)
require.Equal(t, NoRuleFound, status)
require.False(t, ok)
req = newRequest("native::object::put", newResource("native::object::cba/def", nil), nil)
status, ok = s.IsAllowed(Ingress, namespace2, req)
require.Equal(t, AccessDenied, status)
require.True(t, ok)
req = newRequest("native::object::get", newResource("native::object::cba/def", nil), nil)
status, ok = s.IsAllowed(Ingress, namespace2, req)
require.Equal(t, NoRuleFound, status)
require.False(t, ok)
})
t.Run("good", func(t *testing.T) {
status, ok = s.IsAllowed(Ingress, namespace, reqGood)
require.Equal(t, NoRuleFound, status)
require.False(t, ok)
t.Run("quota on a different container", func(t *testing.T) {
s.AddOverride(Ingress, &Chain{
Rules: []Rule{{
Status: QuotaLimitReached,
Actions: Actions{Names: []string{"native::object::put"}},
Resources: Resources{Names: []string{"native::object::cba/*"}},
}},
})
status, ok = s.IsAllowed(Ingress, namespace, reqGood)
require.Equal(t, NoRuleFound, status)
require.False(t, ok)
})
t.Run("quota on the request container", func(t *testing.T) {
s.AddOverride(Ingress, &Chain{
Rules: []Rule{{
Status: QuotaLimitReached,
Actions: Actions{Names: []string{"native::object::put"}},
Resources: Resources{Names: []string{"native::object::abc/*"}},
}},
})
status, ok = s.IsAllowed(Ingress, namespace, reqGood)
require.Equal(t, QuotaLimitReached, status)
require.True(t, ok)
})
})
}