{"id":18947627,"url":"https://github.com/yousafkhamza/sagemaker-notebook-instance-autoshutdown","last_synced_at":"2026-05-08T06:44:51.127Z","repository":{"id":195965553,"uuid":"519409109","full_name":"yousafkhamza/SageMaker-Notebook-Instance-AutoShutDown","owner":"yousafkhamza","description":"This is a terraform script and it includes a python script that we can use to shutdown sagemaker notebook instances using the lambda function with tags. Also, terraform creates a cloudwatch trigger for lambda, and which that time you can assign whenever you want.","archived":false,"fork":false,"pushed_at":"2022-07-30T09:14:18.000Z","size":523,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-01T01:19:53.706Z","etag":null,"topics":["aws","lambda-functions","python","sagemaker-notebook-container","script","shutdown","terraform"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yousafkhamza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-07-30T03:33:39.000Z","updated_at":"2022-09-03T03:42:13.000Z","dependencies_parsed_at":"2023-09-20T20:13:37.451Z","dependency_job_id":null,"html_url":"https://github.com/yousafkhamza/SageMaker-Notebook-Instance-AutoShutDown","commit_stats":null,"previous_names":["yousafkhamza/sagemaker-notebook-instance-autoshutdown"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FSageMaker-Notebook-Instance-AutoShutDown","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FSageMaker-Notebook-Instance-AutoShutDown/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FSageMaker-Notebook-Instance-AutoShutDown/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FSageMaker-Notebook-Instance-AutoShutDown/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yousafkhamza","download_url":"https://codeload.github.com/yousafkhamza/SageMaker-Notebook-Instance-AutoShutDown/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239946876,"owners_count":19723014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","lambda-functions","python","sagemaker-notebook-container","script","shutdown","terraform"],"created_at":"2024-11-08T13:10:42.096Z","updated_at":"2025-10-15T06:26:09.077Z","avatar_url":"https://github.com/yousafkhamza.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SageMaker Instance AutoShutDown with Python and Terraform\n\n[![Build](https://travis-ci.org/joemccann/dillinger.svg?branch=master)](https://travis-ci.org/joemccann/dillinger)\n\n---\n## Description\nThis is a terraform script and it includes a python script that we can use to shutdown sagemaker notebook instances using the lambda function with tags. Also, terraform creates a cloudwatch trigger for lambda, and which that time you can assign whenever you want.\n\nFurthermore, if you have a sagemaker notebook instance please add a tag like \"AutoStop: True\". Please note that the lambda python script works with the tag so please add the same from yourself on your existing sagemaker notebook instances.\n\n----\n## Feature\n- Save Money (SageMaker instances are too costly.)\n- Automated with CloudWatch Event Rule\n- SageMaker Shutdown with tags feature.\n\n----\n## Architecture\n![alt text](https://i.ibb.co/tXS81cJ/flow.jpg)\n\n----\n## Services Created\n\n- IAM Role (Custom Inline Policies for lambda)\n- Lambda Function (Python for SageMaker ShutDown)\n- Cloudwatch Event Rule Trigger\n\n----\n## Pre-Requests\n- Terraform (Configure your machine with AWS Creds with the above service access)\n- Git\n- Please add tag (Key: AutoStop, Value: True)\n![alt text](https://i.ibb.co/fvHY48f/Screenshot-7.png)\n\n#### Terraform Installation\n[Terraform Installation from official](https://www.terraform.io/downloads)\n\n_TFSwitch Installation:_\n```\ncurl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/release/install.sh | bash\n```\n\n#### Pre-Requests (for RedHat-based-Linux)\n```\nyum install -y git\n```\n\n#### Pre-Requests (for Debian-based-Linux)\n````\napt install -y git\n````\n\n#### Pre-Requests (for Termux-based-Linux)\n````\npkg upgrade\npkg install git\n````\n\n---\n## How to Get\n```\ngit clone https://github.com/yousafkhamza/SageMaker-Notebook-Instance-AutoShutDown.git\ncd SageMaker-Notebook-Instance-AutoShutDown\n```\n\n----\n## How to execute\n```\nterraform init\nterraform plan\nterraform apply\n```\n\n----\n## Output be like\n```\n$terraform apply --auto-approve\n\nTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following\nsymbols:\n  + create\n\nTerraform will perform the following actions:\n\n  # aws_cloudwatch_event_rule.trigger_to_stop_sagemaker_instance will be created\n  + resource \"aws_cloudwatch_event_rule\" \"trigger_to_stop_sagemaker_instance\" {\n      + arn                 = (known after apply)\n      + description         = \"Trigger that moving data lambda\"\n      + event_bus_name      = \"default\"\n      + id                  = (known after apply)\n      + is_enabled          = true\n      + name                = \"Trigger-stop-sagemaker-instance-lambda\"\n      + name_prefix         = (known after apply)\n      + schedule_expression = \"cron(0 16 * * ? *)\"\n      + tags                = {\n          + \"Name\" = \"sagemaker stop cloudwatch trigger\"\n        }\n      + tags_all            = {\n          + \"Name\" = \"sagemaker stop cloudwatch trigger\"\n        }\n    }\n\n  # aws_cloudwatch_event_target.send_to_stop_lambda_target will be created\n  + resource \"aws_cloudwatch_event_target\" \"send_to_stop_lambda_target\" {\n      + arn            = (known after apply)\n      + event_bus_name = \"default\"\n      + id             = (known after apply)\n      + rule           = \"Trigger-stop-sagemaker-instance-lambda\"\n      + target_id      = \"SendToLambda\"\n    }\n\n  # aws_iam_role.lambda_iam_role_terraform will be created\n  + resource \"aws_iam_role\" \"lambda_iam_role_terraform\" {\n      + arn                   = (known after apply)\n      + assume_role_policy    = jsonencode(\n            {\n              + Statement = [\n                  + {\n                      + Action    = \"sts:AssumeRole\"\n                      + Effect    = \"Allow\"\n                      + Principal = {\n                          + Service = \"lambda.amazonaws.com\"\n                        }\n                      + Sid       = \"\"\n                    },\n                ]\n              + Version   = \"2012-10-17\"\n            }\n        )\n      + create_date           = (known after apply)\n      + description           = \"IAM role for lambda to stop that SageMaker instance which we used tags AutoStop\"\n      + force_detach_policies = false\n      + id                    = (known after apply)\n      + managed_policy_arns   = (known after apply)\n      + max_session_duration  = 3600\n      + name                  = \"Lambda-IAM-Role-For-SageMaker-Auto-ShutDown\"\n      + name_prefix           = (known after apply)\n      + path                  = \"/lambda/\"\n      + tags_all              = (known after apply)\n      + unique_id             = (known after apply)\n\n      + inline_policy {\n          + name   = \"SageMaker-Auto-ShutDown-Inline-Policy\"\n          + policy = jsonencode(\n                {\n                  + Statement = [\n                      + {\n                          + Action   = [\n                              + \"sagemaker:StopNotebookInstance\",\n                              + \"sagemaker:ListTags\",\n                              + \"sagemaker:DescribeNotebookInstance\",\n                              + \"sagemaker:AddTags\",\n                            ]\n                          + Effect   = \"Allow\"\n                          + Resource = \"arn:aws:sagemaker:ap-south-1:514645378310:notebook-instance/*\"\n                          + Sid      = \"\"\n                        },\n                      + {\n                          + Action   = \"sagemaker:ListNotebookInstances\"\n                          + Effect   = \"Allow\"\n                          + Resource = \"*\"\n                          + Sid      = \"\"\n                        },\n                    ]\n                  + Version   = \"2012-10-17\"\n                }\n            )\n        }\n    }\n\n  # aws_lambda_function.sagemaker_stop_lambda_function will be created\n  + resource \"aws_lambda_function\" \"sagemaker_stop_lambda_function\" {\n      + architectures                  = (known after apply)\n      + arn                            = (known after apply)\n      + description                    = \"This lambda using to stop the sagemaker instance which we mentioned\"\n      + filename                       = \"tmp/stop-lambda-function.zip\"\n      + function_name                  = \"sagemaker-stop-lambda-function\"\n      + handler                        = \"lambda_function.lambda_handler\"\n      + id                             = (known after apply)\n      + invoke_arn                     = (known after apply)\n      + last_modified                  = (known after apply)\n      + memory_size                    = 128\n      + package_type                   = \"Zip\"\n      + publish                        = false\n      + qualified_arn                  = (known after apply)\n      + reserved_concurrent_executions = -1\n      + role                           = (known after apply)\n      + runtime                        = \"python3.9\"\n      + signing_job_arn                = (known after apply)\n      + signing_profile_version_arn    = (known after apply)\n      + source_code_hash               = (known after apply)\n      + source_code_size               = (known after apply)\n      + tags                           = {\n          + \"Name\" = \"sagemaker stop lambda function\"\n        }\n      + tags_all                       = {\n          + \"Name\" = \"sagemaker stop lambda function\"\n        }\n      + timeout                        = 60\n      + version                        = (known after apply)\n\n      + environment {\n          + variables = {\n              + \"REGION\" = \"ap-south-1\"\n            }\n        }\n\n      + ephemeral_storage {\n          + size = (known after apply)\n        }\n\n      + tracing_config {\n          + mode = (known after apply)\n        }\n    }\n\n  # aws_lambda_permission.allow_cloudwatch_to_call_stop_lambda will be created\n  + resource \"aws_lambda_permission\" \"allow_cloudwatch_to_call_stop_lambda\" {\n      + action              = \"lambda:InvokeFunction\"\n      + function_name       = \"sagemaker-stop-lambda-function\"\n      + id                  = (known after apply)\n      + principal           = \"events.amazonaws.com\"\n      + source_arn          = (known after apply)\n      + statement_id        = \"AllowExecutionFromCloudWatch\"\n      + statement_id_prefix = (known after apply)\n    }\n\nPlan: 5 to add, 0 to change, 0 to destroy.\naws_iam_role.lambda_iam_role_terraform: Creating...\naws_iam_role.lambda_iam_role_terraform: Creation complete after 4s [id=Lambda-IAM-Role-For-SageMaker-Auto-ShutDown]\naws_lambda_function.sagemaker_stop_lambda_function: Creating...\naws_lambda_function.sagemaker_stop_lambda_function: Still creating... [10s elapsed]\naws_lambda_function.sagemaker_stop_lambda_function: Still creating... [20s elapsed]\naws_lambda_function.sagemaker_stop_lambda_function: Creation complete after 22s [id=sagemaker-stop-lambda-function]\naws_cloudwatch_event_rule.trigger_to_stop_sagemaker_instance: Creating...\naws_cloudwatch_event_rule.trigger_to_stop_sagemaker_instance: Creation complete after 1s [id=Trigger-stop-sagemaker-instance-lambda]\naws_lambda_permission.allow_cloudwatch_to_call_stop_lambda: Creating...\naws_cloudwatch_event_target.send_to_stop_lambda_target: Creating...\naws_cloudwatch_event_target.send_to_stop_lambda_target: Creation complete after 0s [id=Trigger-stop-sagemaker-instance-lambda-SendToLambda]\naws_lambda_permission.allow_cloudwatch_to_call_stop_lambda: Creation complete after 0s [id=AllowExecutionFromCloudWatch]\n\nApply complete! Resources: 5 added, 0 changed, 0 destroyed.\n```\n### _Output Screenshots (at AWS)_\n![alt text](https://i.ibb.co/vPp6Csq/Screenshot-8.png)\n\n----\n## Behind the code\n### Terraform code\n`Fetch.tf`:\n```\n# Fetch Account ID for IAM.\ndata \"aws_caller_identity\" \"current\" {\n}\n```\n\u003e File used to fetch current account id and the account used to secure IAM role creation for lambda\n\n`IAM.tf`:\n```\n# ----------------------------------\n# IAM Role for Lambda Function \n# ----------------------------------\n# Assume Role - For Lambda\ndata \"aws_iam_policy_document\" \"lambda_assume_role\" {\n  statement {\n    effect = \"Allow\"\n    actions = [\n    \"sts:AssumeRole\"]\n    principals {\n      type = \"Service\"\n      identifiers = [\n      \"lambda.amazonaws.com\"]\n    }\n  }\n}\n\n# Inline policy for sagemaker stop for lambda\ndata \"aws_iam_policy_document\" \"auto_shutdown_iam_inline\" {\n  statement {\n    actions = [\n        \"sagemaker:ListTags\",\n        \"sagemaker:StopNotebookInstance\",\n        \"sagemaker:DescribeNotebookInstance\",\n        \"sagemaker:AddTags\"\n    ]\n    resources = [\n        \"arn:aws:sagemaker:${var.aws_region}:${data.aws_caller_identity.current.account_id}:notebook-instance/*\",\n    ]\n  }\n  statement {\n    actions = [\n        \"sagemaker:ListNotebookInstances\",\n    ]\n    resources = [\n        \"*\",\n    ]\n  }\n}\n\n\n\n# Role for Lambda and both assume and inline integrated \nresource \"aws_iam_role\" \"lambda_iam_role_terraform\" {\n  name               = \"Lambda-IAM-Role-For-SageMaker-Auto-ShutDown\"\n  path               = \"/lambda/\"\n  assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json\n\n  description = \"IAM role for lambda to stop that SageMaker instance which we used tags AutoStop\"\n\n  inline_policy {\n    name   = \"SageMaker-Auto-ShutDown-Inline-Policy\"\n    policy = data.aws_iam_policy_document.auto_shutdown_iam_inline.json\n  }\n}\n```\n\u003e Creating IAM role with SageMaker Shutdown and tag describing privilege for lambda function execution\n\n`Lambda_Stop.tf`:\n```\n# ----------------------------------\n# Lambda_Function\n# ----------------------------------\n#archiving py file to zipping\ndata \"archive_file\" \"stop_lambda_zip\" {\n  type        = \"zip\"\n  source_dir  = \"./lambda_code/stop/\"\n  output_path = \"tmp/${local.stop_lambda_function}.zip\"\n}\n\nresource \"aws_lambda_function\" \"sagemaker_stop_lambda_function\" {\n  filename      = data.archive_file.stop_lambda_zip.output_path\n  function_name = \"sagemaker-stop-lambda-function\"\n  role          = aws_iam_role.lambda_iam_role_terraform.arn\n  description   = \"This lambda using to stop the sagemaker instance which we used AutoStop tag\"\n  handler       = \"lambda_function.lambda_handler\"\n  runtime       = local.runtime_lambda_function\n  timeout       = 60\n  memory_size   = 128\n\n  environment {\n    variables = {\n      REGION = var.aws_region\n    }\n  }\n\n  tags = tomap({\"Name\" = \"sagemaker stop lambda function\"})\n}\n\n\n#-----------------------\n# CloudWatch Trigger to stop sagemaker instance\n#-----------------------\nresource \"aws_cloudwatch_event_rule\" \"trigger_to_stop_sagemaker_instance\" {\n  name                  = \"Trigger-stop-sagemaker-instance-lambda\"\n  description           = \"Trigger that moving data lambda\"\n  schedule_expression   = var.stop_cron\n  tags = tomap({\"Name\" = \"sagemaker stop cloudwatch trigger\"})\n\n  depends_on = [aws_lambda_function.sagemaker_stop_lambda_function]\n}\n\nresource \"aws_cloudwatch_event_target\" \"send_to_stop_lambda_target\" {\n  rule      = aws_cloudwatch_event_rule.trigger_to_stop_sagemaker_instance.name\n  target_id = \"SendToLambda\"\n  arn       = aws_lambda_function.sagemaker_stop_lambda_function.arn\n\n  depends_on = [aws_lambda_function.sagemaker_stop_lambda_function]\n}\n\nresource \"aws_lambda_permission\" \"allow_cloudwatch_to_call_stop_lambda\" {\n    statement_id = \"AllowExecutionFromCloudWatch\"\n    action = \"lambda:InvokeFunction\"\n    function_name = aws_lambda_function.sagemaker_stop_lambda_function.function_name\n    principal = \"events.amazonaws.com\"\n    source_arn = aws_cloudwatch_event_rule.trigger_to_stop_sagemaker_instance.arn\n\n    depends_on = [aws_lambda_function.sagemaker_stop_lambda_function,aws_cloudwatch_event_rule.trigger_to_stop_sagemaker_instance]\n}\n```\n\u003e will create a lambda function with the python code. also, create a cloudwatch trigger with your time and set up target with the same lambda as we created the same. \n\n`provider.tf`:\n```\nprovider \"aws\" {\nregion = var.aws_region\n}\n```\n\u003e which region do you want? \n\n`variables.tf`:\n```\nvariable \"aws_region\" {\n  type        = string\n  description = \"Which region do you use\"\n  default     = \"\"\n}\n\nvariable \"stop_cron\" {\n  type        = string\n  description = \"Cron time stop the instance which we created\"\n  default     = \"cron(0 17 * * ? *)\"\n}\n\nlocals {\nstop_lambda_function = \"stop-lambda-function\"\nruntime_lambda_function = \"python3.9\"\n}\n```\n\u003e variables creation and values are stored in tfvars file\n\n`terraform.tfvars`:\n```\naws_region = \"ap-south-1\"            # mention which region you need here.\nstop_cron = \"cron(0 16 * * ? *)\"     # Which time to stop that SageMaker instance here.\n```\n\u003e Mention your region and lambda cloudwatch event trigger cron time\n\n`versions.tf`:\n```\nterraform {\n  required_version = \"\u003e= 0.13\"\n\n  required_providers {\n    aws = \"\u003e= 3.36\"\n  }\n}\n```\n\u003e Supported versions with terraform\n\n`lambda_function.py`:\n```\nimport boto3\nfrom botocore.exceptions import ClientError\nimport os\n\nREGION = os.environ['REGION']\n\ndef lambda_handler(event, context):\n    client = boto3.client('sagemaker', region_name=REGION)\n    response = client.list_notebook_instances(MaxResults=100)\n    notebooks = response['NotebookInstances']\n    notebook_list = []\n    for notebook in notebooks:\n        notebook_dict = dict()\n        notebook_dict['NotebookInstanceName'] = notebook['NotebookInstanceName']\n        notebook_dict['NotebookInstanceArn'] = notebook['NotebookInstanceArn']\n        notebook_dict['NotebookInstanceStatus'] = notebook['NotebookInstanceStatus']\n        notebook_dict['InstanceType'] = notebook['InstanceType']\n        notebook_list.append(notebook_dict)\n\n    for InstanceName in notebook_list:\n        InstanceSName=InstanceName['NotebookInstanceName']\n        DescribeInstance = client.describe_notebook_instance(\n        NotebookInstanceName=f'{InstanceSName}')\n        InstanceArn=DescribeInstance['NotebookInstanceArn']\n        Tags=client.list_tags(\n        ResourceArn=f'{InstanceArn}')\n        if len(Tags['Tags']) != 0:\n            if Tags['Tags'][0]['Key'] == \"AutoStop\" and Tags['Tags'][0]['Value'] == 'True':\n                    if DescribeInstance['NotebookInstanceStatus'] == 'InService':\n                        try:\n                            print(\"Stopping SageMaker Instance : {}\".format(InstanceSName))\n                            response = client.stop_notebook_instance(NotebookInstanceName=f'{InstanceSName}')\n                        except ClientError as e:\n                            print(e.response['Error']['Message'])\n```\n\u003e lambda function code with sagemaker instance shutdown and please note that we are using tags AutoStop. So, if you need to change please change inside the code\n\n----\n## Conclusion\nSageMaker Notebook instances are costly. So, if you forget to shut down an instance and get more bills then you can use the terraform script and deploy the same to your aws account and add the tags to your existing instances then this will help you to shut down a particular time daily. Please note that you may start the instance yourself that couldn't be included in the script.\n\n### ⚙️ Connect with Me \n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"mailto:yousaf.k.hamza@gmail.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/Gmail-D14836?style=for-the-badge\u0026logo=gmail\u0026logoColor=white\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://www.linkedin.com/in/yousafkhamza\"\u003e\u003cimg src=\"https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge\u0026logo=linkedin\u0026logoColor=white\"/\u003e\u003c/a\u003e \n\u003ca href=\"https://www.instagram.com/yousafkhamza\"\u003e\u003cimg src=\"https://img.shields.io/badge/Instagram-E4405F?style=for-the-badge\u0026logo=instagram\u0026logoColor=white\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://wa.me/%2B917736720639?text=This%20message%20from%20GitHub.\"\u003e\u003cimg src=\"https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge\u0026logo=whatsapp\u0026logoColor=white\"/\u003e\u003c/a\u003e\u003cbr /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyousafkhamza%2Fsagemaker-notebook-instance-autoshutdown","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyousafkhamza%2Fsagemaker-notebook-instance-autoshutdown","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyousafkhamza%2Fsagemaker-notebook-instance-autoshutdown/lists"}