diff --git a/moto/ec2/models/dhcp_options.py b/moto/ec2/models/dhcp_options.py
index 8f8e2ebe7..397407147 100644
--- a/moto/ec2/models/dhcp_options.py
+++ b/moto/ec2/models/dhcp_options.py
@@ -69,6 +69,11 @@ class DHCPOptionsSetBackend:
dhcp_options.vpc = vpc
vpc.dhcp_options = dhcp_options
+ def disassociate_dhcp_options(self, vpc: Any) -> None:
+ if vpc.dhcp_options:
+ vpc.dhcp_options.vpc = None
+ vpc.dhcp_options = None
+
def create_dhcp_options(
self,
domain_name_servers: Optional[List[str]] = None,
diff --git a/moto/ec2/responses/dhcp_options.py b/moto/ec2/responses/dhcp_options.py
index 6c3160004..153943eed 100644
--- a/moto/ec2/responses/dhcp_options.py
+++ b/moto/ec2/responses/dhcp_options.py
@@ -6,10 +6,13 @@ class DHCPOptions(EC2BaseResponse):
dhcp_opt_id = self._get_param("DhcpOptionsId")
vpc_id = self._get_param("VpcId")
- dhcp_opt = self.ec2_backend.describe_dhcp_options([dhcp_opt_id])[0]
vpc = self.ec2_backend.get_vpc(vpc_id)
- self.ec2_backend.associate_dhcp_options(dhcp_opt, vpc)
+ if dhcp_opt_id == "default":
+ self.ec2_backend.disassociate_dhcp_options(vpc)
+ else:
+ dhcp_opt = self.ec2_backend.describe_dhcp_options([dhcp_opt_id])[0]
+ self.ec2_backend.associate_dhcp_options(dhcp_opt, vpc)
template = self.response_template(ASSOCIATE_DHCP_OPTIONS_RESPONSE)
return template.render()
diff --git a/moto/ec2/responses/vpcs.py b/moto/ec2/responses/vpcs.py
index 2f0f2e91f..93a80f90c 100644
--- a/moto/ec2/responses/vpcs.py
+++ b/moto/ec2/responses/vpcs.py
@@ -374,7 +374,7 @@ CREATE_VPC_RESPONSE = """
{% endfor %}
{% endif %}
- {% if vpc.dhcp_options %}{{ vpc.dhcp_options.id }}{% else %}dopt-1a2b3c4d2{% endif %}
+ {% if vpc.dhcp_options %}{{ vpc.dhcp_options.id }}{% else %}default{% endif %}
{{ vpc.instance_tenancy }}
{{ vpc.owner_id }}
@@ -475,7 +475,7 @@ DESCRIBE_VPCS_RESPONSE = """
{% endfor %}
{% endif %}
- {% if vpc.dhcp_options %}{{ vpc.dhcp_options.id }}{% else %}dopt-7a8b9c2d{% endif %}
+ {% if vpc.dhcp_options %}{{ vpc.dhcp_options.id }}{% else %}default{% endif %}
{{ vpc.instance_tenancy }}
{{ vpc.is_default }}
{{ vpc.owner_id }}
diff --git a/tests/test_ec2/test_dhcp_options.py b/tests/test_ec2/test_dhcp_options.py
index d63a48838..7910c0c81 100644
--- a/tests/test_ec2/test_dhcp_options.py
+++ b/tests/test_ec2/test_dhcp_options.py
@@ -66,6 +66,34 @@ def test_dhcp_options_associate_invalid_vpc_id():
assert ex.value.response["Error"]["Code"] == "InvalidVpcID.NotFound"
+@mock_ec2
+def test_dhcp_options_disassociation():
+ """Ensure that VPCs can be set to the 'default' DHCP options set for disassociation."""
+ ec2 = boto3.resource("ec2", region_name="us-west-1")
+ client = boto3.client("ec2", region_name="us-west-1")
+ dhcp_options = ec2.create_dhcp_options(
+ DhcpConfigurations=[
+ {"Key": "domain-name", "Values": [SAMPLE_DOMAIN_NAME]},
+ {"Key": "domain-name-servers", "Values": SAMPLE_NAME_SERVERS},
+ ]
+ )
+ vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
+
+ # Ensure newly created VPCs without any DHCP options can be disassociated
+ client.associate_dhcp_options(DhcpOptionsId="default", VpcId=vpc.id)
+ vpc.reload()
+ assert vpc.dhcp_options_id == "default"
+
+ client.associate_dhcp_options(DhcpOptionsId=dhcp_options.id, VpcId=vpc.id)
+ vpc.reload()
+ assert vpc.dhcp_options_id == dhcp_options.id
+
+ # Ensure VPCs with already associated DHCP options can be disassociated
+ client.associate_dhcp_options(DhcpOptionsId="default", VpcId=vpc.id)
+ vpc.reload()
+ assert vpc.dhcp_options_id == "default"
+
+
@mock_ec2
def test_dhcp_options_delete_with_vpc():
"""Test deletion of dhcp options with vpc"""