Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Extend Session Lifetime for MFA #36

Closed
drewsonne opened this issue Jan 29, 2018 · 8 comments
Closed

[RFC] Extend Session Lifetime for MFA #36

drewsonne opened this issue Jan 29, 2018 · 8 comments

Comments

@drewsonne
Copy link
Contributor

drewsonne commented Jan 29, 2018

Problem:
When using AWS SAML federation, there is a maximum of 1 hour of the lifetime of the AWS STS credentials. This is not a problem if the application can automatically renew the AWS STS credentials through the SAML assertion without human intervention. When using the official onelogin python client as in #33 the user should not be prompted for a new MFA challenge, until the OneLogin refresh token expires (which is 10 hours).

NOTE: Although the authentication to AWS is done through SAML, the authentication to OneLogin is handled by OAuth, so the refresh tokens are used by the OneLogin python client by default which gives us a 10 hour lifetime without mfa. See:

To ensure credentials are continually re-generated, the onelogin-aws-login client must be run in a runtime with the --durationSeconds flag enabled. This requires a user to keep the process open and running in a terminal, which is fragile as the user may accidentally close the tab or application.

Proposed Solution:

  1. Create a new bin/ scripts onelogin-aws-daemon, which will run in daemon mode, handle the hourly AWS SAML/STS role assumption and expose a socket with two features:
  • report on the current validity of the AWS tokens
  • act as a listener to the subsequent onelogin-aws-login command to allow the user to re-enter their MFA OTP.
  1. Modify the existing onelogin-aws-login to discover the running daemon and change into client mode to forward MFA OTP details onto the onelogin-aws-daemon when the AWS STS session has expired.
  2. Create daemon configurations for:
  • a systemd service file (centos>=7,debian>=8)
  • a launchd plist (macos)
  1. Move the existing configuration to ~/.onelogin-aws/credentials which will contain the existing contents of ~/.onelogin-aws.config
  2. Create a new file ~/.onelogin-aws/config which will hold user-specific configurations such as username, flags to specify whether or not to save the username/password, and the daemon port.
  3. Allow the user to save their username to a config file
  4. Allow the user to save their password to a system keychain using a library such as https://github.com/jaraco/keyring
  5. Maintain all existing functionality. Eg, allow the user to run onelogin-aws-login with --renewSeconds in a tty session.

The main benefit here is the reduced overhead on the engineer/data scientist/tech to ensure their AWS creds are always valid and that they are not responsible for the persistent running of the process, and this can be delegated to systemd, launchd, upstart, sysvinit, etc.

@slycoder @cameronmarlow thoughts?

@cameronmarlow
Copy link
Contributor

I like this approach. I was trying to get this working before and having issues with the refresh tokens. Now that we're using the official SDK (thanks for that!) I assume it will work more reliably.

Some thoughts on your implementation:

  • I think it's fine to allow caching of credentials, especially if os implementations require authentication once to access the credentials
  • On the topic of a daemon, how would it work if you need to give an OTP every 10 hours?
  • Also for daemons, doesn't it defeat the purpose of having an identity platform if it's running in the background continuously?

Personally I think having to enter credentials once every 10 hours is reasonable for an engineer working with an organization that is requiring an identity platform such as onelogin, but would be willing to change my mind if others disagree.

Also, I think the username/password caching would be uncontroversial, maybe separate that into another task?

Thanks for all your help!

@drewsonne
Copy link
Contributor Author

Now that we're using the official SDK (thanks for that!) I assume it will work more reliably.

It could all still end in tears, but I am optimistic :-)

On the topic of a daemon, how would it work if you need to give an OTP every 10 hours?

I am envisioning being able to interact with the daemon through the normal onelogin-aws-login app. For example:

$ onelogin-aws-daemon --config_name data-science-production --profile default
Starting daemon...
Loading credentials for `data-science-production`
Daemon started.
The configuration `data-science-production` has MFA. Please run `onelogin-aws-login -d --config_name data-science-production` to enter your MFA

$ onelogin-aws-login -d
Connecting to daemon...
Using default profile
Onelogin username: drew.sonne@example.com
Onelogin password: *******
1. Google Authenticator
2. Yubico YubiKey
3. OneLogin Protect
Which OTP Device?
OTP Token: *******

Daemon has successfully authenticated.

$ onelogin-aws-login -d
Connecting to daemon...
Daemon has successfully authenticated.

# 10 hours later...

$ onelogin-aws-login -d
Connecting to daemon...
Using default profile
Onelogin username: drew.sonne@example.com
Onelogin password: *******
1. Google Authenticator
2. Yubico YubiKey
3. OneLogin Protect
Which OTP Device?
OTP Token: *******

I'm making up those cli options, but that's the general drive of it.

My motivation for making this more complex with a daemon is that my company has engineers, but we also have UX, data scientists, business analysts, and a couple of others who are not as au fait with the terminal, as other engineers but use applications that read from ~/.aws/credentials (eg, simple s3 upload/download, and Athena/Redshift through intelliJ), so we'd like to smooth this process as much as possible.

Also for daemons, doesn't it defeat the purpose of having an identity platform if it's running in the background continuously?

The OneLogin session will still expire and require MFA OTP every 10 hours, which I think is reasonable, as it's already what OneLogin themselves allow if you access AWS through the GUI. If we wish/need to very quickly rescind access, we can do that, as the SAML Assertion is every hour.

Also, I think the username/password caching would be uncontroversial, maybe separate that into another task?

There would be a few PR's :-)

We centrally manage all our macs so being able to set this behaviour centrally is quite important to us. I had a thought to save having to split the config file into two as I mentioned above, would you be averse to sections like:

[config onelogin-aws-login]
save_username = true
save_password = true

[config onelogin-aws-daemon]
socket = 38311

[default]
base_uri = https://api.us.onelogin.com/
client_id = 8f741af1990db20ad72...
client_secret = 340f51d4566f19c8...
aws_app_id = 123456
subdomain = my_company
...

@cameronmarlow
Copy link
Contributor

I'm game, I'm sure we would all be happier if this was the interaction.

It does seem that the properties of this system should be configurable by an admin based on the necessary policy, but without any controls I think 10h is reasonable.

@drewsonne
Copy link
Contributor Author

drewsonne commented Mar 8, 2018

@cameronmarlow @slycoder There is a working PoC of this in https://github.com/drewsonne/onelogin-aws-cli/tree/feature/daemon if you are interested. It's definitely a PoC and will need heavy refactoring.

Set this package up in a virtualenv, and run:

pip install --editable .
onelogin-aws-daemon
onelogin-aws-login --client

Warning... you are going to hit the daemon with a very big hammer to stop it running.
Probably a kill 9 or force-quit in activity monitor, as I do not have the signal intercepts setup properly.

Also, at this stage, the order of prompts is a bit... unusual.

If you are prompted for your OTP twice, just ctrl-C the onelogin-aws-login --client process, and wait until the daemon logs show the auth has been successfull

You can then run onelogin-aws-login --client again and it should immediatly tell you the auth is fine.

@drewsonne
Copy link
Contributor Author

drewsonne commented Mar 8, 2018

@drewsonne
Copy link
Contributor Author

drewsonne commented Mar 14, 2018

I think I should expand on point 2 in the solution above, as it brushes over a lot of details.

  1. Modify the existing onelogin-aws-login to discover the running daemon and change into client mode to forward MFA OTP details onto the onelogin-aws-daemon when the AWS STS session has expired.
    • Daemon:
      The PoC I have created (see above) is quite heavy. It has an HTTP server in it composed of both the request handler and the server itself, which may be a bit excessive.
      The Daemon will also write the location (be it port number or file socket) to a file, so the client can communicate with it. I'd rather this, that a bunch of autodiscover/zeroconf code.
      At this stage, the daemon will consist of 3 Thread objects in addition to the main process: Orchestrator, AuthProcess, Communicator.
      1. AuthProcess
        The AuthProcess will be the existing OneLoginAWS with maybe a couple of status flags attached to let other objects know what details it needs to perform authentication (missing OTP/Username/Password, etc). These values will be able to be provided through an interface on that object; either through a newly created MFA handler class and/or a special daemon UserCredentials class.
      2. Communicator
        Will expose a socket with an interface of some kind. In the PoC above, the interface is restful, but as I mentioned that is quite heavy. I am thinking perhaps a socket is enough for that.
      3. Orchestrator
        The Orchestrator Thread will be responsible for handling communication between the AuthProcess and the Communicator.
    • Client:
      Will have a single thread where it communicates with the daemon to determine if the daemon needs any information to authenticate (OTP/Username/Password, etc)

@drewsonne
Copy link
Contributor Author

Will be made redundant by #71 and can be closed when that is merged in.

@drewsonne
Copy link
Contributor Author

Handled by #72

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants