> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        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

        1. In the AWS Console, go to **VPC** service.
        2. Choose (or create) a **VPC** you want to use.
        3. Under **Subnets**, pick a **private subnet** (recommended) with:
           * Route to required services (e.g., NAT Gateway for internet access if needed).
        4. 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

        1. Go to **Amazon SageMaker** in the console.
        2. In the left navigation pane, select **Notebook instances**.
        3. Click **Create notebook instance**.
        4. Fill in:
           * **Notebook instance name**: e.g., `sagemaker-notebook-in-vpc`.
           * **Notebook instance type**: same as your current instance or as needed.
        5. **IAM role**:
           * Select **Existing role** if you already have a SageMaker execution role.
           * Otherwise, choose **Create a new role** and allow required S3 access.
        6. 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.
        7. (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.
        8. Click **Create notebook instance**.
        9. Wait until the status becomes **InService**.

        ***

        ## 3. Migrate Your Work (Notebooks, Code, Data)

        1. Open the **old** notebook instance:
           * From **Notebook instances**, click **Open Jupyter** or **Open JupyterLab**.
        2. 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.
        3. Open the **new** VPC‑based notebook instance:
           * From **Notebook instances**, click **Open Jupyter** or **Open JupyterLab**.
        4. Restore content:
           * Download from S3 or upload from local machine into the new notebook instance.
        5. 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

        1. In **Amazon SageMaker** → **Notebook instances**:
           * Select the **old** notebook instance.
        2. Choose **Stop**.
        3. Wait until the status is **Stopped**.
        4. With the instance selected, choose **Delete**.
        5. 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.
      </Accordion>

      <Accordion title="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

        ```bash theme={null}
        aws sagemaker list-notebook-instances \
          --query 'NotebookInstances[*].NotebookInstanceName' \
          --output text
        ```

        For each notebook:

        ```bash theme={null}
        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:

        ```bash theme={null}
        aws ec2 describe-vpcs \
          --query 'Vpcs[*].{VpcId:VpcId,CidrBlock:CidrBlock}' \
          --output table
        ```

        Get subnets for a chosen VPC:

        ```bash theme={null}
        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:

        ```bash theme={null}
        # 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:

        ```bash theme={null}
        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 with `sagemaker:*` / S3 permissions
        * `SUBNET_ID` – from step 2
        * `SG_ID` – from step 2
        * Optional: lifecycle config, volume size, etc.

        ```bash theme={null}
        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`:

        ```bash theme={null}
        aws sagemaker wait notebook-instance-in-service \
          --notebook-instance-name "$NB_NEW_NAME"
        ```

        Confirm VPC settings:

        ```bash theme={null}
        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):

        1. From the old notebook, ensure all notebooks and code are saved to **S3** (e.g., `~/SageMaker` auto‑syncs to S3 if configured).

        2. Alternatively, sync manually:

           ```bash theme={null}
           aws s3 sync /home/ec2-user/SageMaker s3://your-bucket/path/
           ```

        3. On the new notebook instance, pull from S3:

           ```bash theme={null}
           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

        ```bash theme={null}
        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:CreateNotebookInstance` if `sagemaker:SubnetId` is not present.
        * Use Infrastructure‑as‑Code (CloudFormation/Terraform) that always sets `SubnetId` and `SecurityGroupIds`.

        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.
      </Accordion>

      <Accordion title="Using Python">
        For SageMaker, a notebook instance **cannot be moved into a VPC after creation**. You must:

        1. Create (or choose) a VPC, subnet, and security group.
        2. Create a **new** SageMaker notebook instance configured to use that VPC.
        3. Migrate code/data from the old notebook (e.g., via Git, S3).
        4. Delete the old non‑VPC notebook.

        Below is the Python/boto3 approach.

        ***

        ### 1. Prerequisites

        * `boto3` installed 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>`

        ***

        ### 2. Create a SageMaker Notebook in a VPC (Python/boto3)

        ```python theme={null}
        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:

        ```python theme={null}
        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

        ```python theme={null}
        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:

        ```python theme={null}
        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"])
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
