The main drawback of the ticketing system is that a major change must be made to OpenStack to implement it. Here, we propose a new, backwards-compatible Fernet extension that we call Recursive Augmented Fernet Tokens (RAFTs), on top of which user-specified restrictions can float independently without requiring additional Keystone interaction. The RAFT token mechanism provides the modularity security requirement in the presence of one or more corrupted services just as ticketing accomplished. Fundamentally, RAFTs use the Fernet HMAC as a shared secret between the user and Keystone that can be used to authenticate arbitrary user-supplied restrictions.
Algorithm 27Ticketing System
1: function Ideal Identity
2: Upon receiving (creds, Job-Type, Restriction-List) from User U:
3: if creds is validthen
4: Create ticket for the Job using{Job-Type, Restriction-List, U};
5: StoreDB(ticket, Service-List);
6: returnticket;
7: else
8: return “fail”;
9: end if
10:
11: Upon receiving (FService,FIdentity, “Validate”,ticket) fromFService:
12: if FindBD(ticket, Service-List) where the ticket is valid and FService is in the Service-List
then
13: New-Service-List=Remove FService from the Service-List;
14: if New-Service-List is Emptythen
15: RemoveDB(ticket, Service-List);
16: else
17: UpdateDB({ticket, Service-List},{New-Service-List, ticket });
18: end if
19: Send-FService(FIdentity, session-id, Successful);
20: else
21: Send-FService(FIdentity, session-id, Fail);
22: end if
23: end function
24: function Service
25: Upon receiving (Sender, ticket) from user U:
26: StoreBuffer (Sender, ticket);
27: Send-FIdentity (FService, “Validate”,ticket);
28:
29: Upon receiving (FIdentity, session-id, valid) fromFIdentity:
30: if valid=1 & FindBuffer(Sender, ticket) where session-ID in the Job-Request=session-id
then
31: Apply the Request;
32: else
33: Return Fail;
34: end if
The Fernet token is a recent innovation that uses cryptography to provide authenticity without accessing a central DB. It is a mechanism by which Keystone creates a private, authenticated channel to itself. It has quickly become the preferred token format for OpenStack as it does not require maintaining a central database of valid tokens, which would add network load and complexity when running a distributed Keystone service. The current Fernet token mechanism is [44]. The Fernet token is represented as follows:
Sk= Keystone signing key
TokenFernet=SpecificationkHMACSk(Specification)
Because the original Fernet token is a bearer one, the link between the user and Keystone must be authenticated and encrypted to ensure that only the user receivesTokenFernet from Keystone.
In RAFT, a user first obtains a Fernet token from Keystone. The user takes theHMACSk(Specification)
as a shared secret keyU kbetween Keystone and himself. Then, for each of his subsequent requests, the user calculates:
TokenRAFT =Requestk
Specificationk
Restrictionsk
HMACU k(RequestkSpecificationkRestrictions)
TheRestrictions could be a composition of anything like a shortened expiration time (“expiration- time = 5 secs”) or endpoint restrictions (“service=cinder”). The RAFT token is a self-explained token and the user request is part of the token and there is no need to accompany the request with the token. Hence, the user just sends the RAFT token to the desired service. For the sake of backward compatibility, which we will talk about later, all the services continue to accept job requests in the format of (Request, T oken) where either T oken = TokenRAFT −Request or
T oken=TokenF ernet.
When a service receives TokenRAFT, the service forwards it to Keystone asking for validation.
If the answer of Keystone was “valid”, the service extracts theRequest and Restrictions from the token and gets the work done accordingly.
In the current OpenStack architecture, each service gets a service token from Keystone. The service token is used to authenticate the service to other services [45]. RAFT replaces this bearer token as well: the token of a service is never sent to other services, but is instead used as a signing key Svk in the RAFT framework. Concretely, if a service needs to involve other services, then it calculates:
Svk=Service signing key, from Keystone N ew TokenRAFT =TokenRAFT k
Restrictionsk
ServiceIdk
HMACSvk(TokenRAFT kRestrictions),
and sends the result to the required services. We highlight three tangible benefits of this method: each service is able to add (but not remove!) Restrictionsto the user’s token, the MAC authenticates
the channel used to make a service-to-service request, and the token provides the recipient service with the provenance of the request [45].
When Keystone receives a token validation request from a service S for tokenT, it follows the Fernet protocol as ifT is a Fernet token. Keystone looks into its blacklist to see whetherT was used byS or not. If yes, Keystone returns fail. Otherwise, Keystone validates all the service signatures. Then, it takes out Specification from T and calculates HM ACSk(Specification) as its signing key.
Using the result, Keystone is able to verify the user’s signature embedded intoT, too. If the token is valid, Keystone adds (T, S) to its blacklist and returns “valid”. Just as in the ticketing system, the expiration time of RAFT tokens are very short. Therefore, the blacklist can be implemented in a lightweight memcached structure.
The RAFT is specified fully in Algorithm 28.
Pros and cons. RAFT uses the Fernet token to create a user to keystone private/authenticated channel, while not jeopardizing keystone’s existing channel to itself. It can be implemented in a backward compatible way. RAFT tokens are larger than Fernet tokens and the size of buffers used for storing tokens in different OpenStack modules must be carefully inspected.