Add spec for MFA auth receipts
Change-Id: Ia8f25cf84070c271fc2ffb9f8fd115f55b3e428e
This commit is contained in:
parent
7364e98854
commit
d3695a1b5d
|
@ -14,6 +14,17 @@ Project Documentation:
|
|||
keystone
|
||||
========
|
||||
|
||||
Rocky approved specs:
|
||||
|
||||
`Rocky Roadmap <https://trello.com/b/wmyzbFq5/keystone-rocky-roadmap>`_
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
:maxdepth: 1
|
||||
|
||||
specs/keystone/rocky/*
|
||||
|
||||
|
||||
Queens approved specs:
|
||||
|
||||
`Queens Roadmap <https://trello.com/b/5F0h9Hoe/keystone-queens-roadmap>`_
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
..
|
||||
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||
License.
|
||||
|
||||
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||
|
||||
================
|
||||
MFA Auth Receipt
|
||||
================
|
||||
|
||||
`mfa-auth-receipt <https://blueprints.launchpad.net/keystone/+spec/
|
||||
mfa-auth-receipt>`_
|
||||
|
||||
|
||||
To provide proper usable multi-factor authentication (MFA) support in
|
||||
OpenStack we need to return an auth receipt to the user representing partial
|
||||
authentication, which can be returned to Keystone as part of a challenge
|
||||
response process.
|
||||
|
||||
|
||||
Problem Description
|
||||
===================
|
||||
|
||||
As of Ocata Keystone supports setting auth rules on a given user and
|
||||
potentially requiring them to auth with multiple methods. This is a good
|
||||
implementation of MFA, but the problem rests in a user or service knowing ahead
|
||||
of time how they need to auth. Most standard MFA systems are challenge response
|
||||
based. You auth with one of your factors, then are given a receipt of that
|
||||
partial authentication, which you can return along with the missing pieces.
|
||||
|
||||
Keystone needs such a mechanism because without it we can't realistically
|
||||
consume MFA anywhere else in OpenStack in a manner that makes sense for users.
|
||||
|
||||
The original proposal for MFA in Keystone actually included this concept but
|
||||
was never implemented:
|
||||
`multi-factor-authn <https://blueprints.launchpad.net/keystone/+spec/
|
||||
multi-factor-authn>`_
|
||||
|
||||
The concept of a half-token was discussed, but it never really got implemented
|
||||
in a way we could use for MFA.
|
||||
|
||||
Proposed Change
|
||||
===============
|
||||
|
||||
The proposal is to add a new mechanism which returns a receipt to the user on a
|
||||
partially successful auth attempt. This would in essence be very similar to a
|
||||
token, and ideally use a similar system for storage (fernet, jwt) to keep
|
||||
internal logic consistent and reusable.
|
||||
|
||||
When a user successfully authenticates with one of their many auth rules, we
|
||||
can infer that they are who they say they are, and then return to them a
|
||||
receipt that contains information about missing auth rules.
|
||||
|
||||
If a user attempts auth with multiple methods and most fail but at least one
|
||||
succeeds, we do not return a receipt, but we do include json error data as to
|
||||
what methods failed, and which did not.
|
||||
|
||||
Using a receipt to get a new receipt with extra auth methods should ideally be
|
||||
possible. If you need three auth methods to get a token, you should be able to
|
||||
add to your receipt until it can become a token.
|
||||
|
||||
This receipt would allow no API interaction, but it would be proof that
|
||||
certain auth methods have been completed. The expiry for the receipt would
|
||||
default to a fairly short time-frame (5 minutes).
|
||||
|
||||
Receipt Response
|
||||
----------------
|
||||
|
||||
The return code for this would be ``401`` as the user is still unauthorized,
|
||||
with the response header containing the receipt id, and the body containing
|
||||
information about the receipt which they need to continue the auth process.
|
||||
|
||||
In addition this response would be explicitly setup to only occur when a user
|
||||
with auth rules successfully auths with one of the methods in any of their auth
|
||||
rules.
|
||||
|
||||
The receipt id (the encrypted payload) would be included in the header of the
|
||||
``401`` response in the same fashion as a token is but under the header
|
||||
``OPENSTACK-AUTH-RECEIPT``.
|
||||
|
||||
An example response::
|
||||
|
||||
{
|
||||
"receipt": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"user_id": "423f19a4ac1e4f48bbb4180756e6eb6c",
|
||||
"expires_at": "2015-11-06T15:32:17.893769Z"
|
||||
},
|
||||
"required_auth_methods": [
|
||||
['password', 'totp'],
|
||||
['password', 'option2'],
|
||||
['password', 'option3', 'option4']
|
||||
]
|
||||
}
|
||||
|
||||
``required_auth_methods`` would be a list of rules that include the
|
||||
successfully authenticated methods and not a list of all of the user's auth
|
||||
rules. The methods in the receipt do not entirely have to be all from the same
|
||||
auth rule, the receipt contains valid methods, and what rules they could apply
|
||||
to, so it's an intersection test.
|
||||
|
||||
Another example response::
|
||||
|
||||
{
|
||||
"receipt": {
|
||||
"methods": [
|
||||
"password", "option3"
|
||||
],
|
||||
"user_id": "423f19a4ac1e4f48bbb4180756e6eb6c",
|
||||
"expires_at": "2015-11-06T15:32:17.893769Z"
|
||||
},
|
||||
"required_auth_methods": [
|
||||
['password', 'option2'],
|
||||
['option3', 'option4']
|
||||
]
|
||||
}
|
||||
|
||||
In this above case, the user now has two optional MFA paths off the same
|
||||
receipt despite there being no overlap between the two auth rules.
|
||||
|
||||
Receipt payload
|
||||
---------------
|
||||
|
||||
The receipt will not include scope data as it isn't relevant to it. A user will
|
||||
supply scope when using the receipt and trying to get a token, Keystone will
|
||||
not look at the receipt for scope. The only reason to potentially introduce
|
||||
scope to the receipt is if and when we introduce auth rules based on scope.
|
||||
|
||||
The actual provider for the receipt should be configurable in the same fashion
|
||||
as token, and similar types (fernet, jwt). In the case of fernet the key
|
||||
repository should ideally be able to be shared with the token provider, but
|
||||
configuration should be possible to split the repo. This minimises potential
|
||||
pain for deployers and gives them time before they need to add a second key
|
||||
repository.
|
||||
|
||||
Ideally any code we can share with the token providers we do, and move as much
|
||||
as makes sense into common utils. Much like tokens, we even handle key
|
||||
rotation in the same way. Accept receipts encrypted by the current and last key
|
||||
but issue new ones with the current key.
|
||||
|
||||
The receipt data itself (before encryption) would likely be::
|
||||
|
||||
{
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"user_id": "423f19a4ac1e4f48bbb4180756e6eb6c",
|
||||
"issued_at": "2015-11-06T14:32:17.893797Z",
|
||||
}
|
||||
|
||||
``methods`` in the above payload being the valid and already satisfied auth
|
||||
methods for that receipt.
|
||||
|
||||
There isn't much data Keystone itself needs that it can't get from database
|
||||
as long as it knows the user id. All we need to pass back is what methods have
|
||||
already been validated, when it was issued at (for expiry checking), and the
|
||||
user the receipt applies to (so we can match it with the user in the auth
|
||||
request).
|
||||
|
||||
Receipt processing
|
||||
------------------
|
||||
|
||||
When auth is continued with a receipt a user must supply the receipt id in the
|
||||
``OPENSTACK-AUTH-RECEIPT`` header. When Keystone sees an auth attempt with
|
||||
that header it will use the set receipt provider to decrypt the payload (id),
|
||||
and will then treat the ``methods`` as defined in the receipt as having been
|
||||
already satisfied as part of auth, and auth continues with the new user
|
||||
supplied methods.
|
||||
|
||||
If all given methods are valid, but all the total valid methods including those
|
||||
from the receipt still do not fulfill any of the auth rules, another receipt is
|
||||
returned.
|
||||
|
||||
If the receipt is expired, don't even process the user supplied auth methods
|
||||
and fail right away.
|
||||
|
||||
A mismatch between receipt user_id and user_id in any of the methods is a
|
||||
failure.
|
||||
|
||||
A failure in any of the user supplied auth methods is a failure, and does not
|
||||
extend the receipt even if some new methods were valid, but should include
|
||||
failure details.
|
||||
|
||||
If a user supplies a method that was already satisfied in the receipt, the user
|
||||
supplied method takes precedence, even if it fails.
|
||||
|
||||
All of these failures return a ``401``.
|
||||
|
||||
Alternatives
|
||||
============
|
||||
|
||||
In Ocata when the auth rules were introduced the alternative was put forward
|
||||
to simply change the error messages of the failed MFA auth to inform the user
|
||||
why their auth failed. Any services could also parse the errors and infer
|
||||
what the missing auth was and generate GUI or cli queries back to the user.
|
||||
|
||||
This doesn't work for a few reasons. While we can structure the response to be
|
||||
parsable it still requires that for every auth attempt ALL methods are
|
||||
supplied. This means an MFA attempt for password+totp needs to cache the
|
||||
password to resubmit it when it is determined that totp is also needed.
|
||||
|
||||
For Horizon that doesn't work. We can't cache the password server-side, and we
|
||||
shouldn't store it in a cookie or in browser really, and asking the user to
|
||||
supply their password again isn't good UX.
|
||||
|
||||
This alternative also isn't a real challenge response.
|
||||
|
||||
Security Impact
|
||||
===============
|
||||
|
||||
A user who authenticates with one successful method now knows what auth rules
|
||||
can be used for a given user. This isn't particularly unsafe, as while they
|
||||
know the rules, they can't auth with them. Additionally it is safe to assume
|
||||
that one successful auth method is enough to prove identity of the user, while
|
||||
not enough to satisfy authentication requirements.
|
||||
|
||||
If any method fails, we still return an error, and auth rules are only exposed
|
||||
if at least one method was valid.
|
||||
|
||||
An additional security concern is that a given receipt could be used to make
|
||||
multiple tokens in the short window it is valid. Given that users can already
|
||||
have multiple tokens, this is only a concern if a receipt is intercepted and
|
||||
completed by someone else. Given though that this receipt exists in the context
|
||||
of MFA, the second factor should limit this concern quite heavily. In reality
|
||||
this isn't a problem unique to the auth receipt, but an eventual action we
|
||||
should take is to do some form of receipt revocations when turned into a token.
|
||||
|
||||
Notifications Impact
|
||||
====================
|
||||
|
||||
Notifications will continue to be issued for successful and fail authentication
|
||||
as today. Issuance of a receipt will not issue a notification.
|
||||
|
||||
We may add receipt notifications in the future.
|
||||
|
||||
Other End User Impact
|
||||
=====================
|
||||
|
||||
The user may now process the returned data and utilize the receipt to
|
||||
authenticate in multiple steps.
|
||||
|
||||
It is important to note that this change does not affect anyone only doing
|
||||
auth with no auth rules set. The default auth use case does not change, only
|
||||
the MFA use case which is not yet fully implemented or used anyway.
|
||||
|
||||
Performance Impact
|
||||
==================
|
||||
|
||||
It is expected load and auth-processing-time will increase a small amount due
|
||||
added encryption and decryption of the receipt.
|
||||
|
||||
Other Deployer Impact
|
||||
=====================
|
||||
|
||||
Depending on how we handle fernet/jwt key repositories, deployers may need to
|
||||
add a second key repository. Ideally we'd allow this to be configurable so at
|
||||
first they didn't need to do this, but had the option to for added security.
|
||||
|
||||
Developer Impact
|
||||
================
|
||||
|
||||
This would only affect authentication workflows in OpenStack and any code
|
||||
dealing with them. This change though will give us a good programmatic way to
|
||||
deal with MFA and will mean those tools can handle failures in a useful way.
|
||||
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
Assignee(s)
|
||||
-----------
|
||||
|
||||
Primary assignee:
|
||||
|
||||
* Adrian Turjak - adriant@catalyst.net.nz (IRC adriant)
|
||||
|
||||
Work Items
|
||||
----------
|
||||
|
||||
#. Add support for the auth receipt to Keystone and change the auth plugin
|
||||
layer to return it on one successful auth method out of configured rules
|
||||
rather than an error, and make the auth layer able to process a receipt for
|
||||
continued auth.
|
||||
#. Add support to KeystoneAuth to handle this correctly and infer from this
|
||||
receipt what other methods are needed, as well as adding proper Multi-Method
|
||||
support into KeystoneAuth.
|
||||
#. Work with the CLI and Dashboard teams to build support in for MFA using the
|
||||
changes made to KeystoneAuth. (optional follow up)
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
N/A
|
||||
|
||||
Documentation Impact
|
||||
====================
|
||||
|
||||
Will require extra documentation for new features, but no existing non-MFA auth
|
||||
paths will change.
|
||||
|
||||
We need to add to the docs that MFA receipts also need encryption keys, and
|
||||
that by default they are shared with fernet. Will need notes added that fernet
|
||||
key rotation affect the receipts if their repository is shared.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
* https://adam.younglogic.com/2012/10/multifactor-auth-and-keystone/
|
||||
* https://blueprints.launchpad.net/keystone/+spec/multi-factor-authn
|
||||
* https://specs.openstack.org/openstack/keystone-specs/specs/keystone/ocata/per-user-auth-plugin-requirements.html
|
Loading…
Reference in New Issue