mirror of https://github.com/status-im/consul.git
Merge pull request #12670 from hashicorp/token-read-expanded
oss: Add expanded token read flag and endpoint option
This commit is contained in:
commit
059bd0a92e
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
cli: The `token read` command now supports the `-expanded` flag to display detailed role and policy information for the token.
|
||||||
|
```
|
|
@ -378,6 +378,9 @@ func (s *HTTPHandlers) ACLTokenGet(resp http.ResponseWriter, req *http.Request,
|
||||||
if err := s.parseEntMeta(req, &args.EnterpriseMeta); err != nil {
|
if err := s.parseEntMeta(req, &args.EnterpriseMeta); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if _, ok := req.URL.Query()["expanded"]; ok {
|
||||||
|
args.Expanded = true
|
||||||
|
}
|
||||||
|
|
||||||
if args.Datacenter == "" {
|
if args.Datacenter == "" {
|
||||||
args.Datacenter = s.agent.config.Datacenter
|
args.Datacenter = s.agent.config.Datacenter
|
||||||
|
@ -393,6 +396,14 @@ func (s *HTTPHandlers) ACLTokenGet(resp http.ResponseWriter, req *http.Request,
|
||||||
return nil, acl.ErrNotFound
|
return nil, acl.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.Expanded {
|
||||||
|
expanded := &structs.ACLTokenExpanded{
|
||||||
|
ACLToken: out.Token,
|
||||||
|
ExpandedTokenInfo: out.ExpandedTokenInfo,
|
||||||
|
}
|
||||||
|
return expanded, nil
|
||||||
|
}
|
||||||
|
|
||||||
return out.Token, nil
|
return out.Token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -724,6 +724,17 @@ func TestACL_HTTP(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, expected, token)
|
require.Equal(t, expected, token)
|
||||||
})
|
})
|
||||||
|
t.Run("Read-expanded", func(t *testing.T) {
|
||||||
|
expected := tokenMap[idMap["token-test"]]
|
||||||
|
req, _ := http.NewRequest("GET", "/v1/acl/token/"+expected.AccessorID+"?token=root&expanded=true", nil)
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
obj, err := a.srv.ACLTokenCRUD(resp, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
tokenResp, ok := obj.(*structs.ACLTokenExpanded)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, expected, tokenResp.ACLToken)
|
||||||
|
require.Len(t, tokenResp.ExpandedPolicies, 3)
|
||||||
|
})
|
||||||
t.Run("Self", func(t *testing.T) {
|
t.Run("Self", func(t *testing.T) {
|
||||||
expected := tokenMap[idMap["token-test"]]
|
expected := tokenMap[idMap["token-test"]]
|
||||||
req, _ := http.NewRequest("GET", "/v1/acl/token/self?token="+expected.SecretID, nil)
|
req, _ := http.NewRequest("GET", "/v1/acl/token/self?token="+expected.SecretID, nil)
|
||||||
|
|
|
@ -325,10 +325,99 @@ func (a *ACL) TokenRead(args *structs.ACLTokenGetRequest, reply *structs.ACLToke
|
||||||
if token == nil {
|
if token == nil {
|
||||||
return errNotFound
|
return errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.Expanded {
|
||||||
|
info, err := a.lookupExpandedTokenInfo(ws, state, token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reply.ExpandedTokenInfo = info
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ACL) lookupExpandedTokenInfo(ws memdb.WatchSet, state *state.Store, token *structs.ACLToken) (structs.ExpandedTokenInfo, error) {
|
||||||
|
policyIDs := make(map[string]struct{})
|
||||||
|
roleIDs := make(map[string]struct{})
|
||||||
|
identityPolicies := make(map[string]*structs.ACLPolicy)
|
||||||
|
tokenInfo := structs.ExpandedTokenInfo{}
|
||||||
|
|
||||||
|
// Add the token's policies and node/service identity policies
|
||||||
|
for _, policy := range token.Policies {
|
||||||
|
policyIDs[policy.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, roleLink := range token.Roles {
|
||||||
|
roleIDs[roleLink.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, identity := range token.ServiceIdentities {
|
||||||
|
policy := identity.SyntheticPolicy(&token.EnterpriseMeta)
|
||||||
|
identityPolicies[policy.ID] = policy
|
||||||
|
}
|
||||||
|
for _, identity := range token.NodeIdentities {
|
||||||
|
policy := identity.SyntheticPolicy(&token.EnterpriseMeta)
|
||||||
|
identityPolicies[policy.ID] = policy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any namespace default roles/policies to look up
|
||||||
|
nsPolicies, nsRoles, err := getTokenNamespaceDefaults(ws, state, &token.EnterpriseMeta)
|
||||||
|
if err != nil {
|
||||||
|
return tokenInfo, err
|
||||||
|
}
|
||||||
|
tokenInfo.NamespaceDefaultPolicyIDs = nsPolicies
|
||||||
|
tokenInfo.NamespaceDefaultRoleIDs = nsRoles
|
||||||
|
for _, id := range nsPolicies {
|
||||||
|
policyIDs[id] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, id := range nsRoles {
|
||||||
|
roleIDs[id] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add each role's policies and node/service identity policies
|
||||||
|
for roleID := range roleIDs {
|
||||||
|
_, role, err := state.ACLRoleGetByID(ws, roleID, &token.EnterpriseMeta)
|
||||||
|
if err != nil {
|
||||||
|
return tokenInfo, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, policy := range role.Policies {
|
||||||
|
policyIDs[policy.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, identity := range role.ServiceIdentities {
|
||||||
|
policy := identity.SyntheticPolicy(&role.EnterpriseMeta)
|
||||||
|
identityPolicies[policy.ID] = policy
|
||||||
|
}
|
||||||
|
for _, identity := range role.NodeIdentities {
|
||||||
|
policy := identity.SyntheticPolicy(&role.EnterpriseMeta)
|
||||||
|
identityPolicies[policy.ID] = policy
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenInfo.ExpandedRoles = append(tokenInfo.ExpandedRoles, role)
|
||||||
|
}
|
||||||
|
|
||||||
|
var policies []*structs.ACLPolicy
|
||||||
|
for id := range policyIDs {
|
||||||
|
_, policy, err := state.ACLPolicyGetByID(ws, id, &token.EnterpriseMeta)
|
||||||
|
if err != nil {
|
||||||
|
return tokenInfo, err
|
||||||
|
}
|
||||||
|
policies = append(policies, policy)
|
||||||
|
}
|
||||||
|
for _, policy := range identityPolicies {
|
||||||
|
policies = append(policies, policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenInfo.ExpandedPolicies = policies
|
||||||
|
tokenInfo.AgentACLDefaultPolicy = a.srv.config.ACLResolverSettings.ACLDefaultPolicy
|
||||||
|
tokenInfo.AgentACLDownPolicy = a.srv.config.ACLResolverSettings.ACLDownPolicy
|
||||||
|
tokenInfo.ResolvedByAgent = a.srv.config.NodeName
|
||||||
|
|
||||||
|
return tokenInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *ACL) TokenClone(args *structs.ACLTokenSetRequest, reply *structs.ACLToken) error {
|
func (a *ACL) TokenClone(args *structs.ACLTokenSetRequest, reply *structs.ACLToken) error {
|
||||||
if err := a.aclPreCheck(); err != nil {
|
if err := a.aclPreCheck(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -5,7 +5,9 @@ package consul
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/consul/agent/consul/authmethod"
|
"github.com/hashicorp/consul/agent/consul/authmethod"
|
||||||
|
"github.com/hashicorp/consul/agent/consul/state"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
memdb "github.com/hashicorp/go-memdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *ACL) tokenUpsertValidateEnterprise(token *structs.ACLToken, existing *structs.ACLToken) error {
|
func (a *ACL) tokenUpsertValidateEnterprise(token *structs.ACLToken, existing *structs.ACLToken) error {
|
||||||
|
@ -37,3 +39,7 @@ func computeTargetEnterpriseMeta(
|
||||||
) (*structs.EnterpriseMeta, error) {
|
) (*structs.EnterpriseMeta, error) {
|
||||||
return &structs.EnterpriseMeta{}, nil
|
return &structs.EnterpriseMeta{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTokenNamespaceDefaults(ws memdb.WatchSet, state *state.Store, entMeta *structs.EnterpriseMeta) ([]string, []string, error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
|
@ -204,6 +204,181 @@ func TestACLEndpoint_TokenRead(t *testing.T) {
|
||||||
require.Nil(t, resp.Token)
|
require.Nil(t, resp.Token)
|
||||||
require.EqualError(t, err, "failed acl token lookup: index error: UUID must be 36 characters")
|
require.EqualError(t, err, "failed acl token lookup: index error: UUID must be 36 characters")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("expanded output with role/policy", func(t *testing.T) {
|
||||||
|
p1, err := upsertTestPolicy(codec, TestDefaultInitialManagementToken, "dc1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
p2, err := upsertTestPolicy(codec, TestDefaultInitialManagementToken, "dc1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r1, err := upsertTestCustomizedRole(codec, TestDefaultInitialManagementToken, "dc1", func(role *structs.ACLRole) {
|
||||||
|
role.Policies = []structs.ACLRolePolicyLink{
|
||||||
|
{
|
||||||
|
ID: p2.ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
setReq := structs.ACLTokenSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
ACLToken: structs.ACLToken{
|
||||||
|
Description: "foobar",
|
||||||
|
Policies: []structs.ACLTokenPolicyLink{
|
||||||
|
{
|
||||||
|
ID: p1.ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Roles: []structs.ACLTokenRoleLink{
|
||||||
|
{
|
||||||
|
ID: r1.ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Local: false,
|
||||||
|
},
|
||||||
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
|
||||||
|
setResp := structs.ACLToken{}
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ACL.TokenSet", &setReq, &setResp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, setResp.AccessorID)
|
||||||
|
|
||||||
|
req := structs.ACLTokenGetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
TokenID: setResp.AccessorID,
|
||||||
|
TokenIDType: structs.ACLTokenAccessor,
|
||||||
|
Expanded: true,
|
||||||
|
QueryOptions: structs.QueryOptions{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
resp := structs.ACLTokenResponse{}
|
||||||
|
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ACL.TokenRead", &req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp.Token)
|
||||||
|
require.ElementsMatch(t, []*structs.ACLPolicy{p1, p2}, resp.ExpandedPolicies)
|
||||||
|
require.ElementsMatch(t, []*structs.ACLRole{r1}, resp.ExpandedRoles)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("expanded output with multiple roles that share a policy", func(t *testing.T) {
|
||||||
|
p1, err := upsertTestPolicy(codec, TestDefaultInitialManagementToken, "dc1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r1, err := upsertTestCustomizedRole(codec, TestDefaultInitialManagementToken, "dc1", func(role *structs.ACLRole) {
|
||||||
|
role.Policies = []structs.ACLRolePolicyLink{
|
||||||
|
{
|
||||||
|
ID: p1.ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r2, err := upsertTestCustomizedRole(codec, TestDefaultInitialManagementToken, "dc1", func(role *structs.ACLRole) {
|
||||||
|
role.Policies = []structs.ACLRolePolicyLink{
|
||||||
|
{
|
||||||
|
ID: p1.ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
setReq := structs.ACLTokenSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
ACLToken: structs.ACLToken{
|
||||||
|
Description: "foobar",
|
||||||
|
Roles: []structs.ACLTokenRoleLink{
|
||||||
|
{
|
||||||
|
ID: r1.ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: r2.ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Local: false,
|
||||||
|
},
|
||||||
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
|
||||||
|
setResp := structs.ACLToken{}
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ACL.TokenSet", &setReq, &setResp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, setResp.AccessorID)
|
||||||
|
|
||||||
|
req := structs.ACLTokenGetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
TokenID: setResp.AccessorID,
|
||||||
|
TokenIDType: structs.ACLTokenAccessor,
|
||||||
|
Expanded: true,
|
||||||
|
QueryOptions: structs.QueryOptions{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
resp := structs.ACLTokenResponse{}
|
||||||
|
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ACL.TokenRead", &req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp.Token)
|
||||||
|
require.ElementsMatch(t, []*structs.ACLPolicy{p1}, resp.ExpandedPolicies)
|
||||||
|
require.ElementsMatch(t, []*structs.ACLRole{r1, r2}, resp.ExpandedRoles)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("expanded output with node/service identities", func(t *testing.T) {
|
||||||
|
setReq := structs.ACLTokenSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
ACLToken: structs.ACLToken{
|
||||||
|
Description: "foobar",
|
||||||
|
ServiceIdentities: []*structs.ACLServiceIdentity{
|
||||||
|
{
|
||||||
|
ServiceName: "web",
|
||||||
|
Datacenters: []string{"dc1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ServiceName: "db",
|
||||||
|
Datacenters: []string{"dc2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NodeIdentities: []*structs.ACLNodeIdentity{
|
||||||
|
{
|
||||||
|
NodeName: "foo",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NodeName: "bar",
|
||||||
|
Datacenter: "dc1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Local: false,
|
||||||
|
},
|
||||||
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedPolicies []*structs.ACLPolicy
|
||||||
|
entMeta := structs.DefaultEnterpriseMetaInDefaultPartition()
|
||||||
|
for _, serviceIdentity := range setReq.ACLToken.ServiceIdentities {
|
||||||
|
expectedPolicies = append(expectedPolicies, serviceIdentity.SyntheticPolicy(entMeta))
|
||||||
|
}
|
||||||
|
for _, serviceIdentity := range setReq.ACLToken.NodeIdentities {
|
||||||
|
expectedPolicies = append(expectedPolicies, serviceIdentity.SyntheticPolicy(entMeta))
|
||||||
|
}
|
||||||
|
|
||||||
|
setResp := structs.ACLToken{}
|
||||||
|
err := msgpackrpc.CallWithCodec(codec, "ACL.TokenSet", &setReq, &setResp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, setResp.AccessorID)
|
||||||
|
|
||||||
|
req := structs.ACLTokenGetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
TokenID: setResp.AccessorID,
|
||||||
|
TokenIDType: structs.ACLTokenAccessor,
|
||||||
|
Expanded: true,
|
||||||
|
QueryOptions: structs.QueryOptions{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
resp := structs.ACLTokenResponse{}
|
||||||
|
|
||||||
|
err = msgpackrpc.CallWithCodec(codec, "ACL.TokenRead", &req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp.Token)
|
||||||
|
require.ElementsMatch(t, expectedPolicies, resp.ExpandedPolicies)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestACLEndpoint_TokenClone(t *testing.T) {
|
func TestACLEndpoint_TokenClone(t *testing.T) {
|
||||||
|
|
|
@ -160,7 +160,8 @@ func (s *ACLServiceIdentity) SyntheticPolicy(entMeta *EnterpriseMeta) *ACLPolicy
|
||||||
policy := &ACLPolicy{}
|
policy := &ACLPolicy{}
|
||||||
policy.ID = hashID
|
policy.ID = hashID
|
||||||
policy.Name = fmt.Sprintf("synthetic-policy-%s", hashID)
|
policy.Name = fmt.Sprintf("synthetic-policy-%s", hashID)
|
||||||
policy.Description = "synthetic policy"
|
sn := NewServiceName(s.ServiceName, entMeta)
|
||||||
|
policy.Description = fmt.Sprintf("synthetic policy for service identity %q", sn.String())
|
||||||
policy.Rules = rules
|
policy.Rules = rules
|
||||||
policy.Syntax = acl.SyntaxCurrent
|
policy.Syntax = acl.SyntaxCurrent
|
||||||
policy.Datacenters = s.Datacenters
|
policy.Datacenters = s.Datacenters
|
||||||
|
@ -204,7 +205,7 @@ func (s *ACLNodeIdentity) SyntheticPolicy(entMeta *EnterpriseMeta) *ACLPolicy {
|
||||||
policy := &ACLPolicy{}
|
policy := &ACLPolicy{}
|
||||||
policy.ID = hashID
|
policy.ID = hashID
|
||||||
policy.Name = fmt.Sprintf("synthetic-policy-%s", hashID)
|
policy.Name = fmt.Sprintf("synthetic-policy-%s", hashID)
|
||||||
policy.Description = "synthetic policy"
|
policy.Description = fmt.Sprintf("synthetic policy for node identity %q", s.NodeName)
|
||||||
policy.Rules = rules
|
policy.Rules = rules
|
||||||
policy.Syntax = acl.SyntaxCurrent
|
policy.Syntax = acl.SyntaxCurrent
|
||||||
policy.Datacenters = []string{s.Datacenter}
|
policy.Datacenters = []string{s.Datacenter}
|
||||||
|
@ -1219,6 +1220,7 @@ func (r *ACLTokenSetRequest) RequestDatacenter() string {
|
||||||
type ACLTokenGetRequest struct {
|
type ACLTokenGetRequest struct {
|
||||||
TokenID string // id used for the token lookup
|
TokenID string // id used for the token lookup
|
||||||
TokenIDType ACLTokenIDType // The Type of ID used to lookup the token
|
TokenIDType ACLTokenIDType // The Type of ID used to lookup the token
|
||||||
|
Expanded bool
|
||||||
Datacenter string // The datacenter to perform the request within
|
Datacenter string // The datacenter to perform the request within
|
||||||
EnterpriseMeta
|
EnterpriseMeta
|
||||||
QueryOptions
|
QueryOptions
|
||||||
|
@ -1315,9 +1317,28 @@ type ACLTokenResponse struct {
|
||||||
Token *ACLToken
|
Token *ACLToken
|
||||||
Redacted bool // whether the token's secret was redacted
|
Redacted bool // whether the token's secret was redacted
|
||||||
SourceDatacenter string
|
SourceDatacenter string
|
||||||
|
|
||||||
|
ExpandedTokenInfo
|
||||||
QueryMeta
|
QueryMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExpandedTokenInfo struct {
|
||||||
|
ExpandedPolicies []*ACLPolicy
|
||||||
|
ExpandedRoles []*ACLRole
|
||||||
|
|
||||||
|
NamespaceDefaultPolicyIDs []string
|
||||||
|
NamespaceDefaultRoleIDs []string
|
||||||
|
|
||||||
|
AgentACLDefaultPolicy string
|
||||||
|
AgentACLDownPolicy string
|
||||||
|
ResolvedByAgent string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ACLTokenExpanded struct {
|
||||||
|
*ACLToken
|
||||||
|
ExpandedTokenInfo
|
||||||
|
}
|
||||||
|
|
||||||
// ACLTokenBatchResponse returns multiple Tokens associated with the same metadata
|
// ACLTokenBatchResponse returns multiple Tokens associated with the same metadata
|
||||||
type ACLTokenBatchResponse struct {
|
type ACLTokenBatchResponse struct {
|
||||||
Tokens []*ACLToken
|
Tokens []*ACLToken
|
||||||
|
|
|
@ -69,7 +69,6 @@ func TestStructs_ACLServiceIdentity_SyntheticPolicy(t *testing.T) {
|
||||||
expect := &ACLPolicy{
|
expect := &ACLPolicy{
|
||||||
Syntax: acl.SyntaxCurrent,
|
Syntax: acl.SyntaxCurrent,
|
||||||
Datacenters: test.datacenters,
|
Datacenters: test.datacenters,
|
||||||
Description: "synthetic policy",
|
|
||||||
Rules: test.expectRules,
|
Rules: test.expectRules,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +78,7 @@ func TestStructs_ACLServiceIdentity_SyntheticPolicy(t *testing.T) {
|
||||||
// strip irrelevant fields before equality
|
// strip irrelevant fields before equality
|
||||||
got.ID = ""
|
got.ID = ""
|
||||||
got.Name = ""
|
got.Name = ""
|
||||||
|
got.Description = ""
|
||||||
got.Hash = nil
|
got.Hash = nil
|
||||||
require.Equal(t, expect, got)
|
require.Equal(t, expect, got)
|
||||||
})
|
})
|
||||||
|
|
40
api/acl.go
40
api/acl.go
|
@ -62,6 +62,20 @@ type ACLToken struct {
|
||||||
AuthMethodNamespace string `json:",omitempty"`
|
AuthMethodNamespace string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ACLTokenExpanded struct {
|
||||||
|
ExpandedPolicies []ACLPolicy
|
||||||
|
ExpandedRoles []ACLRole
|
||||||
|
|
||||||
|
NamespaceDefaultPolicies []string
|
||||||
|
NamespaceDefaultRoles []string
|
||||||
|
|
||||||
|
AgentACLDefaultPolicy string
|
||||||
|
AgentACLDownPolicy string
|
||||||
|
ResolvedByAgent string
|
||||||
|
|
||||||
|
ACLToken
|
||||||
|
}
|
||||||
|
|
||||||
type ACLTokenListEntry struct {
|
type ACLTokenListEntry struct {
|
||||||
CreateIndex uint64
|
CreateIndex uint64
|
||||||
ModifyIndex uint64
|
ModifyIndex uint64
|
||||||
|
@ -788,6 +802,32 @@ func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta,
|
||||||
return &out, qm, nil
|
return &out, qm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TokenReadExpanded retrieves the full token details, as well as the contents of any policies affecting the token.
|
||||||
|
// The tokenID parameter must be a valid Accessor ID of an existing token.
|
||||||
|
func (a *ACL) TokenReadExpanded(tokenID string, q *QueryOptions) (*ACLTokenExpanded, *QueryMeta, error) {
|
||||||
|
r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
r.params.Set("expanded", "true")
|
||||||
|
rtt, resp, err := a.c.doRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer closeResponseBody(resp)
|
||||||
|
if err := requireOK(resp); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out ACLTokenExpanded
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TokenReadSelf retrieves the full token details of the token currently
|
// TokenReadSelf retrieves the full token details of the token currently
|
||||||
// assigned to the API Client. In this manner its possible to read a token
|
// assigned to the API Client. In this manner its possible to read a token
|
||||||
// by its Secret ID.
|
// by its Secret ID.
|
||||||
|
|
|
@ -6,17 +6,22 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PrettyFormat string = "pretty"
|
PrettyFormat string = "pretty"
|
||||||
JSONFormat string = "json"
|
JSONFormat string = "json"
|
||||||
|
|
||||||
|
WHITESPACE_2 string = "\t"
|
||||||
|
WHITESPACE_4 string = "\t\t"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Formatter defines methods provided by token command output formatter
|
// Formatter defines methods provided by token command output formatter
|
||||||
type Formatter interface {
|
type Formatter interface {
|
||||||
FormatToken(token *api.ACLToken) (string, error)
|
FormatToken(token *api.ACLToken) (string, error)
|
||||||
|
FormatTokenExpanded(token *api.ACLTokenExpanded) (string, error)
|
||||||
FormatTokenList(tokens []*api.ACLTokenListEntry) (string, error)
|
FormatTokenList(tokens []*api.ACLTokenListEntry) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +113,159 @@ func (f *prettyFormatter) FormatToken(token *api.ACLToken) (string, error) {
|
||||||
return buffer.String(), nil
|
return buffer.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *prettyFormatter) FormatTokenExpanded(token *api.ACLTokenExpanded) (string, error) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
buffer.WriteString(fmt.Sprintf("AccessorID: %s\n", token.AccessorID))
|
||||||
|
buffer.WriteString(fmt.Sprintf("SecretID: %s\n", token.SecretID))
|
||||||
|
if token.Partition != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Partition: %s\n", token.Partition))
|
||||||
|
}
|
||||||
|
if token.Namespace != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Namespace: %s\n", token.Namespace))
|
||||||
|
}
|
||||||
|
buffer.WriteString(fmt.Sprintf("Description: %s\n", token.Description))
|
||||||
|
buffer.WriteString(fmt.Sprintf("Local: %t\n", token.Local))
|
||||||
|
if token.AuthMethod != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Auth Method: %s (Namespace: %s)\n", token.AuthMethod, token.AuthMethodNamespace))
|
||||||
|
}
|
||||||
|
buffer.WriteString(fmt.Sprintf("Create Time: %v\n", token.CreateTime))
|
||||||
|
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Expiration Time: %v\n", *token.ExpirationTime))
|
||||||
|
}
|
||||||
|
if f.showMeta {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Hash: %x\n", token.Hash))
|
||||||
|
buffer.WriteString(fmt.Sprintf("Create Index: %d\n", token.CreateIndex))
|
||||||
|
buffer.WriteString(fmt.Sprintf("Modify Index: %d\n", token.ModifyIndex))
|
||||||
|
}
|
||||||
|
|
||||||
|
policies := make(map[string]api.ACLPolicy)
|
||||||
|
roles := make(map[string]api.ACLRole)
|
||||||
|
for _, policy := range token.ExpandedPolicies {
|
||||||
|
policies[policy.ID] = policy
|
||||||
|
}
|
||||||
|
for _, role := range token.ExpandedRoles {
|
||||||
|
roles[role.ID] = role
|
||||||
|
}
|
||||||
|
|
||||||
|
formatPolicy := func(policy api.ACLPolicy, indent string) {
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+"Policy Name: %s\n", policy.Name))
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+WHITESPACE_2+"ID: %s\n", policy.ID))
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+WHITESPACE_2+"Description: %s\n", policy.Description))
|
||||||
|
buffer.WriteString(indent + WHITESPACE_2 + "Rules:\n")
|
||||||
|
buffer.WriteString(indent + WHITESPACE_4)
|
||||||
|
buffer.WriteString(strings.ReplaceAll(policy.Rules, "\n", "\n"+indent+WHITESPACE_4))
|
||||||
|
buffer.WriteString("\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(token.ACLToken.Policies) > 0 {
|
||||||
|
buffer.WriteString("Policies:\n")
|
||||||
|
for _, policyLink := range token.ACLToken.Policies {
|
||||||
|
formatPolicy(policies[policyLink.ID], WHITESPACE_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entMeta := structs.NewEnterpriseMetaWithPartition(token.Partition, token.Namespace)
|
||||||
|
formatServiceIdentity := func(svcIdentity *api.ACLServiceIdentity, indent string) {
|
||||||
|
if len(svcIdentity.Datacenters) > 0 {
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+"Name: %s (Datacenters: %s)\n", svcIdentity.ServiceName, strings.Join(svcIdentity.Datacenters, ", ")))
|
||||||
|
} else {
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+"Name: %s (Datacenters: all)\n", svcIdentity.ServiceName))
|
||||||
|
}
|
||||||
|
identity := structs.ACLServiceIdentity{ServiceName: svcIdentity.ServiceName, Datacenters: svcIdentity.Datacenters}
|
||||||
|
policy := identity.SyntheticPolicy(&entMeta)
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+WHITESPACE_2+"Description: %s\n", policy.Description))
|
||||||
|
buffer.WriteString(indent + WHITESPACE_2 + "Rules:")
|
||||||
|
buffer.WriteString(strings.ReplaceAll(policy.Rules, "\n", "\n"+indent+WHITESPACE_4))
|
||||||
|
buffer.WriteString("\n\n")
|
||||||
|
}
|
||||||
|
if len(token.ACLToken.ServiceIdentities) > 0 {
|
||||||
|
buffer.WriteString("Service Identities:\n")
|
||||||
|
for _, svcIdentity := range token.ACLToken.ServiceIdentities {
|
||||||
|
formatServiceIdentity(svcIdentity, WHITESPACE_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatNodeIdentity := func(nodeIdentity *api.ACLNodeIdentity, indent string) {
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+"Name: %s (Datacenter: %s)\n", nodeIdentity.NodeName, nodeIdentity.Datacenter))
|
||||||
|
identity := structs.ACLNodeIdentity{NodeName: nodeIdentity.NodeName, Datacenter: nodeIdentity.Datacenter}
|
||||||
|
policy := identity.SyntheticPolicy(&entMeta)
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+WHITESPACE_2+"Description: %s\n", policy.Description))
|
||||||
|
buffer.WriteString(indent + WHITESPACE_2 + "Rules:")
|
||||||
|
buffer.WriteString(strings.ReplaceAll(policy.Rules, "\n", "\n"+indent+WHITESPACE_4))
|
||||||
|
buffer.WriteString("\n\n")
|
||||||
|
}
|
||||||
|
if len(token.ACLToken.NodeIdentities) > 0 {
|
||||||
|
buffer.WriteString("Node Identities:\n")
|
||||||
|
for _, nodeIdentity := range token.ACLToken.NodeIdentities {
|
||||||
|
formatNodeIdentity(nodeIdentity, WHITESPACE_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatRole := func(role api.ACLRole, indent string) {
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+"Role Name: %s\n", role.Name))
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+WHITESPACE_2+"ID: %s\n", role.ID))
|
||||||
|
buffer.WriteString(fmt.Sprintf(indent+WHITESPACE_2+"Description: %s\n", role.Description))
|
||||||
|
|
||||||
|
if len(role.Policies) > 0 {
|
||||||
|
buffer.WriteString(indent + WHITESPACE_2 + "Policies:\n")
|
||||||
|
for _, policyLink := range role.Policies {
|
||||||
|
formatPolicy(policies[policyLink.ID], indent+WHITESPACE_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(role.ServiceIdentities) > 0 {
|
||||||
|
buffer.WriteString(indent + WHITESPACE_2 + "Service Identities:\n")
|
||||||
|
for _, svcIdentity := range role.ServiceIdentities {
|
||||||
|
formatServiceIdentity(svcIdentity, indent+WHITESPACE_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(role.NodeIdentities) > 0 {
|
||||||
|
buffer.WriteString(indent + WHITESPACE_2 + "Node Identities:\n")
|
||||||
|
for _, nodeIdentity := range role.NodeIdentities {
|
||||||
|
formatNodeIdentity(nodeIdentity, indent+WHITESPACE_4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(token.ACLToken.Roles) > 0 {
|
||||||
|
buffer.WriteString("Roles:\n")
|
||||||
|
for _, roleLink := range token.ACLToken.Roles {
|
||||||
|
role := roles[roleLink.ID]
|
||||||
|
formatRole(role, WHITESPACE_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString("=== End of Authorizer Layer 0: Token ===\n")
|
||||||
|
|
||||||
|
if len(token.NamespaceDefaultPolicies) > 0 || len(token.NamespaceDefaultRoles) > 0 {
|
||||||
|
buffer.WriteString("=== Start of Authorizer Layer 1: Token Namespace’s Defaults (Inherited) ===\n")
|
||||||
|
buffer.WriteString(fmt.Sprintf("Description: ACL Roles inherited by all Tokens in Namespace %q\n\n", token.Namespace))
|
||||||
|
|
||||||
|
buffer.WriteString("Namespace Policy Defaults:\n")
|
||||||
|
for _, policyID := range token.NamespaceDefaultPolicies {
|
||||||
|
formatPolicy(policies[policyID], WHITESPACE_2)
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString("Namespace Role Defaults:\n")
|
||||||
|
for _, roleID := range token.NamespaceDefaultRoles {
|
||||||
|
formatRole(roles[roleID], WHITESPACE_2)
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString("=== End of Authorizer Layer 1: Token Namespace’s Defaults (Inherited) ===\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString("=== Start of Authorizer Layer 2: Agent Configuration Defaults (Inherited) ===\n")
|
||||||
|
buffer.WriteString("Description: Defined at request-time by the agent that resolves the ACL token; other agents may have different configuration defaults\n")
|
||||||
|
buffer.WriteString(fmt.Sprintf("Resolved By Agent: %q\n\n", token.ResolvedByAgent))
|
||||||
|
buffer.WriteString(fmt.Sprintf("Default Policy: %s\n", token.AgentACLDefaultPolicy))
|
||||||
|
buffer.WriteString(WHITESPACE_2 + "Description: Backstop rule used if no preceding layer has a matching rule (refer to default_policy option in agent configuration)\n\n")
|
||||||
|
buffer.WriteString(fmt.Sprintf("Down Policy: %s\n", token.AgentACLDownPolicy))
|
||||||
|
buffer.WriteString(WHITESPACE_2 + "Description: Defines what to do if this Token's information cannot be read from the primary_datacenter (refer to down_policy option in agent configuration)\n\n")
|
||||||
|
|
||||||
|
return buffer.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *prettyFormatter) FormatTokenList(tokens []*api.ACLTokenListEntry) (string, error) {
|
func (f *prettyFormatter) FormatTokenList(tokens []*api.ACLTokenListEntry) (string, error) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
@ -204,3 +362,11 @@ func (f *jsonFormatter) FormatToken(token *api.ACLToken) (string, error) {
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *jsonFormatter) FormatTokenExpanded(token *api.ACLTokenExpanded) (string, error) {
|
||||||
|
b, err := json.MarshalIndent(token, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to marshal token: %v", err)
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build !consulent
|
||||||
|
// +build !consulent
|
||||||
|
|
||||||
|
package token
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatTokenExpanded(t *testing.T) {
|
||||||
|
testFormatTokenExpanded(t, "FormatTokenExpanded/oss")
|
||||||
|
}
|
|
@ -254,3 +254,239 @@ func TestFormatTokenList(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
tokenExpanded api.ACLTokenExpanded
|
||||||
|
overrideGoldenName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeRef(in time.Time) *time.Time {
|
||||||
|
return &in
|
||||||
|
}
|
||||||
|
|
||||||
|
var expandedTokenTestCases = map[string]testCase{
|
||||||
|
"basic": {
|
||||||
|
tokenExpanded: api.ACLTokenExpanded{
|
||||||
|
ExpandedPolicies: []api.ACLPolicy{
|
||||||
|
{
|
||||||
|
ID: "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
Name: "foo",
|
||||||
|
Description: "user policy on token",
|
||||||
|
Rules: `service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
Name: "bar",
|
||||||
|
Description: "other user policy on token",
|
||||||
|
Rules: `operator = "read"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AgentACLDefaultPolicy: "allow",
|
||||||
|
AgentACLDownPolicy: "deny",
|
||||||
|
ResolvedByAgent: "leader",
|
||||||
|
ACLToken: api.ACLToken{
|
||||||
|
AccessorID: "fbd2447f-7479-4329-ad13-b021d74f86ba",
|
||||||
|
SecretID: "869c6e91-4de9-4dab-b56e-87548435f9c6",
|
||||||
|
Description: "test token",
|
||||||
|
Local: false,
|
||||||
|
CreateTime: time.Date(2020, 5, 22, 18, 52, 31, 0, time.UTC),
|
||||||
|
Hash: []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'},
|
||||||
|
CreateIndex: 42,
|
||||||
|
ModifyIndex: 100,
|
||||||
|
Policies: []*api.ACLLink{
|
||||||
|
{
|
||||||
|
ID: "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"complex": {
|
||||||
|
tokenExpanded: api.ACLTokenExpanded{
|
||||||
|
ExpandedPolicies: []api.ACLPolicy{
|
||||||
|
{
|
||||||
|
ID: "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
Name: "hobbiton",
|
||||||
|
Description: "user policy on token",
|
||||||
|
Rules: `service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
Name: "bywater",
|
||||||
|
Description: "other user policy on token",
|
||||||
|
Rules: `operator = "read"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "6204f4cd-4709-441c-ac1b-cb029e940263",
|
||||||
|
Name: "shire-policy",
|
||||||
|
Description: "policy for shire role",
|
||||||
|
Rules: `operator = "write"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "e86f0d1f-71b1-4690-bdfd-ff8c2cd4ae93",
|
||||||
|
Name: "west-farthing-policy",
|
||||||
|
Description: "policy for west-farthing role",
|
||||||
|
Rules: `service "foo" {
|
||||||
|
policy = "read"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2b582ff1-4a43-457f-8a2b-30a8265e29a5",
|
||||||
|
Name: "default-policy-1",
|
||||||
|
Description: "default policy 1",
|
||||||
|
Rules: `key "foo" { policy = "write" }`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "b55dce64-f2cc-4eb5-8e5f-50e90e63c6ea",
|
||||||
|
Name: "default-policy-2",
|
||||||
|
Description: "default policy 2",
|
||||||
|
Rules: `key "bar" { policy = "read" }`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpandedRoles: []api.ACLRole{
|
||||||
|
{
|
||||||
|
ID: "3b0a78fe-b9c3-40de-b8ea-7d4d6674b366",
|
||||||
|
Name: "shire",
|
||||||
|
Description: "shire role",
|
||||||
|
Policies: []*api.ACLRolePolicyLink{
|
||||||
|
{
|
||||||
|
ID: "6204f4cd-4709-441c-ac1b-cb029e940263",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceIdentities: []*api.ACLServiceIdentity{
|
||||||
|
{
|
||||||
|
ServiceName: "foo",
|
||||||
|
Datacenters: []string{"middleearth-southwest"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "6c9d1e1d-34bc-4d55-80f3-add0890ad791",
|
||||||
|
Name: "west-farthing",
|
||||||
|
Description: "west-farthing role",
|
||||||
|
Policies: []*api.ACLRolePolicyLink{
|
||||||
|
{
|
||||||
|
ID: "e86f0d1f-71b1-4690-bdfd-ff8c2cd4ae93",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NodeIdentities: []*api.ACLNodeIdentity{
|
||||||
|
{
|
||||||
|
NodeName: "bar",
|
||||||
|
Datacenter: "middleearth-southwest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "56033f2b-e1a6-4905-b71d-e011c862bc65",
|
||||||
|
Name: "ns-default",
|
||||||
|
Description: "default role",
|
||||||
|
Policies: []*api.ACLRolePolicyLink{
|
||||||
|
{
|
||||||
|
ID: "b55dce64-f2cc-4eb5-8e5f-50e90e63c6ea",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceIdentities: []*api.ACLServiceIdentity{
|
||||||
|
{
|
||||||
|
ServiceName: "web",
|
||||||
|
Datacenters: []string{"middleearth-northeast"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NodeIdentities: []*api.ACLNodeIdentity{
|
||||||
|
{
|
||||||
|
NodeName: "db",
|
||||||
|
Datacenter: "middleearth-northwest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NamespaceDefaultPolicies: []string{"2b582ff1-4a43-457f-8a2b-30a8265e29a5"},
|
||||||
|
NamespaceDefaultRoles: []string{"56033f2b-e1a6-4905-b71d-e011c862bc65"},
|
||||||
|
AgentACLDefaultPolicy: "deny",
|
||||||
|
AgentACLDownPolicy: "extend-cache",
|
||||||
|
ResolvedByAgent: "server-1",
|
||||||
|
ACLToken: api.ACLToken{
|
||||||
|
AccessorID: "fbd2447f-7479-4329-ad13-b021d74f86ba",
|
||||||
|
SecretID: "869c6e91-4de9-4dab-b56e-87548435f9c6",
|
||||||
|
Namespace: "foo",
|
||||||
|
Description: "test token",
|
||||||
|
Local: false,
|
||||||
|
AuthMethod: "bar",
|
||||||
|
AuthMethodNamespace: "baz",
|
||||||
|
CreateTime: time.Date(2020, 5, 22, 18, 52, 31, 0, time.UTC),
|
||||||
|
ExpirationTime: timeRef(time.Date(2020, 5, 22, 19, 52, 31, 0, time.UTC)),
|
||||||
|
Hash: []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'},
|
||||||
|
CreateIndex: 5,
|
||||||
|
ModifyIndex: 10,
|
||||||
|
Policies: []*api.ACLLink{
|
||||||
|
{
|
||||||
|
ID: "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
Name: "hobbiton",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
Name: "bywater",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Roles: []*api.ACLLink{
|
||||||
|
{
|
||||||
|
ID: "3b0a78fe-b9c3-40de-b8ea-7d4d6674b366",
|
||||||
|
Name: "shire",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "6c9d1e1d-34bc-4d55-80f3-add0890ad791",
|
||||||
|
Name: "west-farthing",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceIdentities: []*api.ACLServiceIdentity{
|
||||||
|
{
|
||||||
|
ServiceName: "gardener",
|
||||||
|
Datacenters: []string{"middleearth-northwest"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NodeIdentities: []*api.ACLNodeIdentity{
|
||||||
|
{
|
||||||
|
NodeName: "bagend",
|
||||||
|
Datacenter: "middleearth-northwest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFormatTokenExpanded(t *testing.T, dirPath string) {
|
||||||
|
formatters := map[string]Formatter{
|
||||||
|
"pretty": newPrettyFormatter(false),
|
||||||
|
"pretty-meta": newPrettyFormatter(true),
|
||||||
|
// the JSON formatter ignores the showMeta
|
||||||
|
"json": newJSONFormatter(false),
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tcase := range expandedTokenTestCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
for fmtName, formatter := range formatters {
|
||||||
|
t.Run(fmtName, func(t *testing.T) {
|
||||||
|
actual, err := formatter.FormatTokenExpanded(&tcase.tokenExpanded)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
gName := fmt.Sprintf("%s.%s", name, fmtName)
|
||||||
|
if tcase.overrideGoldenName != "" {
|
||||||
|
gName = tcase.overrideGoldenName
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := golden(t, path.Join(dirPath, gName), actual)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ type cmd struct {
|
||||||
self bool
|
self bool
|
||||||
showMeta bool
|
showMeta bool
|
||||||
format string
|
format string
|
||||||
|
expanded bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cmd) init() {
|
func (c *cmd) init() {
|
||||||
|
@ -36,6 +37,8 @@ func (c *cmd) init() {
|
||||||
"as the content hash and Raft indices should be shown for each entry")
|
"as the content hash and Raft indices should be shown for each entry")
|
||||||
c.flags.BoolVar(&c.self, "self", false, "Indicates that the current HTTP token "+
|
c.flags.BoolVar(&c.self, "self", false, "Indicates that the current HTTP token "+
|
||||||
"should be read by secret ID instead of expecting a -id option")
|
"should be read by secret ID instead of expecting a -id option")
|
||||||
|
c.flags.BoolVar(&c.expanded, "expanded", false, "Indicates that the contents of the "+
|
||||||
|
" policies and roles affecting the token should also be shown.")
|
||||||
c.flags.StringVar(&c.tokenID, "id", "", "The Accessor ID of the token to read. "+
|
c.flags.StringVar(&c.tokenID, "id", "", "The Accessor ID of the token to read. "+
|
||||||
"It may be specified as a unique ID prefix but will error if the prefix "+
|
"It may be specified as a unique ID prefix but will error if the prefix "+
|
||||||
"matches multiple token Accessor IDs")
|
"matches multiple token Accessor IDs")
|
||||||
|
@ -69,6 +72,7 @@ func (c *cmd) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
var t *api.ACLToken
|
var t *api.ACLToken
|
||||||
|
var expanded *api.ACLTokenExpanded
|
||||||
if !c.self {
|
if !c.self {
|
||||||
tokenID, err := acl.GetTokenIDFromPartial(client, c.tokenID)
|
tokenID, err := acl.GetTokenIDFromPartial(client, c.tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -76,7 +80,12 @@ func (c *cmd) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.expanded {
|
||||||
t, _, err = client.ACL().TokenRead(tokenID, nil)
|
t, _, err = client.ACL().TokenRead(tokenID, nil)
|
||||||
|
} else {
|
||||||
|
expanded, _, err = client.ACL().TokenReadExpanded(tokenID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Error reading token %q: %v", tokenID, err))
|
c.UI.Error(fmt.Sprintf("Error reading token %q: %v", tokenID, err))
|
||||||
return 1
|
return 1
|
||||||
|
@ -94,7 +103,12 @@ func (c *cmd) Run(args []string) int {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
out, err := formatter.FormatToken(t)
|
var out string
|
||||||
|
if !c.expanded {
|
||||||
|
out, err = formatter.FormatToken(t)
|
||||||
|
} else {
|
||||||
|
out, err = formatter.FormatTokenExpanded(expanded)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(err.Error())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"ExpandedPolicies": [
|
||||||
|
{
|
||||||
|
"ID": "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
"Name": "foo",
|
||||||
|
"Description": "user policy on token",
|
||||||
|
"Rules": "service_prefix \"\" {\n policy = \"read\"\n}",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
"Name": "bar",
|
||||||
|
"Description": "other user policy on token",
|
||||||
|
"Rules": "operator = \"read\"",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ExpandedRoles": null,
|
||||||
|
"NamespaceDefaultPolicies": null,
|
||||||
|
"NamespaceDefaultRoles": null,
|
||||||
|
"AgentACLDefaultPolicy": "allow",
|
||||||
|
"AgentACLDownPolicy": "deny",
|
||||||
|
"ResolvedByAgent": "leader",
|
||||||
|
"CreateIndex": 42,
|
||||||
|
"ModifyIndex": 100,
|
||||||
|
"AccessorID": "fbd2447f-7479-4329-ad13-b021d74f86ba",
|
||||||
|
"SecretID": "869c6e91-4de9-4dab-b56e-87548435f9c6",
|
||||||
|
"Description": "test token",
|
||||||
|
"Policies": [
|
||||||
|
{
|
||||||
|
"ID": "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
"Name": "foo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
"Name": "bar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Local": false,
|
||||||
|
"CreateTime": "2020-05-22T18:52:31Z",
|
||||||
|
"Hash": "YWJjZGVmZ2g="
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
AccessorID: fbd2447f-7479-4329-ad13-b021d74f86ba
|
||||||
|
SecretID: 869c6e91-4de9-4dab-b56e-87548435f9c6
|
||||||
|
Description: test token
|
||||||
|
Local: false
|
||||||
|
Create Time: 2020-05-22 18:52:31 +0000 UTC
|
||||||
|
Hash: 6162636465666768
|
||||||
|
Create Index: 42
|
||||||
|
Modify Index: 100
|
||||||
|
Policies:
|
||||||
|
Policy Name: foo
|
||||||
|
ID: beb04680-815b-4d7c-9e33-3d707c24672c
|
||||||
|
Description: user policy on token
|
||||||
|
Rules:
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Policy Name: bar
|
||||||
|
ID: 18788457-584c-4812-80d3-23d403148a90
|
||||||
|
Description: other user policy on token
|
||||||
|
Rules:
|
||||||
|
operator = "read"
|
||||||
|
|
||||||
|
=== End of Authorizer Layer 0: Token ===
|
||||||
|
=== Start of Authorizer Layer 2: Agent Configuration Defaults (Inherited) ===
|
||||||
|
Description: Defined at request-time by the agent that resolves the ACL token; other agents may have different configuration defaults
|
||||||
|
Resolved By Agent: "leader"
|
||||||
|
|
||||||
|
Default Policy: allow
|
||||||
|
Description: Backstop rule used if no preceding layer has a matching rule (refer to default_policy option in agent configuration)
|
||||||
|
|
||||||
|
Down Policy: deny
|
||||||
|
Description: Defines what to do if this Token's information cannot be read from the primary_datacenter (refer to down_policy option in agent configuration)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
AccessorID: fbd2447f-7479-4329-ad13-b021d74f86ba
|
||||||
|
SecretID: 869c6e91-4de9-4dab-b56e-87548435f9c6
|
||||||
|
Description: test token
|
||||||
|
Local: false
|
||||||
|
Create Time: 2020-05-22 18:52:31 +0000 UTC
|
||||||
|
Policies:
|
||||||
|
Policy Name: foo
|
||||||
|
ID: beb04680-815b-4d7c-9e33-3d707c24672c
|
||||||
|
Description: user policy on token
|
||||||
|
Rules:
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Policy Name: bar
|
||||||
|
ID: 18788457-584c-4812-80d3-23d403148a90
|
||||||
|
Description: other user policy on token
|
||||||
|
Rules:
|
||||||
|
operator = "read"
|
||||||
|
|
||||||
|
=== End of Authorizer Layer 0: Token ===
|
||||||
|
=== Start of Authorizer Layer 2: Agent Configuration Defaults (Inherited) ===
|
||||||
|
Description: Defined at request-time by the agent that resolves the ACL token; other agents may have different configuration defaults
|
||||||
|
Resolved By Agent: "leader"
|
||||||
|
|
||||||
|
Default Policy: allow
|
||||||
|
Description: Backstop rule used if no preceding layer has a matching rule (refer to default_policy option in agent configuration)
|
||||||
|
|
||||||
|
Down Policy: deny
|
||||||
|
Description: Defines what to do if this Token's information cannot be read from the primary_datacenter (refer to down_policy option in agent configuration)
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
{
|
||||||
|
"ExpandedPolicies": [
|
||||||
|
{
|
||||||
|
"ID": "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
"Name": "hobbiton",
|
||||||
|
"Description": "user policy on token",
|
||||||
|
"Rules": "service_prefix \"\" {\n policy = \"read\"\n}",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
"Name": "bywater",
|
||||||
|
"Description": "other user policy on token",
|
||||||
|
"Rules": "operator = \"read\"",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "6204f4cd-4709-441c-ac1b-cb029e940263",
|
||||||
|
"Name": "shire-policy",
|
||||||
|
"Description": "policy for shire role",
|
||||||
|
"Rules": "operator = \"write\"",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "e86f0d1f-71b1-4690-bdfd-ff8c2cd4ae93",
|
||||||
|
"Name": "west-farthing-policy",
|
||||||
|
"Description": "policy for west-farthing role",
|
||||||
|
"Rules": "service \"foo\" {\n policy = \"read\"\n}",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "2b582ff1-4a43-457f-8a2b-30a8265e29a5",
|
||||||
|
"Name": "default-policy-1",
|
||||||
|
"Description": "default policy 1",
|
||||||
|
"Rules": "key \"foo\" { policy = \"write\" }",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "b55dce64-f2cc-4eb5-8e5f-50e90e63c6ea",
|
||||||
|
"Name": "default-policy-2",
|
||||||
|
"Description": "default policy 2",
|
||||||
|
"Rules": "key \"bar\" { policy = \"read\" }",
|
||||||
|
"Datacenters": null,
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ExpandedRoles": [
|
||||||
|
{
|
||||||
|
"ID": "3b0a78fe-b9c3-40de-b8ea-7d4d6674b366",
|
||||||
|
"Name": "shire",
|
||||||
|
"Description": "shire role",
|
||||||
|
"Policies": [
|
||||||
|
{
|
||||||
|
"ID": "6204f4cd-4709-441c-ac1b-cb029e940263",
|
||||||
|
"Name": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ServiceIdentities": [
|
||||||
|
{
|
||||||
|
"ServiceName": "foo",
|
||||||
|
"Datacenters": [
|
||||||
|
"middleearth-southwest"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "6c9d1e1d-34bc-4d55-80f3-add0890ad791",
|
||||||
|
"Name": "west-farthing",
|
||||||
|
"Description": "west-farthing role",
|
||||||
|
"Policies": [
|
||||||
|
{
|
||||||
|
"ID": "e86f0d1f-71b1-4690-bdfd-ff8c2cd4ae93",
|
||||||
|
"Name": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"NodeIdentities": [
|
||||||
|
{
|
||||||
|
"NodeName": "bar",
|
||||||
|
"Datacenter": "middleearth-southwest"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "56033f2b-e1a6-4905-b71d-e011c862bc65",
|
||||||
|
"Name": "ns-default",
|
||||||
|
"Description": "default role",
|
||||||
|
"Policies": [
|
||||||
|
{
|
||||||
|
"ID": "b55dce64-f2cc-4eb5-8e5f-50e90e63c6ea",
|
||||||
|
"Name": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ServiceIdentities": [
|
||||||
|
{
|
||||||
|
"ServiceName": "web",
|
||||||
|
"Datacenters": [
|
||||||
|
"middleearth-northeast"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"NodeIdentities": [
|
||||||
|
{
|
||||||
|
"NodeName": "db",
|
||||||
|
"Datacenter": "middleearth-northwest"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Hash": null,
|
||||||
|
"CreateIndex": 0,
|
||||||
|
"ModifyIndex": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"NamespaceDefaultPolicies": [
|
||||||
|
"2b582ff1-4a43-457f-8a2b-30a8265e29a5"
|
||||||
|
],
|
||||||
|
"NamespaceDefaultRoles": [
|
||||||
|
"56033f2b-e1a6-4905-b71d-e011c862bc65"
|
||||||
|
],
|
||||||
|
"AgentACLDefaultPolicy": "deny",
|
||||||
|
"AgentACLDownPolicy": "extend-cache",
|
||||||
|
"ResolvedByAgent": "server-1",
|
||||||
|
"CreateIndex": 5,
|
||||||
|
"ModifyIndex": 10,
|
||||||
|
"AccessorID": "fbd2447f-7479-4329-ad13-b021d74f86ba",
|
||||||
|
"SecretID": "869c6e91-4de9-4dab-b56e-87548435f9c6",
|
||||||
|
"Description": "test token",
|
||||||
|
"Policies": [
|
||||||
|
{
|
||||||
|
"ID": "beb04680-815b-4d7c-9e33-3d707c24672c",
|
||||||
|
"Name": "hobbiton"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "18788457-584c-4812-80d3-23d403148a90",
|
||||||
|
"Name": "bywater"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Roles": [
|
||||||
|
{
|
||||||
|
"ID": "3b0a78fe-b9c3-40de-b8ea-7d4d6674b366",
|
||||||
|
"Name": "shire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "6c9d1e1d-34bc-4d55-80f3-add0890ad791",
|
||||||
|
"Name": "west-farthing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ServiceIdentities": [
|
||||||
|
{
|
||||||
|
"ServiceName": "gardener",
|
||||||
|
"Datacenters": [
|
||||||
|
"middleearth-northwest"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"NodeIdentities": [
|
||||||
|
{
|
||||||
|
"NodeName": "bagend",
|
||||||
|
"Datacenter": "middleearth-northwest"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Local": false,
|
||||||
|
"AuthMethod": "bar",
|
||||||
|
"ExpirationTime": "2020-05-22T19:52:31Z",
|
||||||
|
"CreateTime": "2020-05-22T18:52:31Z",
|
||||||
|
"Hash": "YWJjZGVmZ2g=",
|
||||||
|
"Namespace": "foo",
|
||||||
|
"AuthMethodNamespace": "baz"
|
||||||
|
}
|
166
command/acl/token/testdata/FormatTokenExpanded/oss/complex.pretty-meta.golden
vendored
Normal file
166
command/acl/token/testdata/FormatTokenExpanded/oss/complex.pretty-meta.golden
vendored
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
AccessorID: fbd2447f-7479-4329-ad13-b021d74f86ba
|
||||||
|
SecretID: 869c6e91-4de9-4dab-b56e-87548435f9c6
|
||||||
|
Namespace: foo
|
||||||
|
Description: test token
|
||||||
|
Local: false
|
||||||
|
Auth Method: bar (Namespace: baz)
|
||||||
|
Create Time: 2020-05-22 18:52:31 +0000 UTC
|
||||||
|
Expiration Time: 2020-05-22 19:52:31 +0000 UTC
|
||||||
|
Hash: 6162636465666768
|
||||||
|
Create Index: 5
|
||||||
|
Modify Index: 10
|
||||||
|
Policies:
|
||||||
|
Policy Name: hobbiton
|
||||||
|
ID: beb04680-815b-4d7c-9e33-3d707c24672c
|
||||||
|
Description: user policy on token
|
||||||
|
Rules:
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Policy Name: bywater
|
||||||
|
ID: 18788457-584c-4812-80d3-23d403148a90
|
||||||
|
Description: other user policy on token
|
||||||
|
Rules:
|
||||||
|
operator = "read"
|
||||||
|
|
||||||
|
Service Identities:
|
||||||
|
Name: gardener (Datacenters: middleearth-northwest)
|
||||||
|
Description: synthetic policy for service identity "gardener"
|
||||||
|
Rules:
|
||||||
|
service "gardener" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "gardener-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Identities:
|
||||||
|
Name: bagend (Datacenter: middleearth-northwest)
|
||||||
|
Description: synthetic policy for node identity "bagend"
|
||||||
|
Rules:
|
||||||
|
node "bagend" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Roles:
|
||||||
|
Role Name: shire
|
||||||
|
ID: 3b0a78fe-b9c3-40de-b8ea-7d4d6674b366
|
||||||
|
Description: shire role
|
||||||
|
Policies:
|
||||||
|
Policy Name: shire-policy
|
||||||
|
ID: 6204f4cd-4709-441c-ac1b-cb029e940263
|
||||||
|
Description: policy for shire role
|
||||||
|
Rules:
|
||||||
|
operator = "write"
|
||||||
|
|
||||||
|
Service Identities:
|
||||||
|
Name: foo (Datacenters: middleearth-southwest)
|
||||||
|
Description: synthetic policy for service identity "foo"
|
||||||
|
Rules:
|
||||||
|
service "foo" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "foo-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Role Name: west-farthing
|
||||||
|
ID: 6c9d1e1d-34bc-4d55-80f3-add0890ad791
|
||||||
|
Description: west-farthing role
|
||||||
|
Policies:
|
||||||
|
Policy Name: west-farthing-policy
|
||||||
|
ID: e86f0d1f-71b1-4690-bdfd-ff8c2cd4ae93
|
||||||
|
Description: policy for west-farthing role
|
||||||
|
Rules:
|
||||||
|
service "foo" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Identities:
|
||||||
|
Name: bar (Datacenter: middleearth-southwest)
|
||||||
|
Description: synthetic policy for node identity "bar"
|
||||||
|
Rules:
|
||||||
|
node "bar" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
=== End of Authorizer Layer 0: Token ===
|
||||||
|
=== Start of Authorizer Layer 1: Token Namespace’s Defaults (Inherited) ===
|
||||||
|
Description: ACL Roles inherited by all Tokens in Namespace "foo"
|
||||||
|
|
||||||
|
Namespace Policy Defaults:
|
||||||
|
Policy Name: default-policy-1
|
||||||
|
ID: 2b582ff1-4a43-457f-8a2b-30a8265e29a5
|
||||||
|
Description: default policy 1
|
||||||
|
Rules:
|
||||||
|
key "foo" { policy = "write" }
|
||||||
|
|
||||||
|
Namespace Role Defaults:
|
||||||
|
Role Name: ns-default
|
||||||
|
ID: 56033f2b-e1a6-4905-b71d-e011c862bc65
|
||||||
|
Description: default role
|
||||||
|
Policies:
|
||||||
|
Policy Name: default-policy-2
|
||||||
|
ID: b55dce64-f2cc-4eb5-8e5f-50e90e63c6ea
|
||||||
|
Description: default policy 2
|
||||||
|
Rules:
|
||||||
|
key "bar" { policy = "read" }
|
||||||
|
|
||||||
|
Service Identities:
|
||||||
|
Name: web (Datacenters: middleearth-northeast)
|
||||||
|
Description: synthetic policy for service identity "web"
|
||||||
|
Rules:
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Identities:
|
||||||
|
Name: db (Datacenter: middleearth-northwest)
|
||||||
|
Description: synthetic policy for node identity "db"
|
||||||
|
Rules:
|
||||||
|
node "db" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
=== End of Authorizer Layer 1: Token Namespace’s Defaults (Inherited) ===
|
||||||
|
=== Start of Authorizer Layer 2: Agent Configuration Defaults (Inherited) ===
|
||||||
|
Description: Defined at request-time by the agent that resolves the ACL token; other agents may have different configuration defaults
|
||||||
|
Resolved By Agent: "server-1"
|
||||||
|
|
||||||
|
Default Policy: deny
|
||||||
|
Description: Backstop rule used if no preceding layer has a matching rule (refer to default_policy option in agent configuration)
|
||||||
|
|
||||||
|
Down Policy: extend-cache
|
||||||
|
Description: Defines what to do if this Token's information cannot be read from the primary_datacenter (refer to down_policy option in agent configuration)
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
AccessorID: fbd2447f-7479-4329-ad13-b021d74f86ba
|
||||||
|
SecretID: 869c6e91-4de9-4dab-b56e-87548435f9c6
|
||||||
|
Namespace: foo
|
||||||
|
Description: test token
|
||||||
|
Local: false
|
||||||
|
Auth Method: bar (Namespace: baz)
|
||||||
|
Create Time: 2020-05-22 18:52:31 +0000 UTC
|
||||||
|
Expiration Time: 2020-05-22 19:52:31 +0000 UTC
|
||||||
|
Policies:
|
||||||
|
Policy Name: hobbiton
|
||||||
|
ID: beb04680-815b-4d7c-9e33-3d707c24672c
|
||||||
|
Description: user policy on token
|
||||||
|
Rules:
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Policy Name: bywater
|
||||||
|
ID: 18788457-584c-4812-80d3-23d403148a90
|
||||||
|
Description: other user policy on token
|
||||||
|
Rules:
|
||||||
|
operator = "read"
|
||||||
|
|
||||||
|
Service Identities:
|
||||||
|
Name: gardener (Datacenters: middleearth-northwest)
|
||||||
|
Description: synthetic policy for service identity "gardener"
|
||||||
|
Rules:
|
||||||
|
service "gardener" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "gardener-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Identities:
|
||||||
|
Name: bagend (Datacenter: middleearth-northwest)
|
||||||
|
Description: synthetic policy for node identity "bagend"
|
||||||
|
Rules:
|
||||||
|
node "bagend" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Roles:
|
||||||
|
Role Name: shire
|
||||||
|
ID: 3b0a78fe-b9c3-40de-b8ea-7d4d6674b366
|
||||||
|
Description: shire role
|
||||||
|
Policies:
|
||||||
|
Policy Name: shire-policy
|
||||||
|
ID: 6204f4cd-4709-441c-ac1b-cb029e940263
|
||||||
|
Description: policy for shire role
|
||||||
|
Rules:
|
||||||
|
operator = "write"
|
||||||
|
|
||||||
|
Service Identities:
|
||||||
|
Name: foo (Datacenters: middleearth-southwest)
|
||||||
|
Description: synthetic policy for service identity "foo"
|
||||||
|
Rules:
|
||||||
|
service "foo" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "foo-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Role Name: west-farthing
|
||||||
|
ID: 6c9d1e1d-34bc-4d55-80f3-add0890ad791
|
||||||
|
Description: west-farthing role
|
||||||
|
Policies:
|
||||||
|
Policy Name: west-farthing-policy
|
||||||
|
ID: e86f0d1f-71b1-4690-bdfd-ff8c2cd4ae93
|
||||||
|
Description: policy for west-farthing role
|
||||||
|
Rules:
|
||||||
|
service "foo" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Identities:
|
||||||
|
Name: bar (Datacenter: middleearth-southwest)
|
||||||
|
Description: synthetic policy for node identity "bar"
|
||||||
|
Rules:
|
||||||
|
node "bar" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
=== End of Authorizer Layer 0: Token ===
|
||||||
|
=== Start of Authorizer Layer 1: Token Namespace’s Defaults (Inherited) ===
|
||||||
|
Description: ACL Roles inherited by all Tokens in Namespace "foo"
|
||||||
|
|
||||||
|
Namespace Policy Defaults:
|
||||||
|
Policy Name: default-policy-1
|
||||||
|
ID: 2b582ff1-4a43-457f-8a2b-30a8265e29a5
|
||||||
|
Description: default policy 1
|
||||||
|
Rules:
|
||||||
|
key "foo" { policy = "write" }
|
||||||
|
|
||||||
|
Namespace Role Defaults:
|
||||||
|
Role Name: ns-default
|
||||||
|
ID: 56033f2b-e1a6-4905-b71d-e011c862bc65
|
||||||
|
Description: default role
|
||||||
|
Policies:
|
||||||
|
Policy Name: default-policy-2
|
||||||
|
ID: b55dce64-f2cc-4eb5-8e5f-50e90e63c6ea
|
||||||
|
Description: default policy 2
|
||||||
|
Rules:
|
||||||
|
key "bar" { policy = "read" }
|
||||||
|
|
||||||
|
Service Identities:
|
||||||
|
Name: web (Datacenters: middleearth-northeast)
|
||||||
|
Description: synthetic policy for service identity "web"
|
||||||
|
Rules:
|
||||||
|
service "web" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service "web-sidecar-proxy" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
node_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Identities:
|
||||||
|
Name: db (Datacenter: middleearth-northwest)
|
||||||
|
Description: synthetic policy for node identity "db"
|
||||||
|
Rules:
|
||||||
|
node "db" {
|
||||||
|
policy = "write"
|
||||||
|
}
|
||||||
|
service_prefix "" {
|
||||||
|
policy = "read"
|
||||||
|
}
|
||||||
|
|
||||||
|
=== End of Authorizer Layer 1: Token Namespace’s Defaults (Inherited) ===
|
||||||
|
=== Start of Authorizer Layer 2: Agent Configuration Defaults (Inherited) ===
|
||||||
|
Description: Defined at request-time by the agent that resolves the ACL token; other agents may have different configuration defaults
|
||||||
|
Resolved By Agent: "server-1"
|
||||||
|
|
||||||
|
Default Policy: deny
|
||||||
|
Description: Backstop rule used if no preceding layer has a matching rule (refer to default_policy option in agent configuration)
|
||||||
|
|
||||||
|
Down Policy: extend-cache
|
||||||
|
Description: Defines what to do if this Token's information cannot be read from the primary_datacenter (refer to down_policy option in agent configuration)
|
||||||
|
|
Loading…
Reference in New Issue