Repository: klothoplatform/klotho
Pull request #577 (2023-05-08 16:30:52)

Allow importing of external VPC and related resources
With config:
```toml
[imports]
'aws:vpc:gg_dev' = 'vpc-0123'
'aws:subnet_public:gg_dev:pub1' = 'subnet-01'
'aws:subnet_public:gg_dev:pub2' = 'subnet-02'
'aws:subnet_private:gg_dev:priv1' = 'subnet-03'
'aws:subnet_private:gg_dev:priv2' = 'subnet-04'
'aws:security_group:gg_dev:gg-dev' = 'sg-0123'
```
Fragments from index.ts:
```ts
const vpcGgDev = aws.ec2.Vpc.get("gg_dev", "vpc-0123")

const restApiGgDevRedisGw = new aws.apigateway.RestApi(`gg-dev-redis-gw`, {
        binaryMediaTypes: [`application/octet-stream`,`image/*`],
    });

const ggDevSubnetPrivatePriv2 = aws.ec2.Subnet.get("priv2", "subnet-04")

const ggDevSubnetPrivatePriv1 = aws.ec2.Subnet.get("priv1", "subnet-03")

// [...]

const eksClusterGgDevEksCluster = new aws.eks.Cluster(`gg-dev-eks-cluster`, {
        vpcConfig: {
            subnetIds: [ggDevSubnetPrivatePriv2,ggDevSubnetPrivatePriv1,ggDevSubnetPublicPub1,ggDevSubnetPublicPub2].map((subnet) => subnet.id),
            securityGroupIds: [ggDevSecurityGroupGgDev].map((sg) => sg.id),
        },
        roleArn: iamRoleGgDevEksClusterK8sAdmin.arn,
    });

// [...]

const eksNodeGroupEksClusterPrivateT3Medium = new aws.eks.NodeGroup(`eks-cluster_private_t3_medium`, {
        clusterName: eksClusterGgDevEksCluster.name,
        nodeRoleArn: iamRoleGgDevEksClusterPrivateT3Medium.arn,
        amiType: `AL2_x86_64`,
        subnetIds: [ggDevSubnetPrivatePriv2,ggDevSubnetPrivatePriv1].map((subnet) => subnet.id),
        scalingConfig: {
            desiredSize: 2,
            maxSize: 2,
            minSize: 1,
        },
        updateConfig: {
            maxUnavailable: 1,
        },
        diskSize: 20,
        instanceTypes: [`t3.medium`],
        labels: {"network_placement":`private`},
    });
```


### Standard checks

- **Unit tests**: Any special considerations?
- **Docs**: Do we need to update any docs, internal or public?
- **Backwards compatibility**: Will this break existing apps? If so, what would be the extra work required to keep them working?


gordon-klotho: Verified functionality with py-redis deploying twice, the second using the VPC, subnets, and security group from the first.

Patch:
diff --git a/go.mod b/go.mod
index dca7087d..6bff0fc0 100644
--- a/go.mod
+++ b/go.mod
@@ -17,12 +17,12 @@ require (
 	github.com/kopoli/go-terminal-size v0.0.0-20170219200355-5c97524c8b54
 	github.com/lithammer/dedent v1.1.0
 	github.com/pborman/ansi v1.0.0
-	github.com/pelletier/go-toml/v2 v2.0.6
+	github.com/pelletier/go-toml/v2 v2.0.8-0.20230509155657-d34104d49374
 	github.com/pkg/errors v0.9.1
 	github.com/schollz/progressbar/v3 v3.13.0
 	github.com/smacker/go-tree-sitter v0.0.0-20220209044044-0d3022e933c3
 	github.com/spf13/cobra v1.6.1
-	github.com/stretchr/testify v1.8.1
+	github.com/stretchr/testify v1.8.2
 	github.com/vmware-labs/yaml-jsonpath v0.3.2
 	go.uber.org/atomic v1.9.0
 	go.uber.org/zap v1.19.1
diff --git a/go.sum b/go.sum
index a3235bc0..da7582a5 100644
--- a/go.sum
+++ b/go.sum
@@ -579,8 +579,8 @@ github.com/pborman/ansi v1.0.0 h1:OqjHMhvlSuCCV5JT07yqPuJPQzQl+WXsiZ14gZsqOrQ=
 github.com/pborman/ansi v1.0.0/go.mod h1:SgWzwMAx1X/Ez7i90VqF8LRiQtx52pWDiQP+x3iGnzw=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
-github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
+github.com/pelletier/go-toml/v2 v2.0.8-0.20230509155657-d34104d49374 h1:rqI9z03O3kEI/JgQKbPmCwgXTYJlP65woSpIrxvIzWo=
+github.com/pelletier/go-toml/v2 v2.0.8-0.20230509155657-d34104d49374/go.mod h1:Rx8EVrBQLLFtSg5qlhPUUFBYSYM6/AxUviY6pVtCfE8=
 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
@@ -704,8 +704,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
diff --git a/pkg/cli/plugins.go b/pkg/cli/plugins.go
index 778bc55a..8d4895d0 100644
--- a/pkg/cli/plugins.go
+++ b/pkg/cli/plugins.go
@@ -19,6 +19,7 @@ import (
 	pyRuntimes "github.com/klothoplatform/klotho/pkg/lang/python/runtimes"
 	"github.com/klothoplatform/klotho/pkg/multierr"
 	"github.com/klothoplatform/klotho/pkg/provider"
+	"github.com/klothoplatform/klotho/pkg/provider/imports"
 	"github.com/klothoplatform/klotho/pkg/provider/providers"
 	staticunit "github.com/klothoplatform/klotho/pkg/static_unit"
 	"github.com/klothoplatform/klotho/pkg/visualizer"
@@ -116,12 +117,13 @@ func (b *PluginSetBuilder) setupProvider() (err error) {
 	if b.provider != nil {
 		return nil
 	}
+	b.Provider = append(b.Provider, kubernetes.Kubernetes{Config: b.Cfg})
 
 	b.provider, err = providers.GetProvider(b.Cfg)
 	if err == nil {
 		b.Provider = append(b.Provider, b.provider)
 	}
-	b.Provider = append([]compiler.ProviderPlugin{kubernetes.Kubernetes{Config: b.Cfg}}, b.Provider...)
+	b.Provider = append(b.Provider, imports.Plugin{Config: b.Cfg})
 	return
 }
 
diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go
index 2ab58ae7..38f2b861 100644
--- a/pkg/compiler/compiler.go
+++ b/pkg/compiler/compiler.go
@@ -2,17 +2,14 @@ package compiler
 
 import (
 	"bytes"
-	"encoding/json"
 	"fmt"
 
 	"github.com/klothoplatform/klotho/pkg/annotation"
 	"github.com/klothoplatform/klotho/pkg/config"
 	"github.com/klothoplatform/klotho/pkg/core"
 	"github.com/klothoplatform/klotho/pkg/validation"
-	"github.com/pelletier/go-toml/v2"
 	"github.com/pkg/errors"
 	"go.uber.org/zap"
-	"gopkg.in/yaml.v2"
 )
 
 type (
@@ -118,23 +115,7 @@ func (c *Compiler) Compile() error {
 func (c *Compiler) createConfigOutputFile() error {
 	c.Document.Configuration.UpdateForResources(c.Document.Constructs.ListConstructs())
 	buf := new(bytes.Buffer)
-	var err error
-	switch c.Document.Configuration.Format {
-	case "toml":
-		enc := toml.NewEncoder(buf)
-		enc.SetArraysMultiline(true)
-		enc.SetIndentTables(true)
-		err = enc.Encode(c.Document.Configuration)
-
-	case "json":
-		err = json.NewEncoder(buf).Encode(c.Document.Configuration)
-
-	case "yaml":
-		err = yaml.NewEncoder(buf).Encode(c.Document.Configuration)
-
-	default:
-		err = errors.Errorf("unsupported config format: %s", c.Document.Configuration.Format)
-	}
+	err := c.Document.Configuration.WriteTo(buf)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 44676307..5d8fb031 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -2,6 +2,7 @@ package config
 
 import (
 	"encoding/json"
+	"io"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -25,18 +26,19 @@ type (
 		Path   string `json:"path" yaml:"path" toml:"path"`
 		OutDir string `json:"out_dir" yaml:"out_dir" toml:"out_dir"`
 
-		Defaults            Defaults                  `json:"defaults" yaml:"defaults" toml:"defaults"`
-		ExecutionUnits      map[string]*ExecutionUnit `json:"execution_units,omitempty" yaml:"execution_units,omitempty" toml:"execution_units,omitempty"`
-		StaticUnit          map[string]*StaticUnit    `json:"static_unit,omitempty" yaml:"static_unit,omitempty" toml:"static_unit,omitempty"`
-		Exposed             map[string]*Expose        `json:"exposed,omitempty" yaml:"exposed,omitempty" toml:"exposed,omitempty"`
-		PersistKv           map[string]*Persist       `json:"persist_kv,omitempty" yaml:"persist_kv,omitempty" toml:"persist_kv,omitempty"`
-		PersistOrm          map[string]*Persist       `json:"persist_orm,omitempty" yaml:"persist_orm,omitempty" toml:"persist_orm,omitempty"`
-		PersistFs           map[string]*Persist       `json:"persist_fs,omitempty" yaml:"persist_fs,omitempty" toml:"persist_fs,omitempty"`
-		PersistSecrets      map[string]*Persist       `json:"persist_secrets,omitempty" yaml:"persist_secrets,omitempty" toml:"persist_secrets,omitempty"`
-		PersistRedisNode    map[string]*Persist       `json:"persist_redis_node,omitempty" yaml:"persist_redis_node,omitempty" toml:"persist_redis_node,omitempty"`
-		PersistRedisCluster map[string]*Persist       `json:"persist_redis_cluster,omitempty" yaml:"persist_redis_cluster,omitempty" toml:"persist_redis_cluster,omitempty"`
-		Config              map[string]*Config        `json:"config,omitempty" yaml:"config,omitempty" toml:"config,omitempty"`
-		Links               []CloudResourceLink       `json:"links,omitempty" yaml:"links,omitempty" toml:"links,omitempty"`
+		Defaults            Defaults                   `json:"defaults" yaml:"defaults" toml:"defaults"`
+		ExecutionUnits      map[string]*ExecutionUnit  `json:"execution_units,omitempty" yaml:"execution_units,omitempty" toml:"execution_units,omitempty"`
+		StaticUnit          map[string]*StaticUnit     `json:"static_unit,omitempty" yaml:"static_unit,omitempty" toml:"static_unit,omitempty"`
+		Exposed             map[string]*Expose         `json:"exposed,omitempty" yaml:"exposed,omitempty" toml:"exposed,omitempty"`
+		PersistKv           map[string]*Persist        `json:"persist_kv,omitempty" yaml:"persist_kv,omitempty" toml:"persist_kv,omitempty"`
+		PersistOrm          map[string]*Persist        `json:"persist_orm,omitempty" yaml:"persist_orm,omitempty" toml:"persist_orm,omitempty"`
+		PersistFs           map[string]*Persist        `json:"persist_fs,omitempty" yaml:"persist_fs,omitempty" toml:"persist_fs,omitempty"`
+		PersistSecrets      map[string]*Persist        `json:"persist_secrets,omitempty" yaml:"persist_secrets,omitempty" toml:"persist_secrets,omitempty"`
+		PersistRedisNode    map[string]*Persist        `json:"persist_redis_node,omitempty" yaml:"persist_redis_node,omitempty" toml:"persist_redis_node,omitempty"`
+		PersistRedisCluster map[string]*Persist        `json:"persist_redis_cluster,omitempty" yaml:"persist_redis_cluster,omitempty" toml:"persist_redis_cluster,omitempty"`
+		Config              map[string]*Config         `json:"config,omitempty" yaml:"config,omitempty" toml:"config,omitempty"`
+		Links               []CloudResourceLink        `json:"links,omitempty" yaml:"links,omitempty" toml:"links,omitempty"`
+		Imports             map[core.ResourceId]string `json:"imports,omitempty" yaml:"imports,omitempty" toml:"imports,omitempty"`
 	}
 
 	CloudResourceLink struct {
@@ -115,20 +117,45 @@ func ReadConfig(fpath string) (Application, error) {
 	}
 	defer f.Close() // nolint:errcheck
 
+	return ReadConfigReader(fpath, f)
+}
+
+func ReadConfigReader(fpath string, reader io.Reader) (Application, error) {
+	var appCfg Application
+
 	switch filepath.Ext(fpath) {
 	case ".json":
-		err = json.NewDecoder(f).Decode(&appCfg)
+		err := json.NewDecoder(reader).Decode(&appCfg)
 		appCfg.Format = "json"
+		return appCfg, err
 
 	case ".yaml", ".yml":
-		err = yaml.NewDecoder(f).Decode(&appCfg)
+		err := yaml.NewDecoder(reader).Decode(&appCfg)
 		appCfg.Format = "yaml"
+		return appCfg, err
 
 	case ".toml":
-		err = toml.NewDecoder(f).Decode(&appCfg)
+		err := toml.NewDecoder(reader).Decode(&appCfg)
 		appCfg.Format = "toml"
+		return appCfg, err
 	}
-	return appCfg, err
+
+	return appCfg, nil
+}
+
+func (a *Application) WriteTo(writer io.Writer) error {
+	switch a.Format {
+	case "json":
+		return json.NewEncoder(writer).Encode(a)
+
+	case "yaml":
+		return yaml.NewEncoder(writer).Encode(a)
+
+	case "toml":
+		return toml.NewEncoder(writer).Encode(a)
+	}
+
+	return nil
 }
 
 func (a *Application) AddLinks(links []core.CloudResourceLink) {
diff --git a/pkg/core/resources.go b/pkg/core/resources.go
index 40c91db4..514f2334 100644
--- a/pkg/core/resources.go
+++ b/pkg/core/resources.go
@@ -1,7 +1,10 @@
 package core
 
 import (
+	"strings"
+
 	"github.com/klothoplatform/klotho/pkg/graph"
+	"github.com/pkg/errors"
 )
 
 type (
@@ -24,7 +27,11 @@ type (
 	ResourceId struct {
 		Provider string
 		Type     string
-		Name     string
+		// Namespace is optional and is used to disambiguate resources that might have
+		// the same name. It can also be used to associate an imported resource with
+		// a specific namespace such as a subnet to a VPC.
+		Namespace string
+		Name      string
 	}
 
 	// CloudResourceLink describes what Resources are necessary to ensure that a dependency between two Constructs are satisfied at an infrastructure level
@@ -56,8 +63,47 @@ type (
 
 const (
 	ALL_RESOURCES_IAC_VALUE = "*"
+
+	// InternalProvider is used for resources that don't directly correspond to a deployed resource,
+	// but are used to convey data or metadata about resources that should be respected during IaC rendering.
+	// A notable usage is for imported resources.
+	//? Do we want to revisit how to accomplish this? It was originally implemented to avoid duplicated
+	// fields or methods across various resources.
+	InternalProvider = "internal"
 )
 
 func (id ResourceId) String() string {
-	return id.Provider + ":" + id.Type + ":" + id.Name
+	s := id.Provider + ":" + id.Type
+	if id.Namespace != "" {
+		s += ":" + id.Namespace
+	}
+	return s + ":" + id.Name
+}
+
+func (id ResourceId) MarshalText() ([]byte, error) {
+	return []byte(id.String()), nil
+}
+
+func (id *ResourceId) UnmarshalText(data []byte) error {
+	parts := strings.Split(string(data), ":")
+	if len(parts) < 3 || len(parts) > 4 {
+		return errors.Errorf("invalid number of parts (%d) in resource id '%s'", len(parts), string(data))
+	}
+	id.Provider = parts[0]
+	id.Type = parts[1]
+	if len(parts) == 4 {
+		id.Namespace = parts[2]
+		id.Name = parts[3]
+	} else {
+		id.Name = parts[2]
+	}
+	return nil
+}
+
+func (id ResourceId) MarshalTOML() ([]byte, error) {
+	return id.MarshalText()
+}
+
+func (id *ResourceId) UnmarshalTOML(data []byte) error {
+	return id.UnmarshalText(data)
 }
diff --git a/pkg/infra/iac2/resources.go b/pkg/infra/iac2/resources.go
index 470af56d..75cb4b4b 100644
--- a/pkg/infra/iac2/resources.go
+++ b/pkg/infra/iac2/resources.go
@@ -27,7 +27,7 @@ type (
 		FromPort        int
 		ToPort          int
 		Protocol        string
-		CidrBlocks      []string
+		CidrBlocks      []core.IaCValue
 		SecurityGroupId core.IaCValue
 		Type            string
 	}
diff --git a/pkg/infra/iac2/templates/security_group_rule/factory.ts b/pkg/infra/iac2/templates/security_group_rule/factory.ts
index c772a3ef..c33e0f9a 100644
--- a/pkg/infra/iac2/templates/security_group_rule/factory.ts
+++ b/pkg/infra/iac2/templates/security_group_rule/factory.ts
@@ -7,7 +7,7 @@ interface Args {
     FromPort: number
     ToPort: number
     Protocol: string
-    CidrBlocks: string[]
+    CidrBlocks: pulumi.Input<string | undefined>[]
     SecurityGroupId: pulumi.Input<string>
     Type: string
 }
@@ -16,7 +16,12 @@ function create(args: Args): aws.ec2.SecurityGroupRule {
     return new aws.ec2.SecurityGroupRule(args.Name, {
         description: args.Description,
         type: args.Type,
-        cidrBlocks: args.CidrBlocks,
+        cidrBlocks: pulumi
+            .all(args.CidrBlocks)
+            .apply(
+                (cidrBlocks) =>
+                    cidrBlocks.filter((cidrBlock) => cidrBlock !== undefined) as string[]
+            ),
         fromPort: args.FromPort,
         protocol: args.Protocol,
         toPort: args.ToPort,
diff --git a/pkg/infra/iac2/templates_compiler.go b/pkg/infra/iac2/templates_compiler.go
index 88e859ed..2f1ffeb7 100644
--- a/pkg/infra/iac2/templates_compiler.go
+++ b/pkg/infra/iac2/templates_compiler.go
@@ -5,7 +5,6 @@ import (
 	"embed"
 	"encoding/json"
 	"fmt"
-	"github.com/klothoplatform/klotho/pkg/provider/aws"
 	"io"
 	"io/fs"
 	"path"
@@ -14,6 +13,9 @@ import (
 	"strings"
 	"text/template"
 
+	"github.com/klothoplatform/klotho/pkg/provider/aws"
+	"github.com/klothoplatform/klotho/pkg/provider/imports"
+
 	"github.com/klothoplatform/klotho/pkg/core"
 	"github.com/klothoplatform/klotho/pkg/infra/kubernetes"
 	"github.com/klothoplatform/klotho/pkg/lang/javascript"
@@ -112,6 +114,10 @@ func (tc TemplatesCompiler) RenderBody(out io.Writer) error {
 		switch resource.(type) {
 		case *resources.AccountId, *resources.Region:
 			continue // skip resources that we know are rendered outside of the body
+		case *imports.Imported:
+			// Imported resources are handled by the rendering of their base resource
+			//? Should this ignore all .Provider == "internal" instead?
+			continue
 		}
 		err := tc.renderResource(out, resource)
 		errs.Append(err)
@@ -121,7 +127,6 @@ func (tc TemplatesCompiler) RenderBody(out io.Writer) error {
 				return err
 			}
 		}
-
 	}
 	return errs.ErrOrNil()
 }
@@ -131,6 +136,10 @@ func (tc TemplatesCompiler) RenderImports(out io.Writer) error {
 
 	allImports := make(map[string]struct{})
 	for _, res := range tc.resourceGraph.ListResources() {
+		switch res.(type) {
+		case *imports.Imported:
+			continue
+		}
 		tmpl, err := tc.getTemplate(res)
 		if err != nil {
 			errs.Append(err)
@@ -171,7 +180,9 @@ func (tc TemplatesCompiler) RenderPackageJSON() (*javascript.NodePackageJson, er
 			errs.Append(err)
 			continue
 		}
-		mainPJson.Merge(&pJson)
+		if pJson != nil {
+			mainPJson.Merge(pJson)
+		}
 	}
 	if err := errs.ErrOrNil(); err != nil {
 		return &mainPJson, err
@@ -209,6 +220,14 @@ func (tc TemplatesCompiler) renderResource(out io.Writer, resource core.Resource
 		return err
 	}
 
+	deps := tc.resourceGraph.GetDownstreamResources(resource)
+	for _, dep := range deps {
+		imp, ok := dep.(*imports.Imported)
+		if ok {
+			return tc.renderResourceImport(out, resource, imp, tmpl)
+		}
+	}
+
 	errs := multierr.Error{}
 
 	baseResourceVal := reflect.ValueOf(resource)
@@ -670,13 +689,18 @@ func (tc TemplatesCompiler) getVarNameByResourceId(id core.ResourceId) string {
 	if name, alreadyResolved := tc.resourceVarNamesById[id]; alreadyResolved {
 		return name
 	}
-	// Generate something like "lambdaFoo", where Lambda is the name of the struct and "foo" is the id
-	desiredName := lowercaseFirst(toUpperCamel(id.String()))
+	// Generate something like "lambdaFoo", where Lambda is the type of the resource and "foo" is the id
+	// Omit the provider for shorter, easier names. For the most part there will only be 1 per file.
+	desiredName := lowercaseFirst(toUpperCamel(fmt.Sprintf("%s:%s:%s", id.Namespace, id.Type, id.Name)))
 	resolvedName := desiredName
-	for i := 1; ; i++ {
+	for i := 0; ; i++ {
 		_, varNameTaken := tc.resourceVarNames[resolvedName]
 		if varNameTaken {
-			resolvedName = fmt.Sprintf("%s_%d", desiredName, i)
+			if i == 0 {
+				resolvedName = lowercaseFirst(toUpperCamel(id.String()))
+			} else {
+				resolvedName = fmt.Sprintf("%s_%d", desiredName, i)
+			}
 		} else {
 			break
 		}
@@ -703,7 +727,7 @@ func (tp templatesProvider) getTemplateForType(typeName string) (ResourceCreatio
 	templateName := camelToSnake(typeName)
 	contents, err := fs.ReadFile(tp.templates, templateName+`/factory.ts`)
 	if err != nil {
-		return ResourceCreationTemplate{}, err
+		return ResourceCreationTemplate{}, errors.Wrapf(err, "could not find template for %s", typeName)
 	}
 	template := ParseResourceCreationTemplate(typeName, contents)
 	tp.resourceTemplatesByStructName[typeName] = template
@@ -747,19 +771,23 @@ func (tp templatesProvider) getNestedTemplate(templatePath string, tc TemplatesC
 	return tmpl, nil
 }
 
-func (tc TemplatesCompiler) GetPackageJSON(v core.Resource) (javascript.NodePackageJson, error) {
-	packageContent := javascript.NodePackageJson{}
+func (tc TemplatesCompiler) GetPackageJSON(v core.Resource) (*javascript.NodePackageJson, error) {
 	typeName := structName(v)
 	templateName := camelToSnake(typeName)
-	contents, err := fs.ReadFile(tc.templates, templateName+`/package.json`)
+	templateFilePath := templateName + `/package.json`
+	contents, err := fs.ReadFile(tc.templates, templateFilePath)
 	if err != nil {
-		return *packageContent.Clone(), err
+		if errors.Is(err, fs.ErrNotExist) {
+			return nil, nil
+		}
+		return nil, err
 	}
+	var packageContent *javascript.NodePackageJson
 	err = json.NewDecoder(bytes.NewReader(contents)).Decode(&packageContent)
 	if err != nil {
-		return *packageContent.Clone(), err
+		return packageContent, err
 	}
-	return *packageContent.Clone(), nil
+	return packageContent, nil
 }
 
 // renderGlueVars renders additional variables associated with a given resource that do not represent specific cloud resources
@@ -795,9 +823,12 @@ func (tc TemplatesCompiler) addIngressRuleToCluster(out io.Writer, cluster *reso
 	_, err := out.Write([]byte("\n\n"))
 	errs.Append(err)
 
-	cidrBlocks := []string{}
-	for _, subnet := range cluster.Subnets {
-		cidrBlocks = append(cidrBlocks, subnet.CidrBlock)
+	cidrBlocks := make([]core.IaCValue, len(cluster.Subnets))
+	for i, subnet := range cluster.Subnets {
+		cidrBlocks[i] = core.IaCValue{
+			Resource: subnet,
+			Property: resources.CIDR_BLOCK_IAC_VALUE,
+		}
 	}
 
 	sgRule := &SecurityGroupRule{
@@ -859,3 +890,10 @@ func (tc TemplatesCompiler) associateRouteTable(out io.Writer, rt *resources.Rou
 
 	return errs.ErrOrNil()
 }
+
+func (tc TemplatesCompiler) renderResourceImport(out io.Writer, source core.Resource, imp *imports.Imported, tmpl ResourceCreationTemplate) error {
+	// TODO delegate to a factory 'import' function on the template or something to allow for customisation
+	varName := tc.getVarName(source)
+	_, err := fmt.Fprintf(out, `const %s = %s.get("%s", "%s")`, varName, tmpl.OutputType, source.Id().Name, imp.ID)
+	return err
+}
diff --git a/pkg/provider/aws/plugin.go b/pkg/provider/aws/plugin.go
index fe86f032..9d3b1cab 100644
--- a/pkg/provider/aws/plugin.go
+++ b/pkg/provider/aws/plugin.go
@@ -157,11 +157,10 @@ func (a *AWS) createEksClusters(result *core.ConstructGraph, dag *core.ResourceG
 			{Property: "0.0.0.0/0"},
 		},
 	})
-	subnets := vpc.GetVpcSubnets(dag)
 
 	var merr multierr.Error
 	for clusterId, units := range clusterIdToUnit {
-		merr.Append(resources.CreateEksCluster(a.Config, clusterId, subnets, vpc.GetSecurityGroups(dag), units, dag))
+		merr.Append(resources.CreateEksCluster(a.Config, clusterId, vpc, vpc.GetSecurityGroups(dag), units, dag))
 	}
 	return merr.ErrOrNil()
 }
diff --git a/pkg/provider/aws/resources/eks.go b/pkg/provider/aws/resources/eks.go
index bc6ca500..3f5f58de 100644
--- a/pkg/provider/aws/resources/eks.go
+++ b/pkg/provider/aws/resources/eks.go
@@ -99,6 +99,7 @@ type (
 		Name           string
 		ConstructsRef  []core.AnnotationKey
 		ClusterRole    *IamRole
+		Vpc            *Vpc
 		Subnets        []*Subnet
 		SecurityGroups []*SecurityGroup
 		Manifests      []core.File
@@ -147,24 +148,19 @@ type (
 //
 // The method will also create a fargate profile in the default namespace and a single NodeGroup.
 // The method will create all the corresponding IAM Roles necessary and attach all the execution units references to the following objects
-func CreateEksCluster(cfg *config.Application, clusterName string, subnets []*Subnet, securityGroups []*SecurityGroup, units []*core.ExecutionUnit, dag *core.ResourceGraph) error {
+func CreateEksCluster(cfg *config.Application, clusterName string, vpc *Vpc, securityGroups []*SecurityGroup, units []*core.ExecutionUnit, dag *core.ResourceGraph) error {
 	references := []core.AnnotationKey{}
 	for _, u := range units {
 		references = append(references, u.Provenance())
 	}
-	privateSubnets := []*Subnet{}
-	for _, sub := range subnets {
-		if sub.Type == PrivateSubnet {
-			privateSubnets = append(privateSubnets, sub)
-		}
-	}
 
 	appName := cfg.AppName
+	subnets := vpc.GetVpcSubnets(dag)
 
 	clusterRole := createClusterAdminRole(appName, clusterName+"-k8sAdmin", references)
 	dag.AddResource(clusterRole)
 
-	cluster := NewEksCluster(appName, clusterName, subnets, securityGroups, clusterRole)
+	cluster := NewEksCluster(appName, clusterName, vpc, subnets, securityGroups, clusterRole)
 	cluster.ConstructsRef = references
 	dag.AddDependenciesReflect(cluster)
 
@@ -200,6 +196,12 @@ func CreateEksCluster(cfg *config.Application, clusterName string, subnets []*Su
 	fargateRole := createPodExecutionRole(appName, clusterName+"-FargateExecutionRole", references)
 	dag.AddDependenciesReflect(fargateRole)
 
+	privateSubnets := make([]*Subnet, 0, len(subnets))
+	for _, sub := range subnets {
+		if sub.Type == PrivateSubnet {
+			privateSubnets = append(privateSubnets, sub)
+		}
+	}
 	profile := NewEksFargateProfile(cluster, privateSubnets, fargateRole, references)
 	profile.Selectors = append(profile.Selectors, &FargateProfileSelector{Namespace: "default", Labels: map[string]string{"klotho-fargate-enabled": "true"}})
 	dag.AddDependenciesReflect(profile)
@@ -580,7 +582,7 @@ func (cluster *EksCluster) InstallAlbController(references []core.AnnotationKey,
 				"name":   saName,
 			},
 			"region": core.IaCValue{Resource: NewRegion(), Property: NAME_IAC_VALUE},
-			"vpcId":  core.IaCValue{Resource: cluster.Subnets[0].Vpc, Property: ID_IAC_VALUE},
+			"vpcId":  core.IaCValue{Resource: cluster.Vpc, Property: ID_IAC_VALUE},
 			"podLabels": map[string]string{
 				"app": "aws-lb-controller",
 			},
@@ -729,7 +731,7 @@ func GetEksCluster(appName string, clusterId string, dag *core.ResourceGraph) *E
 	if clusterId == "" {
 		clusterId = DEFAULT_CLUSTER_NAME
 	}
-	cluster := NewEksCluster(appName, clusterId, nil, nil, nil)
+	cluster := NewEksCluster(appName, clusterId, nil, nil, nil, nil)
 	resource := dag.GetResource(cluster.Id())
 	if existingCluster, ok := resource.(*EksCluster); ok {
 		return existingCluster
@@ -779,9 +781,10 @@ func createNodeRole(appName string, roleName string, refs []core.AnnotationKey)
 	return nodeRole
 }
 
-func NewEksCluster(appName string, clusterName string, subnets []*Subnet, securityGroups []*SecurityGroup, role *IamRole) *EksCluster {
+func NewEksCluster(appName string, clusterName string, vpc *Vpc, subnets []*Subnet, securityGroups []*SecurityGroup, role *IamRole) *EksCluster {
 	return &EksCluster{
 		Name:           clusterSanitizer.Apply(fmt.Sprintf("%s-%s", appName, clusterName)),
+		Vpc:            vpc,
 		Subnets:        subnets,
 		SecurityGroups: securityGroups,
 		ClusterRole:    role,
diff --git a/pkg/provider/aws/resources/securitygroup.go b/pkg/provider/aws/resources/securitygroup.go
index fed79fbd..3a6a122a 100644
--- a/pkg/provider/aws/resources/securitygroup.go
+++ b/pkg/provider/aws/resources/securitygroup.go
@@ -32,41 +32,45 @@ func GetSecurityGroup(cfg *config.Application, dag *core.ResourceGraph) *Securit
 			return sg
 		}
 	}
+
 	vpc := GetVpc(cfg, dag)
-	vpcIngressRule := SecurityGroupRule{
-		Description: "Allow ingress traffic from ip addresses within the vpc",
-		CidrBlocks: []core.IaCValue{
-			{Resource: vpc, Property: CIDR_BLOCK_IAC_VALUE},
-		},
-		FromPort: 0,
-		Protocol: "-1",
-		ToPort:   0,
-	}
-	selfIngressRule := SecurityGroupRule{
-		Description: "Allow ingress traffic from within the same security group",
-		FromPort:    0,
-		Protocol:    "-1",
-		ToPort:      0,
-		Self:        true,
-	}
-	AllOutboundRule := SecurityGroupRule{
-		Description: "Allows all outbound IPv4 traffic.",
-		FromPort:    0,
-		Protocol:    "-1",
-		ToPort:      0,
-		CidrBlocks: []core.IaCValue{
-			{Property: "0.0.0.0/0"},
-		},
-	}
 
 	sg := &SecurityGroup{
-		Name:         cfg.AppName,
-		Vpc:          vpc,
-		IngressRules: []SecurityGroupRule{vpcIngressRule, selfIngressRule},
-		EgressRules:  []SecurityGroupRule{AllOutboundRule},
+		Name: cfg.AppName,
+		Vpc:  vpc,
 	}
-	dag.AddResource(sg)
-	dag.AddDependency(sg, sg.Vpc)
+	if _, ok := cfg.Imports[sg.Id()]; !ok {
+		vpcIngressRule := SecurityGroupRule{
+			Description: "Allow ingress traffic from ip addresses within the vpc",
+			CidrBlocks: []core.IaCValue{
+				{Resource: vpc, Property: CIDR_BLOCK_IAC_VALUE},
+			},
+			FromPort: 0,
+			Protocol: "-1",
+			ToPort:   0,
+		}
+		selfIngressRule := SecurityGroupRule{
+			Description: "Allow ingress traffic from within the same security group",
+			FromPort:    0,
+			Protocol:    "-1",
+			ToPort:      0,
+			Self:        true,
+		}
+		sg.IngressRules = append(sg.IngressRules, vpcIngressRule, selfIngressRule)
+
+		allOutboundRule := SecurityGroupRule{
+			Description: "Allows all outbound IPv4 traffic.",
+			FromPort:    0,
+			Protocol:    "-1",
+			ToPort:      0,
+			CidrBlocks: []core.IaCValue{
+				{Property: "0.0.0.0/0"},
+			},
+		}
+		sg.EgressRules = append(sg.EgressRules, allOutboundRule)
+	}
+
+	dag.AddDependenciesReflect(sg)
 	return sg
 }
 
@@ -77,9 +81,14 @@ func (sg *SecurityGroup) KlothoConstructRef() []core.AnnotationKey {
 
 // Id returns the id of the cloud resource
 func (sg *SecurityGroup) Id() core.ResourceId {
-	return core.ResourceId{
+	id := core.ResourceId{
 		Provider: AWS_PROVIDER,
 		Type:     SG_TYPE,
 		Name:     sg.Name,
 	}
+	if sg.Vpc != nil {
+		// Realistically, this should only be the case for tests
+		id.Namespace = sg.Vpc.Name
+	}
+	return id
 }
diff --git a/pkg/provider/aws/resources/vpc.go b/pkg/provider/aws/resources/vpc.go
index 4ed49a1b..e894ca54 100644
--- a/pkg/provider/aws/resources/vpc.go
+++ b/pkg/provider/aws/resources/vpc.go
@@ -2,10 +2,12 @@ package resources
 
 import (
 	"fmt"
+	"strings"
 
 	"github.com/klothoplatform/klotho/pkg/config"
 	"github.com/klothoplatform/klotho/pkg/core"
 	"github.com/klothoplatform/klotho/pkg/sanitization/aws"
+	"go.uber.org/zap"
 )
 
 var elasticIpSanitizer = aws.SubnetSanitizer
@@ -19,13 +21,13 @@ const (
 	PublicSubnet   = "public"
 	IsolatedSubnet = "isolated"
 
-	ELASTIC_IP_TYPE       = "elastic_ip"
-	INTERNET_GATEWAY_TYPE = "internet_gateway"
-	NAT_GATEWAY_TYPE      = "nat_gateway"
-	VPC_SUBNET_TYPE       = "vpc_subnet"
-	VPC_ENDPOINT_TYPE     = "vpc_endpoint"
-	VPC_TYPE              = "vpc"
-	ROUTE_TABLE_TYPE      = "route_table"
+	ELASTIC_IP_TYPE        = "elastic_ip"
+	INTERNET_GATEWAY_TYPE  = "internet_gateway"
+	NAT_GATEWAY_TYPE       = "nat_gateway"
+	VPC_SUBNET_TYPE_PREFIX = "subnet_"
+	VPC_ENDPOINT_TYPE      = "vpc_endpoint"
+	VPC_TYPE               = "vpc"
+	ROUTE_TABLE_TYPE       = "route_table"
 
 	CIDR_BLOCK_IAC_VALUE = "cidr_block"
 )
@@ -103,84 +105,109 @@ func CreateNetwork(config *config.Application, dag *core.ResourceGraph) *Vpc {
 	if dag.GetResource(vpc.Id()) != nil {
 		return vpc
 	}
-
 	region := NewRegion()
-	azs := NewAvailabilityZones()
-	igw := NewInternetGateway(appName, "igw1", vpc)
+	dag.AddDependency(vpc, region)
+
 	publicRt := &RouteTable{
 		Name: fmt.Sprintf("%s-public", vpc.Name),
 		Vpc:  vpc,
-		Routes: []*RouteTableRoute{
-			{CidrBlock: "0.0.0.0/0", GatewayId: core.IaCValue{Resource: igw, Property: ID_IAC_VALUE}},
-		},
 	}
-	dag.AddDependenciesReflect(publicRt)
 
-	dag.AddResource(region)
-	dag.AddDependency(azs, region)
-	dag.AddResource(vpc)
-	dag.AddDependency(vpc, region)
-	dag.AddResource(igw)
-	dag.AddDependency(igw, vpc)
+	importId := config.Imports[vpc.Id()]
+	if importId == "" {
+		igw := NewInternetGateway(appName, "igw1", vpc)
+		dag.AddDependenciesReflect(igw)
 
-	az1 := core.IaCValue{
-		Resource: azs,
-		Property: "0",
+		publicRt.Routes = append(publicRt.Routes, &RouteTableRoute{CidrBlock: "0.0.0.0/0", GatewayId: core.IaCValue{Resource: igw, Property: ID_IAC_VALUE}})
 	}
-	az2 := core.IaCValue{
-		Resource: azs,
-		Property: "1",
+	dag.AddDependenciesReflect(publicRt)
+
+	var importSubnetIds []core.ResourceId
+	for id := range config.Imports {
+		if id.Provider == AWS_PROVIDER && strings.HasPrefix(id.Type, VPC_SUBNET_TYPE_PREFIX) {
+			importSubnetIds = append(importSubnetIds, id)
+		}
 	}
 
-	public1 := CreatePublicSubnet("public1", az1, vpc, "10.0.128.0/18", dag)
+	if len(importSubnetIds) > 0 {
+		for _, id := range importSubnetIds {
+			sn := &Subnet{
+				Name: id.Name,
+				Vpc:  vpc,
+			}
+			err := sn.SetTypeFromId(id)
+			if err != nil {
+				//? Should we return an error here instead of warning?
+				zap.S().Warnf("Failed to import subnet, ignoring: %v", err)
+			} else {
+				dag.AddDependenciesReflect(sn)
+			}
+		}
+		// TODO either add or check the auxillary resources such as
+		// gateways, route tables, etc.
+	} else {
+		azs := NewAvailabilityZones()
+		dag.AddDependency(azs, region)
+		az1 := core.IaCValue{
+			Resource: azs,
+			Property: "0",
+		}
+		az2 := core.IaCValue{
+			Resource: azs,
+			Property: "1",
+		}
 
-	ip1 := NewElasticIp(appName, "public1")
-	dag.AddDependenciesReflect(ip1)
-	natGateway1 := NewNatGateway(appName, "public1", public1, ip1)
-	dag.AddDependenciesReflect(natGateway1)
+		public1 := CreatePublicSubnet("public1", az1, vpc, "10.0.128.0/18", dag)
 
-	public2 := CreatePublicSubnet("public2", az2, vpc, "10.0.192.0/18", dag)
+		ip1 := NewElasticIp(appName, "public1")
+		dag.AddDependenciesReflect(ip1)
+		natGateway1 := NewNatGateway(appName, "public1", public1, ip1)
+		dag.AddDependenciesReflect(natGateway1)
 
-	ip2 := NewElasticIp(appName, "public2")
-	dag.AddDependenciesReflect(ip2)
-	natGateway2 := NewNatGateway(appName, "public2", public2, ip2)
-	dag.AddDependenciesReflect(natGateway2)
+		public2 := CreatePublicSubnet("public2", az2, vpc, "10.0.192.0/18", dag)
 
-	dag.AddDependency(publicRt, public1)
-	dag.AddDependency(publicRt, public2)
+		ip2 := NewElasticIp(appName, "public2")
+		dag.AddDependenciesReflect(ip2)
+		natGateway2 := NewNatGateway(appName, "public2", public2, ip2)
+		dag.AddDependenciesReflect(natGateway2)
 
-	private1 := CreatePrivateSubnet(appName, "private1", az1, vpc, "10.0.0.0/18", dag)
+		dag.AddDependency(publicRt, public1)
+		dag.AddDependency(publicRt, public2)
 
-	rt1 := &RouteTable{
-		Name: private1.Name,
-		Vpc:  vpc,
-		Routes: []*RouteTableRoute{
-			{CidrBlock: "0.0.0.0/0", NatGatewayId: core.IaCValue{Resource: natGateway1, Property: ID_IAC_VALUE}},
-		},
-	}
-	dag.AddDependenciesReflect(rt1)
-	dag.AddDependency(rt1, private1)
+		private1 := CreatePrivateSubnet(appName, "private1", az1, vpc, "10.0.0.0/18", dag)
 
-	private2 := CreatePrivateSubnet(appName, "private2", az2, vpc, "10.0.64.0/18", dag)
-	rt2 := &RouteTable{
-		Name: private2.Name,
-		Vpc:  vpc,
-		Routes: []*RouteTableRoute{
-			{CidrBlock: "0.0.0.0/0", NatGatewayId: core.IaCValue{Resource: natGateway2, Property: ID_IAC_VALUE}},
-		},
-	}
-	dag.AddDependenciesReflect(rt2)
-	dag.AddDependency(rt2, private2)
+		rt1 := &RouteTable{
+			Name: private1.Name,
+			Vpc:  vpc,
+			Routes: []*RouteTableRoute{
+				{CidrBlock: "0.0.0.0/0", NatGatewayId: core.IaCValue{Resource: natGateway1, Property: ID_IAC_VALUE}},
+			},
+		}
+		dag.AddDependenciesReflect(rt1)
+		dag.AddDependency(rt1, private1)
+
+		private2 := CreatePrivateSubnet(appName, "private2", az2, vpc, "10.0.64.0/18", dag)
+		rt2 := &RouteTable{
+			Name: private2.Name,
+			Vpc:  vpc,
+			Routes: []*RouteTableRoute{
+				{CidrBlock: "0.0.0.0/0", NatGatewayId: core.IaCValue{Resource: natGateway2, Property: ID_IAC_VALUE}},
+			},
+		}
+		dag.AddDependenciesReflect(rt2)
+		dag.AddDependency(rt2, private2)
 
-	routeTables := []*RouteTable{publicRt, rt1, rt2}
-	// VPC Endpoints are dependent upon the subnets so we need to ensure the subnets are created first
-	CreateGatewayVpcEndpoint("s3", vpc, region, routeTables, dag)
-	CreateGatewayVpcEndpoint("dynamodb", vpc, region, routeTables, dag)
+		routeTables := []*RouteTable{publicRt, rt1, rt2}
 
-	CreateInterfaceVpcEndpoint("lambda", vpc, region, dag, config)
-	CreateInterfaceVpcEndpoint("sqs", vpc, region, dag, config)
-	CreateInterfaceVpcEndpoint("sns", vpc, region, dag, config)
-	CreateInterfaceVpcEndpoint("secretsmanager", vpc, region, dag, config)
+		// VPC Endpoints are dependent upon the subnets so we need to ensure the subnets are created first
+		CreateGatewayVpcEndpoint("s3", vpc, region, routeTables, dag)
+		CreateGatewayVpcEndpoint("dynamodb", vpc, region, routeTables, dag)
+
+		CreateInterfaceVpcEndpoint("lambda", vpc, region, dag, config)
+		CreateInterfaceVpcEndpoint("sqs", vpc, region, dag, config)
+		CreateInterfaceVpcEndpoint("sns", vpc, region, dag, config)
+		CreateInterfaceVpcEndpoint("secretsmanager", vpc, region, dag, config)
+	}
 
 	return vpc
 }
@@ -363,23 +390,6 @@ func NewSubnet(subnetName string, vpc *Vpc, cidrBlock string, subnetType string,
 	}
 }
 
-// IsPublic returns whether this Subnet is public within the resource graph. A subnet is public iff its upstream
-// RouteTable has a downstream InternetGateway.
-func (subnet *Subnet) IsPublic(dag *core.ResourceGraph) bool {
-	for _, upstreamFromSubnet := range dag.GetUpstreamResources(subnet) {
-		routeTable, ok := upstreamFromSubnet.(*RouteTable)
-		if !ok {
-			continue
-		}
-		for _, downstreamFromRouteTable := range dag.GetAllDownstreamResources(routeTable) {
-			if _, isIGW := downstreamFromRouteTable.(*InternetGateway); isIGW {
-				return true
-			}
-		}
-	}
-	return false
-}
-
 // KlothoConstructRef returns AnnotationKey of the klotho resource the cloud resource is correlated to
 func (subnet *Subnet) KlothoConstructRef() []core.AnnotationKey {
 	return subnet.ConstructsRef
@@ -387,11 +397,27 @@ func (subnet *Subnet) KlothoConstructRef() []core.AnnotationKey {
 
 // Id returns the id of the cloud resource
 func (subnet *Subnet) Id() core.ResourceId {
-	return core.ResourceId{
+	id := core.ResourceId{
 		Provider: AWS_PROVIDER,
-		Type:     VPC_SUBNET_TYPE,
+		Type:     VPC_SUBNET_TYPE_PREFIX + subnet.Type,
 		Name:     subnet.Name,
 	}
+	if subnet.Vpc != nil {
+		// Realistically, this should only be the case for tests
+		id.Namespace = subnet.Vpc.Name
+	}
+	return id
+}
+
+func (subnet *Subnet) SetTypeFromId(id core.ResourceId) error {
+	if id.Provider != AWS_PROVIDER || !strings.HasPrefix(id.Type, VPC_SUBNET_TYPE_PREFIX) {
+		return fmt.Errorf("invalid id '%s' for partial subnet '%s'", id, subnet.Name)
+	}
+	if subnet.Vpc.Name != id.Namespace {
+		return fmt.Errorf("invalid id '%s' not matching subnet vpc: %s in partial subnet '%s'", id, subnet.Vpc.Name, subnet.Name)
+	}
+	subnet.Type = strings.TrimPrefix(id.Type, VPC_SUBNET_TYPE_PREFIX)
+	return nil
 }
 
 func NewVpcEndpoint(service string, vpc *Vpc, endpointType string, region *Region, subnets []*Subnet) *VpcEndpoint {
diff --git a/pkg/provider/imports/plugin.go b/pkg/provider/imports/plugin.go
new file mode 100644
index 00000000..a41f309f
--- /dev/null
+++ b/pkg/provider/imports/plugin.go
@@ -0,0 +1,32 @@
+package imports
+
+import (
+	"github.com/klothoplatform/klotho/pkg/config"
+	"github.com/klothoplatform/klotho/pkg/core"
+	"go.uber.org/zap"
+)
+
+// Plugin is responsible for adding the `Imported` resource to the graph, and adding a dependency from the resource
+// which is to be replaced with the import. This mechanism for importing will work for all providers, so it is accomplished
+// here in a generic plugin to prevent unnecessary reimplementation.
+// If any special coordinating logic is required for a specific provider or resource, that should be implemented in the provider plugin.
+type Plugin struct {
+	Config *config.Application
+}
+
+func (p Plugin) Name() string {
+	return "imports"
+}
+
+func (p Plugin) Translate(result *core.ConstructGraph, dag *core.ResourceGraph) (links []core.CloudResourceLink, err error) {
+	log := zap.S()
+	for resId, importId := range p.Config.Imports {
+		res := dag.GetResource(resId)
+		if res == nil {
+			log.Warnf("No resource found for import '%s'", resId)
+			continue
+		}
+		dag.AddDependency(res, &Imported{ID: importId})
+	}
+	return
+}
diff --git a/pkg/provider/imports/resource.go b/pkg/provider/imports/resource.go
new file mode 100644
index 00000000..4a773af7
--- /dev/null
+++ b/pkg/provider/imports/resource.go
@@ -0,0 +1,26 @@
+package imports
+
+import "github.com/klothoplatform/klotho/pkg/core"
+
+// Imported is an internal resource to signal that the resource that depends on this
+// should be imported from `ID`.
+//
+//	OriginalResource -> Imported
+//
+// Any IaC rendering should replace the resource with
+// this import and not render the original resource.
+type Imported struct {
+	ID string
+}
+
+func (imp Imported) KlothoConstructRef() []core.AnnotationKey {
+	return nil
+}
+
+func (imp Imported) Id() core.ResourceId {
+	return core.ResourceId{
+		Provider: core.InternalProvider,
+		Type:     "import",
+		Name:     imp.ID,
+	}
+}
diff --git a/pkg/visualizer/file.go b/pkg/visualizer/file.go
index ce7b8fc4..84fd1b04 100644
--- a/pkg/visualizer/file.go
+++ b/pkg/visualizer/file.go
@@ -74,6 +74,11 @@ func (f *File) WriteTo(w io.Writer) (n int64, err error) {
 	}
 	for _, resourceId := range resourceIds {
 		resource := f.DAG.GetResourceByVertexId(resourceId)
+		if resource.Id().Provider == core.InternalProvider {
+			// Don't show internal resources such as imported in the topology
+			// TODO maybe make some way of indicating imported resources in the visualizer
+			continue
+		}
 		key := f.KeyFor(resource)
 		if key == "" {
 			continue
diff --git a/pkg/visualizer/node_properties.go b/pkg/visualizer/node_properties.go
index 338a3b60..b6cc1048 100644
--- a/pkg/visualizer/node_properties.go
+++ b/pkg/visualizer/node_properties.go
@@ -8,6 +8,6 @@ import (
 func subnetProperties(res *resources.Subnet, dag *core.ResourceGraph) map[string]any {
 	return map[string]any{
 		"cidr_block": res.CidrBlock,
-		"public":     res.IsPublic(dag),
+		"public":     res.Type == resources.PublicSubnet,
 	}
 }


Test patch:
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index c7b3c22f..541c9b2c 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -1,6 +1,8 @@
 package config
 
 import (
+	"bytes"
+	"fmt"
 	"testing"
 
 	"github.com/klothoplatform/klotho/pkg/core"
@@ -260,3 +262,47 @@ func Test_MergeInfraParams(t *testing.T) {
 		})
 	}
 }
+
+func TestReadConfigReader(t *testing.T) {
+	tests := []struct {
+		name string
+		cfg  Application
+	}{
+		{
+			name: "empty config",
+			cfg:  Application{},
+		},
+		{
+			name: "config with imports",
+			cfg: Application{
+				Imports: map[core.ResourceId]string{
+					{Provider: "prov", Type: "type", Namespace: "ns", Name: "name"}: "1",
+					{Provider: "prov", Type: "type", Name: "name"}:                  "2",
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			for _, cfgFmt := range []string{"json", "yaml", "toml"} {
+				t.Run(cfgFmt, func(t *testing.T) {
+					assert := assert.New(t)
+					tt.cfg.Format = cfgFmt
+
+					buf := new(bytes.Buffer)
+					err := tt.cfg.WriteTo(buf)
+					if !assert.NoError(err) {
+						return
+					}
+					t.Logf("config:\n%s", buf.String())
+
+					cfg, err := ReadConfigReader(fmt.Sprintf("klotho.%s", cfgFmt), buf)
+					if !assert.NoError(err) {
+						return
+					}
+					assert.Equal(tt.cfg, cfg)
+				})
+			}
+		})
+	}
+}
diff --git a/pkg/infra/iac2/templates_compiler_test.go b/pkg/infra/iac2/templates_compiler_test.go
index 57ab06cc..75cd5b6e 100644
--- a/pkg/infra/iac2/templates_compiler_test.go
+++ b/pkg/infra/iac2/templates_compiler_test.go
@@ -14,6 +14,7 @@ import (
 	"github.com/klothoplatform/klotho/pkg/core"
 	"github.com/klothoplatform/klotho/pkg/graph"
 	"github.com/klothoplatform/klotho/pkg/provider/aws/resources"
+	"github.com/klothoplatform/klotho/pkg/provider/imports"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -31,6 +32,7 @@ func TestOutputBody(t *testing.T) {
 			Arr: []string{"val1", "val2"},
 		},
 	}
+	thingToImport := &DummyFizz{Value: "imported"}
 	graph := core.NewResourceGraph()
 	graph.AddResource(fizz)
 	graph.AddResource(buzz)
@@ -41,6 +43,7 @@ func TestOutputBody(t *testing.T) {
 	graph.AddDependency(parent, void)
 	graph.AddDependency(fizz, buzz)
 	graph.AddDependency(void, fizz)
+	graph.AddDependency(thingToImport, &imports.Imported{ID: "fizz-123"})
 
 	compiler := CreateTemplatesCompiler(graph)
 	compiler.templates = filesMapToFsMap(dummyTemplateFiles)
@@ -59,6 +62,8 @@ func TestOutputBody(t *testing.T) {
 			"",
 			"fs.ReadFile();",
 			"",
+			`const fizzImported = aws.fizz.DummyResource.get("fizz-imported", "fizz-123")`,
+			"",
 			"const bigMain = new DummyParent(",
 			"				fizzMyHello,",
 			"				{",
@@ -217,7 +222,7 @@ func Test_renderGlueVars(t *testing.T) {
 				{Provider: "aws", Type: "lambda_function", Name: "test_"}: "testFunction",
 				{Provider: "aws", Type: "iam_policy", Name: "test-t"}:     "testPolicy",
 			},
-			want: "\n\nconst awsRolePolicyAttachTestTTestT = new aws.iam.RolePolicyAttachment(`test-t-test-t`, {\n\t\t\t\t\t\tpolicyArn: testPolicy.arn,\n\t\t\t\t\t\trole: testRole\n\t\t\t\t\t});",
+			want: "\n\nconst rolePolicyAttachTestTTestT = new aws.iam.RolePolicyAttachment(`test-t-test-t`, {\n\t\t\t\t\t\tpolicyArn: testPolicy.arn,\n\t\t\t\t\t\trole: testRole\n\t\t\t\t\t});",
 		},
 		{
 			name:        "routeTableAssociation",
@@ -236,7 +241,7 @@ func Test_renderGlueVars(t *testing.T) {
 				{Provider: "aws", Type: "route_table", Name: "rt1"}: "testRouteTable",
 				{Provider: "aws", Type: "vpc_subnet", Name: "s1"}:   "subnet1",
 			},
-			want: "\n\nconst pulumiRouteTableAssociationS1 = new aws.ec2.RouteTableAssociation(`s1`, {\n\t\t\t\tsubnetId: subnet1.id,\n\t\t\trouteTableId: testRouteTable.id,\n\t\t\t});\n\n",
+			want: "\n\nconst routeTableAssociationS1 = new aws.ec2.RouteTableAssociation(`s1`, {\n\t\t\t\tsubnetId: subnetS1.id,\n\t\t\trouteTableId: testRouteTable.id,\n\t\t\t});\n\n",
 		},
 	}
 	for _, tt := range cases {
@@ -292,7 +297,7 @@ func Test_handleIaCValue(t *testing.T) {
 		{
 			name: "value with applied outputs, cluster oidc arn",
 			value: core.IaCValue{
-				Resource: resources.NewEksCluster("test-app", "cluster1", nil, nil, nil),
+				Resource: resources.NewEksCluster("test-app", "cluster1", nil, nil, nil, nil),
 				Property: resources.OIDC_SUB_IAC_VALUE,
 			},
 			resourceVarNamesById: map[core.ResourceId]string{
@@ -315,7 +320,7 @@ func Test_handleIaCValue(t *testing.T) {
 			resourceVarNamesById: map[core.ResourceId]string{
 				{Provider: "aws", Type: "availability_zones", Name: "AvailabilityZones"}: "azs",
 			},
-			want: "awsAvailabilityZones.names[2]",
+			want: "availabilityZones.names[2]",
 		},
 		{
 			name: "nlb uri",
diff --git a/pkg/provider/aws/execution_unit_test.go b/pkg/provider/aws/execution_unit_test.go
index 82fa3b6d..f43be46e 100644
--- a/pkg/provider/aws/execution_unit_test.go
+++ b/pkg/provider/aws/execution_unit_test.go
@@ -19,7 +19,7 @@ func Test_GenerateExecUnitResources(t *testing.T) {
 	bucket := resources.NewS3Bucket(fs, "test")
 	policy1 := &resources.IamPolicy{Name: "policy1"}
 	policy2 := &resources.IamPolicy{Name: "policy2"}
-	cluster := resources.NewEksCluster("test", resources.DEFAULT_CLUSTER_NAME, nil, nil, nil)
+	cluster := resources.NewEksCluster("test", resources.DEFAULT_CLUSTER_NAME, nil, nil, nil, nil)
 	oidc := &resources.OpenIdConnectProvider{Name: cluster.Name}
 	chart := &kubernetes.HelmChart{
 		Name:           "chart",
@@ -119,89 +119,89 @@ func Test_GenerateExecUnitResources(t *testing.T) {
 					"aws:route_table:test_private1",
 					"aws:route_table:test_private2",
 					"aws:s3_bucket:test-test",
+					"aws:security_group:test:test",
+					"aws:subnet_private:test:test_private1",
+					"aws:subnet_private:test:test_private2",
+					"aws:subnet_public:test:test_public1",
+					"aws:subnet_public:test:test_public2",
 					"aws:target_group:test-test",
 					"aws:vpc:test",
-					"aws:security_group:test",
 					"aws:vpc_endpoint:test_dynamodb",
 					"aws:vpc_endpoint:test_lambda",
 					"aws:vpc_endpoint:test_s3",
 					"aws:vpc_endpoint:test_secretsmanager",
 					"aws:vpc_endpoint:test_sns",
 					"aws:vpc_endpoint:test_sqs",
-					"aws:vpc_subnet:test_private1",
-					"aws:vpc_subnet:test_private2",
-					"aws:vpc_subnet:test_public1",
-					"aws:vpc_subnet:test_public2",
 					"kubernetes:helm_chart:chart",
 				},
 				Deps: []coretesting.StringDep{
 					{Source: "aws:availability_zones:AvailabilityZones", Destination: "aws:region:region"},
 					{Source: "aws:ecr_image:test-test", Destination: "aws:ecr_repo:test"},
 					{Source: "aws:iam_oidc_provider:test-eks-cluster", Destination: "aws:eks_cluster:test-eks-cluster"},
+					{Source: "aws:iam_role:test-test-ExecutionRole", Destination: "aws:iam_oidc_provider:test-eks-cluster"},
 					{Source: "aws:iam_role:test-test-ExecutionRole", Destination: "aws:iam_policy:policy1"},
 					{Source: "aws:iam_role:test-test-ExecutionRole", Destination: "aws:iam_policy:policy2"},
 					{Source: "aws:iam_role:test-test-ExecutionRole", Destination: "aws:s3_bucket:test-test"},
-					{Source: "aws:iam_role:test-test-ExecutionRole", Destination: "aws:iam_oidc_provider:test-eks-cluster"},
 					{Source: "aws:internet_gateway:test_igw1", Destination: "aws:vpc:test"},
-					{Source: "aws:load_balancer:test-test", Destination: "aws:vpc_subnet:test_private1"},
-					{Source: "aws:load_balancer:test-test", Destination: "aws:vpc_subnet:test_private2"},
+					{Source: "aws:load_balancer:test-test", Destination: "aws:subnet_private:test:test_private1"},
+					{Source: "aws:load_balancer:test-test", Destination: "aws:subnet_private:test:test_private2"},
 					{Source: "aws:load_balancer_listener:test-test-test", Destination: "aws:load_balancer:test-test"},
 					{Source: "aws:load_balancer_listener:test-test-test", Destination: "aws:target_group:test-test"},
 					{Source: "aws:nat_gateway:test_public1", Destination: "aws:elastic_ip:test_public1"},
-					{Source: "aws:nat_gateway:test_public1", Destination: "aws:vpc_subnet:test_public1"},
+					{Source: "aws:nat_gateway:test_public1", Destination: "aws:subnet_public:test:test_public1"},
 					{Source: "aws:nat_gateway:test_public2", Destination: "aws:elastic_ip:test_public2"},
-					{Source: "aws:nat_gateway:test_public2", Destination: "aws:vpc_subnet:test_public2"},
+					{Source: "aws:nat_gateway:test_public2", Destination: "aws:subnet_public:test:test_public2"},
 					{Source: "aws:route_table:test-public", Destination: "aws:internet_gateway:test_igw1"},
+					{Source: "aws:route_table:test-public", Destination: "aws:subnet_public:test:test_public1"},
+					{Source: "aws:route_table:test-public", Destination: "aws:subnet_public:test:test_public2"},
 					{Source: "aws:route_table:test-public", Destination: "aws:vpc:test"},
-					{Source: "aws:route_table:test-public", Destination: "aws:vpc_subnet:test_public1"},
-					{Source: "aws:route_table:test-public", Destination: "aws:vpc_subnet:test_public2"},
 					{Source: "aws:route_table:test_private1", Destination: "aws:nat_gateway:test_public1"},
+					{Source: "aws:route_table:test_private1", Destination: "aws:subnet_private:test:test_private1"},
 					{Source: "aws:route_table:test_private1", Destination: "aws:vpc:test"},
-					{Source: "aws:route_table:test_private1", Destination: "aws:vpc_subnet:test_private1"},
 					{Source: "aws:route_table:test_private2", Destination: "aws:nat_gateway:test_public2"},
+					{Source: "aws:route_table:test_private2", Destination: "aws:subnet_private:test:test_private2"},
 					{Source: "aws:route_table:test_private2", Destination: "aws:vpc:test"},
-					{Source: "aws:route_table:test_private2", Destination: "aws:vpc_subnet:test_private2"},
+					{Source: "aws:security_group:test:test", Destination: "aws:vpc:test"},
+					{Source: "aws:subnet_private:test:test_private1", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_private:test:test_private1", Destination: "aws:vpc:test"},
+					{Source: "aws:subnet_private:test:test_private2", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_private:test:test_private2", Destination: "aws:vpc:test"},
+					{Source: "aws:subnet_public:test:test_public1", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_public:test:test_public1", Destination: "aws:vpc:test"},
+					{Source: "aws:subnet_public:test:test_public2", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_public:test:test_public2", Destination: "aws:vpc:test"},
 					{Source: "aws:target_group:test-test", Destination: "aws:vpc:test"},
 					{Source: "aws:vpc:test", Destination: "aws:region:region"},
-					{Source: "aws:security_group:test", Destination: "aws:vpc:test"},
 					{Source: "aws:vpc_endpoint:test_dynamodb", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_dynamodb", Destination: "aws:route_table:test-public"},
 					{Source: "aws:vpc_endpoint:test_dynamodb", Destination: "aws:route_table:test_private1"},
 					{Source: "aws:vpc_endpoint:test_dynamodb", Destination: "aws:route_table:test_private2"},
 					{Source: "aws:vpc_endpoint:test_dynamodb", Destination: "aws:vpc:test"},
 					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:region:region"},
+					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:security_group:test:test"},
+					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:subnet_private:test:test_private1"},
+					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:subnet_private:test:test_private2"},
 					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:vpc_subnet:test_private1"},
-					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:vpc_subnet:test_private2"},
-					{Source: "aws:vpc_endpoint:test_lambda", Destination: "aws:security_group:test"},
 					{Source: "aws:vpc_endpoint:test_s3", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_s3", Destination: "aws:route_table:test-public"},
 					{Source: "aws:vpc_endpoint:test_s3", Destination: "aws:route_table:test_private1"},
 					{Source: "aws:vpc_endpoint:test_s3", Destination: "aws:route_table:test_private2"},
 					{Source: "aws:vpc_endpoint:test_s3", Destination: "aws:vpc:test"},
 					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:region:region"},
+					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:security_group:test:test"},
+					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:subnet_private:test:test_private1"},
+					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:subnet_private:test:test_private2"},
 					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:security_group:test"},
-					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:vpc_subnet:test_private1"},
-					{Source: "aws:vpc_endpoint:test_secretsmanager", Destination: "aws:vpc_subnet:test_private2"},
 					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:region:region"},
+					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:security_group:test:test"},
+					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:subnet_private:test:test_private1"},
+					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:subnet_private:test:test_private2"},
 					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:security_group:test"},
-					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:vpc_subnet:test_private1"},
-					{Source: "aws:vpc_endpoint:test_sns", Destination: "aws:vpc_subnet:test_private2"},
-					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:security_group:test"},
 					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:region:region"},
+					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:security_group:test:test"},
+					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:subnet_private:test:test_private1"},
+					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:subnet_private:test:test_private2"},
 					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:vpc_subnet:test_private1"},
-					{Source: "aws:vpc_endpoint:test_sqs", Destination: "aws:vpc_subnet:test_private2"},
-					{Source: "aws:vpc_subnet:test_private1", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_private1", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_subnet:test_private2", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_private2", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_subnet:test_public1", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_public1", Destination: "aws:vpc:test"},
-					{Source: "aws:vpc_subnet:test_public2", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_public2", Destination: "aws:vpc:test"},
 					{Source: "kubernetes:helm_chart:chart", Destination: "aws:ecr_image:test-test"},
 					{Source: "kubernetes:helm_chart:chart", Destination: "aws:eks_cluster:test-eks-cluster"},
 					{Source: "kubernetes:helm_chart:chart", Destination: "aws:iam_role:test-test-ExecutionRole"},
diff --git a/pkg/provider/aws/expose_test.go b/pkg/provider/aws/expose_test.go
index 5776b726..63c070bf 100644
--- a/pkg/provider/aws/expose_test.go
+++ b/pkg/provider/aws/expose_test.go
@@ -21,13 +21,33 @@ func Test_CreateRestApi(t *testing.T) {
 	unit2 := &core.ExecutionUnit{
 		AnnotationKey: core.AnnotationKey{ID: "test2", Capability: annotation.ExecutionUnitCapability},
 	}
+
+	makeCluster := func() []core.Resource {
+		vpc := &resources.Vpc{Name: "test"}
+		cluster := &resources.EksCluster{
+			Name:          "Cluster",
+			Vpc:           vpc,
+			ConstructsRef: []core.AnnotationKey{unit1.AnnotationKey, unit2.AnnotationKey},
+			Subnets:       []*resources.Subnet{resources.NewSubnet("1", vpc, "", "", core.IaCValue{})},
+		}
+		chart := &kubernetes.HelmChart{
+			Name:          "chart",
+			ConstructRefs: []core.AnnotationKey{unit1.AnnotationKey, unit2.AnnotationKey},
+			ExecutionUnits: []*kubernetes.HelmExecUnit{
+				{Name: "test"},
+				{Name: "test2"},
+			},
+		}
+		oidc := &resources.OpenIdConnectProvider{Name: "test", Cluster: cluster}
+		return []core.Resource{vpc, cluster, chart, oidc}
+	}
+
 	cases := []struct {
 		name                   string
 		gw                     *core.Gateway
 		units                  []*core.ExecutionUnit
 		constructIdToResources map[string][]core.Resource
 		existingResources      []core.Resource
-		existingDependencies   []graph.Edge[core.Resource]
 		cfg                    config.Application
 		want                   coretesting.ResourcesExpectation
 		wantErr                bool
@@ -229,29 +249,7 @@ func Test_CreateRestApi(t *testing.T) {
 					resources.NewLoadBalancer(appName, unit2.ID, nil, "internal", "network", nil, nil),
 				},
 			},
-			existingResources: []core.Resource{
-				&resources.EksCluster{
-					Name:          "Cluster",
-					ConstructsRef: []core.AnnotationKey{unit1.AnnotationKey, unit2.AnnotationKey},
-					Subnets:       []*resources.Subnet{resources.NewSubnet("1", resources.NewVpc("test"), "", "", core.IaCValue{})},
-				},
-				&kubernetes.HelmChart{
-					Name:          "chart",
-					ConstructRefs: []core.AnnotationKey{unit1.AnnotationKey, unit2.AnnotationKey},
-					ExecutionUnits: []*kubernetes.HelmExecUnit{
-						{Name: "test"},
-						{Name: "test2"},
-					},
-				},
-				&resources.OpenIdConnectProvider{Name: "test"},
-			},
-			existingDependencies: []graph.Edge[core.Resource]{
-				{Source: &resources.OpenIdConnectProvider{Name: "test"}, Destination: &resources.EksCluster{
-					Name:          "Cluster",
-					ConstructsRef: []core.AnnotationKey{unit1.AnnotationKey, unit2.AnnotationKey},
-					Subnets:       []*resources.Subnet{resources.NewSubnet("1", resources.NewVpc("test"), "", "", core.IaCValue{})},
-				}},
-			},
+			existingResources: makeCluster(),
 			cfg: config.Application{
 				AppName: appName,
 				Defaults: config.Defaults{
@@ -282,6 +280,7 @@ func Test_CreateRestApi(t *testing.T) {
 					"aws:iam_role:Cluster-alb-controller",
 					"aws:region:region",
 					"aws:vpc:test",
+					"aws:subnet_:test:test_1",
 					"kubernetes:helm_chart:Cluster-alb-controller",
 					"kubernetes:manifest:Cluster-alb-controller-service-account",
 					"aws:iam_oidc_provider:test",
@@ -339,6 +338,8 @@ func Test_CreateRestApi(t *testing.T) {
 					{Source: "kubernetes:manifest:Cluster-alb-controller-service-account", Destination: "aws:eks_cluster:Cluster"},
 					{Source: "kubernetes:manifest:Cluster-alb-controller-service-account", Destination: "aws:iam_role:Cluster-alb-controller"},
 					{Source: "kubernetes:helm_chart:chart", Destination: "kubernetes:helm_chart:Cluster-alb-controller"},
+					{Source: "aws:eks_cluster:Cluster", Destination: "aws:subnet_:test:test_1"},
+					{Source: "aws:eks_cluster:Cluster", Destination: "aws:vpc:test"},
 				},
 			},
 		},
@@ -358,10 +359,7 @@ func Test_CreateRestApi(t *testing.T) {
 				}
 			}
 			for _, res := range tt.existingResources {
-				dag.AddResource(res)
-			}
-			for _, dep := range tt.existingDependencies {
-				dag.AddDependency(dep.Source, dep.Destination)
+				dag.AddDependenciesReflect(res)
 			}
 			result := core.NewConstructGraph()
 			result.AddConstruct(tt.gw)
diff --git a/pkg/provider/aws/orm_test.go b/pkg/provider/aws/orm_test.go
index 964ee5c3..37f0b1d8 100644
--- a/pkg/provider/aws/orm_test.go
+++ b/pkg/provider/aws/orm_test.go
@@ -24,11 +24,11 @@ func Test_GenerateOrmResources(t *testing.T) {
 			want: coretesting.ResourcesExpectation{
 				AssertSubset: true,
 				Deps: []coretesting.StringDep{
-					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:vpc_subnet:test_app_private1"},
-					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:vpc_subnet:test_app_private2"},
-					{Source: "aws:security_group:test-app", Destination: "aws:vpc:test_app"},
-					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:vpc_subnet:test_app_private1"},
-					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:vpc_subnet:test_app_private2"},
+					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:security_group:test_app:test-app", Destination: "aws:vpc:test_app"},
+					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:subnet_private:test_app:test_app_private1"},
 				},
 			},
 		},
diff --git a/pkg/provider/aws/resources/eks_test.go b/pkg/provider/aws/resources/eks_test.go
index b369cafa..52f5e3ce 100644
--- a/pkg/provider/aws/resources/eks_test.go
+++ b/pkg/provider/aws/resources/eks_test.go
@@ -53,7 +53,7 @@ func Test_CreateEksCluster(t *testing.T) {
 					"aws:iam_role:test-app-test-cluster_private_t3_medium",
 					"aws:region:region",
 					"aws:vpc:test_app",
-					"aws:vpc_subnet:test_app_test_subnet",
+					"aws:subnet_private:test_app:test_app_test_subnet",
 					"kubernetes:helm_chart:test-app-test-cluster-cert-manager",
 					"kubernetes:helm_chart:test-app-test-cluster-metrics-server",
 					"kubernetes:manifest:test-app-test-cluster-awmazon-cloudwatch-ns",
@@ -66,20 +66,21 @@ func Test_CreateEksCluster(t *testing.T) {
 				Deps: []coretesting.StringDep{
 					{Source: "aws:eks_addon:test-app-test-cluster-addon-vpc-cni", Destination: "aws:eks_cluster:test-app-test-cluster"},
 					{Source: "aws:eks_cluster:test-app-test-cluster", Destination: "aws:iam_role:test-app-test-cluster-k8sAdmin"},
-					{Source: "aws:eks_cluster:test-app-test-cluster", Destination: "aws:vpc_subnet:test_app_test_subnet"},
+					{Source: "aws:eks_cluster:test-app-test-cluster", Destination: "aws:subnet_private:test_app:test_app_test_subnet"},
 					{Source: "aws:eks_fargate_profile:test-app-test-cluster", Destination: "aws:eks_cluster:test-app-test-cluster"},
 					{Source: "aws:eks_fargate_profile:test-app-test-cluster", Destination: "aws:iam_role:test-app-test-cluster-FargateExecutionRole"},
-					{Source: "aws:eks_fargate_profile:test-app-test-cluster", Destination: "aws:vpc_subnet:test_app_test_subnet"},
+					{Source: "aws:eks_fargate_profile:test-app-test-cluster", Destination: "aws:subnet_private:test_app:test_app_test_subnet"},
 					{Source: "aws:eks_node_group:test-cluster_private_g2", Destination: "aws:eks_cluster:test-app-test-cluster"},
 					{Source: "aws:eks_node_group:test-cluster_private_g2", Destination: "aws:iam_role:test-app-test-cluster_private_g2"},
-					{Source: "aws:eks_node_group:test-cluster_private_g2", Destination: "aws:vpc_subnet:test_app_test_subnet"},
+					{Source: "aws:eks_node_group:test-cluster_private_g2", Destination: "aws:subnet_private:test_app:test_app_test_subnet"},
 					{Source: "aws:eks_node_group:test-cluster_private_t3_medium", Destination: "aws:eks_cluster:test-app-test-cluster"},
 					{Source: "aws:eks_node_group:test-cluster_private_t3_medium", Destination: "aws:iam_role:test-app-test-cluster_private_t3_medium"},
-					{Source: "aws:eks_node_group:test-cluster_private_t3_medium", Destination: "aws:vpc_subnet:test_app_test_subnet"},
+					{Source: "aws:eks_node_group:test-cluster_private_t3_medium", Destination: "aws:subnet_private:test_app:test_app_test_subnet"},
 					{Source: "aws:iam_oidc_provider:test-app-test-cluster", Destination: "aws:eks_cluster:test-app-test-cluster"},
 					{Source: "aws:iam_oidc_provider:test-app-test-cluster", Destination: "aws:region:region"},
 					{Source: "aws:vpc:test_app", Destination: "aws:region:region"},
-					{Source: "aws:vpc_subnet:test_app_test_subnet", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_private:test_app:test_app_test_subnet", Destination: "aws:vpc:test_app"},
+					{Source: "aws:eks_cluster:test-app-test-cluster", Destination: "aws:vpc:test_app"},
 					{Source: "kubernetes:helm_chart:test-app-test-cluster-cert-manager", Destination: "aws:eks_node_group:test-cluster_private_g2"},
 					{Source: "kubernetes:helm_chart:test-app-test-cluster-cert-manager", Destination: "aws:eks_node_group:test-cluster_private_t3_medium"},
 					{Source: "kubernetes:helm_chart:test-app-test-cluster-metrics-server", Destination: "aws:eks_node_group:test-cluster_private_g2"},
@@ -110,7 +111,7 @@ func Test_CreateEksCluster(t *testing.T) {
 			dag.AddDependency(subnet, vpc)
 			dag.AddDependency(vpc, region)
 
-			assert.NoError(CreateEksCluster(&cfg, clusterName, []*Subnet{subnet}, nil, eus, dag))
+			assert.NoError(CreateEksCluster(&cfg, clusterName, vpc, nil, eus, dag))
 			for _, r := range dag.ListResources() {
 				if cluster, ok := r.(*EksCluster); ok {
 					assert.Len(cluster.Manifests, 4)
@@ -128,7 +129,7 @@ func Test_CreateEksCluster(t *testing.T) {
 func Test_InstallCloudMapController(t *testing.T) {
 	assert := assert.New(t)
 	dag := core.NewResourceGraph()
-	cluster := NewEksCluster("test", "cluster", nil, nil, nil)
+	cluster := NewEksCluster("test", "cluster", nil, nil, nil, nil)
 	nodeGroup1 := &EksNodeGroup{
 		Name:    "nodegroup1",
 		Cluster: cluster,
@@ -173,7 +174,7 @@ func Test_InstallCloudMapController(t *testing.T) {
 func Test_getClustersNodeGroups(t *testing.T) {
 	assert := assert.New(t)
 	dag := core.NewResourceGraph()
-	cluster := NewEksCluster("test", "cluster", nil, nil, nil)
+	cluster := NewEksCluster("test", "cluster", nil, nil, nil, nil)
 	nodeGroup1 := &EksNodeGroup{
 		Name:    "nodegroup1",
 		Cluster: cluster,
diff --git a/pkg/provider/aws/resources/rds_test.go b/pkg/provider/aws/resources/rds_test.go
index 561472d6..83c83ed9 100644
--- a/pkg/provider/aws/resources/rds_test.go
+++ b/pkg/provider/aws/resources/rds_test.go
@@ -34,7 +34,7 @@ func Test_CreateRdsInstance(t *testing.T) {
 					"aws:secret:test-app-orm:test",
 					"aws:secret_version:test-app-orm:test",
 					"aws:security_group:test",
-					"aws:vpc_subnet:test_app_subnet",
+					"aws:subnet_private:test_app:test_app_subnet",
 				},
 				Deps: []coretesting.StringDep{
 					{Source: "aws:iam_policy:test-app-test-ormsecretpolicy", Destination: "aws:secret:test-app-orm:test"},
@@ -44,10 +44,10 @@ func Test_CreateRdsInstance(t *testing.T) {
 					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:iam_role:test-app-test-ormsecretrole"},
 					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:secret:test-app-orm:test"},
 					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:security_group:test"},
-					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:vpc_subnet:test_app_subnet"},
+					{Source: "aws:rds_proxy:test-app-test", Destination: "aws:subnet_private:test_app:test_app_subnet"},
 					{Source: "aws:rds_proxy_target_group:test-app-test", Destination: "aws:rds_instance:test-app-test"},
 					{Source: "aws:rds_proxy_target_group:test-app-test", Destination: "aws:rds_proxy:test-app-test"},
-					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:vpc_subnet:test_app_subnet"},
+					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:subnet_private:test_app:test_app_subnet"},
 					{Source: "aws:secret_version:test-app-orm:test", Destination: "aws:secret:test-app-orm:test"},
 				},
 			},
@@ -59,12 +59,12 @@ func Test_CreateRdsInstance(t *testing.T) {
 					"aws:rds_instance:test-app-test",
 					"aws:rds_subnet_group:test-app-test",
 					"aws:security_group:test",
-					"aws:vpc_subnet:test_app_subnet",
+					"aws:subnet_private:test_app:test_app_subnet",
 				},
 				Deps: []coretesting.StringDep{
 					{Source: "aws:rds_instance:test-app-test", Destination: "aws:rds_subnet_group:test-app-test"},
 					{Source: "aws:rds_instance:test-app-test", Destination: "aws:security_group:test"},
-					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:vpc_subnet:test_app_subnet"},
+					{Source: "aws:rds_subnet_group:test-app-test", Destination: "aws:subnet_private:test_app:test_app_subnet"},
 				},
 			},
 		},
diff --git a/pkg/provider/aws/resources/vpc_test.go b/pkg/provider/aws/resources/vpc_test.go
index 8bbcbe55..a42dbdb9 100644
--- a/pkg/provider/aws/resources/vpc_test.go
+++ b/pkg/provider/aws/resources/vpc_test.go
@@ -32,37 +32,37 @@ func Test_CreateNetwork(t *testing.T) {
 					"aws:route_table:test_app_private1",
 					"aws:route_table:test_app_private2",
 					"aws:vpc:test_app",
-					"aws:security_group:test-app",
+					"aws:security_group:test_app:test-app",
 					"aws:vpc_endpoint:test_app_dynamodb",
 					"aws:vpc_endpoint:test_app_lambda",
 					"aws:vpc_endpoint:test_app_s3",
 					"aws:vpc_endpoint:test_app_secretsmanager",
 					"aws:vpc_endpoint:test_app_sns",
 					"aws:vpc_endpoint:test_app_sqs",
-					"aws:vpc_subnet:test_app_private1",
-					"aws:vpc_subnet:test_app_private2",
-					"aws:vpc_subnet:test_app_public1",
-					"aws:vpc_subnet:test_app_public2",
+					"aws:subnet_private:test_app:test_app_private1",
+					"aws:subnet_private:test_app:test_app_private2",
+					"aws:subnet_public:test_app:test_app_public1",
+					"aws:subnet_public:test_app:test_app_public2",
 				},
 				Deps: []coretesting.StringDep{
 					{Source: "aws:availability_zones:AvailabilityZones", Destination: "aws:region:region"},
 					{Source: "aws:internet_gateway:test_app_igw1", Destination: "aws:vpc:test_app"},
 					{Source: "aws:nat_gateway:test_app_public1", Destination: "aws:elastic_ip:test_app_public1"},
-					{Source: "aws:nat_gateway:test_app_public1", Destination: "aws:vpc_subnet:test_app_public1"},
+					{Source: "aws:nat_gateway:test_app_public1", Destination: "aws:subnet_public:test_app:test_app_public1"},
 					{Source: "aws:nat_gateway:test_app_public2", Destination: "aws:elastic_ip:test_app_public2"},
-					{Source: "aws:nat_gateway:test_app_public2", Destination: "aws:vpc_subnet:test_app_public2"},
+					{Source: "aws:nat_gateway:test_app_public2", Destination: "aws:subnet_public:test_app:test_app_public2"},
 					{Source: "aws:route_table:test_app-public", Destination: "aws:internet_gateway:test_app_igw1"},
 					{Source: "aws:route_table:test_app-public", Destination: "aws:vpc:test_app"},
-					{Source: "aws:route_table:test_app-public", Destination: "aws:vpc_subnet:test_app_public1"},
-					{Source: "aws:route_table:test_app-public", Destination: "aws:vpc_subnet:test_app_public2"},
+					{Source: "aws:route_table:test_app-public", Destination: "aws:subnet_public:test_app:test_app_public1"},
+					{Source: "aws:route_table:test_app-public", Destination: "aws:subnet_public:test_app:test_app_public2"},
 					{Source: "aws:route_table:test_app_private1", Destination: "aws:nat_gateway:test_app_public1"},
 					{Source: "aws:route_table:test_app_private1", Destination: "aws:vpc:test_app"},
-					{Source: "aws:route_table:test_app_private1", Destination: "aws:vpc_subnet:test_app_private1"},
+					{Source: "aws:route_table:test_app_private1", Destination: "aws:subnet_private:test_app:test_app_private1"},
 					{Source: "aws:route_table:test_app_private2", Destination: "aws:nat_gateway:test_app_public2"},
 					{Source: "aws:route_table:test_app_private2", Destination: "aws:vpc:test_app"},
-					{Source: "aws:route_table:test_app_private2", Destination: "aws:vpc_subnet:test_app_private2"},
+					{Source: "aws:route_table:test_app_private2", Destination: "aws:subnet_private:test_app:test_app_private2"},
 					{Source: "aws:vpc:test_app", Destination: "aws:region:region"},
-					{Source: "aws:security_group:test-app", Destination: "aws:vpc:test_app"},
+					{Source: "aws:security_group:test_app:test-app", Destination: "aws:vpc:test_app"},
 					{Source: "aws:vpc_endpoint:test_app_dynamodb", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_app_dynamodb", Destination: "aws:vpc:test_app"},
 					{Source: "aws:vpc_endpoint:test_app_dynamodb", Destination: "aws:route_table:test_app-public"},
@@ -70,9 +70,9 @@ func Test_CreateNetwork(t *testing.T) {
 					{Source: "aws:vpc_endpoint:test_app_dynamodb", Destination: "aws:route_table:test_app_private2"},
 					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:security_group:test-app"},
-					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:vpc_subnet:test_app_private1"},
-					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:vpc_subnet:test_app_private2"},
+					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:security_group:test_app:test-app"},
+					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:vpc_endpoint:test_app_lambda", Destination: "aws:subnet_private:test_app:test_app_private2"},
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:vpc:test_app"},
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:route_table:test_app-public"},
@@ -80,27 +80,27 @@ func Test_CreateNetwork(t *testing.T) {
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:route_table:test_app_private2"},
 					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:security_group:test-app"},
-					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:vpc_subnet:test_app_private1"},
-					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:vpc_subnet:test_app_private2"},
+					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:security_group:test_app:test-app"},
+					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:vpc_endpoint:test_app_secretsmanager", Destination: "aws:subnet_private:test_app:test_app_private2"},
 					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:security_group:test-app"},
-					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:vpc_subnet:test_app_private1"},
-					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:vpc_subnet:test_app_private2"},
+					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:security_group:test_app:test-app"},
+					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:vpc_endpoint:test_app_sns", Destination: "aws:subnet_private:test_app:test_app_private2"},
 					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:region:region"},
 					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:security_group:test-app"},
-					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:vpc_subnet:test_app_private1"},
-					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:vpc_subnet:test_app_private2"},
-					{Source: "aws:vpc_subnet:test_app_private1", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_app_private1", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_subnet:test_app_private2", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_app_private2", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_subnet:test_app_public1", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_app_public1", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_subnet:test_app_public2", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_app_public2", Destination: "aws:vpc:test_app"},
+					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:security_group:test_app:test-app"},
+					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:subnet_private:test_app:test_app_private1"},
+					{Source: "aws:vpc_endpoint:test_app_sqs", Destination: "aws:subnet_private:test_app:test_app_private2"},
+					{Source: "aws:subnet_private:test_app:test_app_private1", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_private:test_app:test_app_private1", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_private:test_app:test_app_private2", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_private:test_app:test_app_private2", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_public:test_app:test_app_public1", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_public:test_app:test_app_public1", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_public:test_app:test_app_public2", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_public:test_app:test_app_public2", Destination: "aws:vpc:test_app"},
 				},
 			},
 		},
@@ -245,11 +245,11 @@ func Test_CreatePrivateSubnet(t *testing.T) {
 				Nodes: []string{
 					"aws:vpc:test_app",
 					"aws:availability_zones:AvailabilityZones",
-					"aws:vpc_subnet:test_app_private1",
+					"aws:subnet_private:test_app:test_app_private1",
 				},
 				Deps: []coretesting.StringDep{
-					{Source: "aws:vpc_subnet:test_app_private1", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_subnet:test_app_private1", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_private:test_app:test_app_private1", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_private:test_app:test_app_private1", Destination: "aws:availability_zones:AvailabilityZones"},
 				},
 			},
 		},
@@ -275,10 +275,10 @@ func Test_CreatePublicSubnet(t *testing.T) {
 		{
 			name: "happy path",
 			want: coretesting.ResourcesExpectation{
-				Nodes: []string{"aws:vpc:test_app", "aws:availability_zones:AvailabilityZones", "aws:vpc_subnet:test_app_public1"},
+				Nodes: []string{"aws:vpc:test_app", "aws:availability_zones:AvailabilityZones", "aws:subnet_public:test_app:test_app_public1"},
 				Deps: []coretesting.StringDep{
-					{Source: "aws:vpc_subnet:test_app_public1", Destination: "aws:availability_zones:AvailabilityZones"},
-					{Source: "aws:vpc_subnet:test_app_public1", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_public:test_app:test_app_public1", Destination: "aws:availability_zones:AvailabilityZones"},
+					{Source: "aws:subnet_public:test_app:test_app_public1", Destination: "aws:vpc:test_app"},
 				},
 			},
 		},
@@ -304,12 +304,12 @@ func Test_CreateGatewayVpcEndpoint(t *testing.T) {
 		{
 			name: "happy path",
 			want: coretesting.ResourcesExpectation{
-				Nodes: []string{"aws:vpc:test_app", "aws:region:region", "aws:vpc_endpoint:test_app_s3", "aws:vpc_subnet:test_app_1", "aws:vpc_subnet:test_app_2", "aws:route_table:rt"},
+				Nodes: []string{"aws:vpc:test_app", "aws:region:region", "aws:vpc_endpoint:test_app_s3", "aws:subnet_private:test_app:test_app_1", "aws:subnet_private:test_app:test_app_2", "aws:route_table:rt"},
 				Deps: []coretesting.StringDep{
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:vpc:test_app"},
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:region:region"},
-					{Source: "aws:vpc_subnet:test_app_1", Destination: "aws:vpc:test_app"},
-					{Source: "aws:vpc_subnet:test_app_2", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_private:test_app:test_app_1", Destination: "aws:vpc:test_app"},
+					{Source: "aws:subnet_private:test_app:test_app_2", Destination: "aws:vpc:test_app"},
 					{Source: "aws:vpc_endpoint:test_app_s3", Destination: "aws:route_table:rt"},
 				},
 			},
@@ -342,20 +342,20 @@ func Test_CreateInterfaceVpcEndpoint(t *testing.T) {
 				Nodes: []string{
 					"aws:vpc:test_app",
 					"aws:region:region",
-					"aws:security_group:test-app",
+					"aws:security_group:test_app:test-app",
 					"aws:vpc_endpoint:test_app_s3",
-					"aws:vpc_subnet:test_app_1",
-					"aws:vpc_subnet:test_app_2",
+					"aws:subnet_private:test_app:test_app_1",
+					"aws:subnet_private:test_app:test_app_2",
 				},
 				Deps: []coretesting.StringDep{
 					{Destination: "aws:vpc:test_app", Source: "aws:vpc_endpoint:test_app_s3"},
-					{Destination: "aws:vpc:test_app", Source: "aws:security_group:test-app"},
+					{Destination: "aws:vpc:test_app", Source: "aws:security_group:test_app:test-app"},
 					{Destination: "aws:region:region", Source: "aws:vpc_endpoint:test_app_s3"},
-					{Destination: "aws:vpc:test_app", Source: "aws:vpc_subnet:test_app_1"},
-					{Destination: "aws:vpc:test_app", Source: "aws:vpc_subnet:test_app_2"},
-					{Destination: "aws:vpc_subnet:test_app_1", Source: "aws:vpc_endpoint:test_app_s3"},
-					{Destination: "aws:vpc_subnet:test_app_2", Source: "aws:vpc_endpoint:test_app_s3"},
-					{Destination: "aws:security_group:test-app", Source: "aws:vpc_endpoint:test_app_s3"},
+					{Destination: "aws:vpc:test_app", Source: "aws:subnet_private:test_app:test_app_1"},
+					{Destination: "aws:vpc:test_app", Source: "aws:subnet_private:test_app:test_app_2"},
+					{Destination: "aws:subnet_private:test_app:test_app_1", Source: "aws:vpc_endpoint:test_app_s3"},
+					{Destination: "aws:subnet_private:test_app:test_app_2", Source: "aws:vpc_endpoint:test_app_s3"},
+					{Destination: "aws:security_group:test_app:test-app", Source: "aws:vpc_endpoint:test_app_s3"},
 				},
 			},
 		},