2018-10-19 16:04:07 +00:00
package consul
import (
"sync/atomic"
2019-04-08 17:05:51 +00:00
"time"
2018-10-19 16:04:07 +00:00
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs"
2020-10-08 19:02:19 +00:00
"github.com/hashicorp/consul/lib/serf"
2018-10-19 16:04:07 +00:00
)
var serverACLCacheConfig * structs . ACLCachesConfig = & structs . ACLCachesConfig {
2018-11-02 17:00:39 +00:00
// The server's ACL caching has a few underlying assumptions:
2018-10-19 16:04:07 +00:00
//
// 1 - All policies can be resolved locally. Hence we do not cache any
2019-04-15 20:43:19 +00:00
// unparsed policies/roles as we have memdb for that.
2018-10-19 16:04:07 +00:00
// 2 - While there could be many identities being used within a DC the
// number of distinct policies and combined multi-policy authorizers
// will be much less.
// 3 - If you need more than 10k tokens cached then you should probably
2018-11-02 17:00:39 +00:00
// enable token replication or be using DC local tokens. In both
2018-10-19 16:04:07 +00:00
// cases resolving the tokens from memdb will avoid the cache
// entirely
//
Identities : 10 * 1024 ,
Policies : 0 ,
ParsedPolicies : 512 ,
Authorizers : 1024 ,
2019-04-15 20:43:19 +00:00
Roles : 0 ,
2018-10-19 16:04:07 +00:00
}
func ( s * Server ) checkTokenUUID ( id string ) ( bool , error ) {
state := s . fsm . State ( )
2019-04-08 17:05:51 +00:00
// We won't check expiration times here. If we generate a UUID that matches
// a token that hasn't been reaped yet, then we won't be able to insert the
// new token due to a collision.
2019-10-24 18:38:09 +00:00
if _ , token , err := state . ACLTokenGetByAccessor ( nil , id , nil ) ; err != nil {
2018-10-19 16:04:07 +00:00
return false , err
} else if token != nil {
return false , nil
}
2019-10-24 18:38:09 +00:00
if _ , token , err := state . ACLTokenGetBySecret ( nil , id , nil ) ; err != nil {
2018-10-19 16:04:07 +00:00
return false , err
} else if token != nil {
return false , nil
}
return ! structs . ACLIDReserved ( id ) , nil
}
func ( s * Server ) checkPolicyUUID ( id string ) ( bool , error ) {
state := s . fsm . State ( )
2019-10-24 18:38:09 +00:00
if _ , policy , err := state . ACLPolicyGetByID ( nil , id , nil ) ; err != nil {
2018-10-19 16:04:07 +00:00
return false , err
} else if policy != nil {
return false , nil
}
return ! structs . ACLIDReserved ( id ) , nil
}
2019-04-15 20:43:19 +00:00
func ( s * Server ) checkRoleUUID ( id string ) ( bool , error ) {
state := s . fsm . State ( )
2019-10-24 18:38:09 +00:00
if _ , role , err := state . ACLRoleGetByID ( nil , id , nil ) ; err != nil {
2019-04-15 20:43:19 +00:00
return false , err
} else if role != nil {
return false , nil
}
return ! structs . ACLIDReserved ( id ) , nil
}
2019-04-26 17:49:28 +00:00
func ( s * Server ) checkBindingRuleUUID ( id string ) ( bool , error ) {
state := s . fsm . State ( )
2019-10-24 18:38:09 +00:00
if _ , rule , err := state . ACLBindingRuleGetByID ( nil , id , nil ) ; err != nil {
2019-04-26 17:49:28 +00:00
return false , err
} else if rule != nil {
return false , nil
}
return ! structs . ACLIDReserved ( id ) , nil
}
2020-03-16 16:54:45 +00:00
func ( s * Server ) updateSerfTags ( key , value string ) {
// Update the LAN serf
2020-10-08 19:02:19 +00:00
serf . UpdateTag ( s . serfLAN , key , value )
2020-03-16 16:54:45 +00:00
if s . serfWAN != nil {
2020-10-08 19:02:19 +00:00
serf . UpdateTag ( s . serfWAN , key , value )
2020-03-16 16:54:45 +00:00
}
s . updateEnterpriseSerfTags ( key , value )
}
2018-10-19 16:04:07 +00:00
func ( s * Server ) updateACLAdvertisement ( ) {
// One thing to note is that once in new ACL mode the server will
// never transition to legacy ACL mode. This is not currently a
// supported use case.
2020-03-16 16:54:45 +00:00
s . updateSerfTags ( "acls" , string ( structs . ACLModeEnabled ) )
}
2018-10-19 16:04:07 +00:00
func ( s * Server ) canUpgradeToNewACLs ( isLeader bool ) bool {
if atomic . LoadInt32 ( & s . useNewACLs ) != 0 {
// can't upgrade because we are already upgraded
return false
}
if ! s . InACLDatacenter ( ) {
2020-03-27 16:31:43 +00:00
foundServers , mode , _ := ServersGetACLMode ( s , "" , s . config . ACLDatacenter )
if mode != structs . ACLModeEnabled || ! foundServers {
2020-04-14 15:54:27 +00:00
s . logger . Debug ( "Cannot upgrade to new ACLs, servers in acl datacenter are not yet upgraded" , "ACLDatacenter" , s . config . ACLDatacenter , "mode" , mode , "found" , foundServers )
2018-10-19 16:04:07 +00:00
return false
}
}
2020-03-27 16:31:43 +00:00
leaderAddr := string ( s . raft . Leader ( ) )
foundServers , mode , leaderMode := ServersGetACLMode ( s , leaderAddr , s . config . Datacenter )
2018-10-19 16:04:07 +00:00
if isLeader {
2020-03-27 16:31:43 +00:00
if mode == structs . ACLModeLegacy {
2018-10-19 16:04:07 +00:00
return true
}
} else {
2020-03-27 16:31:43 +00:00
if leaderMode == structs . ACLModeEnabled {
2018-10-19 16:04:07 +00:00
return true
}
}
2020-04-14 15:54:27 +00:00
s . logger . Debug ( "Cannot upgrade to new ACLs" , "leaderMode" , leaderMode , "mode" , mode , "found" , foundServers , "leader" , leaderAddr )
2018-10-19 16:04:07 +00:00
return false
}
func ( s * Server ) InACLDatacenter ( ) bool {
2018-10-31 20:00:46 +00:00
return s . config . ACLDatacenter == "" || s . config . Datacenter == s . config . ACLDatacenter
2018-10-19 16:04:07 +00:00
}
func ( s * Server ) UseLegacyACLs ( ) bool {
return atomic . LoadInt32 ( & s . useNewACLs ) == 0
}
func ( s * Server ) LocalTokensEnabled ( ) bool {
// in ACL datacenter so local tokens are always enabled
if s . InACLDatacenter ( ) {
return true
}
2019-02-27 19:28:31 +00:00
if ! s . config . ACLTokenReplication || s . tokens . ReplicationToken ( ) == "" {
2020-08-07 10:02:02 +00:00
// token replication is off so local tokens are disabled
2018-10-19 16:04:07 +00:00
return false
}
return true
}
func ( s * Server ) ACLDatacenter ( legacy bool ) string {
// For resolution running on servers the only option
// is to contact the configured ACL Datacenter
if s . config . ACLDatacenter != "" {
return s . config . ACLDatacenter
}
// This function only gets called if ACLs are enabled.
// When no ACL DC is set then it is assumed that this DC
// is the primary DC
return s . config . Datacenter
}
2020-01-27 19:54:32 +00:00
// ResolveIdentityFromToken retrieves a token's full identity given its secretID.
2018-10-19 16:04:07 +00:00
func ( s * Server ) ResolveIdentityFromToken ( token string ) ( bool , structs . ACLIdentity , error ) {
// only allow remote RPC resolution when token replication is off and
// when not in the ACL datacenter
if ! s . InACLDatacenter ( ) && ! s . config . ACLTokenReplication {
return false , nil , nil
}
2019-10-24 18:38:09 +00:00
index , aclToken , err := s . fsm . State ( ) . ACLTokenGetBySecret ( nil , token , nil )
2018-10-19 16:04:07 +00:00
if err != nil {
return true , nil , err
2019-04-08 17:05:51 +00:00
} else if aclToken != nil && ! aclToken . IsExpired ( time . Now ( ) ) {
2018-10-19 16:04:07 +00:00
return true , aclToken , nil
}
return s . InACLDatacenter ( ) || index > 0 , nil , acl . ErrNotFound
}
func ( s * Server ) ResolvePolicyFromID ( policyID string ) ( bool , * structs . ACLPolicy , error ) {
2019-10-24 18:38:09 +00:00
index , policy , err := s . fsm . State ( ) . ACLPolicyGetByID ( nil , policyID , nil )
2018-10-19 16:04:07 +00:00
if err != nil {
return true , nil , err
} else if policy != nil {
return true , policy , nil
}
// If the max index of the policies table is non-zero then we have acls, until then
// we may need to allow remote resolution. This is particularly useful to allow updating
// the replication token via the API in a non-primary dc.
return s . InACLDatacenter ( ) || index > 0 , policy , acl . ErrNotFound
}
2019-04-15 20:43:19 +00:00
func ( s * Server ) ResolveRoleFromID ( roleID string ) ( bool , * structs . ACLRole , error ) {
2019-10-24 18:38:09 +00:00
index , role , err := s . fsm . State ( ) . ACLRoleGetByID ( nil , roleID , nil )
2019-04-15 20:43:19 +00:00
if err != nil {
return true , nil , err
} else if role != nil {
return true , role , nil
}
// If the max index of the roles table is non-zero then we have acls, until then
// we may need to allow remote resolution. This is particularly useful to allow updating
// the replication token via the API in a non-primary dc.
return s . InACLDatacenter ( ) || index > 0 , role , acl . ErrNotFound
}
2018-10-19 16:04:07 +00:00
func ( s * Server ) ResolveToken ( token string ) ( acl . Authorizer , error ) {
2020-02-04 20:58:56 +00:00
_ , authz , err := s . ResolveTokenToIdentityAndAuthorizer ( token )
return authz , err
2018-10-19 16:04:07 +00:00
}
2020-05-13 17:00:08 +00:00
func ( s * Server ) ResolveTokenToIdentity ( token string ) ( structs . ACLIdentity , error ) {
// not using ResolveTokenToIdentityAndAuthorizer because in this case we don't
// need to resolve the roles, policies and namespace but just want the identity
// information such as accessor id.
return s . acls . ResolveTokenToIdentity ( token )
}
2019-12-18 18:46:53 +00:00
func ( s * Server ) ResolveTokenToIdentityAndAuthorizer ( token string ) ( structs . ACLIdentity , acl . Authorizer , error ) {
2020-02-04 20:58:56 +00:00
if id , authz := s . ResolveEntTokenToIdentityAndAuthorizer ( token ) ; id != nil && authz != nil {
return id , authz , nil
}
2019-12-18 18:46:53 +00:00
return s . acls . ResolveTokenToIdentityAndAuthorizer ( token )
}
2020-01-27 19:54:32 +00:00
// ResolveTokenIdentityAndDefaultMeta retrieves an identity and authorizer for the caller,
// and populates the EnterpriseMeta based on the AuthorizerContext.
func ( s * Server ) ResolveTokenIdentityAndDefaultMeta ( token string , entMeta * structs . EnterpriseMeta , authzContext * acl . AuthorizerContext ) ( structs . ACLIdentity , acl . Authorizer , error ) {
2020-03-11 18:08:49 +00:00
identity , authz , err := s . ResolveTokenToIdentityAndAuthorizer ( token )
2019-12-18 18:46:53 +00:00
if err != nil {
2020-01-27 19:54:32 +00:00
return nil , nil , err
2019-12-18 18:46:53 +00:00
}
// Default the EnterpriseMeta based on the Tokens meta or actual defaults
// in the case of unknown identity
if identity != nil {
entMeta . Merge ( identity . EnterpriseMetadata ( ) )
} else {
entMeta . Merge ( structs . DefaultEnterpriseMeta ( ) )
}
// Use the meta to fill in the ACL authorization context
entMeta . FillAuthzContext ( authzContext )
2020-01-27 19:54:32 +00:00
return identity , authz , err
}
// ResolveTokenAndDefaultMeta passes through to ResolveTokenIdentityAndDefaultMeta, eliding the identity from its response.
func ( s * Server ) ResolveTokenAndDefaultMeta ( token string , entMeta * structs . EnterpriseMeta , authzContext * acl . AuthorizerContext ) ( acl . Authorizer , error ) {
_ , authz , err := s . ResolveTokenIdentityAndDefaultMeta ( token , entMeta , authzContext )
2019-12-18 18:46:53 +00:00
return authz , err
}
2018-10-19 16:04:07 +00:00
func ( s * Server ) filterACL ( token string , subj interface { } ) error {
2020-03-11 18:08:49 +00:00
if id , authz := s . ResolveEntTokenToIdentityAndAuthorizer ( token ) ; id != nil && authz != nil {
return s . acls . filterACLWithAuthorizer ( authz , subj )
}
2018-10-19 16:04:07 +00:00
return s . acls . filterACL ( token , subj )
}
func ( s * Server ) filterACLWithAuthorizer ( authorizer acl . Authorizer , subj interface { } ) error {
return s . acls . filterACLWithAuthorizer ( authorizer , subj )
}