# Net VPC Factory

This module implements the creation of VPCs, subnets, and firewall rules via YAML configurations. It is designed to be embedded in other factories such as the [FAST networking stage](../../fast/stages/2-networking).

It supports:

-   **VPCs** and **Subnets** leveraging the [net-vpc](../net-vpc/) module.
-   **Firewall rules** leveraging the [net-vpc-firewall](../net-vpc-firewall/) module.
-   **Context-based interpolation** for referring to resources dynamically (e.g., project IDs, IAM principals, Locations).

The factory is implemented as a thin data translation layer over the underlying modules, ensuring transparency and ease of debugging.

The factory is implemented as a thin data translation layer over the underlying modules, so that no "magic" or hidden side effects are implemented in code, and debugging or integration of new features are simple.

The code is meant to be executed by a principal with permissions over the network infrastructure across the projects where VPCs are defined:

- **Network Admin** (`roles/compute.networkAdmin`): to manage VPCs, subnets, routes, and firewall rules.
- **DNS Admin** (`roles/dns.admin`): to manage DNS policies.
- **Security Admin** (`roles/compute.securityAdmin`): to manage firewall policies.

## Contents

<!-- BEGIN TOC -->
- [VPC Factory](#vpc-factory)
  - [Defaults](#defaults)
  - [Subnets](#subnets)
  - [Firewall rules](#firewall-rules)
- [Context-based interpolation](#context-based-interpolation)
  - [Project context ids](#project-context-ids)
  - [Other context ids](#other-context-ids)
- [Example](#example)
- [Variables](#variables)
- [Outputs](#outputs)
<!-- END TOC -->

## VPC Factory

The VPC factory is configured via the `factories_config.vpcs` variable, which sets the path containing the YAML definitions for VPCs, where each VPC and their dependent resources are defined in a dedicated directory.

Each VPC directory contains a `.config.yaml` file. The structure of the YAML file mirrors the variables of the [`net-vpc`](../net-vpc/) module.

```yaml
project_id: $project_ids:my-project # Or use the project id directly
description: "My VPC"
routing_mode: GLOBAL
subnets:
  - name: subnet-a
    region: europe-west1
    ip_cidr_range: 10.0.0.0/24
```

### Defaults

In addition to the YAML-based VPC configurations, the factory accepts three additional sets of inputs via Terraform variables to control defaults:

-   `data_defaults`: defaults for specific VPC attributes, used if not present in YAML.
-   `data_overrides`: overrides that take precedence over YAML values.
-   `factories_config.defaults`: path to a YAML file containing global context and VPC defaults.

```hcl
module "net-vpc-factory" {
  source = "./modules/net-vpc-factory"
  data_defaults = {
    routing_mode = "REGIONAL"
  }
  factories_config = {
    vpcs = "data/vpcs"
  }
}
```

### Subnets

Subnets can be defined inline in the VPC `.config.yaml` file (as shown above) or in separate files within a `subnets` subdirectory in the VPC's folder. The factory automatically scans the `subnets` folder if it exists.

```text
data/vpcs/
└── my-vpc/
    ├── .config.yaml
    └── subnets/
        ├── subnet-a.yaml
        └── subnet-b.yaml
```

This allows splitting complex subnet configurations (like those with massive secondary ranges or specialized IAM bindings) into manageable files.

### Firewall rules

Firewall rules are managed via a `firewall-rules` subdirectory in the VPC's folder. The factory uses the [`net-vpc-firewall`](../net-vpc-firewall/) module to provision these rules - the YAML format for firewall rules follows the structure expected by the module itself.

```text
data/vpcs/
└── my-vpc/
    ├── .config.yaml
    └── firewall-rules/
        ├── allow-ssh.yaml
        └── allow-internal.yaml
```

## Context-based interpolation

Interpolation allows referring to resources which are external or created at runtime via short aliases. This is particularly useful for Project IDs, which might be generated by the Project Factory.

Contexts are passed via the `context` variable or the `factories_config.defaults` file.

### Project context ids

Project IDs use the `$project_ids:` namespace. This allows decoupling the VPC definition from the actual Project ID string.

```yaml
# data/vpcs/vpc-0/.config.yaml
project_id: $project_ids:data-project
name: vpc-0
```

```hcl
module "net-vpc-factory" {
  # ...
  context = {
    project_ids = {
      data-project = "prefix-prod-data-app-0"
    }
  }
}
```

### Other context ids

Other contexts can be defined freely. Common uses include:

-   `$locations:` for GCP regions.
-   `$iam_principals:` for IAM principals.

## Example

```hcl
module "net-vpc-factory" {
  source = "./fabric/modules/net-vpc-factory"

  context = {
    project_ids = {
      net-project = "my-host-project-id"
    }
    locations = {
      primary = "europe-west1"
    }
  }

  factories_config = {
    vpcs = "data/vpcs"
  }
}
# tftest files=vpc,fw modules=3 inventory=example.yaml
```

**data/vpcs/shared-vpc/.config.yaml**
```yaml
project_id: $project_ids:net-project
name: data-vpc-0
subnets:
  - name: primary-subnet
    region: $locations:primary
    ip_cidr_range: 10.10.0.0/24
# tftest-file id=vpc path=data/vpcs/data-vpc-0/.config.yaml schema=vpc.schema.json
```

**data/vpcs/data-vpc-0/firewall-rules/allow-iap.yaml**
```yaml
ingress:
  allow-iap:
    description: Allow IAP for SSH
    source_ranges:
      - 35.235.240.0/20
    rules:
      - protocol: tcp
        ports: [22]
    targets: ["ssh"]
# tftest-file id=fw path=data/vpcs/data-vpc-0/firewall-rules/allow-iap.yaml schema=firewall-rules.schema.json
```
<!-- BEGIN TFDOC -->
## Variables

| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [context](variables.tf#L17) | Context-specific interpolations. | <code title="object&#40;&#123;&#10;  locations   &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;  project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> |  | <code>&#123;&#125;</code> |
| [data_defaults](variables.tf#L27) | Optional default values used when corresponding vpc data from files are missing. | <code title="object&#40;&#123;&#10;  project_id                        &#61; optional&#40;string&#41;&#10;  description                       &#61; optional&#40;string, &#34;Terraform managed&#34;&#41;&#10;  auto_create_subnetworks           &#61; optional&#40;bool&#41;&#10;  delete_default_routes_on_create   &#61; optional&#40;bool, true&#41;&#10;  mtu                               &#61; optional&#40;number&#41;&#10;  routing_mode                      &#61; optional&#40;string, &#34;GLOBAL&#34;&#41;&#10;  firewall_policy_enforcement_order &#61; optional&#40;string, &#34;AFTER_CLASSIC_FIREWALL&#34;&#41;&#10;  create_googleapis_routes &#61; optional&#40;object&#40;&#123;&#10;    directpath   &#61; optional&#40;bool&#41;&#10;    directpath-6 &#61; optional&#40;bool&#41;&#10;    private      &#61; optional&#40;bool&#41;&#10;    private-6    &#61; optional&#40;bool&#41;&#10;    restricted   &#61; optional&#40;bool&#41;&#10;    restricted-6 &#61; optional&#40;bool&#41;&#10;  &#125;&#41;, &#123;&#125;&#41;&#10;  dns_policy &#61; optional&#40;object&#40;&#123;&#10;    inbound &#61; optional&#40;bool&#41;&#10;    logging &#61; optional&#40;bool&#41;&#10;    outbound &#61; optional&#40;object&#40;&#123;&#10;      private_ns &#61; optional&#40;list&#40;string&#41;&#41;&#10;      public_ns  &#61; optional&#40;list&#40;string&#41;&#41;&#10;    &#125;&#41;&#41;&#10;  &#125;&#41;&#41;&#10;  ipv6_config &#61; optional&#40;object&#40;&#123;&#10;    enable_ula_internal &#61; optional&#40;bool&#41;&#10;    internal_range      &#61; optional&#40;string&#41;&#10;  &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> |  | <code>&#123;&#125;</code> |
| [data_overrides](variables.tf#L62) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | <code title="object&#40;&#123;&#10;  project_id                        &#61; optional&#40;string&#41;&#10;  description                       &#61; optional&#40;string&#41;&#10;  auto_create_subnetworks           &#61; optional&#40;bool&#41;&#10;  delete_default_routes_on_create   &#61; optional&#40;bool&#41;&#10;  mtu                               &#61; optional&#40;number&#41;&#10;  routing_mode                      &#61; optional&#40;string&#41;&#10;  firewall_policy_enforcement_order &#61; optional&#40;string&#41;&#10;  create_googleapis_routes &#61; optional&#40;object&#40;&#123;&#10;    directpath   &#61; optional&#40;bool&#41;&#10;    directpath-6 &#61; optional&#40;bool&#41;&#10;    private      &#61; optional&#40;bool&#41;&#10;    private-6    &#61; optional&#40;bool&#41;&#10;    restricted   &#61; optional&#40;bool&#41;&#10;    restricted-6 &#61; optional&#40;bool&#41;&#10;  &#125;&#41;&#41;&#10;  dns_policy &#61; optional&#40;object&#40;&#123;&#10;    inbound &#61; optional&#40;bool&#41;&#10;    logging &#61; optional&#40;bool&#41;&#10;    outbound &#61; optional&#40;object&#40;&#123;&#10;      private_ns &#61; optional&#40;list&#40;string&#41;&#41;&#10;      public_ns  &#61; optional&#40;list&#40;string&#41;&#41;&#10;    &#125;&#41;&#41;&#10;  &#125;&#41;&#41;&#10;  ipv6_config &#61; optional&#40;object&#40;&#123;&#10;    enable_ula_internal &#61; optional&#40;bool&#41;&#10;    internal_range      &#61; optional&#40;string&#41;&#10;  &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> |  | <code>&#123;&#125;</code> |
| [factories_config](variables.tf#L97) | Path to folder with YAML resource description data files. | <code title="object&#40;&#123;&#10;  vpcs     &#61; optional&#40;string&#41;&#10;  defaults &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> |  | <code>&#123;&#125;</code> |

## Outputs

| name | description | sensitive |
|---|---|:---:|
| [firewall_rules](outputs.tf#L17) | Firewall rules. |  |
| [vpcs](outputs.tf#L22) | VPCs. |  |
| [vpcs_config](outputs.tf#L27) | Processed VPC configuration data. |  |
<!-- END TFDOC -->
