> ## 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 Domains Should Have VPC Only Network Access Enabled

### More Info:

Sagemaker Domains should have VPC only network access enabled

### Risk Level

Medium

### Address

Monitoring, 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">
        To enforce **VPC-only network access** for SageMaker Domains, you must use a **VPCOnly** domain. The network access type **cannot be changed on an existing domain**, so you’ll create a new domain with VPCOnly and migrate users.

        ### 1. Check existing SageMaker Domain(s)

        1. Sign in to AWS Console.
        2. Go to **Amazon SageMaker**.
        3. In the left menu, choose **Admin configurations → Domains** (or **SageMaker Studio → Domains**, depending on console version).
        4. For each domain, check:
           * **Network access type** (e.g., `PublicInternetOnly` or `VPCOnly`).
           * **Region** (you’ll recreate in the same Region).
           * **VPC, subnets, security groups**, and **execution roles** in use.

        If the domain is not `VPCOnly`, plan to replace it.

        ***

        ### 2. Prepare networking for VPC-only access

        You need a VPC with subnets and security groups that meet Studio requirements.

        1. In the console, go to **VPC**.
        2. Either:
           * Use an existing VPC, or
           * Create a new VPC:
             * Choose **Create VPC → VPC and more**.
             * Provide a name, IPv4 CIDR, and at least two **private subnets** (recommended).
        3. Ensure:
           * Private subnets have outbound access to AWS services as required (via NAT Gateway and route tables, or VPC endpoints).
        4. (Recommended) Add **VPC endpoints** (Interface/ Gateway) for:
           * `com.amazonaws.<region>.sagemaker`, `sts`, `logs`, `ecr.api`, `ecr.dkr`, `s3` (Gateway), etc., depending on what Studio needs to reach without public internet.
        5. Create or identify a **security group** to associate with the domain:
           * Outbound: allow required egress (e.g., to S3, SageMaker, etc., via endpoints / NAT).
           * Inbound: typically no inbound from the internet; inbound from load balancer/endpoints as needed.

        ***

        ### 3. Create a new SageMaker Domain with VPC-only access

        1. Go to **Amazon SageMaker → Admin configurations → Domains**.
        2. Click **Create domain**.
        3. Choose **Domain type** (e.g., **SageMaker Studio** or **Studio Classic**, depending on what you use).
        4. In **Authentication**:
           * Choose **AWS IAM** or **SSO** according to your environment.
        5. In **Network and storage** (names may differ slightly by console version):
           * **Network access type**: select **VPC Only**.
           * **VPC**: choose the prepared VPC.
           * **Subnets**: choose at least one (preferably multiple) **private** subnets.
           * **Security groups**: select your security group(s).
        6. In **Execution role**:
           * Use an existing SageMaker execution role or create a new one with appropriate IAM permissions.
        7. Configure **Default user settings** (app types, storage, lifecycle configs, etc.).
        8. Review all settings and click **Create domain**.
        9. Wait until the new domain status is **InService**.

        ***

        ### 4. Migrate users / projects to the VPCOnly domain

        Because you can’t change the network access type in-place, you need to move usage from the old domain to the new VPCOnly domain:

        1. For each user:
           * Export or copy important notebooks, code, and data from the old domain (e.g., to S3).
        2. In the new VPCOnly domain:
           * Create **User profiles** matching the previous users (if using IAM, map to IAM users/roles as needed).
           * Have users open **SageMaker Studio** from the new domain and restore their notebooks/projects from S3 or version control.
        3. Validate:
           * Users can access required data (S3, Git, etc.) through VPC endpoints or internal paths.
           * No direct access relies on public internet from Studio kernels unless explicitly allowed via NAT, if that’s part of your design.

        ***

        ### 5. Decommission non-compliant (non-VPCOnly) Domain

        After successfully migrating:

        1. Ensure no active workspaces/apps are needed in the old domain.
        2. Back up any remaining data to S3.
        3. In the SageMaker console, go to **Admin configurations → Domains**.
        4. Select the old domain (with `PublicInternetOnly` or mixed access).
        5. Choose **Delete domain** (optionally delete associated user profiles and apps, depending on prompts).
        6. Confirm deletion.

        You now have only **VPCOnly** SageMaker Domains, satisfying the requirement that SageMaker Domains have VPC-only network access enabled.
      </Accordion>

      <Accordion title="Using CLI">
        Below are the concrete AWS CLI steps to enforce **VPC-only network access** for an existing SageMaker Domain.

        ***

        ### 1. Prerequisites

        You must already have:

        * A VPC with:
          * Private subnets for SageMaker (no direct Internet gateway route)
          * Appropriate route tables (e.g., to a NAT gateway or no Internet at all)
        * Security groups allowing required traffic inside the VPC
        * (Recommended) VPC endpoints: `sagemaker.api`, `sagemaker.runtime`, `s3`, `sts`, `ecr.api`, `ecr.dkr`, `logs`, etc. depending on your use case

        Your existing SageMaker Domain must be associated with that VPC and subnets already. You cannot just switch to `VpcOnly` if the Domain is not configured with VPC details.

        ***

        ### 2. Identify your SageMaker Domain

        ```bash theme={null}
        aws sagemaker list-domains \
          --query "Domains[*].{DomainName:DomainName,DomainId:DomainId,Status:Status,AppNetworkAccessType:AppNetworkAccessType}" \
          --output table
        ```

        Note the `DomainId` you want to fix (e.g. `d-xxxxxxxxxx`) and confirm `AppNetworkAccessType` is `PublicInternetOnly`.

        ***

        ### 3. Get current Domain configuration (for reference)

        ```bash theme={null}
        DOMAIN_ID="d-xxxxxxxxxx"

        aws sagemaker describe-domain \
          --domain-id "$DOMAIN_ID" \
          --output json > domain-current.json
        ```

        Inspect `domain-current.json` to confirm:

        * `VpcId`
        * `SubnetIds`
        * `SecurityGroupIds`
        * Current `AppNetworkAccessType` (likely `PublicInternetOnly`)

        You do **not** need to change any of that just to switch to VPC-only.

        ***

        ### 4. Update Domain to VPC-Only

        Run:

        ```bash theme={null}
        aws sagemaker update-domain \
          --domain-id "$DOMAIN_ID" \
          --app-network-access-type VpcOnly
        ```

        This instructs SageMaker to restrict apps to VPC-only network paths.

        You can optionally wait for the update to complete:

        ```bash theme={null}
        aws sagemaker describe-domain \
          --domain-id "$DOMAIN_ID" \
          --query "Status"
        ```

        Wait until you see `InService` again.

        ***

        ### 5. Verify the change

        ```bash theme={null}
        aws sagemaker describe-domain \
          --domain-id "$DOMAIN_ID" \
          --query "{DomainId:DomainId,AppNetworkAccessType:AppNetworkAccessType,Status:Status}" \
          --output table
        ```

        You should now see:

        * `AppNetworkAccessType` = `VpcOnly`
        * `Status` = `InService`

        ***

        ### 6. (Recommended) Validate connectivity from within VPC

        From a notebook or app in the Domain, validate it can still:

        * Access required AWS services over VPC endpoints (e.g., `aws s3 ls` to S3 buckets, call SageMaker APIs, etc.)
        * Reach any private data sources reachable within your VPC

        If something breaks, check:

        * Route tables for the subnets used by the Domain
        * Security group rules
        * Presence and configuration of required VPC endpoints

        ***

        These steps remediate the “SageMaker Domains should have VPC only network access enabled” issue using AWS CLI.
      </Accordion>

      <Accordion title="Using Python">
        Below are the concrete steps and Python code to enforce **VPC-only network access** on an existing SageMaker Domain using `boto3`.

        ***

        ## 1. Prerequisites

        1. You have `boto3` installed:
           ```bash theme={null}
           pip install boto3
           ```
        2. Your AWS credentials and region are configured (via environment variables, AWS CLI, or config files).
        3. Your IAM principal has permissions such as:
           * `sagemaker:DescribeDomain`
           * `sagemaker:UpdateDomain`

        ***

        ## 2. Understand What Needs to Be Changed

        SageMaker Studio domains have a property:

        * `AppNetworkAccessType`:
          * `"PublicInternetOnly"` (insecure for this requirement)
          * `"VpcOnly"` (what you need)

        You’ll use `UpdateDomain` to set `AppNetworkAccessType="VpcOnly"`.

        ***

        ## 3. Identify Your Domain and Check Current Setting

        ```python theme={null}
        import boto3

        sm = boto3.client("sagemaker", region_name="us-east-1")  # change region if needed

        def list_domains():
            paginator = sm.get_paginator("list_domains")
            for page in paginator.paginate():
                for d in page["Domains"]:
                    print(f"DomainId: {d['DomainId']}, Name: {d['DomainName']}")

        list_domains()
        ```

        Pick the `DomainId` you want to remediate, then:

        ```python theme={null}
        DOMAIN_ID = "d-xxxxxxxxxxxxxxxxxxxx"  # replace with your domain ID

        domain_desc = sm.describe_domain(DomainId=DOMAIN_ID)
        print("Current AppNetworkAccessType:", domain_desc.get("AppNetworkAccessType"))
        ```

        If it is `"PublicInternetOnly"`, you need to change it.

        ***

        ## 4. Build the Update Payload

        `UpdateDomain` requires you to pass **all** `DefaultUserSettings` you care about, not just the field you’re changing. A safe approach is to:

        1. Read the existing `DefaultUserSettings` from `DescribeDomain`.
        2. Reuse them when calling `UpdateDomain`.
        3. Add `AppNetworkAccessType="VpcOnly"` at the top level of the call.

        ```python theme={null}
        default_user_settings = domain_desc["DefaultUserSettings"]

        # OPTIONAL: you can adjust security groups here if needed, e.g.:
        # default_user_settings["SecurityGroups"] = ["sg-xxxxxxxxxxxxxxxxx"]
        ```

        ***

        ## 5. Update the Domain to VPC-Only

        ```python theme={null}
        response = sm.update_domain(
            DomainId=DOMAIN_ID,
            AppNetworkAccessType="VpcOnly",
            DefaultUserSettings=default_user_settings
        )

        print("UpdateDomain response:", response)
        ```

        This triggers an update of the domain. Studio may briefly be unavailable while the change applies.

        ***

        ## 6. Verify the Change

        ```python theme={null}
        import time

        time.sleep(10)  # short wait; you can also poll until status is 'InService'

        updated = sm.describe_domain(DomainId=DOMAIN_ID)
        print("Updated AppNetworkAccessType:", updated.get("AppNetworkAccessType"))
        ```

        You should see:

        ```text theme={null}
        Updated AppNetworkAccessType: VpcOnly
        ```

        ***

        ## 7. Full Minimal Script

        ```python theme={null}
        import time
        import boto3

        REGION = "us-east-1"                # change as needed
        DOMAIN_ID = "d-xxxxxxxxxxxxxxxxxxxx"  # replace with your domain ID

        sm = boto3.client("sagemaker", region_name=REGION)

        def set_domain_vpc_only(domain_id: str):
            # Describe the domain
            desc = sm.describe_domain(DomainId=domain_id)
            print("Current AppNetworkAccessType:", desc.get("AppNetworkAccessType"))

            default_user_settings = desc["DefaultUserSettings"]

            # Optionally adjust SecurityGroups or other settings here if required
            # default_user_settings["SecurityGroups"] = ["sg-xxxxxxxxxxxxxxxxx"]

            # Update to VpcOnly
            resp = sm.update_domain(
                DomainId=domain_id,
                AppNetworkAccessType="VpcOnly",
                DefaultUserSettings=default_user_settings
            )
            print("UpdateDomain initiated:", resp["DomainArn"])

            # Wait a bit and verify
            time.sleep(20)
            updated = sm.describe_domain(DomainId=domain_id)
            print("New AppNetworkAccessType:", updated.get("AppNetworkAccessType"))

        if __name__ == "__main__":
            set_domain_vpc_only(DOMAIN_ID)
        ```

        Running this script will remediate the misconfiguration by enforcing **VPC-only network access** on the specified SageMaker Domain.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
