open-consul/agent/consul/state/acl_test.go

1635 lines
48 KiB
Go
Raw Normal View History

package state
import (
"testing"
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
"time"
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs"
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
"github.com/stretchr/testify/require"
)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
func setupGlobalManagement(t *testing.T, s *Store) {
policy := structs.ACLPolicy{
ID: structs.ACLPolicyGlobalManagementID,
Name: "global-management",
Description: "Builtin Policy that grants unlimited access",
Rules: structs.ACLPolicyGlobalManagement,
Syntax: acl.SyntaxCurrent,
}
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
policy.SetHash(true)
require.NoError(t, s.ACLPolicySet(1, &policy))
}
func setupAnonymous(t *testing.T, s *Store) {
token := structs.ACLToken{
AccessorID: structs.ACLTokenAnonymousID,
SecretID: "anonymous",
Description: "Anonymous Token",
}
token.SetHash(true)
require.NoError(t, s.ACLTokenSet(1, &token, false))
}
func testACLStateStore(t *testing.T) *Store {
s := testStateStore(t)
setupGlobalManagement(t, s)
setupAnonymous(t, s)
return s
}
func setupExtraPolicies(t *testing.T, s *Store) {
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
Name: "node-read",
Description: "Allows reading all node information",
Rules: `node_prefix "" { policy = "read" }`,
Syntax: acl.SyntaxCurrent,
},
}
for _, policy := range policies {
policy.SetHash(true)
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
}
func testACLTokensStateStore(t *testing.T) *Store {
s := testACLStateStore(t)
setupExtraPolicies(t, s)
return s
}
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
func TestStateStore_ACLBootstrap(t *testing.T) {
t.Parallel()
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
token1 := &structs.ACLToken{
AccessorID: "30fca056-9fbb-4455-b94a-bf0e2bc575d6",
SecretID: "cbe1c6fd-d865-4034-9d6d-64fef7fb46a9",
Description: "Bootstrap Token (Global Management)",
Policies: []structs.ACLTokenPolicyLink{
{
ID: structs.ACLPolicyGlobalManagementID,
},
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
},
CreateTime: time.Now(),
Local: false,
// DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs
Type: structs.ACLTokenTypeManagement,
}
token2 := &structs.ACLToken{
AccessorID: "fd5c17fa-1503-4422-a424-dd44cdf35919",
SecretID: "7fd776b1-ded1-4d15-931b-db4770fc2317",
Description: "Bootstrap Token (Global Management)",
Policies: []structs.ACLTokenPolicyLink{
{
ID: structs.ACLPolicyGlobalManagementID,
},
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
},
CreateTime: time.Now(),
Local: false,
// DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs
Type: structs.ACLTokenTypeManagement,
}
stripIrrelevantFields := func(token *structs.ACLToken) *structs.ACLToken {
tokenCopy := token.Clone()
// When comparing the tokens disregard the policy link names. This
// data is not cleanly updated in a variety of scenarios and should not
// be relied upon.
for i, _ := range tokenCopy.Policies {
tokenCopy.Policies[i].Name = ""
}
// The raft indexes won't match either because the requester will not
// have access to that.
tokenCopy.RaftIndex = structs.RaftIndex{}
return tokenCopy
}
compareTokens := func(expected, actual *structs.ACLToken) {
require.Equal(t, stripIrrelevantFields(expected), stripIrrelevantFields(actual))
}
s := testStateStore(t)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
setupGlobalManagement(t, s)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
canBootstrap, index, err := s.CanBootstrapACLToken()
require.NoError(t, err)
require.True(t, canBootstrap)
require.Equal(t, uint64(0), index)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
// Perform a regular bootstrap.
require.NoError(t, s.ACLBootstrap(3, 0, token1.Clone(), false))
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
// Make sure we can't bootstrap again
canBootstrap, index, err = s.CanBootstrapACLToken()
require.NoError(t, err)
require.False(t, canBootstrap)
require.Equal(t, uint64(3), index)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
// Make sure another attempt fails.
err = s.ACLBootstrap(4, 0, token2.Clone(), false)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.Error(t, err)
require.Equal(t, structs.ACLBootstrapNotAllowedErr, err)
// Check that the bootstrap state remains the same.
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
canBootstrap, index, err = s.CanBootstrapACLToken()
require.NoError(t, err)
require.False(t, canBootstrap)
require.Equal(t, uint64(3), index)
// Make sure the ACLs are in an expected state.
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
_, tokens, err := s.ACLTokenList(nil, true, true, "")
require.NoError(t, err)
require.Len(t, tokens, 1)
compareTokens(token1, tokens[0])
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
// bootstrap reset
err = s.ACLBootstrap(32, index-1, token2.Clone(), false)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.Error(t, err)
require.Equal(t, structs.ACLBootstrapInvalidResetIndexErr, err)
// bootstrap reset
err = s.ACLBootstrap(32, index, token2.Clone(), false)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.NoError(t, err)
_, tokens, err = s.ACLTokenList(nil, true, true, "")
require.NoError(t, err)
require.Len(t, tokens, 2)
}
func TestStateStore_ACLToken_SetGet_Legacy(t *testing.T) {
t.Parallel()
t.Run("Legacy - Existing With Policies", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "c8d0378c-566a-4535-8fc9-c883a8cc9849",
SecretID: "6d48ce91-2558-4098-bdab-8737e4e57d5f",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
}
require.NoError(t, s.ACLTokenSet(2, token, false))
// legacy flag is set so it should disallow setting this token
err := s.ACLTokenSet(3, token, true)
require.Error(t, err)
})
t.Run("Legacy - Empty Type", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "271cd056-0038-4fd3-90e5-f97f50fb3ac8",
SecretID: "c0056225-5785-43b3-9b77-3954f06d6aee",
}
require.NoError(t, s.ACLTokenSet(2, token, false))
// legacy flag is set so it should disallow setting this token
err := s.ACLTokenSet(3, token, true)
require.Error(t, err)
})
t.Run("Legacy - New", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
SecretID: "2989e271-6169-4f34-8fec-4618d70008fb",
Type: structs.ACLTokenTypeClient,
Rules: `service "" { policy = "read" }`,
}
require.NoError(t, s.ACLTokenSet(2, token, true))
idx, rtoken, err := s.ACLTokenGetBySecret(nil, token.SecretID)
require.NoError(t, err)
require.Equal(t, uint64(2), idx)
require.NotNil(t, rtoken)
require.Equal(t, "", rtoken.AccessorID)
require.Equal(t, "2989e271-6169-4f34-8fec-4618d70008fb", rtoken.SecretID)
require.Equal(t, "", rtoken.Description)
require.Len(t, rtoken.Policies, 0)
require.Equal(t, structs.ACLTokenTypeClient, rtoken.Type)
require.Equal(t, uint64(2), rtoken.CreateIndex)
require.Equal(t, uint64(2), rtoken.ModifyIndex)
})
t.Run("Legacy - Update", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
original := &structs.ACLToken{
SecretID: "2989e271-6169-4f34-8fec-4618d70008fb",
Type: structs.ACLTokenTypeClient,
Rules: `service "" { policy = "read" }`,
}
require.NoError(t, s.ACLTokenSet(2, original, true))
updatedRules := `service "" { policy = "read" } service "foo" { policy = "deny"}`
update := &structs.ACLToken{
SecretID: "2989e271-6169-4f34-8fec-4618d70008fb",
Type: structs.ACLTokenTypeClient,
Rules: updatedRules,
}
require.NoError(t, s.ACLTokenSet(3, update, true))
idx, rtoken, err := s.ACLTokenGetBySecret(nil, original.SecretID)
require.NoError(t, err)
require.Equal(t, uint64(3), idx)
require.NotNil(t, rtoken)
require.Equal(t, "", rtoken.AccessorID)
require.Equal(t, "2989e271-6169-4f34-8fec-4618d70008fb", rtoken.SecretID)
require.Equal(t, "", rtoken.Description)
require.Len(t, rtoken.Policies, 0)
require.Equal(t, structs.ACLTokenTypeClient, rtoken.Type)
require.Equal(t, updatedRules, rtoken.Rules)
require.Equal(t, uint64(2), rtoken.CreateIndex)
require.Equal(t, uint64(3), rtoken.ModifyIndex)
})
}
func TestStateStore_ACLToken_SetGet(t *testing.T) {
t.Parallel()
t.Run("Missing Secret", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "39171632-6f34-4411-827f-9416403687f4",
}
err := s.ACLTokenSet(2, token, false)
require.Error(t, err)
require.Equal(t, ErrMissingACLTokenSecret, err)
})
t.Run("Missing Accessor", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
SecretID: "39171632-6f34-4411-827f-9416403687f4",
}
err := s.ACLTokenSet(2, token, false)
require.Error(t, err)
require.Equal(t, ErrMissingACLTokenAccessor, err)
})
t.Run("Missing Policy ID", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
SecretID: "39171632-6f34-4411-827f-9416403687f4",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
Name: "no-id",
},
},
}
err := s.ACLTokenSet(2, token, false)
require.Error(t, err)
})
t.Run("Unresolvable Policy ID", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
SecretID: "39171632-6f34-4411-827f-9416403687f4",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "4f20e379-b496-4b99-9599-19a197126490",
},
},
}
err := s.ACLTokenSet(2, token, false)
require.Error(t, err)
})
t.Run("New", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
SecretID: "39171632-6f34-4411-827f-9416403687f4",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
}
require.NoError(t, s.ACLTokenSet(2, token, false))
idx, rtoken, err := s.ACLTokenGetByAccessor(nil, "daf37c07-d04d-4fd5-9678-a8206a57d61a")
require.NoError(t, err)
require.Equal(t, uint64(2), idx)
// pointer equality
require.True(t, rtoken == token)
require.Equal(t, uint64(2), rtoken.CreateIndex)
require.Equal(t, uint64(2), rtoken.ModifyIndex)
require.Len(t, rtoken.Policies, 1)
require.Equal(t, "node-read", rtoken.Policies[0].Name)
})
t.Run("Update", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
SecretID: "39171632-6f34-4411-827f-9416403687f4",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
}
require.NoError(t, s.ACLTokenSet(2, token, false))
updated := &structs.ACLToken{
AccessorID: "daf37c07-d04d-4fd5-9678-a8206a57d61a",
SecretID: "39171632-6f34-4411-827f-9416403687f4",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
}
require.NoError(t, s.ACLTokenSet(3, updated, false))
idx, rtoken, err := s.ACLTokenGetByAccessor(nil, "daf37c07-d04d-4fd5-9678-a8206a57d61a")
require.NoError(t, err)
require.Equal(t, uint64(3), idx)
// pointer equality
require.True(t, rtoken == updated)
require.Equal(t, uint64(2), rtoken.CreateIndex)
require.Equal(t, uint64(3), rtoken.ModifyIndex)
require.Len(t, rtoken.Policies, 1)
require.Equal(t, structs.ACLPolicyGlobalManagementID, rtoken.Policies[0].ID)
require.Equal(t, "global-management", rtoken.Policies[0].Name)
})
}
func TestStateStore_ACLTokens_UpsertBatchRead(t *testing.T) {
t.Parallel()
t.Run("CAS - Deleted", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
// CAS op + nonexistent token should not work. This prevents modifying
// deleted tokens
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
RaftIndex: structs.RaftIndex{CreateIndex: 2, ModifyIndex: 3},
},
}
require.NoError(t, s.ACLTokenBatchSet(2, tokens, true))
_, token, err := s.ACLTokenGetByAccessor(nil, tokens[0].AccessorID)
require.NoError(t, err)
require.Nil(t, token)
})
t.Run("CAS - Updated", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
// CAS op + nonexistent token should not work. This prevents modifying
// deleted tokens
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
},
}
require.NoError(t, s.ACLTokenBatchSet(5, tokens, true))
updated := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
Description: "wont update",
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 4},
},
}
require.NoError(t, s.ACLTokenBatchSet(6, updated, true))
_, token, err := s.ACLTokenGetByAccessor(nil, tokens[0].AccessorID)
require.NoError(t, err)
require.NotNil(t, token)
require.Equal(t, "", token.Description)
})
t.Run("CAS - Already Exists", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
},
}
require.NoError(t, s.ACLTokenBatchSet(5, tokens, true))
updated := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
Description: "wont update",
},
}
require.NoError(t, s.ACLTokenBatchSet(6, updated, true))
_, token, err := s.ACLTokenGetByAccessor(nil, tokens[0].AccessorID)
require.NoError(t, err)
require.NotNil(t, token)
require.Equal(t, "", token.Description)
})
t.Run("Normal", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
},
&structs.ACLToken{
AccessorID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
SecretID: "ff826eaf-4b88-4881-aaef-52b1089e5d5d",
},
}
require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
idx, rtokens, err := s.ACLTokenBatchGet(nil, []string{
"a4f68bd6-3af5-4f56-b764-3c6f20247879",
"a2719052-40b3-4a4b-baeb-f3df1831a217"})
require.NoError(t, err)
require.Equal(t, uint64(2), idx)
require.Len(t, rtokens, 2)
require.ElementsMatch(t, tokens, rtokens)
require.Equal(t, uint64(2), rtokens[0].CreateIndex)
require.Equal(t, uint64(2), rtokens[0].ModifyIndex)
require.Equal(t, uint64(2), rtokens[1].CreateIndex)
require.Equal(t, uint64(2), rtokens[1].ModifyIndex)
})
t.Run("Update", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
},
&structs.ACLToken{
AccessorID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
SecretID: "ff826eaf-4b88-4881-aaef-52b1089e5d5d",
},
}
require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
updates := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
SecretID: "00ff4564-dd96-4d1b-8ad6-578a08279f79",
Description: "first token",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
},
&structs.ACLToken{
AccessorID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
SecretID: "ff826eaf-4b88-4881-aaef-52b1089e5d5d",
Description: "second token",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
}
require.NoError(t, s.ACLTokenBatchSet(3, updates, false))
idx, rtokens, err := s.ACLTokenBatchGet(nil, []string{
"a4f68bd6-3af5-4f56-b764-3c6f20247879",
"a2719052-40b3-4a4b-baeb-f3df1831a217"})
require.NoError(t, err)
require.Equal(t, uint64(3), idx)
require.Len(t, rtokens, 2)
rtokens.Sort()
require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", rtokens[0].AccessorID)
require.Equal(t, "ff826eaf-4b88-4881-aaef-52b1089e5d5d", rtokens[0].SecretID)
require.Equal(t, "second token", rtokens[0].Description)
require.Len(t, rtokens[0].Policies, 1)
require.Equal(t, structs.ACLPolicyGlobalManagementID, rtokens[0].Policies[0].ID)
require.Equal(t, "global-management", rtokens[0].Policies[0].Name)
require.Equal(t, uint64(2), rtokens[0].CreateIndex)
require.Equal(t, uint64(3), rtokens[0].ModifyIndex)
require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", rtokens[1].AccessorID)
require.Equal(t, "00ff4564-dd96-4d1b-8ad6-578a08279f79", rtokens[1].SecretID)
require.Equal(t, "first token", rtokens[1].Description)
require.Len(t, rtokens[1].Policies, 1)
require.Equal(t, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286", rtokens[1].Policies[0].ID)
require.Equal(t, "node-read", rtokens[1].Policies[0].Name)
require.Equal(t, uint64(2), rtokens[1].CreateIndex)
require.Equal(t, uint64(3), rtokens[1].ModifyIndex)
})
}
func TestStateStore_ACLTokens_ListUpgradeable(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
require.NoError(t, s.ACLTokenSet(2, &structs.ACLToken{
SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Type: structs.ACLTokenTypeManagement,
}, true))
require.NoError(t, s.ACLTokenSet(3, &structs.ACLToken{
SecretID: "8de2dd39-134d-4cb1-950b-b7ab96ea20ba",
Type: structs.ACLTokenTypeManagement,
}, true))
require.NoError(t, s.ACLTokenSet(4, &structs.ACLToken{
SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
Type: structs.ACLTokenTypeManagement,
}, true))
require.NoError(t, s.ACLTokenSet(5, &structs.ACLToken{
SecretID: "3ee33676-d9b8-4144-bf0b-92618cff438b",
Type: structs.ACLTokenTypeManagement,
}, true))
require.NoError(t, s.ACLTokenSet(6, &structs.ACLToken{
SecretID: "fa9d658a-6e26-42ab-a5f0-1ea05c893dee",
Type: structs.ACLTokenTypeManagement,
}, true))
tokens, _, err := s.ACLTokenListUpgradeable(3)
require.NoError(t, err)
require.Len(t, tokens, 3)
tokens, _, err = s.ACLTokenListUpgradeable(10)
require.NoError(t, err)
require.Len(t, tokens, 5)
updates := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
&structs.ACLToken{
AccessorID: "54866514-3cf2-4fec-8a8a-710583831834",
SecretID: "8de2dd39-134d-4cb1-950b-b7ab96ea20ba",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
&structs.ACLToken{
AccessorID: "47eea4da-bda1-48a6-901c-3e36d2d9262f",
SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
&structs.ACLToken{
AccessorID: "af1dffe5-8ac2-4282-9336-aeed9f7d951a",
SecretID: "3ee33676-d9b8-4144-bf0b-92618cff438b",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
&structs.ACLToken{
AccessorID: "511df589-3316-4784-b503-6e25ead4d4e1",
SecretID: "fa9d658a-6e26-42ab-a5f0-1ea05c893dee",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
}
require.NoError(t, s.ACLTokenBatchSet(7, updates, false))
tokens, _, err = s.ACLTokenListUpgradeable(10)
require.NoError(t, err)
require.Len(t, tokens, 0)
}
func TestStateStore_ACLToken_List(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
tokens := structs.ACLTokens{
// the local token
&structs.ACLToken{
AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
Local: true,
},
// the global token
&structs.ACLToken{
AccessorID: "54866514-3cf2-4fec-8a8a-710583831834",
SecretID: "8de2dd39-134d-4cb1-950b-b7ab96ea20ba",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
},
// the policy specific token
&structs.ACLToken{
AccessorID: "47eea4da-bda1-48a6-901c-3e36d2d9262f",
SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
},
// the policy specific token and local
&structs.ACLToken{
AccessorID: "4915fc9d-3726-4171-b588-6c271f45eecd",
SecretID: "f6998577-fd9b-4e6c-b202-cc3820513d32",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
Local: true,
},
}
require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
type testCase struct {
name string
local bool
global bool
policy string
accessors []string
}
cases := []testCase{
{
name: "Global",
local: false,
global: true,
policy: "",
accessors: []string{
structs.ACLTokenAnonymousID,
"47eea4da-bda1-48a6-901c-3e36d2d9262f",
"54866514-3cf2-4fec-8a8a-710583831834",
},
},
{
name: "Local",
local: true,
global: false,
policy: "",
accessors: []string{
"4915fc9d-3726-4171-b588-6c271f45eecd",
"f1093997-b6c7-496d-bfb8-6b1b1895641b",
},
},
{
name: "Policy",
local: true,
global: true,
policy: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
accessors: []string{
"47eea4da-bda1-48a6-901c-3e36d2d9262f",
"4915fc9d-3726-4171-b588-6c271f45eecd",
},
},
{
name: "Policy - Local",
local: true,
global: false,
policy: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
accessors: []string{
"4915fc9d-3726-4171-b588-6c271f45eecd",
},
},
{
name: "Policy - Global",
local: false,
global: true,
policy: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
accessors: []string{
"47eea4da-bda1-48a6-901c-3e36d2d9262f",
},
},
{
name: "All",
local: true,
global: true,
policy: "",
accessors: []string{
structs.ACLTokenAnonymousID,
"47eea4da-bda1-48a6-901c-3e36d2d9262f",
"4915fc9d-3726-4171-b588-6c271f45eecd",
"54866514-3cf2-4fec-8a8a-710583831834",
"f1093997-b6c7-496d-bfb8-6b1b1895641b",
},
},
}
for _, tc := range cases {
tc := tc // capture range variable
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
_, tokens, err := s.ACLTokenList(nil, tc.local, tc.global, tc.policy)
require.NoError(t, err)
require.Len(t, tokens, len(tc.accessors))
tokens.Sort()
for i, token := range tokens {
require.Equal(t, tc.accessors[i], token.AccessorID)
}
})
}
}
func TestStateStore_ACLToken_FixupPolicyLinks(t *testing.T) {
// This test wants to ensure a couple of things.
//
// 1. Doing a token list/get should never modify the data
// tracked by memdb
// 2. Token list/get operations should return an accurate set
// of policy links
t.Parallel()
s := testACLTokensStateStore(t)
// the policy specific token
token := &structs.ACLToken{
AccessorID: "47eea4da-bda1-48a6-901c-3e36d2d9262f",
SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
},
},
}
require.NoError(t, s.ACLTokenSet(2, token, false))
_, retrieved, err := s.ACLTokenGetByAccessor(nil, token.AccessorID)
require.NoError(t, err)
// pointer equality check these should be identical
require.True(t, token == retrieved)
require.Len(t, retrieved.Policies, 1)
require.Equal(t, "node-read", retrieved.Policies[0].Name)
// rename the policy
renamed := &structs.ACLPolicy{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
Name: "node-read-renamed",
Description: "Allows reading all node information",
Rules: `node_prefix "" { policy = "read" }`,
Syntax: acl.SyntaxCurrent,
}
renamed.SetHash(true)
require.NoError(t, s.ACLPolicySet(3, renamed))
// retrieve the token again
_, retrieved, err = s.ACLTokenGetByAccessor(nil, token.AccessorID)
require.NoError(t, err)
// pointer equality check these should be different if we cloned things appropriately
require.True(t, token != retrieved)
require.Len(t, retrieved.Policies, 1)
require.Equal(t, "node-read-renamed", retrieved.Policies[0].Name)
// list tokens without stale links
_, tokens, err := s.ACLTokenList(nil, true, true, "")
require.NoError(t, err)
found := false
for _, tok := range tokens {
if tok.AccessorID == token.AccessorID {
// these pointers shouldn't be equal because the link should have been fixed
require.True(t, tok != token)
require.Len(t, tok.Policies, 1)
require.Equal(t, "node-read-renamed", tok.Policies[0].Name)
found = true
break
}
}
require.True(t, found)
// batch get without stale links
_, tokens, err = s.ACLTokenBatchGet(nil, []string{token.AccessorID})
require.NoError(t, err)
found = false
for _, tok := range tokens {
if tok.AccessorID == token.AccessorID {
// these pointers shouldn't be equal because the link should have been fixed
require.True(t, tok != token)
require.Len(t, tok.Policies, 1)
require.Equal(t, "node-read-renamed", tok.Policies[0].Name)
found = true
break
}
}
require.True(t, found)
// delete the policy
require.NoError(t, s.ACLPolicyDeleteByID(4, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286"))
// retrieve the token again
_, retrieved, err = s.ACLTokenGetByAccessor(nil, token.AccessorID)
require.NoError(t, err)
// pointer equality check these should be different if we cloned things appropriately
require.True(t, token != retrieved)
require.Len(t, retrieved.Policies, 0)
// list tokens without stale links
_, tokens, err = s.ACLTokenList(nil, true, true, "")
require.NoError(t, err)
found = false
for _, tok := range tokens {
if tok.AccessorID == token.AccessorID {
// these pointers shouldn't be equal because the link should have been fixed
require.True(t, tok != token)
require.Len(t, tok.Policies, 0)
found = true
break
}
}
require.True(t, found)
// batch get without stale links
_, tokens, err = s.ACLTokenBatchGet(nil, []string{token.AccessorID})
require.NoError(t, err)
found = false
for _, tok := range tokens {
if tok.AccessorID == token.AccessorID {
// these pointers shouldn't be equal because the link should have been fixed
require.True(t, tok != token)
require.Len(t, tok.Policies, 0)
found = true
break
}
}
require.True(t, found)
}
func TestStateStore_ACLToken_Delete(t *testing.T) {
t.Parallel()
t.Run("Accessor", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
Local: true,
}
require.NoError(t, s.ACLTokenSet(2, token, false))
_, rtoken, err := s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.NotNil(t, rtoken)
require.NoError(t, s.ACLTokenDeleteByAccessor(3, "f1093997-b6c7-496d-bfb8-6b1b1895641b"))
_, rtoken, err = s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.Nil(t, rtoken)
})
t.Run("Secret", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
token := &structs.ACLToken{
AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
Local: true,
}
require.NoError(t, s.ACLTokenSet(2, token, false))
_, rtoken, err := s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.NotNil(t, rtoken)
require.NoError(t, s.ACLTokenDeleteBySecret(3, "34ec8eb3-095d-417a-a937-b439af7a8e8b"))
_, rtoken, err = s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.Nil(t, rtoken)
})
t.Run("Multiple", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
Local: true,
},
&structs.ACLToken{
AccessorID: "a0bfe8d4-b2f3-4b48-b387-f28afb820eab",
SecretID: "be444e46-fb95-4ccc-80d5-c873f34e6fa6",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: structs.ACLPolicyGlobalManagementID,
},
},
Local: true,
},
}
require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
_, rtoken, err := s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.NotNil(t, rtoken)
_, rtoken, err = s.ACLTokenGetByAccessor(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
require.NoError(t, err)
require.NotNil(t, rtoken)
require.NoError(t, s.ACLTokenBatchDelete(2, []string{
"f1093997-b6c7-496d-bfb8-6b1b1895641b",
"a0bfe8d4-b2f3-4b48-b387-f28afb820eab"}))
_, rtoken, err = s.ACLTokenGetByAccessor(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.Nil(t, rtoken)
_, rtoken, err = s.ACLTokenGetByAccessor(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
require.NoError(t, err)
require.Nil(t, rtoken)
})
t.Run("Anonymous", func(t *testing.T) {
t.Parallel()
s := testACLTokensStateStore(t)
require.Error(t, s.ACLTokenDeleteByAccessor(3, structs.ACLTokenAnonymousID))
require.Error(t, s.ACLTokenDeleteBySecret(3, "anonymous"))
})
t.Run("Not Found", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
// deletion of non-existent policies is not an error
require.NoError(t, s.ACLTokenDeleteByAccessor(3, "ea58a09c-2100-4aef-816b-8ee0ade77dcd"))
require.NoError(t, s.ACLTokenDeleteBySecret(3, "376d0cae-dd50-4213-9668-2c7797a7fb2d"))
})
}
func TestStateStore_ACLPolicy_SetGet(t *testing.T) {
t.Parallel()
t.Run("Missing ID", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policy := structs.ACLPolicy{
Name: "test-policy",
Description: "test",
Rules: `keyring = "write"`,
}
require.Error(t, s.ACLPolicySet(3, &policy))
})
t.Run("Missing Name", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policy := structs.ACLPolicy{
ID: "2c74a9b8-271c-4a21-b727-200db397c01c",
Description: "test",
Rules: `keyring = "write"`,
}
require.Error(t, s.ACLPolicySet(3, &policy))
})
t.Run("Global Management", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
t.Run("Rules", func(t *testing.T) {
t.Parallel()
policy := structs.ACLPolicy{
ID: structs.ACLPolicyGlobalManagementID,
Name: "global-management",
Description: "Global Management",
Rules: `acl = "write"`,
}
require.Error(t, s.ACLPolicySet(3, &policy))
})
t.Run("Datacenters", func(t *testing.T) {
t.Parallel()
policy := structs.ACLPolicy{
ID: structs.ACLPolicyGlobalManagementID,
Name: "global-management",
Description: "Global Management",
Rules: structs.ACLPolicyGlobalManagement,
Datacenters: []string{"dc1"},
}
require.Error(t, s.ACLPolicySet(3, &policy))
})
t.Run("Change", func(t *testing.T) {
t.Parallel()
policy := structs.ACLPolicy{
ID: structs.ACLPolicyGlobalManagementID,
Name: "management",
Description: "Modified",
Rules: structs.ACLPolicyGlobalManagement,
}
require.NoError(t, s.ACLPolicySet(3, &policy))
_, rpolicy, err := s.ACLPolicyGetByName(nil, "management")
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.Equal(t, structs.ACLPolicyGlobalManagementID, rpolicy.ID)
require.Equal(t, "management", rpolicy.Name)
require.Equal(t, "Modified", rpolicy.Description)
require.Equal(t, uint64(1), rpolicy.CreateIndex)
require.Equal(t, uint64(3), rpolicy.ModifyIndex)
})
})
t.Run("New", func(t *testing.T) {
t.Parallel()
// this actually creates a new policy - we just need to verify it.
s := testACLStateStore(t)
policy := structs.ACLPolicy{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
Name: "node-read",
Description: "Allows reading all node information",
Rules: `node_prefix "" { policy = "read" }`,
Syntax: acl.SyntaxCurrent,
Datacenters: []string{"dc1"},
}
require.NoError(t, s.ACLPolicySet(3, &policy))
idx, rpolicy, err := s.ACLPolicyGetByID(nil, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286")
require.Equal(t, uint64(3), idx)
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.Equal(t, "node-read", rpolicy.Name)
require.Equal(t, "Allows reading all node information", rpolicy.Description)
require.Equal(t, `node_prefix "" { policy = "read" }`, rpolicy.Rules)
require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax)
require.Len(t, rpolicy.Datacenters, 1)
require.Equal(t, "dc1", rpolicy.Datacenters[0])
require.Equal(t, uint64(3), rpolicy.CreateIndex)
require.Equal(t, uint64(3), rpolicy.ModifyIndex)
// also verify the global management policy that testACLStateStore Set while we are at it.
idx, rpolicy, err = s.ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID)
require.Equal(t, uint64(3), idx)
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.Equal(t, "global-management", rpolicy.Name)
require.Equal(t, "Builtin Policy that grants unlimited access", rpolicy.Description)
require.Equal(t, structs.ACLPolicyGlobalManagement, rpolicy.Rules)
require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax)
require.Len(t, rpolicy.Datacenters, 0)
require.Equal(t, uint64(1), rpolicy.CreateIndex)
require.Equal(t, uint64(1), rpolicy.ModifyIndex)
})
t.Run("Update", func(t *testing.T) {
t.Parallel()
// this creates the node read policy which we can update
s := testACLTokensStateStore(t)
update := structs.ACLPolicy{
ID: "a0625e95-9b3e-42de-a8d6-ceef5b6f3286",
Name: "node-read-modified",
Description: "Modified",
Rules: `node_prefix "" { policy = "read" } node "secret" { policy = "deny" }`,
Syntax: acl.SyntaxCurrent,
Datacenters: []string{"dc1", "dc2"},
}
require.NoError(t, s.ACLPolicySet(3, &update))
idx, rpolicy, err := s.ACLPolicyGetByID(nil, "a0625e95-9b3e-42de-a8d6-ceef5b6f3286")
require.Equal(t, uint64(3), idx)
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.Equal(t, "node-read-modified", rpolicy.Name)
require.Equal(t, "Modified", rpolicy.Description)
require.Equal(t, `node_prefix "" { policy = "read" } node "secret" { policy = "deny" }`, rpolicy.Rules)
require.Equal(t, acl.SyntaxCurrent, rpolicy.Syntax)
require.ElementsMatch(t, []string{"dc1", "dc2"}, rpolicy.Datacenters)
require.Equal(t, uint64(2), rpolicy.CreateIndex)
require.Equal(t, uint64(3), rpolicy.ModifyIndex)
})
}
func TestStateStore_ACLPolicy_UpsertBatchRead(t *testing.T) {
t.Parallel()
t.Run("Normal", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
Name: "service-read",
Rules: `service_prefix "" { policy = "read" }`,
},
&structs.ACLPolicy{
ID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
Name: "acl-write-dc3",
Description: "Can manage ACLs in dc3",
Datacenters: []string{"dc3"},
Rules: `acl = "write"`,
},
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
idx, rpolicies, err := s.ACLPolicyBatchGet(nil, []string{
"a4f68bd6-3af5-4f56-b764-3c6f20247879",
"a2719052-40b3-4a4b-baeb-f3df1831a217"})
require.NoError(t, err)
require.Equal(t, uint64(2), idx)
require.Len(t, rpolicies, 2)
require.ElementsMatch(t, policies, rpolicies)
require.Equal(t, uint64(2), rpolicies[0].CreateIndex)
require.Equal(t, uint64(2), rpolicies[0].ModifyIndex)
require.Equal(t, uint64(2), rpolicies[1].CreateIndex)
require.Equal(t, uint64(2), rpolicies[1].ModifyIndex)
})
t.Run("Update", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
Name: "service-read",
Rules: `service_prefix "" { policy = "read" }`,
},
&structs.ACLPolicy{
ID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
Name: "acl-write-dc3",
Description: "Can manage ACLs in dc3",
Datacenters: []string{"dc3"},
Rules: `acl = "write"`,
},
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
updates := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
Name: "service-write",
Rules: `service_prefix "" { policy = "write" }`,
Datacenters: []string{"dc1"},
},
&structs.ACLPolicy{
ID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
Name: "acl-write",
Description: "Modified",
Rules: `acl = "write"`,
},
}
require.NoError(t, s.ACLPolicyBatchSet(3, updates))
idx, rpolicies, err := s.ACLPolicyBatchGet(nil, []string{
"a4f68bd6-3af5-4f56-b764-3c6f20247879",
"a2719052-40b3-4a4b-baeb-f3df1831a217"})
require.NoError(t, err)
require.Equal(t, uint64(3), idx)
require.Len(t, rpolicies, 2)
rpolicies.Sort()
require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", rpolicies[0].ID)
require.Equal(t, "acl-write", rpolicies[0].Name)
require.Equal(t, "Modified", rpolicies[0].Description)
require.Equal(t, `acl = "write"`, rpolicies[0].Rules)
require.Empty(t, rpolicies[0].Datacenters)
require.Equal(t, uint64(2), rpolicies[0].CreateIndex)
require.Equal(t, uint64(3), rpolicies[0].ModifyIndex)
require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", rpolicies[1].ID)
require.Equal(t, "service-write", rpolicies[1].Name)
require.Equal(t, "", rpolicies[1].Description)
require.Equal(t, `service_prefix "" { policy = "write" }`, rpolicies[1].Rules)
require.ElementsMatch(t, []string{"dc1"}, rpolicies[1].Datacenters)
require.Equal(t, uint64(2), rpolicies[1].CreateIndex)
require.Equal(t, uint64(3), rpolicies[1].ModifyIndex)
})
}
func TestStateStore_ACLPolicy_List(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "a4f68bd6-3af5-4f56-b764-3c6f20247879",
Name: "service-read",
Rules: `service_prefix "" { policy = "read" }`,
},
&structs.ACLPolicy{
ID: "a2719052-40b3-4a4b-baeb-f3df1831a217",
Name: "acl-write-dc3",
Description: "Can manage ACLs in dc3",
Datacenters: []string{"dc3"},
Rules: `acl = "write"`,
},
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
_, policies, err := s.ACLPolicyList(nil)
require.NoError(t, err)
require.Len(t, policies, 3)
policies.Sort()
require.Equal(t, structs.ACLPolicyGlobalManagementID, policies[0].ID)
require.Equal(t, "global-management", policies[0].Name)
require.Equal(t, "Builtin Policy that grants unlimited access", policies[0].Description)
require.Empty(t, policies[0].Datacenters)
require.NotEqual(t, []byte{}, policies[0].Hash)
require.Equal(t, uint64(1), policies[0].CreateIndex)
require.Equal(t, uint64(1), policies[0].ModifyIndex)
require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", policies[1].ID)
require.Equal(t, "acl-write-dc3", policies[1].Name)
require.Equal(t, "Can manage ACLs in dc3", policies[1].Description)
require.ElementsMatch(t, []string{"dc3"}, policies[1].Datacenters)
require.Nil(t, policies[1].Hash)
require.Equal(t, uint64(2), policies[1].CreateIndex)
require.Equal(t, uint64(2), policies[1].ModifyIndex)
require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", policies[2].ID)
require.Equal(t, "service-read", policies[2].Name)
require.Equal(t, "", policies[2].Description)
require.Empty(t, policies[2].Datacenters)
require.Nil(t, policies[2].Hash)
require.Equal(t, uint64(2), policies[2].CreateIndex)
require.Equal(t, uint64(2), policies[2].ModifyIndex)
}
func TestStateStore_ACLPolicy_Delete(t *testing.T) {
t.Parallel()
t.Run("ID", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policy := &structs.ACLPolicy{
ID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
Name: "test-policy",
Rules: `acl = "read"`,
}
require.NoError(t, s.ACLPolicySet(2, policy))
_, rpolicy, err := s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.NoError(t, s.ACLPolicyDeleteByID(3, "f1093997-b6c7-496d-bfb8-6b1b1895641b"))
require.NoError(t, err)
_, rpolicy, err = s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.Nil(t, rpolicy)
})
t.Run("Name", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policy := &structs.ACLPolicy{
ID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
Name: "test-policy",
Rules: `acl = "read"`,
}
require.NoError(t, s.ACLPolicySet(2, policy))
_, rpolicy, err := s.ACLPolicyGetByName(nil, "test-policy")
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.NoError(t, s.ACLPolicyDeleteByName(3, "test-policy"))
require.NoError(t, err)
_, rpolicy, err = s.ACLPolicyGetByName(nil, "test-policy")
require.NoError(t, err)
require.Nil(t, rpolicy)
})
t.Run("Multiple", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "f1093997-b6c7-496d-bfb8-6b1b1895641b",
Name: "34ec8eb3-095d-417a-a937-b439af7a8e8b",
Rules: `acl = "read"`,
},
&structs.ACLPolicy{
ID: "a0bfe8d4-b2f3-4b48-b387-f28afb820eab",
Name: "be444e46-fb95-4ccc-80d5-c873f34e6fa6",
Rules: `acl = "write"`,
},
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
_, rpolicy, err := s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.NotNil(t, rpolicy)
_, rpolicy, err = s.ACLPolicyGetByID(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
require.NoError(t, err)
require.NotNil(t, rpolicy)
require.NoError(t, s.ACLPolicyBatchDelete(3, []string{
"f1093997-b6c7-496d-bfb8-6b1b1895641b",
"a0bfe8d4-b2f3-4b48-b387-f28afb820eab"}))
_, rpolicy, err = s.ACLPolicyGetByID(nil, "f1093997-b6c7-496d-bfb8-6b1b1895641b")
require.NoError(t, err)
require.Nil(t, rpolicy)
_, rpolicy, err = s.ACLPolicyGetByID(nil, "a0bfe8d4-b2f3-4b48-b387-f28afb820eab")
require.NoError(t, err)
require.Nil(t, rpolicy)
})
t.Run("Global-Management", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
require.Error(t, s.ACLPolicyDeleteByID(5, structs.ACLPolicyGlobalManagementID))
require.Error(t, s.ACLPolicyDeleteByName(5, "global-management"))
})
t.Run("Not Found", func(t *testing.T) {
t.Parallel()
s := testACLStateStore(t)
// deletion of non-existent policies is not an error
require.NoError(t, s.ACLPolicyDeleteByName(3, "not-found"))
require.NoError(t, s.ACLPolicyDeleteByID(3, "376d0cae-dd50-4213-9668-2c7797a7fb2d"))
})
}
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
func TestStateStore_ACLTokens_Snapshot_Restore(t *testing.T) {
s := testStateStore(t)
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "ca1fc52c-3676-4050-82ed-ca223e38b2c9",
Name: "policy1",
Description: "policy1",
Rules: `node_prefix "" { policy = "read" }`,
Syntax: acl.SyntaxCurrent,
},
&structs.ACLPolicy{
ID: "7b70fa0f-58cd-412d-93c3-a0f17bb19a3e",
Name: "policy2",
Description: "policy2",
Rules: `acl = "read"`,
Syntax: acl.SyntaxCurrent,
},
}
for _, policy := range policies {
policy.SetHash(true)
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "68016c3d-835b-450c-a6f9-75db9ba740be",
SecretID: "838f72b5-5c15-4a9e-aa6d-31734c3a0286",
Description: "token1",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "ca1fc52c-3676-4050-82ed-ca223e38b2c9",
Name: "policy1",
},
structs.ACLTokenPolicyLink{
ID: "7b70fa0f-58cd-412d-93c3-a0f17bb19a3e",
Name: "policy2",
},
},
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
Hash: []byte{1, 2, 3, 4},
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
},
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
&structs.ACLToken{
AccessorID: "b2125a1b-2a52-41d4-88f3-c58761998a46",
SecretID: "ba5d9239-a4ab-49b9-ae09-1f19eed92204",
Description: "token2",
Policies: []structs.ACLTokenPolicyLink{
structs.ACLTokenPolicyLink{
ID: "ca1fc52c-3676-4050-82ed-ca223e38b2c9",
Name: "policy1",
},
structs.ACLTokenPolicyLink{
ID: "7b70fa0f-58cd-412d-93c3-a0f17bb19a3e",
Name: "policy2",
},
},
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
Hash: []byte{1, 2, 3, 4},
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
},
}
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.NoError(t, s.ACLTokenBatchSet(2, tokens, false))
// Snapshot the ACLs.
snap := s.Snapshot()
defer snap.Close()
// Alter the real state store.
require.NoError(t, s.ACLTokenDeleteByAccessor(3, tokens[0].AccessorID))
// Verify the snapshot.
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.Equal(t, uint64(2), snap.LastIndex())
iter, err := snap.ACLTokens()
require.NoError(t, err)
var dump structs.ACLTokens
for token := iter.Next(); token != nil; token = iter.Next() {
dump = append(dump, token.(*structs.ACLToken))
}
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.ElementsMatch(t, dump, tokens)
// Restore the values into a new state store.
func() {
s := testStateStore(t)
restore := s.Restore()
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
for _, token := range dump {
require.NoError(t, restore.ACLToken(token))
}
restore.Commit()
// need to ensure we have the policies or else the links will be removed
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
// Read the restored ACLs back out and verify that they match.
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
idx, res, err := s.ACLTokenList(nil, true, true, "")
require.NoError(t, err)
require.Equal(t, uint64(2), idx)
require.ElementsMatch(t, tokens, res)
require.Equal(t, uint64(2), s.maxIndex("acl-tokens"))
}()
}
func TestStateStore_ACLPolicies_Snapshot_Restore(t *testing.T) {
s := testStateStore(t)
policies := structs.ACLPolicies{
&structs.ACLPolicy{
ID: "68016c3d-835b-450c-a6f9-75db9ba740be",
Name: "838f72b5-5c15-4a9e-aa6d-31734c3a0286",
Description: "policy1",
Rules: `acl = "read"`,
Hash: []byte{1, 2, 3, 4},
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
},
&structs.ACLPolicy{
ID: "b2125a1b-2a52-41d4-88f3-c58761998a46",
Name: "ba5d9239-a4ab-49b9-ae09-1f19eed92204",
Description: "policy2",
Rules: `operator = "read"`,
Hash: []byte{1, 2, 3, 4},
RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2},
},
}
require.NoError(t, s.ACLPolicyBatchSet(2, policies))
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
// Snapshot the ACLs.
snap := s.Snapshot()
defer snap.Close()
// Alter the real state store.
require.NoError(t, s.ACLPolicyDeleteByID(3, policies[0].ID))
// Verify the snapshot.
require.Equal(t, uint64(2), snap.LastIndex())
iter, err := snap.ACLPolicies()
require.NoError(t, err)
var dump structs.ACLPolicies
for policy := iter.Next(); policy != nil; policy = iter.Next() {
dump = append(dump, policy.(*structs.ACLPolicy))
}
require.ElementsMatch(t, dump, policies)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
// Restore the values into a new state store.
func() {
s := testStateStore(t)
restore := s.Restore()
for _, policy := range dump {
require.NoError(t, restore.ACLPolicy(policy))
}
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
restore.Commit()
// Read the restored ACLs back out and verify that they match.
idx, res, err := s.ACLPolicyList(nil)
New ACLs (#4791) This PR is almost a complete rewrite of the ACL system within Consul. It brings the features more in line with other HashiCorp products. Obviously there is quite a bit left to do here but most of it is related docs, testing and finishing the last few commands in the CLI. I will update the PR description and check off the todos as I finish them over the next few days/week. Description At a high level this PR is mainly to split ACL tokens from Policies and to split the concepts of Authorization from Identities. A lot of this PR is mostly just to support CRUD operations on ACLTokens and ACLPolicies. These in and of themselves are not particularly interesting. The bigger conceptual changes are in how tokens get resolved, how backwards compatibility is handled and the separation of policy from identity which could lead the way to allowing for alternative identity providers. On the surface and with a new cluster the ACL system will look very similar to that of Nomads. Both have tokens and policies. Both have local tokens. The ACL management APIs for both are very similar. I even ripped off Nomad's ACL bootstrap resetting procedure. There are a few key differences though. Nomad requires token and policy replication where Consul only requires policy replication with token replication being opt-in. In Consul local tokens only work with token replication being enabled though. All policies in Nomad are globally applicable. In Consul all policies are stored and replicated globally but can be scoped to a subset of the datacenters. This allows for more granular access management. Unlike Nomad, Consul has legacy baggage in the form of the original ACL system. The ramifications of this are: A server running the new system must still support other clients using the legacy system. A client running the new system must be able to use the legacy RPCs when the servers in its datacenter are running the legacy system. The primary ACL DC's servers running in legacy mode needs to be a gate that keeps everything else in the entire multi-DC cluster running in legacy mode. So not only does this PR implement the new ACL system but has a legacy mode built in for when the cluster isn't ready for new ACLs. Also detecting that new ACLs can be used is automatic and requires no configuration on the part of administrators. This process is detailed more in the "Transitioning from Legacy to New ACL Mode" section below.
2018-10-19 16:04:07 +00:00
require.NoError(t, err)
require.Equal(t, uint64(2), idx)
require.ElementsMatch(t, policies, res)
require.Equal(t, uint64(2), s.maxIndex("acl-policies"))
}()
}