AWS Storage Blog

Using Okta with multi-factor authentication for AWS Transfer for SFTP

Enterprises often use SFTP to provide third parties like vendors, partners, or offsite laboratories access to their data lakes for things like uploads, downloads, or distributing data exports to clients. AWS Transfer Family provides a fully managed SFTP (now expanded to offer FTPS and FTP) service for Amazon S3. The service frees you from managing any server infrastructure or disrupting your existing file transfer workflows. You can authenticate your users using SSH key based authentication (using private/public key pairs) or passwords. Additionally, you can apply different strategies for securing access to your data lake to meet your internal corporate security requirements. One thing you may do is require the use of multi-factor authentication (MFA) as an added layer of security.

Last year, we published a blog post on how you can use Okta as an identity provider for AWS Transfer for SFTP. Okta provides secure identity management with single sign-on (SSO), MFA, and more. In this follow up post, we outline the steps required so you can authenticate your SFTP users with MFA using the same Okta integration. The solution works with existing SFTP clients such as FileZilla, CyberDuck, and others.

We begin with a primer on MFA. Then we walk through setting up your AWS SFTP server for Okta as an identity provider, enable MFA, and finally, test by authenticating a user using MFA. This solution, which was also presented during re:Invent 2019, can be modified to integrate with a different identity provider that supports MFA.

MFA primer

Let’s start with a primer on MFA. It is a simple best practice that adds an extra layer of protection on top of user name and password authentication.

You start with a user name and password, the first factor, also known as “what you know.” In addition, you provide an authentication code, which is the second factor, also known as “what you have.” The authentication code is generated using a hardware or virtual MFA device. The following diagram illustrates how these multiple factors layer on to provide secure access to your resources.

Multi-factor authentication adds an extra layer of protection on top of user name and password authentication

Identity provider integration with SFTP

Initially provided is an AWS CloudFormation template here that sets up API Gateway, a Lambda function to interact with the Okta authentication API, and an AWS Transfer Family endpoint (with SFTP). Download this template and create a new CloudFormation stack using it.

The following steps outline the overall flow of the proposed solution. Please note steps one and two are one-time setup only and are done by the CloudFormation template provided previously.

  1. Set up an Amazon API Gateway and AWS Lambda function for custom identity provider access.
  2. Create an AWS Transfer Family endpoint (with SFTP) and provide the API Gateway URL during setup.
  3. End-users (using SFTP client) or enterprise applications (using programmatic access) provide credentials and an MFA token.
  4. AWS Transfer Family endpoint (with SFTP) invokes API Gateway, which in turn executes the Lambda function. The Lambda function passes user credentials and the MFA token to Okta’s authentication API, which authenticates the user.
  5. API Gateway sends a response back to the AWS Transfer Family endpoint (with SFTP), which grants the end-user or enterprise application access to the Amazon S3 bucket.

The provided AWS CloudFormation template asks you for a few parameters before deployment:

  • Give your CloudFormation stack a stack name.
  • Provide an existing Amazon S3 bucket.
  • Specify whether you want the stack to create a server internally or not with the desired Boolean value.
  • Provide your Okta endpoint from your Okta authorization server for the OktaAuthAPIURL. This can be found in the Authorization Servers tab of your Okta developer console under API.
    • The default Okta authorization server should be: https://<your-domain>.okta.com/oauth2/default. When providing the CloudFormation OktaAuthAPIURL parameter, be sure to enter: https://<your-domain>.okta.com/api/v1/authn.
  • Finally, provide the sign-on domain of your user.

Setting up an Amazon API Gateway and AWS Lambda function, creating an SFTP endpoint, providing credentials, invoking the API Gateway, and granting access to S3

Okta setup

Begin with an Okta setup and ensure that MFA configuration is enabled. Okta supports a variety of Factor Types such as Okta VerifySMS AuthenticationVoice Call AuthenticationGoogle AuthenticatorYubiKey, and a few others. For this solution, Google Authenticator is used. Please note that the MFA token generated by Google Authenticator is valid for 30 seconds.

To do this, first log in to your Okta account using administrator permissions. You may have to change the console view to Classic UI once logged in. Under Security settings, select Multifactor and enable Google Authenticator from the Factor Types tab. Ensure that your Okta users are enrolled in the chosen factor by creating a new Multifactor Policy under Factor Enrollment, and by adding the relevant Okta user groups to that policy. You may also have to create an Authentication policy to require multi-factor authentication every time a user logs in. To do so, set a new Okta sign-on policy under Security settings, within the Sign On tab.

Next, log in as an Okta user. You are prompted to set up multi-factor authentication. You see Google Authenticator as the option, as shown in the following screenshot:

Log in as an Okta user. You are prompted to set up multi-factor authentication and see Google Authenticator as the option.

Select Setup under Google Authenticator and continue setting up Google Authenticator for this Okta user. Pick the device type, ensure you have downloaded the Google Authenticator app on the selected device, and choose Next.

Select Setup under Google Authenticator and continue setting up Google Authenticator for this Okta user.

On the next step, you are asked to use the Google Authenticator app to scan the barcode. NOTE: choose the Can’t scan? option following the barcode, as highlighted in the following screenshot.

Choose the Can't Scan option following the barcode

Note down the Secret Key, as that is used later in the blog post. Choose Scan barcode, which takes you back to the barcode screen, and finish setting up MFA for the Okta user.

Note down the Secret Key, as that is used later. Choose scan barcode, and finish setting up MFA for the Okta user.

Once you return back to the barcode option, finish setting up the user so they can successfully authenticate in the following step.

Authenticating SFTP using MFA

Depending on your workflow, your SFTP users may connect using clients such as CyberDuck, WinSCP, FileZilla, or OpenSSH, or via machine-to-machine using scripts and programs (a.k.a programmatically). In the next two sections, we cover both methods.

End-users using SFTP client

Using any SFTP client (we use FileZilla in this demo), enter your server details in the Host field and provide your Okta user name in the Username field. Next, in the Password field, enter the Okta user’s password and then the MFA token from Google Authenticator, all as a single string. For example, if an Okta user’s password is “VerySecretPassword” and the MFA code is “123456” enter “VerySecretPassword123456” as the password. The Lambda function has the logic to parse this string and separate the Okta user’s password from the MFA token and pass it to Okta’s Authentication API as required.

Logging into the SFTP client - in the password filed, enter the Okta user's password and then the MDA token from Google Authenticator, all as a single string

Enterprise applications using programmatic access

In this section, we go over how your enterprise applications can leverage enhanced security of MFA with Okta to access the AWS Transfer for SFTP service securely. You have created a sample Python script that uses the PyOTP library, which is compatible with Google Authenticator. Now, use the Paramiko library to programmatically interact with the AWS SFTP endpoint. In the following code, we use the Secret Key that was noted previously in the Okta setup section and set that to the MFAuserCode variable:

import paramiko
import pyotp
import getpass

hostname = "<AWS_SFTP_Server_Endpoint>"
MFAuserCode = "<SECRET_NOTED_FROM_Okta_Setup_Section>"

#Filepath and file name that needs to be uploaded
filename = "<FILENAME>.<EXTENSION>"
localfilepath = "<PATH_TO_THE_FILE>" + filename

username = getpass.getpass("Enter sftp username: ")
userpass = getpass.getpass("Enter sftp password: ")

#Compatible with Google Authenticator and generates 6-digit OTP
totp = pyotp.TOTP(MFAuserCode)
MFAcode = totp.now()
print("Current OTP:", MFAcode)
passwordwithMFA= userpass + MFAcode

sftp = None
transport = None
try:
    transport = paramiko.Transport((hostname, 22))
    transport.connect(username = username, password = passwordwithMFA)
    sftp = paramiko.SFTPClient.from_transport(transport)
    uploadfile = sftp.put(localfilepath, "/personal/sample_file.png")
    sftp.close()
    transport.close()
    response = "File " + filename + " uploaded successfully"
except Exception as e:
response = 'An error occurred creating SFTP client: %s: %s' % (e.__class__, e)

print(response)

The following code shows how the Lambda function you deployed using the AWS CloudFormation template invokes Okta Auth API for MFA. First, extract the password from the event object and parse it to separate out the Okta user’s password and MFA token. Next, invoke Okta Auth API providing the Okta user name and password. Finally, use the response from this request and make another request providing the MFA token.

#Step 1: Extract credentials from event object
username = event["username"]
passwordwithMFA = event["password"]
mfaToken = passwordwithMFA[-6:]
password = passwordwithMFA[:-6]

#### Authenticate with Okta's Auth API ####

#Step 2:Invoke Okta Auth API & provide Okta username and password
auth_api_url = 'https://${yourOktaDomain}/api/v1/authn'
headers = {'Accept': 'application/json', 'Content-Type': 'application/json'}
credentials = {'username': username, 'password': password}
resp1 = req.post(url=auth_api_url, data=json.dumps(credentials), headers=headers)

#Step 3: Pass MFA token
primary = resp1.json()
stateToken = primary['stateToken']
url = primary['_embedded']['factors'][0]['_links']['verify']['href']
screds = {"stateToken": stateToken, "passCode": mfaToken }
resp2 = req.post(url=url, data=json.dumps(screds), headers=headers)

To follow best practice for security, check to make sure you are not printing passwords to log files.

As demonstrated, the programmatic approach is simple to implement and improves the security posture of your enterprise applications by using MFA while connecting to an AWS SFTP endpoint.

Summary

In this blog post, we have demonstrated how MFA can be used with Okta as a custom identity provider for AWS Transfer for SFTP. If you’re providing access using SFTP to your data lake on AWS, deploying this solution provides an additional layer of security through MFA. In addition, if you have enterprise applications (third-party systems or internal) that need SFTP access to data in Amazon S3, MFA provides the same additional layer of security.

Thanks for reading this blog post, if you have any comments or questions, please don’t hesitate to leave them in the comments section.