diff --git a/modules/cloud-run-v2/README.md b/modules/cloud-run-v2/README.md
new file mode 100644
index 000000000..3b2e6d0c3
--- /dev/null
+++ b/modules/cloud-run-v2/README.md
@@ -0,0 +1,353 @@
+# Cloud Run Module
+
+Cloud Run management, with support for IAM roles and Eventarc trigger creation.
+
+## Examples
+
+
+- [Examples](#examples)
+ - [IAM and environment variables](#iam-and-environment-variables)
+ - [Mounting secrets as volumes](#mounting-secrets-as-volumes)
+ - [Beta features](#beta-features)
+ - [VPC Access Connector](#vpc-access-connector)
+ - [Eventarc triggers](#eventarc-triggers)
+ - [PubSub](#pubsub)
+ - [Audit logs](#audit-logs)
+ - [Using custom service accounts for triggers](#using-custom-service-accounts-for-triggers)
+ - [Cloud Run Service account](#cloud-run-service-account)
+- [Variables](#variables)
+- [Outputs](#outputs)
+
+
+### IAM and environment variables
+
+IAM bindings support the usual syntax. Container environment values can be declared as key-value strings or as references to Secret Manager secrets. Both can be combined as long as there is no duplication of keys:
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ region = var.region
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ env = {
+ VAR1 = "VALUE1"
+ VAR2 = "VALUE2"
+ }
+ env_from_key = {
+ SECRET1 = {
+ secret = "credentials"
+ version = "1"
+ }
+ }
+ }
+ }
+ iam = {
+ "roles/run.invoker" = ["allUsers"]
+ }
+}
+# tftest modules=1 resources=2
+```
+
+### Mounting secrets as volumes
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ region = var.region
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ volume_mounts = {
+ "credentials" = "/credentials"
+ }
+ }
+ }
+ volumes = {
+ credentials = {
+ secret = {
+ name = "secret-manager-id"
+ path = "my-secret"
+ }
+ }
+ }
+}
+# tftest modules=1 resources=1
+```
+
+### Beta features
+
+To use beta features like Direct VPC Egress, set the launch stage to a preview stage to allow its use.
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ region = var.region
+ launch_stage = "BETA"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ revision = {
+ gen2_execution_environment = true
+ max_instance_count = 20
+ vpc_access = {
+ egress = "ALL_TRAFFIC"
+ subnet = "default"
+ tags = ["tag1", "tag2", "tag3"]
+ }
+ }
+}
+# tftest modules=1 resources=1
+```
+
+### VPC Access Connector
+
+You can use a [VPC Access Connector](https://cloud.google.com/vpc/docs/serverless-vpc-access) to connect to a VPC from Cloud Run.
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ revision = {
+ vpc_access = {
+ connector = "connector-id"
+ egress = "ALL_TRAFFIC"
+ }
+ }
+}
+# tftest modules=1 resources=1
+```
+
+If previous creation of the VPC Access Connector is required, use the `vpc_connector_create` variable which also supports optional attributes like number of instances, machine type, or throughput. The connector will be used automatically.
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ vpc_connector_create = {
+ ip_cidr_range = "10.10.10.0/24"
+ vpc_self_link = "projects/example/global/networks/vpc"
+ instances = {
+ max = 10
+ min = 2
+ }
+ }
+}
+# tftest modules=1 resources=2
+```
+
+Note that if you are using a Shared VPC for the connector, you need to specify a subnet and the host project if this is not where the Cloud Run service is deployed.
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ vpc_connector_create = {
+ machine_type = "e2-standard-4"
+ subnet = {
+ name = "subnet-name"
+ project_id = "host-project"
+ }
+ }
+}
+# tftest modules=1 resources=2
+```
+
+### Eventarc triggers
+
+#### PubSub
+
+This deploys a Cloud Run service that will be triggered when messages are published to Pub/Sub topics.
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ eventarc_triggers = {
+ pubsub = {
+ topic-1 = "topic1"
+ topic-2 = "topic2"
+ }
+ }
+}
+# tftest modules=1 resources=3
+```
+
+#### Audit logs
+
+This deploys a Cloud Run service that will be triggered when specific log events are written to Google Cloud audit logs.
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ eventarc_triggers = {
+ audit_log = {
+ setiampolicy = {
+ method = "SetIamPolicy"
+ service = "cloudresourcemanager.googleapis.com"
+ }
+ }
+ }
+}
+# tftest modules=1 resources=2
+```
+
+#### Using custom service accounts for triggers
+
+By default `Compute default service account` is used to trigger Cloud Run. If you want to use custom Service Accounts you can either provide your own in `eventarc_triggers.service_account_email` or set `eventarc_triggers.service_account_create` to true and service account named `tf-cr-trigger-${var.name}` will be created with `roles/run.invoker` granted on this Cloud Run service.
+
+Example using provided service account:
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ eventarc_triggers = {
+ audit_log = {
+ setiampolicy = {
+ method = "SetIamPolicy"
+ service = "cloudresourcemanager.googleapis.com"
+ }
+ }
+ service_account_email = "cloud-run-trigger@my-project.iam.gserviceaccount.com"
+ }
+}
+# tftest modules=1 resources=2
+```
+
+Example using automatically created service account:
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ eventarc_triggers = {
+ pubsub = {
+ topic-1 = "topic1"
+ topic-2 = "topic2"
+ }
+ service_account_create = true
+ }
+}
+# tftest modules=1 resources=5
+```
+
+### Cloud Run Service account
+
+To use a custom service account managed by the module, set `service_account_create` to `true` and leave `service_account` set to `null` (default).
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ service_account_create = true
+}
+# tftest modules=1 resources=2
+```
+
+To use an externally managed service account, use its email in `service_account` and leave `service_account_create` to `false` (default).
+
+```hcl
+module "cloud_run" {
+ source = "./fabric/modules/cloud-run-v2"
+ project_id = var.project_id
+ name = "hello"
+ containers = {
+ hello = {
+ image = "us-docker.pkg.dev/cloudrun/container/hello"
+ }
+ }
+ service_account = "cloud-run@my-project.iam.gserviceaccount.com"
+}
+# tftest modules=1 resources=1
+```
+
+## Variables
+
+| name | description | type | required | default |
+|---|---|:---:|:---:|:---:|
+| [name](variables.tf#L137) | Name used for Cloud Run service. | string | ✓ | |
+| [project_id](variables.tf#L152) | Project id used for all resources. | string | ✓ | |
+| [containers](variables.tf#L17) | Containers in name => attributes format. | map(object({…})) | | {} |
+| [eventarc_triggers](variables.tf#L77) | Event arc triggers for different sources. | object({…}) | | {} |
+| [iam](variables.tf#L91) | IAM bindings for Cloud Run service in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
+| [ingress](variables.tf#L97) | Ingress settings. | string | | null |
+| [labels](variables.tf#L114) | Resource labels. | map(string) | | {} |
+| [launch_stage](variables.tf#L120) | The launch stage as defined by Google Cloud Platform Launch Stages. | string | | null |
+| [prefix](variables.tf#L142) | Optional prefix used for resource names. | string | | null |
+| [region](variables.tf#L157) | Region used for all resources. | string | | "europe-west1" |
+| [revision](variables.tf#L163) | Revision template configurations. | object({…}) | | {} |
+| [service_account](variables.tf#L190) | Service account email. Unused if service account is auto-created. | string | | null |
+| [service_account_create](variables.tf#L196) | Auto-create service account. | bool | | false |
+| [volumes](variables.tf#L202) | Named volumes in containers in name => attributes format. | map(object({…})) | | {} |
+| [vpc_connector_create](variables-vpcconnector.tf#L17) | Populate this to create a Serverless VPC Access connector. | object({…}) | | null |
+
+## Outputs
+
+| name | description | sensitive |
+|---|---|:---:|
+| [id](outputs.tf#L17) | Fully qualified service id. | |
+| [service](outputs.tf#L22) | Cloud Run service. | |
+| [service_account](outputs.tf#L27) | Service account resource. | |
+| [service_account_email](outputs.tf#L32) | Service account email. | |
+| [service_account_iam_email](outputs.tf#L37) | Service account email. | |
+| [service_name](outputs.tf#L45) | Cloud Run service name. | |
+| [vpc_connector](outputs.tf#L50) | VPC connector resource if created. | |
+