mirror of
https://github.com/status-im/consul.git
synced 2025-01-15 08:14:54 +00:00
18b29c45c4
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.
699 lines
19 KiB
Go
699 lines
19 KiB
Go
package structs
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"hash/fnv"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hashicorp/consul/acl"
|
|
"github.com/hashicorp/consul/sentinel"
|
|
"golang.org/x/crypto/blake2b"
|
|
)
|
|
|
|
type ACLMode string
|
|
|
|
const (
|
|
// ACLs are disabled by configuration
|
|
ACLModeDisabled ACLMode = "0"
|
|
// ACLs are enabled
|
|
ACLModeEnabled ACLMode = "1"
|
|
// DEPRECATED (ACL-Legacy-Compat) - only needed while legacy ACLs are supported
|
|
// ACLs are enabled and using legacy ACLs
|
|
ACLModeLegacy ACLMode = "2"
|
|
// DEPRECATED (ACL-Legacy-Compat) - only needed while legacy ACLs are supported
|
|
// ACLs are assumed enabled but not being advertised
|
|
ACLModeUnknown ACLMode = "3"
|
|
)
|
|
|
|
// ACLOp is used in RPCs to encode ACL operations.
|
|
type ACLOp string
|
|
|
|
type ACLTokenIDType string
|
|
|
|
const (
|
|
ACLTokenSecret ACLTokenIDType = "secret"
|
|
ACLTokenAccessor ACLTokenIDType = "accessor"
|
|
)
|
|
|
|
type ACLPolicyIDType string
|
|
|
|
const (
|
|
ACLPolicyName ACLPolicyIDType = "name"
|
|
ACLPolicyID ACLPolicyIDType = "id"
|
|
)
|
|
|
|
const (
|
|
// All policy ids with the first 120 bits set to all zeroes are
|
|
// reserved for builtin policies. Policy creation will ensure we
|
|
// dont accidentally create them when autogenerating uuids.
|
|
|
|
// This policy gives unlimited access to everything. Users
|
|
// may rename if desired but cannot delete or modify the rules
|
|
ACLPolicyGlobalManagementID = "00000000-0000-0000-0000-000000000001"
|
|
ACLPolicyGlobalManagement = `
|
|
acl = "write"
|
|
agent_prefix "" {
|
|
policy = "write"
|
|
}
|
|
event_prefix "" {
|
|
policy = "write"
|
|
}
|
|
key_prefix "" {
|
|
policy = "write"
|
|
}
|
|
keyring = "write"
|
|
node_prefix "" {
|
|
policy = "write"
|
|
}
|
|
operator = "write"
|
|
query_prefix "" {
|
|
policy = "write"
|
|
}
|
|
service_prefix "" {
|
|
policy = "write"
|
|
intentions = "write"
|
|
}
|
|
session_prefix "" {
|
|
policy = "write"
|
|
}`
|
|
|
|
// This is the policy ID for anonymous access. This is configurable by the
|
|
ACLTokenAnonymousID = "00000000-0000-0000-0000-000000000002"
|
|
)
|
|
|
|
func ACLIDReserved(id string) bool {
|
|
return strings.HasPrefix(id, "00000000-0000-0000-0000-0000000000")
|
|
}
|
|
|
|
const (
|
|
// ACLSet creates or updates a token.
|
|
ACLSet ACLOp = "set"
|
|
|
|
// ACLDelete deletes a token.
|
|
ACLDelete ACLOp = "delete"
|
|
)
|
|
|
|
// ACLBootstrapNotAllowedErr is returned once we know that a bootstrap can no
|
|
// longer be done since the cluster was bootstrapped
|
|
var ACLBootstrapNotAllowedErr = errors.New("ACL bootstrap no longer allowed")
|
|
|
|
// ACLBootstrapInvalidResetIndexErr is returned when bootstrap is requested with a non-zero
|
|
// reset index but the index doesn't match the bootstrap index
|
|
var ACLBootstrapInvalidResetIndexErr = errors.New("Invalid ACL bootstrap reset index")
|
|
|
|
type ACLIdentity interface {
|
|
// ID returns a string that can be used for logging and telemetry. This should not
|
|
// contain any secret data used for authentication
|
|
ID() string
|
|
SecretToken() string
|
|
PolicyIDs() []string
|
|
EmbeddedPolicy() *ACLPolicy
|
|
}
|
|
|
|
type ACLTokenPolicyLink struct {
|
|
ID string
|
|
Name string `hash:"ignore"`
|
|
}
|
|
|
|
type ACLToken struct {
|
|
// This is the UUID used for tracking and management purposes
|
|
AccessorID string
|
|
|
|
// This is the UUID used as the api token by clients
|
|
SecretID string
|
|
|
|
// Human readable string to display for the token (Optional)
|
|
Description string
|
|
|
|
// List of policy links - nil/empty for legacy tokens
|
|
// Note this is the list of IDs and not the names. Prior to token creation
|
|
// the list of policy names gets validated and the policy IDs get stored herein
|
|
Policies []ACLTokenPolicyLink
|
|
|
|
// Type is the V1 Token Type
|
|
// DEPRECATED (ACL-Legacy-Compat) - remove once we no longer support v1 ACL compat
|
|
// Even though we are going to auto upgrade management tokens we still
|
|
// want to be able to have the old APIs operate on the upgraded management tokens
|
|
// so this field is being kept to identify legacy tokens even after an auto-upgrade
|
|
Type string `json:"-"`
|
|
|
|
// Rules is the V1 acl rules associated with
|
|
// DEPRECATED (ACL-Legacy-Compat) - remove once we no longer support v1 ACL compat
|
|
Rules string `json:",omitempty"`
|
|
|
|
// Whether this token is DC local. This means that it will not be synced
|
|
// to the ACL datacenter and replicated to others.
|
|
Local bool
|
|
|
|
// The time when this token was created
|
|
CreateTime time.Time `json:",omitempty"`
|
|
|
|
// Hash of the contents of the token
|
|
//
|
|
// This is needed mainly for replication purposes. When replicating from
|
|
// one DC to another keeping the content Hash will allow us to avoid
|
|
// unnecessary calls to the authoritative DC
|
|
Hash []byte
|
|
|
|
// Embedded Raft Metadata
|
|
RaftIndex
|
|
}
|
|
|
|
func (t *ACLToken) ID() string {
|
|
return t.AccessorID
|
|
}
|
|
|
|
func (t *ACLToken) SecretToken() string {
|
|
return t.SecretID
|
|
}
|
|
|
|
func (t *ACLToken) PolicyIDs() []string {
|
|
var ids []string
|
|
for _, link := range t.Policies {
|
|
ids = append(ids, link.ID)
|
|
}
|
|
return ids
|
|
}
|
|
|
|
func (t *ACLToken) EmbeddedPolicy() *ACLPolicy {
|
|
// DEPRECATED (ACL-Legacy-Compat)
|
|
//
|
|
// For legacy tokens with embedded rules this provides a way to map those
|
|
// rules to an ACLPolicy. This function can just return nil once legacy
|
|
// acl compatibility is no longer needed.
|
|
//
|
|
// Additionally for management tokens we must embed the policy rules
|
|
// as well
|
|
policy := &ACLPolicy{}
|
|
if t.Rules != "" || t.Type == ACLTokenTypeClient {
|
|
hasher := fnv.New128a()
|
|
policy.ID = fmt.Sprintf("%x", hasher.Sum([]byte(t.Rules)))
|
|
policy.Name = fmt.Sprintf("legacy-policy-%s", policy.ID)
|
|
policy.Rules = t.Rules
|
|
policy.Syntax = acl.SyntaxLegacy
|
|
} else if t.Type == ACLTokenTypeManagement {
|
|
hasher := fnv.New128a()
|
|
policy.ID = fmt.Sprintf("%x", hasher.Sum([]byte(ACLPolicyGlobalManagement)))
|
|
policy.Name = "legacy-management"
|
|
policy.Rules = ACLPolicyGlobalManagement
|
|
policy.Syntax = acl.SyntaxCurrent
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
policy.SetHash(true)
|
|
return policy
|
|
}
|
|
|
|
func (t *ACLToken) SetHash(force bool) []byte {
|
|
if force || t.Hash == nil {
|
|
// Initialize a 256bit Blake2 hash (32 bytes)
|
|
hash, err := blake2b.New256(nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Write all the user set fields
|
|
hash.Write([]byte(t.Description))
|
|
hash.Write([]byte(t.Type))
|
|
hash.Write([]byte(t.Rules))
|
|
|
|
if t.Local {
|
|
hash.Write([]byte("local"))
|
|
} else {
|
|
hash.Write([]byte("global"))
|
|
}
|
|
|
|
for _, link := range t.Policies {
|
|
hash.Write([]byte(link.ID))
|
|
}
|
|
|
|
// Finalize the hash
|
|
hashVal := hash.Sum(nil)
|
|
|
|
// Set and return the hash
|
|
t.Hash = hashVal
|
|
}
|
|
return t.Hash
|
|
}
|
|
|
|
func (t *ACLToken) EstimateSize() int {
|
|
// 33 = 16 (RaftIndex) + 8 (Hash) + 8 (CreateTime) + 1 (Local)
|
|
size := 33 + len(t.AccessorID) + len(t.SecretID) + len(t.Description) + len(t.Type) + len(t.Rules)
|
|
for _, link := range t.Policies {
|
|
size += len(link.ID) + len(link.Name)
|
|
}
|
|
return size
|
|
}
|
|
|
|
// ACLTokens is a slice of ACLTokens.
|
|
type ACLTokens []*ACLToken
|
|
|
|
type ACLTokenListStub struct {
|
|
AccessorID string
|
|
Description string
|
|
Policies []ACLTokenPolicyLink
|
|
Local bool
|
|
CreateTime time.Time `json:",omitempty"`
|
|
Hash []byte
|
|
CreateIndex uint64
|
|
ModifyIndex uint64
|
|
Legacy bool `json:",omitempty"`
|
|
}
|
|
|
|
type ACLTokenListStubs []*ACLTokenListStub
|
|
|
|
func (token *ACLToken) Stub() *ACLTokenListStub {
|
|
return &ACLTokenListStub{
|
|
AccessorID: token.AccessorID,
|
|
Description: token.Description,
|
|
Policies: token.Policies,
|
|
Local: token.Local,
|
|
CreateTime: token.CreateTime,
|
|
Hash: token.Hash,
|
|
CreateIndex: token.CreateIndex,
|
|
ModifyIndex: token.ModifyIndex,
|
|
Legacy: token.Rules != "",
|
|
}
|
|
}
|
|
|
|
func (tokens ACLTokens) Sort() {
|
|
sort.Slice(tokens, func(i, j int) bool {
|
|
return tokens[i].AccessorID < tokens[j].AccessorID
|
|
})
|
|
}
|
|
|
|
func (tokens ACLTokenListStubs) Sort() {
|
|
sort.Slice(tokens, func(i, j int) bool {
|
|
return tokens[i].AccessorID < tokens[j].AccessorID
|
|
})
|
|
}
|
|
|
|
type ACLPolicy struct {
|
|
// This is the internal UUID associated with the policy
|
|
ID string
|
|
|
|
// Unique name to reference the policy by.
|
|
// - Valid Characters: [a-zA-Z0-9-]
|
|
// - Valid Lengths: 1 - 128
|
|
Name string
|
|
|
|
// Human readable description (Optional)
|
|
Description string
|
|
|
|
// The rule set (using the updated rule syntax)
|
|
Rules string
|
|
|
|
// DEPRECATED (ACL-Legacy-Compat) - This is only needed while we support the legacy ACLS
|
|
Syntax acl.SyntaxVersion `json:"-"`
|
|
|
|
// Datacenters that the policy is valid within.
|
|
// - No wildcards allowed
|
|
// - If empty then the policy is valid within all datacenters
|
|
Datacenters []string `json:",omitempty"`
|
|
|
|
// Hash of the contents of the policy
|
|
// This does not take into account the ID (which is immutable)
|
|
// nor the raft metadata.
|
|
//
|
|
// This is needed mainly for replication purposes. When replicating from
|
|
// one DC to another keeping the content Hash will allow us to avoid
|
|
// unnecessary calls to the authoritative DC
|
|
Hash []byte
|
|
|
|
// Embedded Raft Metadata
|
|
RaftIndex `hash:"ignore"`
|
|
}
|
|
|
|
type ACLPolicyListStub struct {
|
|
ID string
|
|
Name string
|
|
Description string
|
|
Datacenters []string
|
|
Hash []byte
|
|
CreateIndex uint64
|
|
ModifyIndex uint64
|
|
}
|
|
|
|
func (p *ACLPolicy) Stub() *ACLPolicyListStub {
|
|
return &ACLPolicyListStub{
|
|
ID: p.ID,
|
|
Name: p.Name,
|
|
Description: p.Description,
|
|
Datacenters: p.Datacenters,
|
|
Hash: p.Hash,
|
|
CreateIndex: p.CreateIndex,
|
|
ModifyIndex: p.ModifyIndex,
|
|
}
|
|
}
|
|
|
|
type ACLPolicies []*ACLPolicy
|
|
type ACLPolicyListStubs []*ACLPolicyListStub
|
|
|
|
func (p *ACLPolicy) SetHash(force bool) []byte {
|
|
if force || p.Hash == nil {
|
|
// Initialize a 256bit Blake2 hash (32 bytes)
|
|
hash, err := blake2b.New256(nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Write all the user set fields
|
|
hash.Write([]byte(p.Name))
|
|
hash.Write([]byte(p.Description))
|
|
hash.Write([]byte(p.Rules))
|
|
for _, dc := range p.Datacenters {
|
|
hash.Write([]byte(dc))
|
|
}
|
|
|
|
// Finalize the hash
|
|
hashVal := hash.Sum(nil)
|
|
|
|
// Set and return the hash
|
|
p.Hash = hashVal
|
|
}
|
|
return p.Hash
|
|
}
|
|
|
|
func (p *ACLPolicy) EstimateSize() int {
|
|
// This is just an estimate. There is other data structure overhead
|
|
// pointers etc that this does not account for.
|
|
|
|
// 64 = 36 (uuid) + 16 (RaftIndex) + 8 (Hash) + 4 (Syntax)
|
|
size := 64 + len(p.Name) + len(p.Description) + len(p.Rules)
|
|
for _, dc := range p.Datacenters {
|
|
size += len(dc)
|
|
}
|
|
|
|
return size
|
|
}
|
|
|
|
// ACLPolicyListHash returns a consistent hash for a set of policies.
|
|
func (policies ACLPolicies) HashKey() string {
|
|
cacheKeyHash, err := blake2b.New256(nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for _, policy := range policies {
|
|
cacheKeyHash.Write([]byte(policy.ID))
|
|
// including the modify index prevents a policy set from being
|
|
// cached if one of the policies has changed
|
|
binary.Write(cacheKeyHash, binary.BigEndian, policy.ModifyIndex)
|
|
}
|
|
return fmt.Sprintf("%x", cacheKeyHash.Sum(nil))
|
|
}
|
|
|
|
func (policies ACLPolicies) Sort() {
|
|
sort.Slice(policies, func(i, j int) bool {
|
|
return policies[i].ID < policies[j].ID
|
|
})
|
|
}
|
|
|
|
func (policies ACLPolicyListStubs) Sort() {
|
|
sort.Slice(policies, func(i, j int) bool {
|
|
return policies[i].ID < policies[j].ID
|
|
})
|
|
}
|
|
|
|
func (policies ACLPolicies) resolveWithCache(cache *ACLCaches, sentinel sentinel.Evaluator) ([]*acl.Policy, error) {
|
|
// Parse the policies
|
|
parsed := make([]*acl.Policy, 0, len(policies))
|
|
for _, policy := range policies {
|
|
policy.SetHash(false)
|
|
cacheKey := fmt.Sprintf("%x", policy.Hash)
|
|
cachedPolicy := cache.GetParsedPolicy(cacheKey)
|
|
if cachedPolicy != nil {
|
|
// policies are content hashed so no need to check the age
|
|
parsed = append(parsed, cachedPolicy.Policy)
|
|
continue
|
|
}
|
|
|
|
p, err := acl.NewPolicyFromSource(policy.ID, policy.ModifyIndex, policy.Rules, policy.Syntax, sentinel)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse %q: %v", policy.Name, err)
|
|
}
|
|
|
|
cache.PutParsedPolicy(cacheKey, p)
|
|
parsed = append(parsed, p)
|
|
}
|
|
|
|
return parsed, nil
|
|
}
|
|
|
|
func (policies ACLPolicies) Compile(parent acl.Authorizer, cache *ACLCaches, sentinel sentinel.Evaluator) (acl.Authorizer, error) {
|
|
// Determine the cache key
|
|
cacheKey := policies.HashKey()
|
|
entry := cache.GetAuthorizer(cacheKey)
|
|
if entry != nil {
|
|
// the hash key takes into account the policy contents. There is no reason to expire this cache or check its age.
|
|
return entry.Authorizer, nil
|
|
}
|
|
|
|
parsed, err := policies.resolveWithCache(cache, sentinel)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse the ACL policies: %v", err)
|
|
}
|
|
|
|
// Create the ACL object
|
|
authorizer, err := acl.NewPolicyAuthorizer(parent, parsed, sentinel)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to construct ACL Authorizer: %v", err)
|
|
}
|
|
|
|
// Update the cache
|
|
cache.PutAuthorizer(cacheKey, authorizer)
|
|
return authorizer, nil
|
|
}
|
|
|
|
func (policies ACLPolicies) Merge(cache *ACLCaches, sentinel sentinel.Evaluator) (*acl.Policy, error) {
|
|
parsed, err := policies.resolveWithCache(cache, sentinel)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return acl.MergePolicies(parsed), nil
|
|
}
|
|
|
|
type ACLReplicationType string
|
|
|
|
const (
|
|
ACLReplicateLegacy ACLReplicationType = "legacy"
|
|
ACLReplicatePolicies ACLReplicationType = "policies"
|
|
ACLReplicateTokens ACLReplicationType = "tokens"
|
|
)
|
|
|
|
// ACLReplicationStatus provides information about the health of the ACL
|
|
// replication system.
|
|
type ACLReplicationStatus struct {
|
|
Enabled bool
|
|
Running bool
|
|
SourceDatacenter string
|
|
ReplicationType ACLReplicationType
|
|
ReplicatedIndex uint64
|
|
ReplicatedTokenIndex uint64
|
|
LastSuccess time.Time
|
|
LastError time.Time
|
|
}
|
|
|
|
// ACLTokenUpsertRequest is used for token creation and update operations
|
|
// at the RPC layer
|
|
type ACLTokenUpsertRequest struct {
|
|
ACLToken ACLToken // Token to manipulate - I really dislike this name but "Token" is taken in the WriteRequest
|
|
Datacenter string // The datacenter to perform the request within
|
|
WriteRequest
|
|
}
|
|
|
|
func (r *ACLTokenUpsertRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLTokenReadRequest is used for token read operations at the RPC layer
|
|
type ACLTokenReadRequest struct {
|
|
TokenID string // id used for the token lookup
|
|
TokenIDType ACLTokenIDType // The Type of ID used to lookup the token
|
|
Datacenter string // The datacenter to perform the request within
|
|
QueryOptions
|
|
}
|
|
|
|
func (r *ACLTokenReadRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLTokenDeleteRequest is used for token deletion operations at the RPC layer
|
|
type ACLTokenDeleteRequest struct {
|
|
TokenID string // ID of the token to delete
|
|
Datacenter string // The datacenter to perform the request within
|
|
WriteRequest
|
|
}
|
|
|
|
func (r *ACLTokenDeleteRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLTokenListRequest is used for token listing operations at the RPC layer
|
|
type ACLTokenListRequest struct {
|
|
IncludeLocal bool // Whether local tokens should be included
|
|
IncludeGlobal bool // Whether global tokens should be included
|
|
Policy string // Policy filter
|
|
Datacenter string // The datacenter to perform the request within
|
|
QueryOptions
|
|
}
|
|
|
|
func (r *ACLTokenListRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLTokenListResponse is used to return the secret data free stubs
|
|
// of the tokens
|
|
type ACLTokenListResponse struct {
|
|
Tokens ACLTokenListStubs
|
|
QueryMeta
|
|
}
|
|
|
|
// ACLTokenBatchReadRequest is used for reading multiple tokens, this is
|
|
// different from the the token list request in that only tokens with the
|
|
// the requested ids are returned
|
|
type ACLTokenBatchReadRequest struct {
|
|
AccessorIDs []string // List of accessor ids to fetch
|
|
Datacenter string // The datacenter to perform the request within
|
|
QueryOptions
|
|
}
|
|
|
|
func (r *ACLTokenBatchReadRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLTokenBatchUpsertRequest is used only at the Raft layer
|
|
// for batching multiple token creation/update operations
|
|
//
|
|
// This is particularly useful during token replication and during
|
|
// automatic legacy token upgrades.
|
|
type ACLTokenBatchUpsertRequest struct {
|
|
Tokens ACLTokens
|
|
AllowCreate bool
|
|
}
|
|
|
|
// ACLTokenBatchDeleteRequest is used only at the Raft layer
|
|
// for batching multiple token deletions.
|
|
//
|
|
// This is particularly useful during token replication when
|
|
// multiple tokens need to be removed from the local DCs state.
|
|
type ACLTokenBatchDeleteRequest struct {
|
|
TokenIDs []string // Tokens to delete
|
|
}
|
|
|
|
// ACLTokenBootstrapRequest is used only at the Raft layer
|
|
// for ACL bootstrapping
|
|
//
|
|
// The RPC layer will use a generic DCSpecificRequest to indicate
|
|
// that bootstrapping must be performed but the actual token
|
|
// and the resetIndex will be generated by that RPC endpoint
|
|
type ACLTokenBootstrapRequest struct {
|
|
Token ACLToken // Token to use for bootstrapping
|
|
ResetIndex uint64 // Reset index
|
|
}
|
|
|
|
// ACLTokenResponse returns a single Token + metadata
|
|
type ACLTokenResponse struct {
|
|
Token *ACLToken
|
|
QueryMeta
|
|
}
|
|
|
|
// ACLTokensResponse returns multiple Tokens associated with the same metadata
|
|
type ACLTokensResponse struct {
|
|
Tokens []*ACLToken
|
|
QueryMeta
|
|
}
|
|
|
|
// ACLPolicyUpsertRequest is used at the RPC layer for creation and update requests
|
|
type ACLPolicyUpsertRequest struct {
|
|
Policy ACLPolicy // The policy to upsert
|
|
Datacenter string // The datacenter to perform the request within
|
|
WriteRequest
|
|
}
|
|
|
|
func (r *ACLPolicyUpsertRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLPolicyDeleteRequest is used at the RPC layer deletion requests
|
|
type ACLPolicyDeleteRequest struct {
|
|
PolicyID string // The id of the policy to delete
|
|
Datacenter string // The datacenter to perform the request within
|
|
WriteRequest
|
|
}
|
|
|
|
func (r *ACLPolicyDeleteRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLPolicyReadRequest is used at the RPC layer to perform policy read operations
|
|
type ACLPolicyReadRequest struct {
|
|
PolicyID string // id used for the policy lookup
|
|
Datacenter string // The datacenter to perform the request within
|
|
QueryOptions
|
|
}
|
|
|
|
func (r *ACLPolicyReadRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLPolicyListRequest is used at the RPC layer to request a listing of policies
|
|
type ACLPolicyListRequest struct {
|
|
DCScope string
|
|
Datacenter string // The datacenter to perform the request within
|
|
QueryOptions
|
|
}
|
|
|
|
func (r *ACLPolicyListRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
type ACLPolicyListResponse struct {
|
|
Policies ACLPolicyListStubs
|
|
QueryMeta
|
|
}
|
|
|
|
// ACLPolicyBatchReadRequest is used at the RPC layer to request a subset of
|
|
// the policies associated with the token used for retrieval
|
|
type ACLPolicyBatchReadRequest struct {
|
|
PolicyIDs []string // List of policy ids to fetch
|
|
Datacenter string // The datacenter to perform the request within
|
|
QueryOptions
|
|
}
|
|
|
|
func (r *ACLPolicyBatchReadRequest) RequestDatacenter() string {
|
|
return r.Datacenter
|
|
}
|
|
|
|
// ACLPolicyResponse returns a single policy + metadata
|
|
type ACLPolicyResponse struct {
|
|
Policy *ACLPolicy
|
|
QueryMeta
|
|
}
|
|
|
|
type ACLPoliciesResponse struct {
|
|
Policies []*ACLPolicy
|
|
QueryMeta
|
|
}
|
|
|
|
// ACLPolicyBatchUpsertRequest is used at the Raft layer for batching
|
|
// multiple policy creations and updates
|
|
//
|
|
// This is particularly useful during replication
|
|
type ACLPolicyBatchUpsertRequest struct {
|
|
Policies ACLPolicies
|
|
}
|
|
|
|
// ACLPolicyBatchDeleteRequest is used at the Raft layer for batching
|
|
// multiple policy deletions
|
|
//
|
|
// This is particularly useful during replication
|
|
type ACLPolicyBatchDeleteRequest struct {
|
|
PolicyIDs []string
|
|
}
|