Add workload identity ACL rules (#18769)

This commit is contained in:
Chris S. Kim 2023-09-12 17:22:51 -04:00 committed by GitHub
parent a55c4a1c25
commit d090668c37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 777 additions and 43 deletions

3
.changelog/18769.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:feature
acl: Adds a new ACL rule for workload identities
```

View File

@ -59,6 +59,31 @@ func (m *MockAuthorizer) EventWrite(segment string, ctx *AuthorizerContext) Enfo
return ret.Get(0).(EnforcementDecision) return ret.Get(0).(EnforcementDecision)
} }
// IdentityRead checks for permission to read a given workload identity.
func (m *MockAuthorizer) IdentityRead(segment string, ctx *AuthorizerContext) EnforcementDecision {
ret := m.Called(segment, ctx)
return ret.Get(0).(EnforcementDecision)
}
// IdentityReadAll checks for permission to read all workload identities.
func (m *MockAuthorizer) IdentityReadAll(ctx *AuthorizerContext) EnforcementDecision {
ret := m.Called(ctx)
return ret.Get(0).(EnforcementDecision)
}
// IdentityWrite checks for permission to create or update a given
// workload identity.
func (m *MockAuthorizer) IdentityWrite(segment string, ctx *AuthorizerContext) EnforcementDecision {
ret := m.Called(segment, ctx)
return ret.Get(0).(EnforcementDecision)
}
// IdentityWriteAny checks for write permission on any workload identity.
func (m *MockAuthorizer) IdentityWriteAny(ctx *AuthorizerContext) EnforcementDecision {
ret := m.Called(ctx)
return ret.Get(0).(EnforcementDecision)
}
// IntentionDefaultAllow determines the default authorized behavior // IntentionDefaultAllow determines the default authorized behavior
// when no intentions match a Connect request. // when no intentions match a Connect request.
func (m *MockAuthorizer) IntentionDefaultAllow(ctx *AuthorizerContext) EnforcementDecision { func (m *MockAuthorizer) IntentionDefaultAllow(ctx *AuthorizerContext) EnforcementDecision {

View File

@ -40,6 +40,22 @@ func checkAllowEventWrite(t *testing.T, authz Authorizer, prefix string, entCtx
require.Equal(t, Allow, authz.EventWrite(prefix, entCtx)) require.Equal(t, Allow, authz.EventWrite(prefix, entCtx))
} }
func checkAllowIdentityRead(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Allow, authz.IdentityRead(prefix, entCtx))
}
func checkAllowIdentityReadAll(t *testing.T, authz Authorizer, _ string, entCtx *AuthorizerContext) {
require.Equal(t, Allow, authz.IdentityReadAll(entCtx))
}
func checkAllowIdentityWrite(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Allow, authz.IdentityWrite(prefix, entCtx))
}
func checkAllowIdentityWriteAny(t *testing.T, authz Authorizer, _ string, entCtx *AuthorizerContext) {
require.Equal(t, Allow, authz.IdentityWriteAny(entCtx))
}
func checkAllowIntentionDefaultAllow(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) { func checkAllowIntentionDefaultAllow(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Allow, authz.IntentionDefaultAllow(entCtx)) require.Equal(t, Allow, authz.IntentionDefaultAllow(entCtx))
} }
@ -172,6 +188,22 @@ func checkDenyEventWrite(t *testing.T, authz Authorizer, prefix string, entCtx *
require.Equal(t, Deny, authz.EventWrite(prefix, entCtx)) require.Equal(t, Deny, authz.EventWrite(prefix, entCtx))
} }
func checkDenyIdentityRead(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Deny, authz.IdentityRead(prefix, entCtx))
}
func checkDenyIdentityReadAll(t *testing.T, authz Authorizer, _ string, entCtx *AuthorizerContext) {
require.Equal(t, Deny, authz.IdentityReadAll(entCtx))
}
func checkDenyIdentityWrite(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Deny, authz.IdentityWrite(prefix, entCtx))
}
func checkDenyIdentityWriteAny(t *testing.T, authz Authorizer, _ string, entCtx *AuthorizerContext) {
require.Equal(t, Deny, authz.IdentityWriteAny(entCtx))
}
func checkDenyIntentionDefaultAllow(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) { func checkDenyIntentionDefaultAllow(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Deny, authz.IntentionDefaultAllow(entCtx)) require.Equal(t, Deny, authz.IntentionDefaultAllow(entCtx))
} }
@ -304,6 +336,22 @@ func checkDefaultEventWrite(t *testing.T, authz Authorizer, prefix string, entCt
require.Equal(t, Default, authz.EventWrite(prefix, entCtx)) require.Equal(t, Default, authz.EventWrite(prefix, entCtx))
} }
func checkDefaultIdentityRead(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Default, authz.IdentityRead(prefix, entCtx))
}
func checkDefaultIdentityReadAll(t *testing.T, authz Authorizer, _ string, entCtx *AuthorizerContext) {
require.Equal(t, Default, authz.IdentityReadAll(entCtx))
}
func checkDefaultIdentityWrite(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Default, authz.IdentityWrite(prefix, entCtx))
}
func checkDefaultIdentityWriteAny(t *testing.T, authz Authorizer, _ string, entCtx *AuthorizerContext) {
require.Equal(t, Default, authz.IdentityWriteAny(entCtx))
}
func checkDefaultIntentionDefaultAllow(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) { func checkDefaultIntentionDefaultAllow(t *testing.T, authz Authorizer, prefix string, entCtx *AuthorizerContext) {
require.Equal(t, Default, authz.IntentionDefaultAllow(entCtx)) require.Equal(t, Default, authz.IntentionDefaultAllow(entCtx))
} }
@ -440,6 +488,10 @@ func TestACL(t *testing.T) {
{name: "DenyIntentionDefaultAllow", check: checkDenyIntentionDefaultAllow}, {name: "DenyIntentionDefaultAllow", check: checkDenyIntentionDefaultAllow},
{name: "DenyIntentionRead", check: checkDenyIntentionRead}, {name: "DenyIntentionRead", check: checkDenyIntentionRead},
{name: "DenyIntentionWrite", check: checkDenyIntentionWrite}, {name: "DenyIntentionWrite", check: checkDenyIntentionWrite},
{name: "DenyIdentityRead", check: checkDenyIdentityRead},
{name: "DenyIdentityReadAll", check: checkDenyIdentityReadAll},
{name: "DenyIdentityWrite", check: checkDenyIdentityWrite},
{name: "DenyIdentityWriteAny", check: checkDenyIdentityWriteAny},
{name: "DenyKeyRead", check: checkDenyKeyRead}, {name: "DenyKeyRead", check: checkDenyKeyRead},
{name: "DenyKeyringRead", check: checkDenyKeyringRead}, {name: "DenyKeyringRead", check: checkDenyKeyringRead},
{name: "DenyKeyringWrite", check: checkDenyKeyringWrite}, {name: "DenyKeyringWrite", check: checkDenyKeyringWrite},
@ -458,6 +510,7 @@ func TestACL(t *testing.T) {
{name: "DenyServiceRead", check: checkDenyServiceRead}, {name: "DenyServiceRead", check: checkDenyServiceRead},
{name: "DenyServiceReadAll", check: checkDenyServiceReadAll}, {name: "DenyServiceReadAll", check: checkDenyServiceReadAll},
{name: "DenyServiceWrite", check: checkDenyServiceWrite}, {name: "DenyServiceWrite", check: checkDenyServiceWrite},
{name: "DenyServiceWriteAny", check: checkDenyServiceWriteAny},
{name: "DenySessionRead", check: checkDenySessionRead}, {name: "DenySessionRead", check: checkDenySessionRead},
{name: "DenySessionWrite", check: checkDenySessionWrite}, {name: "DenySessionWrite", check: checkDenySessionWrite},
{name: "DenySnapshot", check: checkDenySnapshot}, {name: "DenySnapshot", check: checkDenySnapshot},
@ -473,6 +526,10 @@ func TestACL(t *testing.T) {
{name: "AllowAgentWrite", check: checkAllowAgentWrite}, {name: "AllowAgentWrite", check: checkAllowAgentWrite},
{name: "AllowEventRead", check: checkAllowEventRead}, {name: "AllowEventRead", check: checkAllowEventRead},
{name: "AllowEventWrite", check: checkAllowEventWrite}, {name: "AllowEventWrite", check: checkAllowEventWrite},
{name: "AllowIdentityRead", check: checkAllowIdentityRead},
{name: "AllowIdentityReadAll", check: checkAllowIdentityReadAll},
{name: "AllowIdentityWrite", check: checkAllowIdentityWrite},
{name: "AllowIdentityWriteAny", check: checkAllowIdentityWriteAny},
{name: "AllowIntentionDefaultAllow", check: checkAllowIntentionDefaultAllow}, {name: "AllowIntentionDefaultAllow", check: checkAllowIntentionDefaultAllow},
{name: "AllowIntentionRead", check: checkAllowIntentionRead}, {name: "AllowIntentionRead", check: checkAllowIntentionRead},
{name: "AllowIntentionWrite", check: checkAllowIntentionWrite}, {name: "AllowIntentionWrite", check: checkAllowIntentionWrite},
@ -494,6 +551,7 @@ func TestACL(t *testing.T) {
{name: "AllowServiceRead", check: checkAllowServiceRead}, {name: "AllowServiceRead", check: checkAllowServiceRead},
{name: "AllowServiceReadAll", check: checkAllowServiceReadAll}, {name: "AllowServiceReadAll", check: checkAllowServiceReadAll},
{name: "AllowServiceWrite", check: checkAllowServiceWrite}, {name: "AllowServiceWrite", check: checkAllowServiceWrite},
{name: "AllowServiceWriteAny", check: checkAllowServiceWriteAny},
{name: "AllowSessionRead", check: checkAllowSessionRead}, {name: "AllowSessionRead", check: checkAllowSessionRead},
{name: "AllowSessionWrite", check: checkAllowSessionWrite}, {name: "AllowSessionWrite", check: checkAllowSessionWrite},
{name: "DenySnapshot", check: checkDenySnapshot}, {name: "DenySnapshot", check: checkDenySnapshot},
@ -509,6 +567,10 @@ func TestACL(t *testing.T) {
{name: "AllowAgentWrite", check: checkAllowAgentWrite}, {name: "AllowAgentWrite", check: checkAllowAgentWrite},
{name: "AllowEventRead", check: checkAllowEventRead}, {name: "AllowEventRead", check: checkAllowEventRead},
{name: "AllowEventWrite", check: checkAllowEventWrite}, {name: "AllowEventWrite", check: checkAllowEventWrite},
{name: "AllowIdentityRead", check: checkAllowIdentityRead},
{name: "AllowIdentityReadAll", check: checkAllowIdentityReadAll},
{name: "AllowIdentityWrite", check: checkAllowIdentityWrite},
{name: "AllowIdentityWriteAny", check: checkAllowIdentityWriteAny},
{name: "AllowIntentionDefaultAllow", check: checkAllowIntentionDefaultAllow}, {name: "AllowIntentionDefaultAllow", check: checkAllowIntentionDefaultAllow},
{name: "AllowIntentionRead", check: checkAllowIntentionRead}, {name: "AllowIntentionRead", check: checkAllowIntentionRead},
{name: "AllowIntentionWrite", check: checkAllowIntentionWrite}, {name: "AllowIntentionWrite", check: checkAllowIntentionWrite},
@ -530,6 +592,7 @@ func TestACL(t *testing.T) {
{name: "AllowServiceRead", check: checkAllowServiceRead}, {name: "AllowServiceRead", check: checkAllowServiceRead},
{name: "AllowServiceReadAll", check: checkAllowServiceReadAll}, {name: "AllowServiceReadAll", check: checkAllowServiceReadAll},
{name: "AllowServiceWrite", check: checkAllowServiceWrite}, {name: "AllowServiceWrite", check: checkAllowServiceWrite},
{name: "AllowServiceWriteAny", check: checkAllowServiceWriteAny},
{name: "AllowSessionRead", check: checkAllowSessionRead}, {name: "AllowSessionRead", check: checkAllowSessionRead},
{name: "AllowSessionWrite", check: checkAllowSessionWrite}, {name: "AllowSessionWrite", check: checkAllowSessionWrite},
{name: "AllowSnapshot", check: checkAllowSnapshot}, {name: "AllowSnapshot", check: checkAllowSnapshot},
@ -905,6 +968,134 @@ func TestACL(t *testing.T) {
{name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowAgentWrite}, {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowAgentWrite},
}, },
}, },
{
name: "IdentityDefaultAllowPolicyDeny",
defaultPolicy: AllowAll(),
policyStack: []*Policy{
{
PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyDeny,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "prefix",
Policy: PolicyDeny,
},
},
},
},
},
checks: []aclCheck{
{name: "IdentityFooReadDenied", prefix: "foo", check: checkDenyIdentityRead},
{name: "IdentityFooWriteDenied", prefix: "foo", check: checkDenyIdentityWrite},
{name: "IdentityPrefixReadDenied", prefix: "prefix", check: checkDenyIdentityRead},
{name: "IdentityPrefixWriteDenied", prefix: "prefix", check: checkDenyIdentityWrite},
{name: "IdentityBarReadAllowed", prefix: "fail", check: checkAllowIdentityRead},
{name: "IdentityBarWriteAllowed", prefix: "fail", check: checkAllowIdentityWrite},
},
},
{
name: "IdentityDefaultDenyPolicyAllow",
defaultPolicy: DenyAll(),
policyStack: []*Policy{
{
PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyWrite,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "prefix",
Policy: PolicyRead,
},
},
},
},
},
checks: []aclCheck{
{name: "IdentityFooReadAllowed", prefix: "foo", check: checkAllowIdentityRead},
{name: "IdentityFooWriteAllowed", prefix: "foo", check: checkAllowIdentityWrite},
{name: "IdentityPrefixReadAllowed", prefix: "prefix", check: checkAllowIdentityRead},
{name: "IdentityPrefixWriteDenied", prefix: "prefix", check: checkDenyIdentityWrite},
{name: "IdentityBarReadDenied", prefix: "fail", check: checkDenyIdentityRead},
{name: "IdentityBarWriteDenied", prefix: "fail", check: checkDenyIdentityWrite},
},
},
{
name: "IdentityDefaultDenyPolicyComplex",
defaultPolicy: DenyAll(),
policyStack: []*Policy{
{
PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "football",
Policy: PolicyRead,
},
{
Name: "prefix-forbidden",
Policy: PolicyDeny,
Intentions: PolicyDeny,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "foo",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
{
Name: "prefix",
Policy: PolicyRead,
Intentions: PolicyWrite,
},
},
},
},
{
PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foozball",
Policy: PolicyWrite,
Intentions: PolicyRead,
},
},
},
},
},
checks: []aclCheck{
{name: "IdentityReadAllowed", prefix: "foo", check: checkAllowIdentityRead},
{name: "IdentityWriteAllowed", prefix: "foo", check: checkAllowIdentityWrite},
{name: "IntentionReadAllowed", prefix: "foo", check: checkAllowIntentionRead},
{name: "IntentionWriteAllowed", prefix: "foo", check: checkAllowIntentionWrite},
{name: "IdentityReadAllowed", prefix: "football", check: checkAllowIdentityRead},
{name: "IdentityWriteDenied", prefix: "football", check: checkDenyIdentityWrite},
{name: "IntentionReadAllowed", prefix: "football", check: checkAllowIntentionRead},
// This might be surprising but omitting intention rule gives at most intention:read
// if we have identity:write perms. This matches services as well.
{name: "IntentionWriteDenied", prefix: "football", check: checkDenyIntentionWrite},
{name: "IdentityReadAllowed", prefix: "prefix", check: checkAllowIdentityRead},
{name: "IdentityWriteDenied", prefix: "prefix", check: checkDenyIdentityWrite},
{name: "IntentionReadAllowed", prefix: "prefix", check: checkAllowIntentionRead},
{name: "IntentionWriteDenied", prefix: "prefix", check: checkAllowIntentionWrite},
{name: "IdentityReadDenied", prefix: "prefix-forbidden", check: checkDenyIdentityRead},
{name: "IdentityWriteDenied", prefix: "prefix-forbidden", check: checkDenyIdentityWrite},
{name: "IntentionReadDenied", prefix: "prefix-forbidden", check: checkDenyIntentionRead},
{name: "IntentionWriteDenied", prefix: "prefix-forbidden", check: checkDenyIntentionWrite},
{name: "IdentityReadAllowed", prefix: "foozball", check: checkAllowIdentityRead},
{name: "IdentityWriteAllowed", prefix: "foozball", check: checkAllowIdentityWrite},
{name: "IntentionReadAllowed", prefix: "foozball", check: checkAllowIntentionRead},
{name: "IntentionWriteDenied", prefix: "foozball", check: checkDenyIntentionWrite},
},
},
{ {
name: "KeyringDefaultAllowPolicyDeny", name: "KeyringDefaultAllowPolicyDeny",
defaultPolicy: AllowAll(), defaultPolicy: AllowAll(),

View File

@ -43,6 +43,7 @@ const (
ResourceACL Resource = "acl" ResourceACL Resource = "acl"
ResourceAgent Resource = "agent" ResourceAgent Resource = "agent"
ResourceEvent Resource = "event" ResourceEvent Resource = "event"
ResourceIdentity Resource = "identity"
ResourceIntention Resource = "intention" ResourceIntention Resource = "intention"
ResourceKey Resource = "key" ResourceKey Resource = "key"
ResourceKeyring Resource = "keyring" ResourceKeyring Resource = "keyring"
@ -77,6 +78,19 @@ type Authorizer interface {
// EventWrite determines if a specific event may be fired. // EventWrite determines if a specific event may be fired.
EventWrite(string, *AuthorizerContext) EnforcementDecision EventWrite(string, *AuthorizerContext) EnforcementDecision
// IdentityRead checks for permission to read a given workload identity.
IdentityRead(string, *AuthorizerContext) EnforcementDecision
// IdentityReadAll checks for permission to read all workload identities.
IdentityReadAll(*AuthorizerContext) EnforcementDecision
// IdentityWrite checks for permission to create or update a given
// workload identity.
IdentityWrite(string, *AuthorizerContext) EnforcementDecision
// IdentityWriteAny checks for write permission on any workload identity.
IdentityWriteAny(*AuthorizerContext) EnforcementDecision
// IntentionDefaultAllow determines the default authorized behavior // IntentionDefaultAllow determines the default authorized behavior
// when no intentions match a Connect request. // when no intentions match a Connect request.
IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision
@ -239,6 +253,40 @@ func (a AllowAuthorizer) EventWriteAllowed(name string, ctx *AuthorizerContext)
return nil return nil
} }
// IdentityReadAllowed checks for permission to read a given workload identity,
func (a AllowAuthorizer) IdentityReadAllowed(name string, ctx *AuthorizerContext) error {
if a.Authorizer.IdentityRead(name, ctx) != Allow {
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessRead, name)
}
return nil
}
// IdentityReadAllAllowed checks for permission to read all workload identities.
func (a AllowAuthorizer) IdentityReadAllAllowed(ctx *AuthorizerContext) error {
if a.Authorizer.IdentityReadAll(ctx) != Allow {
// This is only used to gate certain UI functions right now (e.g metrics)
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessRead, "all identities") // read
}
return nil
}
// IdentityWriteAllowed checks for permission to create or update a given
// workload identity.
func (a AllowAuthorizer) IdentityWriteAllowed(name string, ctx *AuthorizerContext) error {
if a.Authorizer.IdentityWrite(name, ctx) != Allow {
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessWrite, name)
}
return nil
}
// IdentityWriteAnyAllowed checks for write permission on any workload identity
func (a AllowAuthorizer) IdentityWriteAnyAllowed(ctx *AuthorizerContext) error {
if a.Authorizer.IdentityWriteAny(ctx) != Allow {
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessWrite, "any identity")
}
return nil
}
// IntentionDefaultAllowAllowed determines the default authorized behavior // IntentionDefaultAllowAllowed determines the default authorized behavior
// when no intentions match a Connect request. // when no intentions match a Connect request.
func (a AllowAuthorizer) IntentionDefaultAllowAllowed(ctx *AuthorizerContext) error { func (a AllowAuthorizer) IntentionDefaultAllowAllowed(ctx *AuthorizerContext) error {
@ -503,6 +551,13 @@ func Enforce(authz Authorizer, rsc Resource, segment string, access string, ctx
case "write": case "write":
return authz.EventWrite(segment, ctx), nil return authz.EventWrite(segment, ctx), nil
} }
case ResourceIdentity:
switch lowerAccess {
case "read":
return authz.IdentityRead(segment, ctx), nil
case "write":
return authz.IdentityWrite(segment, ctx), nil
}
case ResourceIntention: case ResourceIntention:
switch lowerAccess { switch lowerAccess {
case "read": case "read":

View File

@ -188,6 +188,34 @@ func TestACL_Enforce(t *testing.T) {
ret: Deny, ret: Deny,
err: "Invalid access level", err: "Invalid access level",
}, },
{
method: "IdentityRead",
resource: ResourceIdentity,
segment: "foo",
access: "read",
ret: Deny,
},
{
method: "IdentityRead",
resource: ResourceIdentity,
segment: "foo",
access: "read",
ret: Allow,
},
{
method: "IdentityWrite",
resource: ResourceIdentity,
segment: "foo",
access: "write",
ret: Deny,
},
{
method: "IdentityWrite",
resource: ResourceIdentity,
segment: "foo",
access: "write",
ret: Allow,
},
{ {
method: "IntentionRead", method: "IntentionRead",
resource: ResourceIntention, resource: ResourceIntention,

View File

@ -80,6 +80,35 @@ func (c *ChainedAuthorizer) EventWrite(name string, entCtx *AuthorizerContext) E
}) })
} }
// IdentityRead checks for permission to read a given workload identity.
func (c *ChainedAuthorizer) IdentityRead(name string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IdentityRead(name, entCtx)
})
}
// IdentityReadAll checks for permission to read all workload identities.
func (c *ChainedAuthorizer) IdentityReadAll(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IdentityReadAll(entCtx)
})
}
// IdentityWrite checks for permission to create or update a given
// workload identity.
func (c *ChainedAuthorizer) IdentityWrite(name string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IdentityWrite(name, entCtx)
})
}
// IdentityWriteAny checks for write permission on any workload identity.
func (c *ChainedAuthorizer) IdentityWriteAny(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IdentityWriteAny(entCtx)
})
}
// IntentionDefaultAllow determines the default authorized behavior // IntentionDefaultAllow determines the default authorized behavior
// when no intentions match a Connect request. // when no intentions match a Connect request.
func (c *ChainedAuthorizer) IntentionDefaultAllow(entCtx *AuthorizerContext) EnforcementDecision { func (c *ChainedAuthorizer) IntentionDefaultAllow(entCtx *AuthorizerContext) EnforcementDecision {

View File

@ -29,6 +29,18 @@ func (authz testAuthorizer) EventRead(string, *AuthorizerContext) EnforcementDec
func (authz testAuthorizer) EventWrite(string, *AuthorizerContext) EnforcementDecision { func (authz testAuthorizer) EventWrite(string, *AuthorizerContext) EnforcementDecision {
return EnforcementDecision(authz) return EnforcementDecision(authz)
} }
func (authz testAuthorizer) IdentityRead(string, *AuthorizerContext) EnforcementDecision {
return EnforcementDecision(authz)
}
func (authz testAuthorizer) IdentityReadAll(*AuthorizerContext) EnforcementDecision {
return EnforcementDecision(authz)
}
func (authz testAuthorizer) IdentityWrite(string, *AuthorizerContext) EnforcementDecision {
return EnforcementDecision(authz)
}
func (authz testAuthorizer) IdentityWriteAny(*AuthorizerContext) EnforcementDecision {
return EnforcementDecision(authz)
}
func (authz testAuthorizer) IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision { func (authz testAuthorizer) IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision {
return EnforcementDecision(authz) return EnforcementDecision(authz)
} }

View File

@ -59,6 +59,8 @@ type PolicyRules struct {
ACL string `hcl:"acl,expand"` ACL string `hcl:"acl,expand"`
Agents []*AgentRule `hcl:"agent,expand"` Agents []*AgentRule `hcl:"agent,expand"`
AgentPrefixes []*AgentRule `hcl:"agent_prefix,expand"` AgentPrefixes []*AgentRule `hcl:"agent_prefix,expand"`
Identities []*IdentityRule `hcl:"identity,expand"`
IdentityPrefixes []*IdentityRule `hcl:"identity_prefix,expand"`
Keys []*KeyRule `hcl:"key,expand"` Keys []*KeyRule `hcl:"key,expand"`
KeyPrefixes []*KeyRule `hcl:"key_prefix,expand"` KeyPrefixes []*KeyRule `hcl:"key_prefix,expand"`
Nodes []*NodeRule `hcl:"node,expand"` Nodes []*NodeRule `hcl:"node,expand"`
@ -90,6 +92,19 @@ type AgentRule struct {
Policy string Policy string
} }
// IdentityRule represents a policy for a workload identity
type IdentityRule struct {
Name string `hcl:",key"`
Policy string
// Intentions is the policy for intentions where this workload identity
// is the destination. This may be empty, in which case the Policy determines
// the intentions policy.
Intentions string
EnterpriseRule `hcl:",squash"`
}
// KeyRule represents a rule for a key // KeyRule represents a rule for a key
type KeyRule struct { type KeyRule struct {
Prefix string `hcl:",key"` Prefix string `hcl:",key"`
@ -168,6 +183,30 @@ func (pr *PolicyRules) Validate(conf *Config) error {
} }
} }
// Validate the identity policies
for _, id := range pr.Identities {
if !isPolicyValid(id.Policy, false) {
return fmt.Errorf("Invalid identity policy: %#v", id)
}
if id.Intentions != "" && !isPolicyValid(id.Intentions, false) {
return fmt.Errorf("Invalid identity intentions policy: %#v", id)
}
if err := id.EnterpriseRule.Validate(id.Policy, conf); err != nil {
return fmt.Errorf("Invalid identity enterprise policy: %#v, got error: %v", id, err)
}
}
for _, id := range pr.IdentityPrefixes {
if !isPolicyValid(id.Policy, false) {
return fmt.Errorf("Invalid identity_prefix policy: %#v", id)
}
if id.Intentions != "" && !isPolicyValid(id.Intentions, false) {
return fmt.Errorf("Invalid identity_prefix intentions policy: %#v", id)
}
if err := id.EnterpriseRule.Validate(id.Policy, conf); err != nil {
return fmt.Errorf("Invalid identity_prefix enterprise policy: %#v, got error: %v", id, err)
}
}
// Validate the key policy // Validate the key policy
for _, kp := range pr.Keys { for _, kp := range pr.Keys {
if !isPolicyValid(kp.Policy, true) { if !isPolicyValid(kp.Policy, true) {

View File

@ -14,6 +14,9 @@ type policyAuthorizer struct {
// agentRules contain the exact-match agent policies // agentRules contain the exact-match agent policies
agentRules *radix.Tree agentRules *radix.Tree
// identityRules contains the identity exact-match policies
identityRules *radix.Tree
// intentionRules contains the service intention exact-match policies // intentionRules contains the service intention exact-match policies
intentionRules *radix.Tree intentionRules *radix.Tree
@ -180,6 +183,48 @@ func (p *policyAuthorizer) loadRules(policy *PolicyRules) error {
} }
} }
// Load the identity policy (exact matches)
for _, id := range policy.Identities {
if err := insertPolicyIntoRadix(id.Name, id.Policy, &id.EnterpriseRule, p.identityRules, false); err != nil {
return err
}
intention := id.Intentions
if intention == "" {
switch id.Policy {
case PolicyRead, PolicyWrite:
intention = PolicyRead
default:
intention = PolicyDeny
}
}
if err := insertPolicyIntoRadix(id.Name, intention, &id.EnterpriseRule, p.intentionRules, false); err != nil {
return err
}
}
// Load the identity policy (prefix matches)
for _, id := range policy.IdentityPrefixes {
if err := insertPolicyIntoRadix(id.Name, id.Policy, &id.EnterpriseRule, p.identityRules, true); err != nil {
return err
}
intention := id.Intentions
if intention == "" {
switch id.Policy {
case PolicyRead, PolicyWrite:
intention = PolicyRead
default:
intention = PolicyDeny
}
}
if err := insertPolicyIntoRadix(id.Name, intention, &id.EnterpriseRule, p.intentionRules, true); err != nil {
return err
}
}
// Load the key policy (exact matches) // Load the key policy (exact matches)
for _, kp := range policy.Keys { for _, kp := range policy.Keys {
if err := insertPolicyIntoRadix(kp.Prefix, kp.Policy, &kp.EnterpriseRule, p.keyRules, false); err != nil { if err := insertPolicyIntoRadix(kp.Prefix, kp.Policy, &kp.EnterpriseRule, p.keyRules, false); err != nil {
@ -349,6 +394,7 @@ func newPolicyAuthorizer(policies []*Policy, ent *Config) (*policyAuthorizer, er
func newPolicyAuthorizerFromRules(rules *PolicyRules, ent *Config) (*policyAuthorizer, error) { func newPolicyAuthorizerFromRules(rules *PolicyRules, ent *Config) (*policyAuthorizer, error) {
p := &policyAuthorizer{ p := &policyAuthorizer{
agentRules: radix.New(), agentRules: radix.New(),
identityRules: radix.New(),
intentionRules: radix.New(), intentionRules: radix.New(),
keyRules: radix.New(), keyRules: radix.New(),
nodeRules: radix.New(), nodeRules: radix.New(),
@ -528,6 +574,33 @@ func (p *policyAuthorizer) EventWrite(name string, _ *AuthorizerContext) Enforce
return Default return Default
} }
// IdentityRead checks for permission to read a given workload identity.
func (p *policyAuthorizer) IdentityRead(name string, _ *AuthorizerContext) EnforcementDecision {
if rule, ok := getPolicy(name, p.identityRules); ok {
return enforce(rule.access, AccessRead)
}
return Default
}
// IdentityReadAll checks for permission to read all workload identities.
func (p *policyAuthorizer) IdentityReadAll(_ *AuthorizerContext) EnforcementDecision {
return p.allAllowed(p.identityRules, AccessRead)
}
// IdentityWrite checks for permission to create or update a given
// workload identity.
func (p *policyAuthorizer) IdentityWrite(name string, _ *AuthorizerContext) EnforcementDecision {
if rule, ok := getPolicy(name, p.identityRules); ok {
return enforce(rule.access, AccessWrite)
}
return Default
}
// IdentityWriteAny checks for write permission on any workload identity.
func (p *policyAuthorizer) IdentityWriteAny(_ *AuthorizerContext) EnforcementDecision {
return p.anyAllowed(p.identityRules, AccessWrite)
}
// IntentionDefaultAllow returns whether the default behavior when there are // IntentionDefaultAllow returns whether the default behavior when there are
// no matching intentions is to allow or deny. // no matching intentions is to allow or deny.
func (p *policyAuthorizer) IntentionDefaultAllow(_ *AuthorizerContext) EnforcementDecision { func (p *policyAuthorizer) IntentionDefaultAllow(_ *AuthorizerContext) EnforcementDecision {

View File

@ -41,6 +41,9 @@ func TestPolicyAuthorizer(t *testing.T) {
{name: "DefaultAgentWrite", prefix: "foo", check: checkDefaultAgentWrite}, {name: "DefaultAgentWrite", prefix: "foo", check: checkDefaultAgentWrite},
{name: "DefaultEventRead", prefix: "foo", check: checkDefaultEventRead}, {name: "DefaultEventRead", prefix: "foo", check: checkDefaultEventRead},
{name: "DefaultEventWrite", prefix: "foo", check: checkDefaultEventWrite}, {name: "DefaultEventWrite", prefix: "foo", check: checkDefaultEventWrite},
{name: "DefaultIdentityRead", prefix: "foo", check: checkDefaultIdentityRead},
{name: "DefaultIdentityWrite", prefix: "foo", check: checkDefaultIdentityWrite},
{name: "DefaultIdentityWriteAny", prefix: "", check: checkDefaultIdentityWriteAny},
{name: "DefaultIntentionDefaultAllow", prefix: "foo", check: checkDefaultIntentionDefaultAllow}, {name: "DefaultIntentionDefaultAllow", prefix: "foo", check: checkDefaultIntentionDefaultAllow},
{name: "DefaultIntentionRead", prefix: "foo", check: checkDefaultIntentionRead}, {name: "DefaultIntentionRead", prefix: "foo", check: checkDefaultIntentionRead},
{name: "DefaultIntentionWrite", prefix: "foo", check: checkDefaultIntentionWrite}, {name: "DefaultIntentionWrite", prefix: "foo", check: checkDefaultIntentionWrite},
@ -185,6 +188,29 @@ func TestPolicyAuthorizer(t *testing.T) {
Policy: PolicyRead, Policy: PolicyRead,
}, },
}, },
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
{
Name: "football",
Policy: PolicyDeny,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "foot",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "fo",
Policy: PolicyRead,
Intentions: PolicyRead,
},
},
Keys: []*KeyRule{ Keys: []*KeyRule{
{ {
Prefix: "foo", Prefix: "foo",
@ -371,20 +397,21 @@ func TestPolicyAuthorizer(t *testing.T) {
{name: "ServiceWriteDenied", prefix: "football", check: checkDenyServiceWrite}, {name: "ServiceWriteDenied", prefix: "football", check: checkDenyServiceWrite},
{name: "ServiceWriteAnyAllowed", prefix: "", check: checkAllowServiceWriteAny}, {name: "ServiceWriteAnyAllowed", prefix: "", check: checkAllowServiceWriteAny},
{name: "NodeReadPrefixAllowed", prefix: "fo", check: checkAllowNodeRead}, {name: "IdentityReadPrefixAllowed", prefix: "fo", check: checkAllowIdentityRead},
{name: "NodeWritePrefixDenied", prefix: "fo", check: checkDenyNodeWrite}, {name: "IdentityWritePrefixDenied", prefix: "fo", check: checkDenyIdentityWrite},
{name: "NodeReadPrefixAllowed", prefix: "for", check: checkAllowNodeRead}, {name: "IdentityReadPrefixAllowed", prefix: "for", check: checkAllowIdentityRead},
{name: "NodeWritePrefixDenied", prefix: "for", check: checkDenyNodeWrite}, {name: "IdentityWritePrefixDenied", prefix: "for", check: checkDenyIdentityWrite},
{name: "NodeReadAllowed", prefix: "foo", check: checkAllowNodeRead}, {name: "IdentityReadAllowed", prefix: "foo", check: checkAllowIdentityRead},
{name: "NodeWriteAllowed", prefix: "foo", check: checkAllowNodeWrite}, {name: "IdentityWriteAllowed", prefix: "foo", check: checkAllowIdentityWrite},
{name: "NodeReadPrefixAllowed", prefix: "foot", check: checkAllowNodeRead}, {name: "IdentityReadPrefixAllowed", prefix: "foot", check: checkAllowIdentityRead},
{name: "NodeWritePrefixDenied", prefix: "foot", check: checkDenyNodeWrite}, {name: "IdentityWritePrefixDenied", prefix: "foot", check: checkDenyIdentityWrite},
{name: "NodeReadPrefixAllowed", prefix: "foot2", check: checkAllowNodeRead}, {name: "IdentityReadPrefixAllowed", prefix: "foot2", check: checkAllowIdentityRead},
{name: "NodeWritePrefixDenied", prefix: "foot2", check: checkDenyNodeWrite}, {name: "IdentityWritePrefixDenied", prefix: "foot2", check: checkDenyIdentityWrite},
{name: "NodeReadPrefixAllowed", prefix: "food", check: checkAllowNodeRead}, {name: "IdentityReadPrefixAllowed", prefix: "food", check: checkAllowIdentityRead},
{name: "NodeWritePrefixDenied", prefix: "food", check: checkDenyNodeWrite}, {name: "IdentityWritePrefixDenied", prefix: "food", check: checkDenyIdentityWrite},
{name: "NodeReadDenied", prefix: "football", check: checkDenyNodeRead}, {name: "IdentityReadDenied", prefix: "football", check: checkDenyIdentityRead},
{name: "NodeWriteDenied", prefix: "football", check: checkDenyNodeWrite}, {name: "IdentityWriteDenied", prefix: "football", check: checkDenyIdentityWrite},
{name: "IdentityWriteAnyAllowed", prefix: "", check: checkAllowIdentityWriteAny},
{name: "IntentionReadPrefixAllowed", prefix: "fo", check: checkAllowIntentionRead}, {name: "IntentionReadPrefixAllowed", prefix: "fo", check: checkAllowIntentionRead},
{name: "IntentionWritePrefixDenied", prefix: "fo", check: checkDenyIntentionWrite}, {name: "IntentionWritePrefixDenied", prefix: "fo", check: checkDenyIntentionWrite},

View File

@ -9,6 +9,8 @@ type policyRulesMergeContext struct {
agentPrefixRules map[string]*AgentRule agentPrefixRules map[string]*AgentRule
eventRules map[string]*EventRule eventRules map[string]*EventRule
eventPrefixRules map[string]*EventRule eventPrefixRules map[string]*EventRule
identityRules map[string]*IdentityRule
identityPrefixRules map[string]*IdentityRule
keyringRule string keyringRule string
keyRules map[string]*KeyRule keyRules map[string]*KeyRule
keyPrefixRules map[string]*KeyRule keyPrefixRules map[string]*KeyRule
@ -33,6 +35,8 @@ func (p *policyRulesMergeContext) init() {
p.agentPrefixRules = make(map[string]*AgentRule) p.agentPrefixRules = make(map[string]*AgentRule)
p.eventRules = make(map[string]*EventRule) p.eventRules = make(map[string]*EventRule)
p.eventPrefixRules = make(map[string]*EventRule) p.eventPrefixRules = make(map[string]*EventRule)
p.identityRules = make(map[string]*IdentityRule)
p.identityPrefixRules = make(map[string]*IdentityRule)
p.keyringRule = "" p.keyringRule = ""
p.keyRules = make(map[string]*KeyRule) p.keyRules = make(map[string]*KeyRule)
p.keyPrefixRules = make(map[string]*KeyRule) p.keyPrefixRules = make(map[string]*KeyRule)
@ -98,6 +102,42 @@ func (p *policyRulesMergeContext) merge(policy *PolicyRules) {
} }
} }
for _, id := range policy.Identities {
existing, found := p.identityRules[id.Name]
if !found {
p.identityRules[id.Name] = id
continue
}
if takesPrecedenceOver(id.Policy, existing.Policy) {
existing.Policy = id.Policy
existing.EnterpriseRule = id.EnterpriseRule
}
if takesPrecedenceOver(id.Intentions, existing.Intentions) {
existing.Intentions = id.Intentions
}
}
for _, id := range policy.IdentityPrefixes {
existing, found := p.identityPrefixRules[id.Name]
if !found {
p.identityPrefixRules[id.Name] = id
continue
}
if takesPrecedenceOver(id.Policy, existing.Policy) {
existing.Policy = id.Policy
existing.EnterpriseRule = id.EnterpriseRule
}
if takesPrecedenceOver(id.Intentions, existing.Intentions) {
existing.Intentions = id.Intentions
}
}
if takesPrecedenceOver(policy.Keyring, p.keyringRule) { if takesPrecedenceOver(policy.Keyring, p.keyringRule) {
p.keyringRule = policy.Keyring p.keyringRule = policy.Keyring
} }
@ -269,6 +309,16 @@ func (p *policyRulesMergeContext) fill(merged *PolicyRules) {
merged.EventPrefixes = append(merged.EventPrefixes, policy) merged.EventPrefixes = append(merged.EventPrefixes, policy)
} }
merged.Identities = []*IdentityRule{}
for _, policy := range p.identityRules {
merged.Identities = append(merged.Identities, policy)
}
merged.IdentityPrefixes = []*IdentityRule{}
for _, policy := range p.identityPrefixRules {
merged.IdentityPrefixes = append(merged.IdentityPrefixes, policy)
}
merged.Keys = []*KeyRule{} merged.Keys = []*KeyRule{}
for _, policy := range p.keyRules { for _, policy := range p.keyRules {
merged.Keys = append(merged.Keys, policy) merged.Keys = append(merged.Keys, policy)

View File

@ -42,6 +42,12 @@ func TestPolicySourceParse(t *testing.T) {
event "bar" { event "bar" {
policy = "deny" policy = "deny"
} }
identity_prefix "" {
policy = "write"
}
identity "foo" {
policy = "read"
}
key_prefix "" { key_prefix "" {
policy = "read" policy = "read"
} }
@ -117,6 +123,16 @@ func TestPolicySourceParse(t *testing.T) {
"policy": "deny" "policy": "deny"
} }
}, },
"identity_prefix": {
"": {
"policy": "write"
}
},
"identity": {
"foo": {
"policy": "read"
}
},
"key_prefix": { "key_prefix": {
"": { "": {
"policy": "read" "policy": "read"
@ -217,6 +233,18 @@ func TestPolicySourceParse(t *testing.T) {
Policy: PolicyDeny, Policy: PolicyDeny,
}, },
}, },
IdentityPrefixes: []*IdentityRule{
{
Name: "",
Policy: PolicyWrite,
},
},
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyRead,
},
},
Keyring: PolicyDeny, Keyring: PolicyDeny,
KeyPrefixes: []*KeyRule{ KeyPrefixes: []*KeyRule{
{ {
@ -303,6 +331,39 @@ func TestPolicySourceParse(t *testing.T) {
}, },
}}, }},
}, },
{
Name: "Identity No Intentions",
Rules: `identity "foo" { policy = "write" }`,
RulesJSON: `{ "identity": { "foo": { "policy": "write" }}}`,
Expected: &Policy{PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: "write",
},
},
}},
},
{
Name: "Identity Intentions",
Rules: `identity "foo" { policy = "write" intentions = "read" }`,
RulesJSON: `{ "identity": { "foo": { "policy": "write", "intentions": "read" }}}`,
Expected: &Policy{PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: "write",
Intentions: "read",
},
},
}},
},
{
Name: "Identity Intention: invalid value",
Rules: `identity "foo" { policy = "write" intentions = "foo" }`,
RulesJSON: `{ "identity": { "foo": { "policy": "write", "intentions": "foo" }}}`,
Err: "Invalid identity intentions policy",
},
{ {
Name: "Service No Intentions", Name: "Service No Intentions",
Rules: `service "foo" { policy = "write" }`, Rules: `service "foo" { policy = "write" }`,
@ -354,6 +415,18 @@ func TestPolicySourceParse(t *testing.T) {
RulesJSON: `{ "agent_prefix": { "foo": { "policy": "nope" }}}`, RulesJSON: `{ "agent_prefix": { "foo": { "policy": "nope" }}}`,
Err: "Invalid agent_prefix policy", Err: "Invalid agent_prefix policy",
}, },
{
Name: "Bad Policy - Identity",
Rules: `identity "foo" { policy = "nope" }`,
RulesJSON: `{ "identity": { "foo": { "policy": "nope" }}}`,
Err: "Invalid identity policy",
},
{
Name: "Bad Policy - Identity Prefix",
Rules: `identity_prefix "foo" { policy = "nope" }`,
RulesJSON: `{ "identity_prefix": { "foo": { "policy": "nope" }}}`,
Err: "Invalid identity_prefix policy",
},
{ {
Name: "Bad Policy - Key", Name: "Bad Policy - Key",
Rules: `key "foo" { policy = "nope" }`, Rules: `key "foo" { policy = "nope" }`,
@ -685,6 +758,109 @@ func TestMergePolicies(t *testing.T) {
}, },
}}, }},
}, },
{
name: "Identities",
input: []*Policy{
{PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
{
Name: "bar",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "baz",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "000",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
{
Name: "111",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "222",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
},
}},
{PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "baz",
Policy: PolicyDeny,
Intentions: PolicyDeny,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "000",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "222",
Policy: PolicyDeny,
Intentions: PolicyDeny,
},
},
}},
},
expected: &Policy{PolicyRules: PolicyRules{
Identities: []*IdentityRule{
{
Name: "foo",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
{
Name: "bar",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "baz",
Policy: PolicyDeny,
Intentions: PolicyDeny,
},
},
IdentityPrefixes: []*IdentityRule{
{
Name: "000",
Policy: PolicyWrite,
Intentions: PolicyWrite,
},
{
Name: "111",
Policy: PolicyRead,
Intentions: PolicyRead,
},
{
Name: "222",
Policy: PolicyDeny,
Intentions: PolicyDeny,
},
},
}},
},
{ {
name: "Node", name: "Node",
input: []*Policy{ input: []*Policy{

View File

@ -75,6 +75,34 @@ func (s *staticAuthorizer) EventWrite(string, *AuthorizerContext) EnforcementDec
return Deny return Deny
} }
func (s *staticAuthorizer) IdentityRead(string, *AuthorizerContext) EnforcementDecision {
if s.defaultAllow {
return Allow
}
return Deny
}
func (s *staticAuthorizer) IdentityReadAll(*AuthorizerContext) EnforcementDecision {
if s.defaultAllow {
return Allow
}
return Deny
}
func (s *staticAuthorizer) IdentityWrite(string, *AuthorizerContext) EnforcementDecision {
if s.defaultAllow {
return Allow
}
return Deny
}
func (s *staticAuthorizer) IdentityWriteAny(*AuthorizerContext) EnforcementDecision {
if s.defaultAllow {
return Allow
}
return Deny
}
func (s *staticAuthorizer) IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision { func (s *staticAuthorizer) IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision {
if s.defaultAllow { if s.defaultAllow {
return Allow return Allow

View File

@ -2190,7 +2190,7 @@ func TestACL_Authorize(t *testing.T) {
policyReq := structs.ACLPolicySetRequest{ policyReq := structs.ACLPolicySetRequest{
Policy: structs.ACLPolicy{ Policy: structs.ACLPolicy{
Name: "test", Name: "test",
Rules: `acl = "read" operator = "write" service_prefix "" { policy = "read"} node_prefix "" { policy= "write" } key_prefix "/foo" { policy = "write" } `, Rules: `acl = "read" operator = "write" identity_prefix "" { policy = "read"} service_prefix "" { policy = "read"} node_prefix "" { policy= "write" } key_prefix "/foo" { policy = "write" } `,
}, },
Datacenter: "dc1", Datacenter: "dc1",
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken}, WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
@ -2276,6 +2276,16 @@ func TestACL_Authorize(t *testing.T) {
Segment: "foo", Segment: "foo",
Access: "write", Access: "write",
}, },
{
Resource: "identity",
Segment: "foo",
Access: "read",
},
{
Resource: "identity",
Segment: "foo",
Access: "write",
},
{ {
Resource: "intention", Resource: "intention",
Segment: "foo", Segment: "foo",
@ -2426,6 +2436,16 @@ func TestACL_Authorize(t *testing.T) {
Segment: "foo", Segment: "foo",
Access: "write", Access: "write",
}, },
{
Resource: "identity",
Segment: "foo",
Access: "read",
},
{
Resource: "identity",
Segment: "foo",
Access: "write",
},
{ {
Resource: "intention", Resource: "intention",
Segment: "foo", Segment: "foo",
@ -2532,6 +2552,8 @@ func TestACL_Authorize(t *testing.T) {
false, // agent:write false, // agent:write
false, // event:read false, // event:read
false, // event:write false, // event:write
true, // identity:read
false, // identity:write
true, // intentions:read true, // intentions:read
false, // intention:write false, // intention:write
false, // key:read false, // key:read

View File

@ -615,10 +615,6 @@ func (d *ACLResolverTestDelegate) ACLDatacenter() string {
return d.datacenter return d.datacenter
} }
func (d *ACLResolverTestDelegate) UseLegacyACLs() bool {
return d.legacy
}
func (d *ACLResolverTestDelegate) ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error) { func (d *ACLResolverTestDelegate) ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error) {
if !d.localTokens { if !d.localTokens {
return false, nil, nil return false, nil, nil
@ -731,7 +727,6 @@ func TestACLResolver_Disabled(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: false, enabled: false,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
} }
r := newTestACLResolver(t, delegate, nil) r := newTestACLResolver(t, delegate, nil)
@ -746,7 +741,6 @@ func TestACLResolver_ResolveRootACL(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
} }
r := newTestACLResolver(t, delegate, nil) r := newTestACLResolver(t, delegate, nil)
@ -797,7 +791,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -825,7 +818,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -853,7 +845,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -889,7 +880,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -920,7 +910,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -971,7 +960,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -1002,7 +990,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1038,7 +1025,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1070,7 +1056,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1117,7 +1102,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1159,7 +1143,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1194,7 +1177,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1230,7 +1212,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -1276,7 +1257,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
@ -1340,7 +1320,6 @@ func TestACLResolver_DownPolicy(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
@ -1398,7 +1377,6 @@ func TestACLResolver_DatacenterScoping(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -1418,7 +1396,6 @@ func TestACLResolver_DatacenterScoping(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc2", datacenter: "dc2",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -1454,7 +1431,6 @@ func TestACLResolver_Client(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
@ -1545,7 +1521,6 @@ func TestACLResolver_Client(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
@ -1608,7 +1583,6 @@ func TestACLResolver_Client_TokensPoliciesAndRoles(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: false, localPolicies: false,
localRoles: false, localRoles: false,
@ -1625,7 +1599,6 @@ func TestACLResolver_LocalTokensPoliciesAndRoles(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: true, localTokens: true,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,
@ -1641,7 +1614,6 @@ func TestACLResolver_LocalPoliciesAndRoles(t *testing.T) {
delegate := &ACLResolverTestDelegate{ delegate := &ACLResolverTestDelegate{
enabled: true, enabled: true,
datacenter: "dc1", datacenter: "dc1",
legacy: false,
localTokens: false, localTokens: false,
localPolicies: true, localPolicies: true,
localRoles: true, localRoles: true,

View File

@ -63,6 +63,10 @@ agent_prefix "" {
event_prefix "" { event_prefix "" {
policy = "%[1]s" policy = "%[1]s"
} }
identity_prefix "" {
policy = "%[1]s"
intentions = "%[1]s"
}
key_prefix "" { key_prefix "" {
policy = "%[1]s" policy = "%[1]s"
} }