Skip to content

Commit

Permalink
Wire up traffic permissions (#18812)
Browse files Browse the repository at this point in the history
Wire up traffic permissions
  • Loading branch information
erichaberkorn authored Sep 15, 2023
1 parent d3dad14 commit 21fdbba
Show file tree
Hide file tree
Showing 32 changed files with 1,085 additions and 511 deletions.
4 changes: 2 additions & 2 deletions agent/xds/proxystateconverter/listeners.go
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ func (s *Converter) makeInboundListener(cfgSnap *proxycfg.ConfigSnapshot, name s
l4Dest.MaxInboundConnections = uint64(cfg.MaxInboundConnections)
}

l4Dest.TrafficPermissions = &pbproxystate.L4TrafficPermissions{}
l4Dest.TrafficPermissions = &pbproxystate.TrafficPermissions{}
}
l.Routers = append(l.Routers, localAppRouter)

Expand Down Expand Up @@ -1576,7 +1576,7 @@ func (g *Converter) makeL7Destination(opts destinationOpts) (*pbproxystate.L7Des
// access and that every filter chain uses our TLS certs.
if len(opts.httpAuthzFilters) > 0 {
// TODO(proxystate) support intentions in the future
dest.TrafficPermissions = &pbproxystate.L7TrafficPermissions{}
dest.TrafficPermissions = &pbproxystate.TrafficPermissions{}
//cfg.HttpFilters = append(opts.httpAuthzFilters, cfg.HttpFilters...)
}

Expand Down
108 changes: 54 additions & 54 deletions agent/xds/rbac_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,25 +556,25 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
}
)

makeL4Spiffe := func(name string, entMeta *acl.EnterpriseMeta) string {
makeSpiffe := func(name string, entMeta *acl.EnterpriseMeta) *pbproxystate.Spiffe {
em := *acl.DefaultEnterpriseMeta()
if entMeta != nil {
em = *entMeta
}
spiffe := makeSpiffePattern(rbacService{
regex := makeSpiffePattern(rbacService{
ServiceName: structs.ServiceName{
Name: name,
EnterpriseMeta: em,
},
TrustDomain: testTrustDomain,
})
return spiffe
return &pbproxystate.Spiffe{Regex: regex}
}

tests := map[string]struct {
intentionDefaultAllow bool
v1Intentions structs.SimplifiedIntentions
v2L4TrafficPermissions *pbproxystate.L4TrafficPermissions
v2L4TrafficPermissions *pbproxystate.TrafficPermissions
}{
"default-deny-mixed-precedence": {
intentionDefaultAllow: false,
Expand All @@ -583,12 +583,12 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
testIntention(t, "*", "api", structs.IntentionActionDeny),
testIntention(t, "web", "*", structs.IntentionActionDeny),
),
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("web", nil),
Spiffe: makeSpiffe("web", nil),
},
},
},
Expand All @@ -600,12 +600,12 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
v1Intentions: sorted(
testSourceIntention("*", structs.IntentionActionAllow),
),
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("*", nil),
Spiffe: makeSpiffe("*", nil),
},
},
},
Expand All @@ -623,12 +623,12 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
v1Intentions: sorted(
testSourceIntention("web", structs.IntentionActionAllow),
),
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("web", nil),
Spiffe: makeSpiffe("web", nil),
},
},
},
Expand All @@ -647,13 +647,13 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
testSourceIntention("web", structs.IntentionActionDeny),
testSourceIntention("*", structs.IntentionActionAllow),
),
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("*", nil),
ExcludeSpiffeRegexes: []string{makeL4Spiffe("web", nil)},
Spiffe: makeSpiffe("*", nil),
ExcludeSpiffes: []*pbproxystate.Spiffe{makeSpiffe("web", nil)},
},
},
},
Expand All @@ -669,22 +669,22 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
testSourceIntention("cron", structs.IntentionActionAllow),
testSourceIntention("*", structs.IntentionActionAllow),
),
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("cron", nil),
Spiffe: makeSpiffe("cron", nil),
},
{
SpiffeRegex: makeL4Spiffe("web", nil),
Spiffe: makeSpiffe("web", nil),
},
{
SpiffeRegex: makeL4Spiffe("*", nil),
ExcludeSpiffeRegexes: []string{
makeL4Spiffe("web", nil),
makeL4Spiffe("unsafe", nil),
makeL4Spiffe("cron", nil),
Spiffe: makeSpiffe("*", nil),
ExcludeSpiffes: []*pbproxystate.Spiffe{
makeSpiffe("web", nil),
makeSpiffe("unsafe", nil),
makeSpiffe("cron", nil),
},
},
},
Expand All @@ -694,37 +694,37 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
},
"v2-kitchen-sink": {
intentionDefaultAllow: false,
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("api", nil),
Spiffe: makeSpiffe("api", nil),
},
{
SpiffeRegex: makeL4Spiffe("*", nil),
ExcludeSpiffeRegexes: []string{
makeL4Spiffe("unsafe", nil),
Spiffe: makeSpiffe("*", nil),
ExcludeSpiffes: []*pbproxystate.Spiffe{
makeSpiffe("unsafe", nil),
},
},
},
},
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("web", nil),
Spiffe: makeSpiffe("web", nil),
},
},
},
},
DenyPermissions: []*pbproxystate.L4Permission{
DenyPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("db", nil),
Spiffe: makeSpiffe("db", nil),
},
{
SpiffeRegex: makeL4Spiffe("cron", nil),
Spiffe: makeSpiffe("cron", nil),
},
},
},
Expand All @@ -733,20 +733,20 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
},
"v2-default-deny": {
intentionDefaultAllow: false,
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{},
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{},
},
"v2-default-allow": {
intentionDefaultAllow: true,
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{},
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{},
},
"v2-default-allow-one-allow": {
intentionDefaultAllow: true,
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
AllowPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
AllowPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("web", nil),
Spiffe: makeSpiffe("web", nil),
},
},
},
Expand All @@ -756,12 +756,12 @@ func TestMakeRBACNetworkAndHTTPFilters(t *testing.T) {
// In v2, having a single permission turns on default deny.
"v2-default-allow-one-deny": {
intentionDefaultAllow: true,
v2L4TrafficPermissions: &pbproxystate.L4TrafficPermissions{
DenyPermissions: []*pbproxystate.L4Permission{
v2L4TrafficPermissions: &pbproxystate.TrafficPermissions{
DenyPermissions: []*pbproxystate.Permission{
{
Principals: []*pbproxystate.L4Principal{
Principals: []*pbproxystate.Principal{
{
SpiffeRegex: makeL4Spiffe("web", nil),
Spiffe: makeSpiffe("web", nil),
},
},
},
Expand Down
14 changes: 7 additions & 7 deletions agent/xdsv2/rbac_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const (
baseL4PermissionKey = "consul-intentions-layer4"
)

func MakeL4RBAC(defaultAllow bool, trafficPermissions *pbproxystate.L4TrafficPermissions) ([]*envoy_listener_v3.Filter, error) {
func MakeL4RBAC(defaultAllow bool, trafficPermissions *pbproxystate.TrafficPermissions) ([]*envoy_listener_v3.Filter, error) {
var filters []*envoy_listener_v3.Filter

if trafficPermissions == nil {
Expand Down Expand Up @@ -60,7 +60,7 @@ func MakeL4RBAC(defaultAllow bool, trafficPermissions *pbproxystate.L4TrafficPer

// includeAllowFilter determines if an Envoy RBAC allow filter will be included in the filter chain.
// We include this filter with default deny or whenever any permissions are configured.
func includeAllowFilter(defaultAllow bool, trafficPermissions *pbproxystate.L4TrafficPermissions) bool {
func includeAllowFilter(defaultAllow bool, trafficPermissions *pbproxystate.TrafficPermissions) bool {
hasPermissions := len(trafficPermissions.DenyPermissions)+len(trafficPermissions.AllowPermissions) > 0
return !defaultAllow || hasPermissions
}
Expand All @@ -73,7 +73,7 @@ func makeRBACFilter(rbac *envoy_rbac_v3.RBAC) (*envoy_listener_v3.Filter, error)
return makeEnvoyFilter("envoy.filters.network.rbac", cfg)
}

func makeRBACPolicies(l4Permissions []*pbproxystate.L4Permission) map[string]*envoy_rbac_v3.Policy {
func makeRBACPolicies(l4Permissions []*pbproxystate.Permission) map[string]*envoy_rbac_v3.Policy {
policyLabel := func(i int) string {
if len(l4Permissions) == 1 {
return baseL4PermissionKey
Expand All @@ -90,11 +90,11 @@ func makeRBACPolicies(l4Permissions []*pbproxystate.L4Permission) map[string]*en
return policies
}

func makeRBACPolicy(p *pbproxystate.L4Permission) *envoy_rbac_v3.Policy {
func makeRBACPolicy(p *pbproxystate.Permission) *envoy_rbac_v3.Policy {
var principals []*envoy_rbac_v3.Principal

for _, l4Principal := range p.Principals {
principals = append(principals, toEnvoyPrincipal(l4Principal.ToL7Principal()))
for _, p := range p.Principals {
principals = append(principals, toEnvoyPrincipal(p))
}

return &envoy_rbac_v3.Policy{
Expand All @@ -103,7 +103,7 @@ func makeRBACPolicy(p *pbproxystate.L4Permission) *envoy_rbac_v3.Policy {
}
}

func toEnvoyPrincipal(p *pbproxystate.L7Principal) *envoy_rbac_v3.Principal {
func toEnvoyPrincipal(p *pbproxystate.Principal) *envoy_rbac_v3.Principal {
includePrincipal := principal(p.Spiffe)

if len(p.ExcludeSpiffes) == 0 {
Expand Down
38 changes: 38 additions & 0 deletions internal/mesh/internal/cache/sidecarproxycache/identities_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package sidecarproxycache

import (
auth "github.com/hashicorp/consul/internal/auth"
"github.com/hashicorp/consul/internal/mesh/internal/types"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/mappers/bimapper"
"github.com/hashicorp/consul/proto-public/pbresource"
)

// IdentitiesCache tracks mappings between workload identities and proxy IDs
// that a configuration applies to. It is the responsibility of the controller to
// keep this cache up-to-date.
type IdentitiesCache struct {
mapper *bimapper.Mapper
}

func NewIdentitiesCache() *IdentitiesCache {
return &IdentitiesCache{
mapper: bimapper.New(types.ProxyStateTemplateType, auth.WorkloadIdentityType),
}
}

func (c *IdentitiesCache) ProxyIDsByWorkloadIdentity(id *pbresource.ID) []*pbresource.ID {
return c.mapper.ItemIDsForLink(id)
}

func (c *IdentitiesCache) TrackPair(identityID *pbresource.ID, proxyID *pbresource.ID) {
c.mapper.TrackItem(proxyID, []resource.ReferenceOrID{identityID})
}

// UntrackProxyID removes tracking for the given proxy state template ID.
func (c *IdentitiesCache) UntrackProxyID(proxyID *pbresource.ID) {
c.mapper.UntrackItem(proxyID)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package sidecarproxycache

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/hashicorp/consul/internal/auth"
"github.com/hashicorp/consul/internal/mesh/internal/types"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/resourcetest"
"github.com/hashicorp/consul/proto-public/pbresource"
)

func TestIdentitiesCache(t *testing.T) {
cache := NewIdentitiesCache()

identityID1 := resourcetest.Resource(auth.WorkloadIdentityType, "workload-identity-1").
WithTenancy(resource.DefaultNamespacedTenancy()).ID()
identityID2 := resourcetest.Resource(auth.WorkloadIdentityType, "workload-identity-2").
WithTenancy(resource.DefaultNamespacedTenancy()).ID()

proxyID1 := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-1").
WithTenancy(resource.DefaultNamespacedTenancy()).ID()
proxyID2 := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-2").
WithTenancy(resource.DefaultNamespacedTenancy()).ID()

// Empty cache
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID1))
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID2))

// Insert value and fetch it.
cache.TrackPair(identityID1, proxyID1)
require.Equal(t, []*pbresource.ID{proxyID1}, cache.ProxyIDsByWorkloadIdentity(identityID1))
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID2))

// Insert another value referencing the same identity.
cache.TrackPair(identityID1, proxyID2)
require.ElementsMatch(t, []*pbresource.ID{proxyID1, proxyID2}, cache.ProxyIDsByWorkloadIdentity(identityID1))
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID2))

// Now proxy 1 uses identity 2
cache.TrackPair(identityID2, proxyID1)
require.Equal(t, []*pbresource.ID{proxyID1}, cache.ProxyIDsByWorkloadIdentity(identityID2))
require.Equal(t, []*pbresource.ID{proxyID2}, cache.ProxyIDsByWorkloadIdentity(identityID1))

// Untrack proxy 2
cache.UntrackProxyID(proxyID2)
require.Equal(t, []*pbresource.ID{proxyID1}, cache.ProxyIDsByWorkloadIdentity(identityID2))
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID1))

// Untrack proxy 1
cache.UntrackProxyID(proxyID1)
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID2))
require.Nil(t, cache.ProxyIDsByWorkloadIdentity(identityID1))
}
Loading

0 comments on commit 21fdbba

Please sign in to comment.