SageMaker Notebook Instance Should Be In VPC
More Info:
Sagemaker Notebook instance should be associated to a VPC
Risk Level
Medium
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- ISO 27001
- ISO/IEC 27018
- ISO/IEC 27701
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SOC2
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Using Console
For SageMaker Notebook Instances, you cannot change an existing notebook from “no VPC” to “in VPC.” You must create a new notebook instance in a VPC and then decommission the old one.
Below are step‑by‑step instructions using the AWS Console:
1. Prerequisites: Identify / Prepare VPC, Subnet, and Security Group
- In the AWS Console, go to VPC service.
- Choose (or create) a VPC you want to use.
- Under Subnets, pick a private subnet (recommended) with:
- Route to required services (e.g., NAT Gateway for internet access if needed).
- Under Security Groups, either:
- Choose an existing one, or
- Create a new security group with:
- Outbound rules to allow access to SageMaker endpoints, S3, etc. (usually “All traffic” outbound is fine if routed via NAT).
- Inbound rules only if you need specific inbound connections (often none are needed for notebooks).
2. Create a New Notebook Instance in the VPC
- Go to Amazon SageMaker in the console.
- In the left navigation pane, select Notebook instances.
- Click Create notebook instance.
- Fill in:
- Notebook instance name: e.g.,
sagemaker-notebook-in-vpc. - Notebook instance type: same as your current instance or as needed.
- Notebook instance name: e.g.,
- IAM role:
- Select Existing role if you already have a SageMaker execution role.
- Otherwise, choose Create a new role and allow required S3 access.
- Scroll down to Network (or Network and security) section:
- VPC: Select your target VPC.
- Subnet: Select the private subnet you prepared.
- Security group(s): Select the security group you prepared.
- (Optional) Under Additional configuration:
- Attach the same Lifecycle configuration as the old instance if you used one.
- Configure any volume size, encryption, etc., to match your requirements.
- Click Create notebook instance.
- Wait until the status becomes InService.
3. Migrate Your Work (Notebooks, Code, Data)
- Open the old notebook instance:
- From Notebook instances, click Open Jupyter or Open JupyterLab.
- Copy notebooks and files to durable storage:
- Preferred: Save them in Amazon S3 (if they’re not already).
- Use the Jupyter file browser “Download” or upload them to S3 using the AWS CLI / SDK / Jupyter extensions.
- Preferred: Save them in Amazon S3 (if they’re not already).
- Open the new VPC‑based notebook instance:
- From Notebook instances, click Open Jupyter or Open JupyterLab.
- Restore content:
- Download from S3 or upload from local machine into the new notebook instance.
- Verify:
- Run a few notebooks to confirm they can access needed data (S3, databases, external APIs via NAT, etc.).
4. Decommission the Old Non‑VPC Notebook Instance
- In Amazon SageMaker → Notebook instances:
- Select the old notebook instance.
- Choose Stop.
- Wait until the status is Stopped.
- With the instance selected, choose Delete.
- Confirm deletion.
5. (Optional) Tighten Network Controls
In VPC → Security groups:
- Restrict inbound rules to only what is necessary.
- Leave outbound open or restrict to required destinations if you have more advanced network controls (VPC endpoints, proxy, etc.).
This process results in your SageMaker Notebook Instance running inside a VPC, satisfying the “Notebook Instance Should Be In VPC” requirement.
Using CLI
For SageMaker, you cannot “move” an existing Notebook Instance into a VPC; you must create a new notebook in a VPC, move any code/data, then delete the old one.
Below are step‑by‑step AWS CLI–based instructions.
1. Identify notebook instances not in a VPC
aws sagemaker list-notebook-instances \
--query 'NotebookInstances[*].NotebookInstanceName' \
--output text
For each notebook:
NB_NAME="your-notebook-name"
aws sagemaker describe-notebook-instance \
--notebook-instance-name "$NB_NAME" \
--query '{Name:NotebookInstanceName,SubnetId:SubnetId,SecurityGroups:SecurityGroups}' \
--output json
Any instance with "SubnetId": null is not in a VPC.
2. Choose / prepare VPC resources
You need:
- A VPC ID
- A private subnet ID in that VPC
- One or more security group IDs allowing needed outbound traffic (and inbound if required, e.g., for SSM or Git)
Get VPCs:
aws ec2 describe-vpcs \
--query 'Vpcs[*].{VpcId:VpcId,CidrBlock:CidrBlock}' \
--output table
Get subnets for a chosen VPC:
VPC_ID="vpc-xxxxxxxx"
aws ec2 describe-subnets \
--filters "Name=vpc-id,Values=$VPC_ID" \
--query 'Subnets[*].{SubnetId:SubnetId,Az:AvailabilityZone,Name:Tags[?Key==`Name`]|[0].Value}' \
--output table
Get or create a security group:
# List existing SGs in VPC
aws ec2 describe-security-groups \
--filters "Name=vpc-id,Values=$VPC_ID" \
--query 'SecurityGroups[*].{GroupId:GroupId,GroupName:GroupName}' \
--output table
Example: create a new SG:
SG_ID=$(aws ec2 create-security-group \
--group-name sagemaker-notebook-sg \
--description "SageMaker Notebook SG" \
--vpc-id "$VPC_ID" \
--query 'GroupId' \
--output text)
# (Optional) allow outbound to anywhere
aws ec2 authorize-security-group-egress \
--group-id "$SG_ID" \
--ip-permissions '[
{
"IpProtocol": "-1",
"IpRanges": [{"CidrIp": "0.0.0.0/0"}]
}
]'
3. Create a new Notebook Instance in the VPC
Decide:
INSTANCE_TYPE(e.g.,ml.t3.medium)ROLE_ARN– execution role withsagemaker:*/ S3 permissionsSUBNET_ID– from step 2SG_ID– from step 2- Optional: lifecycle config, volume size, etc.
NB_NEW_NAME="your-new-notebook-name"
INSTANCE_TYPE="ml.t3.medium"
ROLE_ARN="arn:aws:iam::123456789012:role/SageMakerExecutionRole"
SUBNET_ID="subnet-xxxxxxxx"
SG_ID="sg-xxxxxxxx"
aws sagemaker create-notebook-instance \
--notebook-instance-name "$NB_NEW_NAME" \
--instance-type "$INSTANCE_TYPE" \
--role-arn "$ROLE_ARN" \
--subnet-id "$SUBNET_ID" \
--security-group-ids "$SG_ID"
Wait for it to be InService:
aws sagemaker wait notebook-instance-in-service \
--notebook-instance-name "$NB_NEW_NAME"
Confirm VPC settings:
aws sagemaker describe-notebook-instance \
--notebook-instance-name "$NB_NEW_NAME" \
--query '{Name:NotebookInstanceName,SubnetId:SubnetId,SecurityGroups:SecurityGroups}' \
--output json
4. Migrate notebooks / data
Typical pattern (if old notebook is still accessible via console):
-
From the old notebook, ensure all notebooks and code are saved to S3 (e.g.,
~/SageMakerauto‑syncs to S3 if configured). -
Alternatively, sync manually:
aws s3 sync /home/ec2-user/SageMaker s3://your-bucket/path/ -
On the new notebook instance, pull from S3:
aws s3 sync s3://your-bucket/path/ /home/ec2-user/SageMaker
If you used Git in your old instance, simply re‑clone your repos in the new instance.
5. Stop and delete old non‑VPC notebook instance
OLD_NB_NAME="old-notebook-name"
aws sagemaker stop-notebook-instance \
--notebook-instance-name "$OLD_NB_NAME"
aws sagemaker wait notebook-instance-stopped \
--notebook-instance-name "$OLD_NB_NAME"
aws sagemaker delete-notebook-instance \
--notebook-instance-name "$OLD_NB_NAME"
6. (Optional) Enforce “must be in VPC” via SCP or IaC
To prevent future non‑VPC notebooks, you can:
- Use a Service Control Policy denying
sagemaker:CreateNotebookInstanceifsagemaker:SubnetIdis not present. - Use Infrastructure‑as‑Code (CloudFormation/Terraform) that always sets
SubnetIdandSecurityGroupIds.
If you share your current notebook config (from describe-notebook-instance), I can give an exact create-notebook-instance CLI command that reproduces it inside a VPC.
Using Python
For SageMaker, a notebook instance cannot be moved into a VPC after creation. You must:
- Create (or choose) a VPC, subnet, and security group.
- Create a new SageMaker notebook instance configured to use that VPC.
- Migrate code/data from the old notebook (e.g., via Git, S3).
- Delete the old non‑VPC notebook.
Below is the Python/boto3 approach.
1. Prerequisites
boto3installed and configured with credentials/region.- You have (or will create) the following:
- VPC ID:
vpc-xxxxxxxx - Subnet ID in that VPC:
subnet-xxxxxxxx - Security Group ID that allows needed traffic:
sg-xxxxxxxx - IAM role with SageMaker permissions:
arn:aws:iam::<account-id>:role/<SageMakerRole>
- VPC ID:
2. Create a SageMaker Notebook in a VPC (Python/boto3)
import boto3
sagemaker = boto3.client("sagemaker", region_name="us-east-1")
notebook_instance_name = "my-vpc-notebook"
role_arn = "arn:aws:iam::<account-id>:role/<SageMakerRole>"
subnet_id = "subnet-xxxxxxxx"
security_group_ids = ["sg-xxxxxxxx"]
response = sagemaker.create_notebook_instance(
NotebookInstanceName=notebook_instance_name,
InstanceType="ml.t3.medium", # choose appropriate instance type
RoleArn=role_arn,
SubnetId=subnet_id,
SecurityGroupIds=security_group_ids,
DirectInternetAccess="Disabled", # or "Enabled" if you require it
VolumeSizeInGB=10, # adjust as needed
Tags=[
{"Key": "Name", "Value": "my-vpc-notebook"},
{"Key": "Environment", "Value": "prod"},
],
)
print("CreateNotebookInstance response:", response)
To wait until it’s ready:
import time
def wait_for_notebook_inservice(name):
while True:
desc = sagemaker.describe_notebook_instance(NotebookInstanceName=name)
status = desc["NotebookInstanceStatus"]
print("Status:", status)
if status in ["InService", "Failed", "Stopped"]:
break
time.sleep(30)
wait_for_notebook_inservice(notebook_instance_name)
3. (Optional) Stop and Delete the Old Non‑VPC Notebook
old_notebook_name = "my-old-nonvpc-notebook"
# Stop (if running)
try:
sagemaker.stop_notebook_instance(NotebookInstanceName=old_notebook_name)
except sagemaker.exceptions.ResourceNotFound:
pass
wait_for_notebook_inservice(old_notebook_name) # will show "Stopped"
# Delete
sagemaker.delete_notebook_instance(NotebookInstanceName=old_notebook_name)
4. Notes for Compliance
- Ensure SubnetId and SecurityGroupIds are always specified when calling
create_notebook_instance. - Enforce via CI/CD or internal tooling so that notebooks are only created with VPC settings.
- If needed, you can verify compliance by listing and checking:
paginator = sagemaker.get_paginator("list_notebook_instances")
for page in paginator.paginate():
for ni in page["NotebookInstances"]:
desc = sagemaker.describe_notebook_instance(
NotebookInstanceName=ni["NotebookInstanceName"]
)
if "SubnetId" not in desc:
print("Non‑VPC notebook:", ni["NotebookInstanceName"])
Using Terraform
resource "aws_sagemaker_notebook_instance" "THIS_NOTEBOOK" {
# Replace THIS_NOTEBOOK with the actual notebook name or keep as-is if already managed
name = "THIS_NOTEBOOK_NAME" # TODO: replace with your notebook name
instance_type = "ml.t3.medium" # TODO: keep your current instance type
role_arn = aws_iam_role.sagemaker_role.arn # TODO: keep your current IAM role
# VPC configuration – this is what fixes the finding
subnet_id = aws_subnet.NOTEBOOK_SUBNET.id # TODO: replace with your target private subnet
security_groups = [
aws_security_group.NOTEBOOK_SG.id # TODO: replace with one or more SGs that allow required access
]
# ...keep any other existing arguments (tags, lifecycle_config_name, etc.)
}
resource "aws_subnet" "NOTEBOOK_SUBNET" {
vpc_id = aws_vpc.MAIN.id # TODO: reference your VPC
cidr_block = "10.0.1.0/24" # TODO: match your network design
availability_zone = "us-east-1a" # TODO: match your AZ
map_public_ip_on_launch = false
# ...other subnet settings as needed
}
resource "aws_security_group" "NOTEBOOK_SG" {
name = "sagemaker-notebook-sg"
description = "Security group for SageMaker notebook in VPC"
vpc_id = aws_vpc.MAIN.id # TODO: reference your VPC
# TODO: tighten rules as appropriate; example for VPC‑internal access only:
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"] # TODO: adjust to your internal CIDR
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Changing an existing SageMaker Notebook Instance from “no VPC” to having subnet_id/security_groups forces resource replacement; expect downtime for this notebook during terraform apply.
Verification: terraform plan should show aws_sagemaker_notebook_instance.THIS_NOTEBOOK being replaced with a new instance that includes subnet_id and security_groups, and no other unrelated changes.