AWS Machine Learning Blog

Automate vending Amazon SageMaker notebooks with Amazon EventBridge and AWS Lambda

Having an environment capable of delivering Amazon SageMaker notebook instances quickly allows data scientists and business analysts to efficiently respond to organizational needs. Data is the lifeblood of an organization, and analyzing that data efficiently provides useful insights for businesses. A common issue that organizations encounter is creating an automated pattern that enables development teams to launch AWS services. Organizations want to enable their developers to launch resources as they need them, but in a centralized and secure fashion.

This post demonstrates how to centralize the management of SageMaker instance notebooks using AWS services including AWS CloudFormation, AWS Serverless Application Model (AWS SAM), AWS Service Catalog, Amazon EventBridge, AWS Systems Manager Parameter Store, Amazon API Gateway, and AWS Lambda. We walk through how to use these AWS services to automate the process of vending SageMaker notebooks to end-users.

Solution overview

In our solution, a notebook user requests a notebook instance using AWS Service Catalog. The request is processed by AWS CloudFormation, which delivers the notebook instance. EventBridge monitors the AWS Service Catalog API for completion of the notebook instance resource provisioning. An event-based rule in EventBridge calls the Lambda event processor, which runs a Lambda function returning the presigned URL.

The following architectural diagram illustrates the infrastructure state as defined in the CloudFormation templates.

The process consists of the following steps:

  1. A user requests a new notebook via the AWS Service Catalog console.
  2. AWS Service Catalog launches a CloudFormation stack.
  3. AWS CloudFormation launches the SageMaker notebook.
  4. A SageMaker notebook is now running.
  5. An EventBridge function is triggered when a new AWS Service Catalog product is launched.
  6. The Amazon CloudWatch event invokes a Lambda function that generates the presigned URL and a user-specific SSM parameter.
  7. A user requests a new presigned URL.
  8. A Lambda function generates a new presigned URL and updates the user’s SSM parameter with the new URL.

Prerequisites

To implement this solution, you must have the following prerequisites:

Deploy resources with AWS CloudFormation

To create your resources with AWS CloudFormation, complete the following steps:

  1. Deploy the s3-iam-config CloudFormation template:
    aws cloudformation create-stack \
    --stack-name s3-iam-config \
    --template-body file://templates/s3-iam-config.yml \
    --parameters file://parameters/s3-iam-params.json \
    --capabilities CAPABILITY_NAMED_IAM

The output should look like the following code:

{
"StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/s3-iam-config/9be9f990-0909-11eb-811c-0a78092beb51"
}

The template creates an Amazon Simple Storage Service (Amazon S3) bucket.

  1. Run the following command to get the S3 bucket name generated in the previous step:
    aws cloudformation describe-stacks \
    --stack-name s3-iam-config \
    --query "Stacks[0].Outputs[?OutputKey=='S3BucketName'].OutputValue" \
    --output text

The output should look like the following:

s3-iam-config-s3bucket-1p85zr5051d86
  1. Run the following command using the output from the previous step (update the bucket name):
    aws s3 cp templates/sm-notebook.yml s3://<bucket_name>/sm-notebook.yml

The output should look like the following:

upload: templates/sm-notebook.yml to s3://s3-iam-config-s3bucket-1p85zr5051d86/sm-notebook.yml
  1. Open the parameters/service-catalog-params.json file and update the S3BucketName parameter to the bucket name from the previous step. Update the UserIAMPrincipal with the ARN of the IAM role you’re using for this demo.
    [
      {
        "ParameterKey" : "NotebookInstanceType",
        "ParameterValue" : "ml.t2.medium"
      },
      {
        "ParameterKey" : "S3IAMConfigStackName",
        "ParameterValue" : "s3-iam-config"
      },
      {
        "ParameterKey" : "ServiceCatalogTemplateName",
        "ParameterValue" : "sm-notebook.yml"
      },
      {
        "ParameterKey" : "S3BucketName",
        "ParameterValue" : "<input_your_bucket_name>"
      },
      {
        "ParameterKey" : "UserIAMPrincipal",
        "ParameterValue" : "<input_your_iam_principal_arn>"
      }
    ]
  2. Deploy the service-catalog CloudFormation template:
    aws cloudformation create-stack \
    --stack-name service-catalog-config \
    --template-body file://templates/service-catalog.yml \
    --parameters file://parameters/service-catalog-params.json \
    --capabilities CAPABILITY_NAMED_IAM

The output should look like the following:

{
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/service-catalog-config/fb29c5e0-28a0-11ec-8337-123f746ae8a3"
}

Deploy resources with AWS SAM

To deploy resources with AWS SAM, complete the following steps:

  1. Change your directory to the lambda directory:
    cd lambda/
  2. Build the application:
    sam build

The output should look like the following:

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
[*] Deploy: sam deploy --guided
  1. Deploy the application:
    sam deploy --guided
  2. Respond to the questions in the CLI as shown in the following code:
      Configuring SAM deploy
    ======================
    
            Looking for config file [samconfig.toml] :  Found
            Reading default arguments  :  Success
    
            Setting default arguments for 'sam deploy'
            =========================================
            Stack Name [sam-app]: sam-app
            AWS Region [us-east-1]: us-east-1
            Parameter EventBridgeFunctionName [EventBridgeFunction]: EventBridgeFunction
            Parameter EventRuleName [SvcCatalogEventRule]: SvcCatalogEventRule
            Parameter RefreshFunctionName [RefreshURLFunction]: RefreshURLFunction
            #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
            Confirm changes before deploy [y/N]: N
            #SAM needs permission to be able to create roles to connect to the resources in your template
            Allow SAM CLI IAM role creation [Y/n]: Y
            #Preserves the state of previously provisioned resources when an operation fails
            Disable rollback [y/N]: N
            EventBridgeFunction may not have authorization defined, Is this okay? [y/N]: Y
            RefreshURLFunction may not have authorization defined, Is this okay? [y/N]: Y
            Save arguments to configuration file [Y/n]: Y
            SAM configuration file [samconfig.toml]: samconfig.toml
            SAM configuration environment [default]: dev

The output should look like the following:

        Looking for resources needed for deployment:
        Creating the required resources...
        Successfully created!
         Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-1f4i68wsmouhw
         A different default S3 bucket can be set in samconfig.toml

        Saved arguments to config file
        Running 'sam deploy' for future deployments will use the parameters saved above.
        The above parameters can be changed by modifying samconfig.toml
        Learn more about samconfig.toml syntax at 
        https://docs.thinkwithwp.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

Uploading to sam-app/6f3e2f13cfdca08133238f77fc2c667b  9425988 / 9425988  (100.00%)
Uploading to sam-app/b153fd4be66b581361f7d46efae25f18  9425968 / 9425968  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : sam-app
        Region                       : us-east-1
        Confirm changeset            : False
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1f4i68wsmouhw
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {"EventBridgeFunctionName": "EventBridgeFunction", "EventRuleName": "SvcCatalogEventRule", "RefreshFunctionName": "RefreshURLFunction"}
        Signing Profiles             : {}

Initiating deployment
=====================
Uploading to sam-app/c82cdea2bfbc2abc6520a97fce4c8a8b.template  6754 / 6754  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                LogicalResourceId                        ResourceType                             Replacement                            
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                    EventBridgeFunctionHelloWorldPermissio   AWS::Lambda::Permission                  N/A                                    
                                         nProd                                                                                                                    
+ Add                                    EventBridgeFunctionRole                  AWS::IAM::Role                           N/A                                    
+ Add                                    EventBridgeFunction                      AWS::Lambda::Function                    N/A                                    
+ Add                                    PermissionForEventsToInvokeLambda        AWS::Lambda::Permission                  N/A                                    
+ Add                                    RefreshURLFunctionHelloWorldPermission   AWS::Lambda::Permission                  N/A                                    
                                         Prod                                                                                                                     
+ Add                                    RefreshURLFunctionRole                   AWS::IAM::Role                           N/A                                    
+ Add                                    RefreshURLFunction                       AWS::Lambda::Function                    N/A                                    
+ Add                                    ServerlessRestApiDeploymentb762875163    AWS::ApiGateway::Deployment              N/A                                    
+ Add                                    ServerlessRestApiProdStage               AWS::ApiGateway::Stage                   N/A                                    
+ Add                                    ServerlessRestApi                        AWS::ApiGateway::RestApi                 N/A                                    
+ Add                                    SvcCatalogEventRule                      AWS::Events::Rule                        N/A                                    
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:us-east-1:123456789012:changeSet/samcli-deploy1641934511/763fe89c-9c6a-4cef-a1a6-90986d7decfd


2022-01-11 15:55:22 - Waiting for stack create/update to complete

CloudFormation events from stack operations
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                           ResourceType                             LogicalResourceId                        ResourceStatusReason                   
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                       AWS::IAM::Role                           RefreshURLFunctionRole                   -                                      
CREATE_IN_PROGRESS                       AWS::IAM::Role                           EventBridgeFunctionRole                  -                                      
CREATE_IN_PROGRESS                       AWS::IAM::Role                           EventBridgeFunctionRole                  Resource creation Initiated            
CREATE_IN_PROGRESS                       AWS::IAM::Role                           RefreshURLFunctionRole                   Resource creation Initiated            
CREATE_COMPLETE                          AWS::IAM::Role                           EventBridgeFunctionRole                  -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Function                    EventBridgeFunction                      -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Function                    EventBridgeFunction                      Resource creation Initiated            
CREATE_COMPLETE                          AWS::IAM::Role                           RefreshURLFunctionRole                   -                                      
CREATE_COMPLETE                          AWS::Lambda::Function                    EventBridgeFunction                      -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Function                    RefreshURLFunction                       -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Function                    RefreshURLFunction                       Resource creation Initiated            
CREATE_IN_PROGRESS                       AWS::Events::Rule                        SvcCatalogEventRule                      -                                      
CREATE_IN_PROGRESS                       AWS::Events::Rule                        SvcCatalogEventRule                      Resource creation Initiated            
CREATE_COMPLETE                          AWS::Lambda::Function                    RefreshURLFunction                       -                                      
CREATE_IN_PROGRESS                       AWS::ApiGateway::RestApi                 ServerlessRestApi                        -                                      
CREATE_COMPLETE                          AWS::ApiGateway::RestApi                 ServerlessRestApi                        -                                      
CREATE_IN_PROGRESS                       AWS::ApiGateway::RestApi                 ServerlessRestApi                        Resource creation Initiated            
CREATE_IN_PROGRESS                       AWS::ApiGateway::Deployment              ServerlessRestApiDeploymentb762875163    -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Permission                  EventBridgeFunctionHelloWorldPermissio   -                                      
                                                                                  nProd                                                                           
CREATE_IN_PROGRESS                       AWS::Lambda::Permission                  RefreshURLFunctionHelloWorldPermission   Resource creation Initiated            
                                                                                  Prod                                                                            
CREATE_IN_PROGRESS                       AWS::Lambda::Permission                  EventBridgeFunctionHelloWorldPermissio   Resource creation Initiated            
                                                                                  nProd                                                                           
CREATE_IN_PROGRESS                       AWS::Lambda::Permission                  RefreshURLFunctionHelloWorldPermission   -                                      
                                                                                  Prod                                                                            
CREATE_IN_PROGRESS                       AWS::ApiGateway::Deployment              ServerlessRestApiDeploymentb762875163    Resource creation Initiated            
CREATE_COMPLETE                          AWS::ApiGateway::Deployment              ServerlessRestApiDeploymentb762875163    -                                      
CREATE_IN_PROGRESS                       AWS::ApiGateway::Stage                   ServerlessRestApiProdStage               -                                      
CREATE_IN_PROGRESS                       AWS::ApiGateway::Stage                   ServerlessRestApiProdStage               Resource creation Initiated            
CREATE_COMPLETE                          AWS::Lambda::Permission                  RefreshURLFunctionHelloWorldPermission   -                                      
                                                                                  Prod                                                                            
CREATE_COMPLETE                          AWS::Lambda::Permission                  EventBridgeFunctionHelloWorldPermissio   -                                      
                                                                                  nProd                                                                           
CREATE_COMPLETE                          AWS::ApiGateway::Stage                   ServerlessRestApiProdStage               -                                      
CREATE_COMPLETE                          AWS::Events::Rule                        SvcCatalogEventRule                      -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Permission                  PermissionForEventsToInvokeLambda        -                                      
CREATE_IN_PROGRESS                       AWS::Lambda::Permission                  PermissionForEventsToInvokeLambda        Resource creation Initiated            
CREATE_COMPLETE                          AWS::Lambda::Permission                  PermissionForEventsToInvokeLambda        -                                      
CREATE_COMPLETE                          AWS::CloudFormation::Stack               sam-app                                  -                                      
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                          
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 RefreshURLFunctionIamRole                                                                                                                    
Description         Implicit IAM Role created for Hello World function                                                                                           
Value               arn:aws:lambda:us-east-1:123456789012:function:RefreshURLFunction                                                                            

Key                 RefreshURLFunctionAPI                                                                                                                        
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                             
Value               https://m94bjaurjb.execute-api.us-east-1.amazonaws.com/Prod/refreshurl/                                                                      

Key                 RefreshURLFunction                                                                                                                           
Description         Hello World Lambda Function ARN                                                                                                              
Value               arn:aws:lambda:us-east-1:123456789012:function:RefreshURLFunction                                                                            
------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - sam-app in us-east-1

Test the solution

Now that you have deployed the solution, let’s test the workflow.

  1. On the AWS Service Catalog console, under Administration in the navigation pane, choose Portfolios.
  2. Choose your SageMaker notebook.
  3. Choose Launch product.
  4. At the bottom of the page, choose Launch product.

You should see a page similar to the following screenshot.

  1. Wait a few moments for the status to show as Available.
  2. Open your terminal and run the following command to get the presigned URL from Parameter Store:
    aws ssm get-parameter \
    --name "/SageMaker/Notebooks/Demo-User-Notebook" \
    --query Parameter.Value

The output should look like the following:

"https://demo-user-notebook.notebook.us-east-1.sagemaker.aws?authToken=eyJhbGciOiJIUzI1NiJ9.eyJmYXNDcmVkZW50aWFscyI6IkFZQURlSlVvLzJjeEcwQ0xtNHBjTTZFOGM1SUFYd0FCQUJWaGQzTXRZM0o1Y0hSdkxYQjFZbXhwWXkxclpYa0FSRUV3U0ZSdU1rNXJZMUpyWnpWWVlsZFBRbUowTmtadVpGcHZlRlJXUW05SVlWaHdiazFJY25WRWVrTmtlVWRUVUZsak56UnhObWQzVTJGS1dYUm5hVk40VVQwOUFBRUFCMkYzY3kxcmJYTUFTMkZ5YmpwaGQzTTZhMjF6T25WekxXVmhjM1F0TVRvM05qUTNNRGM1TWpRME1UVTZhMlY1TDJJM01ETTNNRE5oTFdVMU5HTXROR1JtWWkxaE1HRTFMVGMyTnpNek1XWXlORGsxT1FDNEFRSUJBSGhlY3J4TGdEdDJaWmRKYk5nd3R4RHJpWmtZQnZUR1cwZWZCWVhaVW1VTTFBRXNiUlBXblloT3hjUWhPUE9jR0FaZUFBQUFmakI4QmdrcWhraUc5dzBCQndhZ2J6QnRBZ0VBTUdnR0NTcUdTSWIzRFFFSEFUQWVCZ2xnaGtnQlpRTUVBUzR3RVFRTUFnMjM1NzZRT1l6azgyc29BZ0VRZ0RzejlwVHd4Q2ZZUHd6SGJvZERIaElRa1BRWjdUUXRxZ2dEaVpkTDBtMnIxaW1jVHp5czJHc0t6T3d2Z2g1cGNSSytVS2ZxTXlnTmVhaHVVd0lBQUFBQURBQUFFQUFBQUFBQUFBQUFBQUFBQUFET3ZoZFMvb01sTE4xZ3hQSFkybklQLy8vLy93QUFBQUVBQUFBQUFBQUFBQUFBQUFFQUFBTmZFc2JYV1RDWXorV0o0S3BwSXhEMkpkMVFzUnZFbW9lS21hZDhvSmNSN0tRMi9CQWd3TTA3YUFOOEN1WE8yc2lLUnpZdjI1YmlLOFYzUDM2d1Fjc3RoS085Ui91TFFzNWk4RytHc3BZSnlNamRsbWdWYTFEd2FZQmd0TUMwcmJMRjZSWXJhcFJtMFArbDVIQWg3bWNyeU9lejZWRVlYTmdJY2FXR0tjZDFwRjQ5bXBLTzNyQW5BSGlCdEVaNCtlSVFYVkJwMmQyV2c4TEFqR0RRYVNyclVBOUhJa3pvaloybm5iVHluY3pLWXlNVjA3Ui8wZmVTZU9jTTBubC9IRHdjWUdyc1RCcDgzM1RVWCtkOGRNRXI4amtpQVAwUTFQRkNrU2h5WS9CU05IalZtWThxd094N05jV3g1ZVpSenl3cm0vWXNZOW5paEt5cWRMaGNIQUhDbXZhWW8yb2lMZ3BGak51WG5udlh1U1UxcmFlRVZMNUlKR1loMVAzRWZnR3huNmlsUTJmVGllQytQdWNmT3dsZWwrSnR5SWNmbVRTeFB0bnE1YW1mVjEycml0Skx5a09WMklEc0YzSEl6RW11SmhYZTBqKzM1dWlITW5BVkFZVm5RbithdWh1K3lVcUNKeWVWU1o2ZWVsYmIwd2tYUGNpOXBkazFMbTFLNUpZcFJuMFoyS1hvSnBxNm52b3pPWkdvNG9jbmVRQWhKODRiYjR6RkdGZ1NOaTdQWEFuMnpDTkZ1S2w0eU9KVldiRDRXMGZGSFc1OE5iUTE5amc5Zlp0czlkVmxKclowSmVrYTJhZi9TaUpoeWdvcDBwQ0pBS0pZZkErVEhTQmdCUTFNUWpyUXV5U25jbnQ4NU5XUW1uVG9PUGJ4bVlyN0JRMllpQlJsekdxSDNuQ0pXN2x4YmNzYUV1c1dFMXB3K0RJc2lLMEV1YVV6anBFWFV0NEt4Zm82T3B3b28vdVcyV0dlSmNQVHk4TkNRYWZlUU1VbXgwaDQ3aDF0UHNIY0hBUjltKzU2c3BzMnJETjl4ZTFUMVdHVDg4a3FFMW5YYzRQeUZNdTVuYXB0UEdUU1B0akpZWDRKKzRsSzlJZzZCNG9qRTNmVEEzUVllSTd0dU9UZG9Vd2R6SkJ4L1NvSjNxU0ZUMWRDZXFDeUcyWUN5cjN0TmFzZlpYNFBBWmU4b1M1QVZTeExkVlVqUkpYcW1DM1ZkNUJPRlFySHpReTZjTkFLNFVOY2tBanh3bUgwbFlNdlFtc3lTODRzcCtLUGdpbXl3eWNDdk5tYWQ1bVltRHRZYVpMU3JCVUZIVzlDS2tTS2pqWWtBWnZ3MXRnS3h5OE9wNjZDRHY3aEZObzNDUWQ3MGpnV0wyamdnU1RIckJ6blJwK2wxQ1VscnNsblNzaGluTDcwbnp4eU02b1NBbm1FdFVscG9yeG1iWGRUbUxld244R1lQS1ZvT0syd1pobXk0TVQzc2xxRlU1enVTU2tBQnp5eURZb3djR3JxemlBTXNDcEZONVhRVk9HNHkzNnlZS3pTU0FVTEppRCtOZFRLeWxJbUFHY3daUUl3TXpoZ25hWitia1h5VmErTWUrYmwxUHBrUXcwMWxMUDZNcExnTGRPbkVKb0RRM0xLc2pLZHlidWx4cmlNK011SEFqRUF3V00zdXpjemZyY1ZWOGNwUzdlUDlBRXluNks5NkNQNFBiVCtYK1VVZERqYXZkR1hrenY3TklkWG4xem9pU0dpIiwiY2lwaGVyVGV4dCI6IkFRSUJBSGhlY3J4TGdEdDJaWmRKYk5nd3R4RHJpWmtZQnZUR1cwZWZCWVhaVW1VTTFBRVRlWjBib1lRWDZSazJ1dzdNREJZY0FBQUFvakNCbndZSktvWklodmNOQVFjR29JR1JNSUdPQWdFQU1JR0lCZ2txaGtpRzl3MEJCd0V3SGdZSllJWklBV1VEQkFFdU1CRUVERjVkR1VSbkt5ZlA4S2dKTVFJQkVJQmJyTkJkSkZEOWhySytrajEvTDRieXMxMlFmR2dxM1pSTVlGa2lwNjJXZGZ2aUhvdkswQ3pKY0VtSUE4akY5cktPRm5ZblFoeHpHdmhxZy84VjU4RjUxbWFKUkJIY0RlUzdjSGRpSkdhOW1MbmZuVzFwQVhoaUp1WlRCdz09Iiwid29ya3NwYWNlTmFtZSI6ImRlbW8tdXNlci1ub3RlYm9vayIsIndvcmtzcGFjZURvbWFpbk5hbWUiOiJkZW1vLXVzZXItbm90ZWJvb2siLCJzdWIiOiIxOTU4ODk2NzE2OTAiLCJleHAiOjE2MzgxNDAyMTQsImlhdCI6MTYzODEzODQxNH0.duv90DKJDan6ZOI_uwgP3sQEtManyMCD61tnhZtI-mY"

EventBridge rule

EventBridge is configured with an event rule to process an API response for the AWS Service Catalog API. This rule is configured to pass the notebook instance state so that you can use Lambda to return a presigned URL response as a triggered action. The event rule is configured as follows:

{
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["servicecatalog.amazonaws.com"],
    "eventName": ["ProvisionProduct"]
  }
}

The following screenshot of the EventBridge console shows your event rule.

The AWS CloudTrail API is being monitored using the event source for servicecatalog.amazonaws.com. The monitored event name is ProvisionProduct. Monitoring this event allows you to take effective action in response to AWS Service Catalog reporting back the successful delivery state of the notebook instance. When a ProvisionProduct event occurs, a Lambda function called DemoEventBridgeFunction is invoked, which returns a presigned URL to the end-user.

Lambda function for returning presigned notebook instance URLs

To ensure secure access to user-requested notebooks via AWS Service Catalog, a presigned URL is created and returned to the user. This provides a secure method of accessing the notebook instance and performing business critical functions. For this purpose, we use the EventBridgeServiceCatalogFunction function, which uses a waiter for the notebook instance state to become available. Waiters provide a means of polling a service and suspending the execution of a task until a specific condition is met. When it’s ready, the function generates a presigned URL. Finally, the function creates an SSM parameter with the generated presigned URL. The SSM parameter uses the following pattern: /SageMaker/Notebooks/%s-Notebook"%user_name/. This allows us to create a common namespace for all our SageMaker notebook SSM parameters while keeping them unique based off of user_name.

Presigned URLs have a defined expiration. The Lambda function deploys notebooks with a session expiration of 12 hours. Because of this, developers need to generate a new presigned URL when their existing presigned URL expires. The RefreshURLFunction accomplishes this by allowing users to invoke the function from calling the API Gateway. Developers can invoke this function and pass their notebook name, and it returns a presigned URL. When the RefreshURLFunction is complete, a user can make a call to Parameter Store, get the new presigned URL, and then access their notebook.

  1. Get the RefreshURLFunction API Gateway URL with the following code:
    aws cloudformation describe-stacks \
    --stack-name sam-app \
    --query "Stacks[0].Outputs[?OutputKey=='RefreshURLFunctionAPI'].OutputValue" \
    --output text \
    --region us-east-1

The output should look like the following:

https://8mnr3ksi0d.execute-api.us-east-1.amazonaws.com/Prod/refreshurl/
  1. Invoke the function RefreshURLFunction by calling the API Gateway. Update input_url with the URL from the previous step:
    curl -X POST <input_url>  -d '{"notebook_user_name": "Demo-User"}'

The output should look like the following:

{"PreSignedURL": "https://demo-user-notebook-dctz.notebook.us-east-1.sagemaker.aws?authToken=eyJhbGciOiJIUzI1NiJ9.eyJmYXNDcmVkZW50aWFscyI6IkFZQURlRGw3R2E2OWZ3SmhjSlZKcDB1VjR2b0FYd0FCQUJWaGQzTXRZM0o1Y0hSdkxYQjFZbXhwWXkxclpYa0FSRUZzYVcxNVNsZGtXRXhCZGpVNGRIRkVTalo0V25SSk5WWTVUVEZHZFZaTVZtVldWRzQ0Tms1UGRWaEpSVFI2UTBwdGVFZDFWbFUxUzNoc1pYSXJia05YWnowOUFBRUFCMkYzY3kxcmJYTUFTMkZ5YmpwaGQzTTZhMjF6T25WekxXVmhjM1F0TVRvM05qUTNNRGM1TWpRME1UVTZhMlY1TDJJM01ETTNNRE5oTFdVMU5HTXROR1JtWWkxaE1HRTFMVGMyTnpNek1XWXlORGsxT1FDNEFRSUJBSGhlY3J4TGdEdDJaWmRKYk5nd3R4RHJpWmtZQnZUR1cwZWZCWVhaVW1VTTFBRjY1ZFVPdW5vQlY2MVdrTnM2OUVsdUFBQUFmakI4QmdrcWhraUc5dzBCQndhZ2J6QnRBZ0VBTUdnR0NTcUdTSWIzRFFFSEFUQWVCZ2xnaGtnQlpRTUVBUzR3RVFRTVhsY1gyeW5WMVQxNkdBRHlBZ0VRZ0RzUEVSVllMRVMzN1FVZklvVTZjd3RZdGI4NkIrT212aVF3cm5BOFVDSnZtMjRxYXJORllaOGgzRGlnSy8wVVBSR3hTeFpoaFhWSTA0Q1RlUUlBQUFBQURBQUFFQUFBQUFBQUFBQUFBQUFBQUFBcUEvUnVZOTk2alBLV09zaFNqZS9GLy8vLy93QUFBQUVBQUFBQUFBQUFBQUFBQUFFQUFBTlhGZFYwR1FHMXZpN2drQkhtOGtmWlBUL0dxcnhOamFSWkU0Tis3ZTJocEI0YXUxS0ozQ2ZnRUMrcHR3dk9JdjQwVGYrdnNWNUt5MjYyNGYvOVhrYmVZQklqdnlLV1JJR0ZyS2dxditVTXdJcE8ydDFIbWcvSmFhdEpGdFhudlJodVcwMG9ldVBLS3ZFeGRKQ3ppYkRkT3J3SG5IMFJqWEhTc2tydGxsTDM2Mll0a3k0Z1cwV2xGOUt3Zm1xb2FjVzZZRTZhV0RUZU9oQWprZXFkQ1FoVi9KRWYwaTA1Q1VxU0k1REZzSC8yS2grZHJxS0tBSVMyTjFRYnNSZ3VGNzFFcnBCM3BoV25PSTFnd3BGL3VNMCs5MHRsTGVCeG5ncElqT1NEY1pkbHlwQmpNZkVadUNYWGU4ZTJGRGQ0bGVENFdOZDdzc0F4OHFQWmV5eWI3WWo2L0FxaUtESmdLOStScS9BVGF6NkRFNFNyL3BaWmpRRFFab1oyV1ZCa2VVWHR2U1piVUd4aXJXRG0rVUUxVk5sbG85TmhwSEhhR1dIZEJPU0w5SUFUWWZDVjV6enVURHNDS2l1dVBQTmFVZGhvSUVuL2c1UXhtOFJvZUlVVUJRcUVvbms3T3d1QzJZOEM2QUowclVxL055T3R5NmF4TWY2VEdYcTFsTHB4WG9wMjlXT3lzR3daQSs4Mmo3em5SZEo2RTZTU005TnJYRi95OWxRS3dBTFBaK3FBNmszSEFvdDg5UlZYSGVMTFQ3TklwazVYVnZlRXY5S3N2MUp1Uk1FVVJEZjI1bnZtOXRmVnp0MUN0R0Y1RVBQNEpid2d5RnZ4RDlnRkVPTUM5dk1rdWloT3JnM3JaaDNwRjd1RDRsVVptVUtTRXV6ZVVmRFd0eEhjVHZoeUxFVmZuczhpcjl6SnFacGxpNVdYdjF3bTQ5WWxJNGlSM1FiamtZM0JybUFsOFBzZkRjYmZJUmVBNmkvQjVNeHFOb3RvU0Y0MHA1OFpJTGZPNmNNWURlVHpzT2dMbENmYXIwT3JMK1lRVk55MU5ETUF3cGRWaXlNeWI1RHl2SzlOV3ZOOUt2c2lMTklrV1IvU2s5ekx1RjBPd3F0aE5GWjhkbWkvMzRzc2pRMUFVR1BMR2ZXbUl1ZmlqRnhrRytnL1lKMjNSa1pIVmRvb1J4TUt3Zmk5OXQvUS96QmI2OUgyQlljbFZwUVl0RGV4Z3ZGWTg2TGpUMm5sSjkya09ad1duWW9OMWpMenIrVTVWQkJKakpDT09ENVA0MXBWckdHN1R4Nlh4UlFscGRqQ3E5ZFhXQlJiRDh6d0JDZ2VMY254SFlZTjUzR2hON2U3S3QyUmZyak5aREtSanUvTWNZSXRSTTVLU2ZaNWFNZ2NJUXY0a0tLNUppVll6OEdaY2VUSE5TT21Zb1FNeG1xMnNOSGJDZzZpUFM4KytvUkErdFhGY1JWMFkxSG9qZlVWS2NzREJjZmFQRVo0TENSZENvZnYrWFVWaHFSNzlCZGpyYW92Wmo1TitqZjFxdHdWZU9mVWJBQm5NR1VDTUN6UU4xMThWMTFZcXcwSWFhbmY0NUtIcjhnUC9MaVZHLzVRTy9yemREbzdZbkZEMmtzM3ZKbFQxVWE5N3kxY25nSXhBS2FxNEJsQ3R4UUc3b2Yxc1BaWld3K2NCalgzcGdIMWhXMHpYOU1zVzJOYXFCSklpUkp1VTJVaUU0cVdDVnh4eVE9PSIsImNpcGhlclRleHQiOiJBUUlCQUhoZWNyeExnRHQyWlpkSmJOZ3d0eERyaVprWUJ2VEdXMGVmQllYWlVtVU0xQUhyWlZxanJHYWVlMUY5c016d2pmM1pBQUFBb2pDQm53WUpLb1pJaHZjTkFRY0dvSUdSTUlHT0FnRUFNSUdJQmdrcWhraUc5dzBCQndFd0hnWUpZSVpJQVdVREJBRXVNQkVFRFBGVFJFbXQ2SmQ2VWoxMExnSUJFSUJibHBFOWtORGxpd21Yb2ltaEFiTC8xNmpYTVRhcDYvNnpSRlFLbjNHWE9mRlVRcUx6VEVBSUQvY095bDlMYU1NdzBRaHBjSWhERmpEL1U1R29sQmUrSHJ4QnJuRk1SMjNrWVR1K2tXUFZVYUcwRExPanl1YVhYR3VDOHc9PSIsIndvcmtzcGFjZU5hbWUiOiJkZW1vLXVzZXItam9lLW5vdGVib29rIiwid29ya3NwYWNlRG9tYWluTmFtZSI6ImRlbW8tdXNlci1qb2Utbm90ZWJvb2steXVvYyIsInN1YiI6IjE5NTg4OTY3MTY5MCIsImV4cCI6MTY0MDc0NDM1OCwiaWF0IjoxNjQwNzQwNzU4fQ.WGFEzQhC3lvA9IguA2tbCS6Us9mhRIV_6LiuRTAytSo"}%  
  1. Open a browser and navigate to the PreSignedURL from the previous step.

The webpage should look like the following screenshot.

Conclusion

In this post, we demonstrated how to deploy the infrastructure components for a SageMaker notebook instance environment using AWS CloudFormation. We then illustrated how to use EventBridge to return the notebook instance state from the AWS Service Catalog API. Lastly, we showed how to use a Lambda function to return the presigned notebook instance URL for accessing the delivered resource. For more information, see the Amazon SageMaker Developer Guide. Thank you for reading!


About the Authors

Joe Keating is a Senior Customer Delivery Architect in Professional Services at Amazon Web Services. He works with AWS customers to design and implement a variety of solutions in the AWS Cloud. Joe enjoys cooking with a glass or two of wine and achieving mediocrity on the golf course.

Matt Hedges is a Cloud Application Architect at Amazon Web Services. He works closely with customers to align technology needs with business drivers to deliver their applications on AWS. With a focus on migrations and modernization, Matt works with enterprise customers around the world to pioneer changes that unlock the full potential of the cloud. Matt enjoys spending time with family, playing musical instruments, cooking, playing video games, fixing old cars, and learning new things.

Virginia Chu is a Senior DevSecOps Architect in Professional Services at Amazon Web Services. She works with enterprise-scale customers around the globe to design and implement a variety of solutions in the AWS Cloud.