Honor Default Traffic Permissions in V2 (#18886)

wire up v2 default traffic permissions
This commit is contained in:
Eric Haberkorn 2023-09-19 10:42:32 -04:00 committed by GitHub
parent 9b497f8c78
commit 170417ac97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 87 additions and 27 deletions

View File

@ -657,13 +657,8 @@ func (a *Agent) Start(ctx context.Context) error {
// Create proxy config manager now because it is a dependency of creating the proxyWatcher
// which will be passed to consul.NewServer so that it is then passed to the
// controller registration for the XDS controller in v2 mode, and the xds server in v1 and v2 mode.
var intentionDefaultAllow bool
switch a.config.ACLResolverSettings.ACLDefaultPolicy {
case "allow":
intentionDefaultAllow = true
case "deny":
intentionDefaultAllow = false
default:
intentionDefaultAllow, err := a.config.ACLResolverSettings.IsDefaultAllow()
if err != nil {
return fmt.Errorf("unexpected ACL default policy value of %q", a.config.ACLResolverSettings.ACLDefaultPolicy)
}

View File

@ -221,6 +221,17 @@ type ACLResolverSettings struct {
ACLDefaultPolicy string
}
func (s ACLResolverSettings) IsDefaultAllow() (bool, error) {
switch s.ACLDefaultPolicy {
case "allow":
return true, nil
case "deny":
return false, nil
default:
return false, fmt.Errorf("unexpected ACL default policy value of %q", s.ACLDefaultPolicy)
}
}
// ACLResolver is the type to handle all your token and policy resolution needs.
//
// Supports:

View File

@ -844,7 +844,9 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server,
s.insecureResourceServiceClient,
logger.Named(logging.ControllerRuntime),
)
s.registerControllers(flat, proxyUpdater)
if err := s.registerControllers(flat, proxyUpdater); err != nil {
return nil, err
}
go s.controllerManager.Run(&lib.StopChannelContext{StopCh: shutdownCh})
go s.trackLeaderChanges()
@ -895,9 +897,15 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server,
return s, nil
}
func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) {
func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) error {
if stringslice.Contains(deps.Experiments, CatalogResourceExperimentName) {
catalog.RegisterControllers(s.controllerManager, catalog.DefaultControllerDependencies())
defaultAllow, err := s.config.ACLResolverSettings.IsDefaultAllow()
if err != nil {
return err
}
mesh.RegisterControllers(s.controllerManager, mesh.ControllerDependencies{
TrustBundleFetcher: func() (*pbproxystate.TrustBundle, error) {
var bundle pbproxystate.TrustBundle
@ -923,6 +931,7 @@ func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) {
LeafCertManager: deps.LeafCertManager,
LocalDatacenter: s.config.Datacenter,
DefaultAllow: defaultAllow,
ProxyUpdater: proxyUpdater,
})
}
@ -932,6 +941,8 @@ func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) {
if s.config.DevMode {
demo.RegisterControllers(s.controllerManager)
}
return nil
}
func newGRPCHandlerFromConfig(deps Deps, config *Config, s *Server) connHandler {

View File

@ -10,7 +10,7 @@ import (
)
const (
ComputedTrafficPermissionsKind = "ComputedTrafficPermission"
ComputedTrafficPermissionsKind = "ComputedTrafficPermissions"
)
var (

View File

@ -21,6 +21,7 @@ import (
type Dependencies struct {
TrustDomainFetcher sidecarproxy.TrustDomainFetcher
LocalDatacenter string
DefaultAllow bool
TrustBundleFetcher xds.TrustBundleFetcher
ProxyUpdater xds.ProxyUpdater
LeafCertManager *leafcert.Manager
@ -44,7 +45,7 @@ func Register(mgr *controller.Manager, deps Dependencies) {
m = sidecarproxymapper.New(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache)
)
mgr.Register(
sidecarproxy.Controller(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache, m, deps.TrustDomainFetcher, deps.LocalDatacenter),
sidecarproxy.Controller(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache, m, deps.TrustDomainFetcher, deps.LocalDatacenter, deps.DefaultAllow),
)
mgr.Register(routes.Controller())

View File

@ -16,6 +16,7 @@ type Builder struct {
proxyCfg *pbmesh.ProxyConfiguration
trustDomain string
localDatacenter string
defaultAllow bool
}
func New(
@ -23,12 +24,14 @@ func New(
identity *pbresource.Reference,
trustDomain string,
dc string,
defaultAllow bool,
proxyCfg *pbmesh.ProxyConfiguration,
) *Builder {
return &Builder{
id: id,
trustDomain: trustDomain,
localDatacenter: dc,
defaultAllow: defaultAllow,
proxyCfg: proxyCfg,
proxyStateTemplate: &pbmesh.ProxyStateTemplate{
ProxyState: &pbmesh.ProxyState{
@ -55,6 +58,7 @@ func (b *Builder) Build() *pbmesh.ProxyStateTemplate {
b.proxyStateTemplate.RequiredTrustBundles[b.id.Tenancy.PeerName] = &pbproxystate.TrustBundleRef{
Peer: b.id.Tenancy.PeerName,
}
b.proxyStateTemplate.ProxyState.TrafficPermissionDefaultAllow = b.defaultAllow
return b.proxyStateTemplate
}

View File

@ -210,7 +210,7 @@ func TestBuildMultiportImplicitDestinations(t *testing.T) {
for name, c := range cases {
t.Run(name, func(t *testing.T) {
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), trustDomain, datacenter, proxyCfg).
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), trustDomain, datacenter, false, proxyCfg).
BuildDestinations(c.getDestinations()).
Build()

View File

@ -243,7 +243,7 @@ func TestBuildExplicitDestinations(t *testing.T) {
for name, c := range cases {
t.Run(name, func(t *testing.T) {
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", nil).
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", false, nil).
BuildDestinations(c.destinations).
Build()
@ -360,7 +360,7 @@ func TestBuildImplicitDestinations(t *testing.T) {
for name, c := range cases {
t.Run(name, func(t *testing.T) {
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", proxyCfg).
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", false, proxyCfg).
BuildDestinations(c.destinations).
Build()

View File

@ -88,7 +88,7 @@ func TestBuildLocalApp_Multiport(t *testing.T) {
for name, c := range cases {
t.Run(name, func(t *testing.T) {
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", nil).
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", false, nil).
BuildLocalApp(c.workload, nil).
Build()

View File

@ -21,8 +21,9 @@ import (
func TestBuildLocalApp(t *testing.T) {
cases := map[string]struct {
workload *pbcatalog.Workload
ctp *pbauth.ComputedTrafficPermissions
workload *pbcatalog.Workload
ctp *pbauth.ComputedTrafficPermissions
defaultAllow bool
}{
"source/l4-single-workload-address-without-ports": {
workload: &pbcatalog.Workload{
@ -83,12 +84,13 @@ func TestBuildLocalApp(t *testing.T) {
},
},
},
defaultAllow: true,
},
}
for name, c := range cases {
t.Run(name, func(t *testing.T) {
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", nil).
proxyTmpl := New(testProxyStateTemplateID(), testIdentityRef(), "foo.consul", "dc1", c.defaultAllow, nil).
BuildLocalApp(c.workload, c.ctp).
Build()
actual := protoToJSON(t, proxyTmpl)

View File

@ -74,7 +74,8 @@
}
]
}
]
],
"trafficPermissionDefaultAllow": true
},
"requiredLeafCertificates": {
"test-identity": {

View File

@ -35,6 +35,7 @@ func Controller(
mapper *sidecarproxymapper.Mapper,
trustDomainFetcher TrustDomainFetcher,
dc string,
defaultAllow bool,
) controller.Controller {
if destinationsCache == nil || proxyCfgCache == nil || computedRoutesCache == nil || identitiesCache == nil || mapper == nil || trustDomainFetcher == nil {
panic("destinations cache, proxy configuration cache, computed routes cache, identities cache, mapper, and trust domain fetcher are required")
@ -99,6 +100,7 @@ func Controller(
identitiesCache: identitiesCache,
getTrustDomain: trustDomainFetcher,
dc: dc,
defaultAllow: defaultAllow,
})
}
@ -108,6 +110,7 @@ type reconciler struct {
computedRoutesCache *sidecarproxycache.ComputedRoutesCache
identitiesCache *sidecarproxycache.IdentitiesCache
getTrustDomain TrustDomainFetcher
defaultAllow bool
dc string
}
@ -194,7 +197,7 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c
ctp = trafficPermissions.Data
}
b := builder.New(req.ID, identityRefFromWorkload(workload), trustDomain, r.dc, proxyCfg).
b := builder.New(req.ID, identityRefFromWorkload(workload), trustDomain, r.dc, r.defaultAllow, proxyCfg).
BuildLocalApp(workload.Data, ctp)
// Get all destinationsData.

View File

@ -226,7 +226,7 @@ func (suite *meshControllerTestSuite) SetupTest() {
Tenancy: suite.apiWorkloadID.Tenancy,
}
suite.proxyStateTemplate = builder.New(suite.apiWorkloadID, identityRef, "test.consul", "dc1", nil).
suite.proxyStateTemplate = builder.New(suite.apiWorkloadID, identityRef, "test.consul", "dc1", false, nil).
BuildLocalApp(suite.apiWorkload, suite.computedTrafficPermissionsData).
Build()
}
@ -357,7 +357,7 @@ func (suite *meshControllerTestSuite) TestController() {
)
trustDomainFetcher := func() (string, error) { return "test.consul", nil }
mgr.Register(Controller(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache, m, trustDomainFetcher, "dc1"))
mgr.Register(Controller(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache, m, trustDomainFetcher, "dc1", false))
mgr.SetRaftLeader(true)
go mgr.Run(suite.ctx)
@ -554,7 +554,10 @@ func (suite *meshControllerTestSuite) TestController() {
requireImplicitDestinationsFound(t, "db", webProxyStateTemplate)
})
testutil.RunStep(suite.T(), "computed traffic permissions force regeneration", func(t *testing.T) {
testutil.RunStep(suite.T(), "traffic permissions", func(t *testing.T) {
dec := resourcetest.MustDecode[*pbmesh.ProxyStateTemplate](t, apiProxyStateTemplate)
require.False(t, dec.Data.ProxyState.TrafficPermissionDefaultAllow)
suite.runtime.Logger.Trace("deleting computed traffic permissions")
_, err := suite.client.Delete(suite.ctx, &pbresource.DeleteRequest{Id: suite.computedTrafficPermissions.Id})
require.NoError(t, err)
@ -622,6 +625,37 @@ func (suite *meshControllerTestSuite) TestController() {
})
}
func (suite *meshControllerTestSuite) TestControllerDefaultAllow() {
// Run the controller manager
mgr := controller.NewManager(suite.client, suite.runtime.Logger)
// Initialize controller dependencies.
var (
destinationsCache = sidecarproxycache.NewDestinationsCache()
proxyCfgCache = sidecarproxycache.NewProxyConfigurationCache()
computedRoutesCache = sidecarproxycache.NewComputedRoutesCache()
identitiesCache = sidecarproxycache.NewIdentitiesCache()
m = sidecarproxymapper.New(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache)
)
trustDomainFetcher := func() (string, error) { return "test.consul", nil }
mgr.Register(Controller(destinationsCache, proxyCfgCache, computedRoutesCache, identitiesCache, m, trustDomainFetcher, "dc1", true))
mgr.SetRaftLeader(true)
go mgr.Run(suite.ctx)
var (
// Create proxy state template IDs to check against in this test.
webProxyStateTemplateID = resourcetest.Resource(types.ProxyStateTemplateType, "web-def").ID()
)
retry.Run(suite.T(), func(r *retry.R) {
suite.client.RequireResourceExists(r, webProxyStateTemplateID)
webProxyStateTemplate := suite.client.RequireResourceExists(r, webProxyStateTemplateID)
dec := resourcetest.MustDecode[*pbmesh.ProxyStateTemplate](r, webProxyStateTemplate)
require.True(r, dec.Data.ProxyState.TrafficPermissionDefaultAllow)
})
}
func TestMeshController(t *testing.T) {
suite.Run(t, new(meshControllerTestSuite))
}

View File

@ -4,8 +4,6 @@
package resourcetest
import (
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
@ -13,8 +11,8 @@ import (
"github.com/hashicorp/consul/proto-public/pbresource"
)
func MustDecode[T proto.Message](t *testing.T, res *pbresource.Resource) *resource.DecodedResource[T] {
dec, err := resource.Decode[T](res)
func MustDecode[Tp proto.Message](t T, res *pbresource.Resource) *resource.DecodedResource[Tp] {
dec, err := resource.Decode[Tp](res)
require.NoError(t, err)
return dec
}