Skip to content

Commit

Permalink
Allow custom policies (#1394)
Browse files Browse the repository at this point in the history
* add custom opa policies support

Signed-off-by: denis-tingaikin <[email protected]>

* fix all broken tests

Signed-off-by: Nikita Skrynnik <[email protected]>

* add reading of files and dirs with policies

Signed-off-by: Nikita Skrynnik <[email protected]>

* add policy files reading from mask

Signed-off-by: Nikita Skrynnik <[email protected]>

* fix remaining issues

Signed-off-by: denis-tingaikin <[email protected]>

* fix policy file paths for windows

Signed-off-by: Nikita Skrynnik <[email protected]>

* move all policies to separate folders

Signed-off-by: Nikita Skrynnik <[email protected]>

* add default policies to networkservice authorize

Signed-off-by: Nikita Skrynnik <[email protected]>

* cleanup

Signed-off-by: Nikita Skrynnik <[email protected]>

* Rerun CI

Signed-off-by: Nikita Skrynnik <[email protected]>

Signed-off-by: denis-tingaikin <[email protected]>
Signed-off-by: Nikita Skrynnik <[email protected]>
Co-authored-by: denis-tingaikin <[email protected]>
  • Loading branch information
NikitaSkrynnik and denis-tingaikin authored Dec 15, 2022
1 parent fa94b07 commit 9709ed4
Show file tree
Hide file tree
Showing 45 changed files with 392 additions and 226 deletions.
15 changes: 7 additions & 8 deletions pkg/networkservice/chains/nsmgr/single_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import (
"github.com/networkservicemesh/sdk/pkg/registry/chains/memory"
"github.com/networkservicemesh/sdk/pkg/registry/common/authorize"
"github.com/networkservicemesh/sdk/pkg/tools/clientinfo"
"github.com/networkservicemesh/sdk/pkg/tools/opa"
"github.com/networkservicemesh/sdk/pkg/tools/sandbox"
"github.com/networkservicemesh/sdk/pkg/tools/token"
)
Expand Down Expand Up @@ -501,13 +500,13 @@ func Test_FailedRegistryAuthorization(t *testing.T) {
nsmgrSuppier := func(ctx context.Context, tokenGenerator token.GeneratorFunc, options ...nsmgr.Option) nsmgr.Nsmgr {
options = append(options,
nsmgr.WithAuthorizeNSERegistryServer(
authorize.NewNetworkServiceEndpointRegistryServer(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))),
authorize.NewNetworkServiceEndpointRegistryServer(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))),
nsmgr.WithAuthorizeNSRegistryServer(
authorize.NewNetworkServiceRegistryServer(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))),
authorize.NewNetworkServiceRegistryServer(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))),
nsmgr.WithAuthorizeNSERegistryClient(
authorize.NewNetworkServiceEndpointRegistryClient(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))),
authorize.NewNetworkServiceEndpointRegistryClient(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))),
nsmgr.WithAuthorizeNSRegistryClient(
authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))),
authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))),
)
return nsmgr.NewServer(ctx, tokenGenerator, options...)
}
Expand All @@ -527,7 +526,7 @@ func Test_FailedRegistryAuthorization(t *testing.T) {
memory.WithProxyRegistryURL(proxyRegistryURL),
memory.WithDialOptions(options...),
memory.WithAuthorizeNSRegistryServer(
authorize.NewNetworkServiceRegistryServer(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))),
authorize.NewNetworkServiceRegistryServer(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))),
)
}
domain := sandbox.NewBuilder(ctx, t).
Expand All @@ -554,15 +553,15 @@ func Test_FailedRegistryAuthorization(t *testing.T) {

nsRegistryClient1 := domain.NewNSRegistryClient(ctx, tokenGeneratorFunc("spiffe://test.com/ns-1"),
registryclient.WithAuthorizeNSRegistryClient(
authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))))
authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))))

ns1 := defaultRegistryService("ns-1")
_, err := nsRegistryClient1.Register(ctx, ns1)
require.NoError(t, err)

nsRegistryClient2 := domain.NewNSRegistryClient(ctx, tokenGeneratorFunc("spiffe://test.com/ns-2"),
registryclient.WithAuthorizeNSRegistryClient(
authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))))
authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))))

ns2 := defaultRegistryService("ns-1")
_, err = nsRegistryClient2.Register(ctx, ns2)
Expand Down
20 changes: 14 additions & 6 deletions pkg/networkservice/common/authorize/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,26 @@ type authorizeClient struct {
// Authorize client checks rigiht side of path.
func NewClient(opts ...Option) networkservice.NetworkServiceClient {
o := &options{
policies: policiesList{
opa.WithTokensValidPolicy(),
opa.WithNextTokenSignedPolicy(),
opa.WithTokensExpiredPolicy(),
opa.WithTokenChainPolicy(),
policyPaths: []string{
"etc/nsm/opa/common/.*.rego",
"etc/nsm/opa/client/.*.rego",
},
}
for _, opt := range opts {
opt(o)
}

policies, err := opa.PoliciesByFileMask(o.policyPaths...)
if err != nil {
panic(errors.Wrap(err, "failed to read policies in NetworkService authorize client").Error())
}
var policyList policiesList
for _, p := range policies {
policyList = append(policyList, p)
}

var result = &authorizeClient{
policies: o.policies,
policies: policyList,
}
return result
}
Expand Down
11 changes: 6 additions & 5 deletions pkg/networkservice/common/authorize/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ package authorize
import "github.com/networkservicemesh/sdk/pkg/tools/spire"

type options struct {
policies policiesList
policyPaths []string
spiffeIDConnectionMap *spire.SpiffeIDConnectionMap
}

Expand All @@ -30,13 +30,14 @@ type Option func(*options)

// Any authorizes any call of request/close
func Any() Option {
return WithPolicies(nil)
return WithPolicies([]string{}...)
}

// WithPolicies sets custom policies
func WithPolicies(p ...Policy) Option {
// WithPolicies sets custom policies for networkservice.
// policyPaths can be combination of both policy files and dirs with policies
func WithPolicies(policyPaths ...string) Option {
return func(o *options) {
o.policies = p
o.policyPaths = policyPaths
}
}

Expand Down
21 changes: 15 additions & 6 deletions pkg/networkservice/common/authorize/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"context"

"github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors"
"google.golang.org/grpc/peer"

"github.com/networkservicemesh/api/pkg/api/networkservice"
Expand All @@ -42,19 +43,27 @@ type authorizeServer struct {
// Authorize server checks left side of Path.
func NewServer(opts ...Option) networkservice.NetworkServiceServer {
o := &options{
policies: policiesList{
opa.WithTokensValidPolicy(),
opa.WithPrevTokenSignedPolicy(),
opa.WithTokensExpiredPolicy(),
opa.WithTokenChainPolicy(),
policyPaths: []string{
"etc/nsm/opa/common/.*.rego",
"etc/nsm/opa/server/.*.rego",
},
spiffeIDConnectionMap: &spire.SpiffeIDConnectionMap{},
}
for _, opt := range opts {
opt(o)
}

policies, err := opa.PoliciesByFileMask(o.policyPaths...)
if err != nil {
panic(errors.Wrap(err, "failed to read policies in NetworkService authorize client").Error())
}
var policyList policiesList
for _, p := range policies {
policyList = append(policyList, p)
}

var s = &authorizeServer{
policies: o.policies,
policies: policyList,
spiffeIDConnectionMap: o.spiffeIDConnectionMap,
}
return s
Expand Down
64 changes: 39 additions & 25 deletions pkg/networkservice/common/authorize/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ import (
"crypto/x509"
"math/big"
"net/url"
"os"
"path"
"path/filepath"
"testing"
"time"

"github.com/networkservicemesh/sdk/pkg/tools/opa"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
Expand Down Expand Up @@ -72,16 +73,16 @@ func withPeer(ctx context.Context, certBytes []byte) (context.Context, error) {
return peer.NewContext(ctx, &peer.Peer{AuthInfo: authInfo}), nil
}

func testPolicy() authorize.Policy {
return opa.WithPolicyFromSource(`
package test
default allow = false
func testPolicy() string {
return `
package test
allow {
input.path_segments[_].token = "allowed"
}
`, "allow", opa.True)
default valid = false
valid {
input.path_segments[_].token = "allowed"
}
`
}

func requestWithToken(token string) *networkservice.NetworkServiceRequest {
Expand Down Expand Up @@ -123,31 +124,44 @@ func TestAuthorize_ShouldCorrectlyWorkWithHeal(t *testing.T) {

func TestAuthzEndpoint(t *testing.T) {
t.Cleanup(func() { goleak.VerifyNone(t) })

dir := filepath.Clean(path.Join(os.TempDir(), t.Name()))
defer func() {
_ = os.RemoveAll(dir)
}()

err := os.MkdirAll(dir, os.ModePerm)
require.Nil(t, err)

policyPath := filepath.Clean(path.Join(dir, "policy.rego"))
err = os.WriteFile(policyPath, []byte(testPolicy()), os.ModePerm)
require.Nil(t, err)

suits := []struct {
name string
policy authorize.Policy
request *networkservice.NetworkServiceRequest
response *networkservice.Connection
denied bool
name string
policyPath string
request *networkservice.NetworkServiceRequest
response *networkservice.Connection
denied bool
}{
{
name: "simple positive test",
policy: testPolicy(),
request: requestWithToken("allowed"),
denied: false,
name: "simple positive test",
policyPath: policyPath,
request: requestWithToken("allowed"),
denied: false,
},
{
name: "simple negative test",
policy: testPolicy(),
request: requestWithToken("not_allowed"),
denied: true,
name: "simple negative test",
policyPath: policyPath,
request: requestWithToken("not_allowed"),
denied: true,
},
}

for i := range suits {
s := suits[i]
t.Run(s.name, func(t *testing.T) {
srv := authorize.NewServer(authorize.WithPolicies(s.policy))
srv := authorize.NewServer(authorize.WithPolicies(s.policyPath))
checkResult := func(err error) {
if !s.denied {
require.Nil(t, err, "request expected to be not denied: ")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !linux
// +build !linux

package recvfd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !linux
// +build !linux

package recvfd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !linux
// +build !linux

package sendfd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !linux
// +build !linux

package sendfd
Expand Down
4 changes: 4 additions & 0 deletions pkg/registry/common/authorize/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/spiffe/go-spiffe/v2/spiffeid"

"github.com/networkservicemesh/sdk/pkg/registry/common/grpcmetadata"
"github.com/networkservicemesh/sdk/pkg/tools/log"
)

// RegistryOpaInput represents input for policies in authorizNSEServer and authorizeNSServer
Expand Down Expand Up @@ -53,8 +54,11 @@ func (l *policiesList) check(ctx context.Context, input RegistryOpaInput) error
}

if err := policy.Check(ctx, input); err != nil {
log.FromContext(ctx).Infof("policy failed %v", policy)
return err
}

log.FromContext(ctx).Infof("policy passed")
}
return nil
}
Expand Down
19 changes: 11 additions & 8 deletions pkg/registry/common/authorize/ns_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,25 @@ type authorizeNSClient struct {
// Authorize registry client checks spiffeID of NS.
func NewNetworkServiceRegistryClient(opts ...Option) registry.NetworkServiceRegistryClient {
o := &options{
policies: policiesList{
opa.WithTokensValidPolicy(),
opa.WithNextTokenSignedPolicy(),
opa.WithTokensExpiredPolicy(),
opa.WithTokenChainPolicy(),
opa.WithRegistryClientAllowedPolicy(),
},
resourcePathIdsMap: new(PathIdsMap),
}

for _, opt := range opts {
opt(o)
}

policies, err := opa.PoliciesByFileMask(o.policyPaths...)
if err != nil {
panic(errors.Wrap(err, "failed to read policies in NetworkServiceRegistry authorize client").Error())
}

var policyList policiesList
for _, p := range policies {
policyList = append(policyList, p)
}

return &authorizeNSClient{
policies: o.policies,
policies: policyList,
nsPathIdsMap: o.resourcePathIdsMap,
}
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/registry/common/authorize/ns_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ import (

"github.com/networkservicemesh/sdk/pkg/registry/common/authorize"
"github.com/networkservicemesh/sdk/pkg/registry/common/grpcmetadata"
"github.com/networkservicemesh/sdk/pkg/tools/opa"

"go.uber.org/goleak"
)

func TestNSRegistryAuthorizeClient(t *testing.T) {
t.Cleanup(func() { goleak.VerifyNone(t) })
client := authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies(opa.WithRegistryClientAllowedPolicy()))

client := authorize.NewNetworkServiceRegistryClient(authorize.WithPolicies("etc/nsm/opa/registry/client_allowed.rego"))
require.NotNil(t, client)

ns := &registry.NetworkService{Name: "ns"}
path1 := getPath(t, spiffeid1)
Expand Down
Loading

0 comments on commit 9709ed4

Please sign in to comment.