Keystone Tokens are bearer tokens, and bearer tokens are vulnerable to replay attacks. What if we wanted to get rid of them?
Keystone comes out of the early days of OpenStack. When you have a single monolith, you can have a password table. Once you start having multiple, related services, you need a shared sign on mechanism for them. While the Keystone token mechanism is not elegant, it served the need: to avoid copying the user’s password to multiple services.
Today, the tokens represent two things. First, that the user has authenticated, and second, that the user is performing an operation in a specific scope. The token has a set of roles assigned to it, and those roles are on either a project or a domain.
In an enterprise that has a centralized authentication mechanism such as Kerberos or X509 Client Certificates, an application typically performs a cryptographic handshake to authenticate the user, and then performs an additional query against a centralized directory to see what groups the user belongs to in order to perform an access control check.
This leads to the first things that could replace tokens: reuse the existing authentication mechanisms to provide access to the remote services. Putting Nova or Glance behind a web server running mod_auth_kerb (or better yet, mod_auth_gssapi, but I get ahead of myself) for Kerberos or using HTTPS with Client Certificate can both be done across the public internet now. Both mechanisms have their pros and cons. Once the user authenticates, the service could then query the roles assignments for the user from Keystone instead of validating a token. The data would be the same.
What if those mechanisms are not acceptable? There is still Federation. Keystone today can serve out tokens using either OpenID connect or SAML. There is no reason these same mechanisms could not be put in front of the other services of OpenStack, with Keystone filling out the Role information either in the assertions or via Server lookup.
All of these mechanism have a greater cost in network calls to the service endpoint, although not necessary to the user, who may not have to make the round trips to Keystone in order to fetch a token (OK SAML is very chatty.) What other options do we have?
If we don’t care about browser support, and focus on just the CLI, then a few more options open up. Keystone could become a registry for public keys, and users could authenticate by signing the request that go to Nova. The signature of a request would only be slightly larger than the size of a Fernet token, and the user would be able to greatly reduce the number of web calls. There would be slightly larger overhead due to the asymmetric cryptography.
Unfortunately, this is not a real option from the browser; the browser support for “naked keys” is currently not sufficient to ensure the operations will succeed. Usage of Client X509 Certificates is still the best way to ensure cryptography from the browser, and will not necessarily support arbitrary document signing. I expect this to change over time, but I suspect the browser support will be uneven at best for a while.
Both versions of OAUTH are designed to address distributed authorization. Without cryptographic signing, the OAUTH (1) protocol degenerates to bearer tokens. With Cryptography, the OAUTH (2) protocol is roughly comparable to SAML; OpenID connect is based on OAUTH2, so this should be no surprise. So, while Keystone tokens could be replaced with some form of OAUTH, and it would at least be closer to a standard, it wouldn’t radically change the current approach to Keystone tokens. OAUTH either gives us what we have with Keystone tokens today or what we would have with SAML.
Keystone tokens provide minimal additional security benefits for an all-in-one deployment. Instead of putting the User ID and password into the body of the request, the user could pass them via the standard Basic-Auth mechanism with no change in the degree of security. This provides parity with how Keystone is deployed today. No outside service should be able to access the Message Broker. Calls between services should be done on internal (localhost) interfaces or domain sockets, not require passwords, and trust the authorization context as set by the caller.
One Time Passwords
One time paswords (OTPs) in conjunction with Basic Auth or some other way to curry the data to the server provides an interesting alternative. In theory, the user could pass the OTP along at the start of the request, the Horizon server would be responsible for timestamping it, and the password could then be used for the duration. This seems impractical, as we are essentially generating a new bearer token. For all-in-one deployments they would work as well as Basic-Auth.