Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3421cfd
feat(storage): Add support for ip_filter to storage buckets
malikalrizky Jun 10, 2025
c399f73
feat(storage): add example
malikalrizky Jun 10, 2025
f49eafe
feat(storage): enhance ip_filter configuration for storage buckets
malikalrizky Jun 16, 2025
5c9b57e
feat(docs): update README with detailed module requirements, inputs, …
malikalrizky Jun 16, 2025
771cc6d
feat(storage): extend ip_filter to include VPC network sources
malikalrizky Jun 16, 2025
eb09a82
refactor(storage): fix lint and update README
malikalrizky Jul 8, 2025
229c9a1
chore(docs): clean up README
malikalrizky Jul 8, 2025
4a21c8b
feat(storage): update ip_filter configuration and dependencies
malikalrizky Jul 8, 2025
8a3d4d0
chore(metadata): remove ip_filter example from module metadata
malikalrizky Aug 11, 2025
8a9fefb
feat(storage): enhance ip_filter configuration with new options
malikalrizky Aug 23, 2025
ceee2bb
feat(storage): enable service agent access in bucket configuration
malikalrizky Aug 23, 2025
2322721
refactor(storage): update module source paths for bucket examples
malikalrizky Aug 23, 2025
a1124f4
refactor(storage): standardize module source paths and clean up varia…
malikalrizky Aug 26, 2025
e10db53
Merge branch 'main' into feat/add-ip-filter-support
malikalrizky Sep 1, 2025
b6d7f60
chore(dependencies): update Google provider version constraints to su…
malikalrizky Sep 1, 2025
e71bcd3
Merge branch 'feat/add-ip-filter-support' of github-personal:malikalr…
malikalrizky Sep 1, 2025
a04f86f
fix: standardize formatting of allow_cross_org_vpcs in metadata files
malikalrizky Sep 1, 2025
e54fd8f
Merge branch 'main' of github.com:terraform-google-modules/terraform-…
malikalrizky Sep 18, 2025
fec647a
Merge branch 'main' into feat/add-ip-filter-support
m0ps Sep 22, 2025
dcdc071
fix: min provider version
m0ps Sep 22, 2025
0c6b9a6
variable description updated
m0ps Sep 22, 2025
4c307ca
test(multiple_buckets): add validation for ip_filter settings
m0ps Sep 22, 2025
f1fe2eb
add ipv6 range to the allowed_ip_cidr_ranges
m0ps Sep 25, 2025
0aa420b
fix: cloud build integration tests
m0ps Sep 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Functional examples are included in the
| hierarchical\_namespace | Optional map of lowercase unprefixed bucket name => boolean, defaults to false. | `map(bool)` | `{}` | no |
| hmac\_key\_admins | IAM-style members who will be granted roles/storage.hmacKeyAdmin on all buckets. | `list(string)` | `[]` | no |
| hmac\_service\_accounts | List of HMAC service accounts to grant access to GCS. | `map(string)` | `{}` | no |
| ip\_filter | The IP filter configuration for a bucket. Map of lowercase unprefixed name => ip filter config object. See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#ip_filter-1 | <pre>map(object({<br> mode = string<br> public_network_source = optional(object({<br> allowed_ip_cidr_ranges = list(string)<br> }))<br> vpc_network_sources = optional(list(object({<br> network = string<br> allowed_ip_cidr_ranges = list(string)<br> })))<br> allow_cross_org_vpcs = optional(bool)<br> allow_all_service_agent_access = optional(bool)<br> }))</pre> | `{}` | no |
| labels | Labels to be attached to the buckets | `map(string)` | `{}` | no |
| lifecycle\_rules | List of lifecycle rules to configure. Format is the same as described in provider documentation https://www.terraform.io/docs/providers/google/r/storage_bucket.html#lifecycle_rule except condition.matches\_storage\_class should be a comma delimited string. | <pre>set(object({<br> # Object with keys:<br> # - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass.<br> # - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule.<br> action = object({<br> type = string<br> storage_class = optional(string)<br> })<br><br> # Object with keys:<br> # - age - (Optional) Minimum age of an object in days to satisfy this condition.<br> # - send_age_if_zero - (Optional) While set true, num_newer_versions value will be sent in the request even for zero value of the field.<br> # - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.<br> # - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY".<br> # - matches_storage_class - (Optional) Comma delimited string for storage class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY.<br> # - matches_prefix - (Optional) One or more matching name prefixes to satisfy this condition.<br> # - matches_suffix - (Optional) One or more matching name suffixes to satisfy this condition.<br> # - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition.<br> # - custom_time_before - (Optional) A date in the RFC 3339 format YYYY-MM-DD. This condition is satisfied when the customTime metadata for the object is set to an earlier date than the date used in this lifecycle condition.<br> # - days_since_custom_time - (Optional) The number of days from the Custom-Time metadata attribute after which this condition becomes true.<br> # - days_since_noncurrent_time - (Optional) Relevant only for versioned objects. Number of days elapsed since the noncurrent timestamp of an object.<br> # - noncurrent_time_before - (Optional) Relevant only for versioned objects. The date in RFC 3339 (e.g. 2017-06-13) when the object became nonconcurrent.<br> condition = object({<br> age = optional(number)<br> send_age_if_zero = optional(bool)<br> created_before = optional(string)<br> with_state = optional(string)<br> matches_storage_class = optional(string)<br> matches_prefix = optional(string)<br> matches_suffix = optional(string)<br> num_newer_versions = optional(number)<br> custom_time_before = optional(string)<br> days_since_custom_time = optional(number)<br> days_since_noncurrent_time = optional(number)<br> noncurrent_time_before = optional(string)<br> })<br> }))</pre> | `[]` | no |
| location | Bucket location. | `string` | `"EU"` | no |
Expand Down
10 changes: 10 additions & 0 deletions examples/multiple_buckets/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,14 @@ module "cloud_storage" {
default_event_based_hold = {
"one" = true
}

ip_filter = {
"one" = {
mode = "Enabled"
public_network_source = {
allowed_ip_cidr_ranges = ["0.0.0.0/0"]
}
allow_all_service_agent_access = true
}
}
}
8 changes: 8 additions & 0 deletions examples/simple_bucket/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,12 @@ module "bucket" {
retention_policy = {
retention_period = 2
}

ip_filter = {
mode = "Enabled"
public_network_source = {
allowed_ip_cidr_ranges = ["0.0.0.0/0"]
}
allow_all_service_agent_access = true
}
}
25 changes: 25 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,31 @@ resource "google_storage_bucket" "buckets" {
retention_duration_seconds = lookup(soft_delete_policy.value, "retention_duration_seconds", null)
}
}

dynamic "ip_filter" {
for_each = lookup(var.ip_filter, each.value, null) != null ? [lookup(var.ip_filter, each.value)] : []

content {
mode = ip_filter.value.mode
allow_cross_org_vpcs = ip_filter.value.allow_cross_org_vpcs
allow_all_service_agent_access = ip_filter.value.allow_all_service_agent_access

dynamic "public_network_source" {
for_each = ip_filter.value.public_network_source != null ? [ip_filter.value.public_network_source] : []
content {
allowed_ip_cidr_ranges = public_network_source.value.allowed_ip_cidr_ranges
}
}

dynamic "vpc_network_sources" {
for_each = ip_filter.value.vpc_network_sources != null ? ip_filter.value.vpc_network_sources : []
content {
network = vpc_network_sources.value.network
allowed_ip_cidr_ranges = vpc_network_sources.value.allowed_ip_cidr_ranges
}
}
}
}
}

resource "google_storage_bucket_iam_binding" "admins" {
Expand Down
22 changes: 19 additions & 3 deletions metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,22 @@ spec:
description: Soft delete policies to apply. Map of lowercase unprefixed name => soft delete policy. Format is the same as described in provider documentation https://www.terraform.io/docs/providers/google/r/storage_bucket.html#nested_soft_delete_policy
varType: map(any)
defaultValue: {}
- name: ip_filter
description: The IP filter configuration for a bucket. Map of lowercase unprefixed name => ip filter config object. See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#ip_filter-1
varType: |-
map(object({
mode = string
public_network_source = optional(object({
allowed_ip_cidr_ranges = list(string)
}))
vpc_network_sources = optional(list(object({
network = string
allowed_ip_cidr_ranges = list(string)
})))
allow_cross_org_vpcs = optional(bool)
allow_all_service_agent_access = optional(bool)
}))
defaultValue: {}
outputs:
- name: apphub_service_uri
description: URI in CAIS style to be used by Apphub.
Expand Down Expand Up @@ -701,18 +717,18 @@ spec:
roles:
- level: Project
roles:
- roles/resourcemanager.projectIamAdmin
- roles/serviceusage.serviceUsageAdmin
- roles/storage.admin
- roles/iam.serviceAccountAdmin
- roles/iam.serviceAccountUser
- roles/resourcemanager.projectIamAdmin
- roles/serviceusage.serviceUsageAdmin
services:
- cloudresourcemanager.googleapis.com
- iam.googleapis.com
- serviceusage.googleapis.com
- storage.googleapis.com
providerVersions:
- source: hashicorp/google
version: ">= 6.9.0, < 7"
version: ">= 6.37.0, < 8"
- source: hashicorp/random
version: ">= 2.1"
1 change: 1 addition & 0 deletions modules/simple_bucket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Functional examples are included in the
| hierarchical\_namespace | When set to true, hierarchical namespace is enable for this bucket. | `bool` | `false` | no |
| iam\_members | The list of IAM members to grant permissions on the bucket. | <pre>list(object({<br> role = string<br> member = string<br> }))</pre> | `[]` | no |
| internal\_encryption\_config | Configuration for the creation of an internal Google Cloud Key Management Service (KMS) Key for use as Customer-managed encryption key (CMEK) for the GCS Bucket<br> instead of creating one in advance and providing the key in the variable `encryption.default_kms_key_name`.<br> create\_encryption\_key: If `true` a Google Cloud Key Management Service (KMS) KeyRing and a Key will be created<br> prevent\_destroy: Set the prevent\_destroy lifecycle attribute on keys.<br> key\_destroy\_scheduled\_duration: Set the period of time that versions of keys spend in the `DESTROY_SCHEDULED` state before transitioning to `DESTROYED`.<br> key\_rotation\_period: Generate a new key every time this period passes. | <pre>object({<br> create_encryption_key = optional(bool, false)<br> prevent_destroy = optional(bool, false)<br> key_destroy_scheduled_duration = optional(string, null)<br> key_rotation_period = optional(string, "7776000s")<br> })</pre> | `{}` | no |
| ip\_filter | The IP filter configuration for the bucket. Restricts access based on source IP addresses.<br><br>- mode: "Enabled" or "Disabled"<br>- public\_network\_source: (Optional) Configure allowed public internet IP ranges<br>- vpc\_network\_sources: (Optional) Configure allowed VPC networks and IP ranges<br>- allow\_cross\_org\_vpcs: (Optional) Allow VPC networks from different organizations<br>- allow\_all\_service\_agent\_access: (Optional) Allow Google Cloud service agents to access the bucket regardless of IP filtering<br><br>Both public\_network\_source and vpc\_network\_sources can be configured together.<br><br>Example:<pre>ip_filter = {<br> mode = "Enabled"<br> public_network_source = {<br> allowed_ip_cidr_ranges = ["203.0.113.0/24"]<br> }<br> vpc_network_sources = [{<br> network = "projects/my-project/global/networks/my-vpc"<br> allowed_ip_cidr_ranges = ["10.0.0.0/8"]<br> }]<br> allow_cross_org_vpcs = true<br> allow_all_service_agent_access = true<br>}</pre>Limits: Max 200 IP CIDR blocks, 25 VPC networks. May block some Google Cloud services.<br>See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#ip_filter-1 | <pre>object({<br> mode = string<br> public_network_source = optional(object({<br> allowed_ip_cidr_ranges = list(string)<br> }))<br> vpc_network_sources = optional(list(object({<br> network = string<br> allowed_ip_cidr_ranges = list(string)<br> })))<br> allow_cross_org_vpcs = optional(bool)<br> allow_all_service_agent_access = optional(bool)<br> })</pre> | `null` | no |
| labels | A set of key/value label pairs to assign to the bucket. | `map(string)` | `null` | no |
| lifecycle\_rules | The bucket's Lifecycle Rules configuration. | <pre>list(object({<br> # Object with keys:<br> # - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass.<br> # - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule.<br> action = object({<br> type = string<br> storage_class = optional(string)<br> })<br><br> # Object with keys:<br> # - age - (Optional) Minimum age of an object in days to satisfy this condition.<br> # - send_age_if_zero - (Optional) While set true, num_newer_versions value will be sent in the request even for zero value of the field.<br> # - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.<br> # - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY".<br> # - matches_storage_class - (Optional) Storage Class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY.<br> # - matches_prefix - (Optional) One or more matching name prefixes to satisfy this condition.<br> # - matches_suffix - (Optional) One or more matching name suffixes to satisfy this condition<br> # - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition.<br> # - custom_time_before - (Optional) A date in the RFC 3339 format YYYY-MM-DD. This condition is satisfied when the customTime metadata for the object is set to an earlier date than the date used in this lifecycle condition.<br> # - days_since_custom_time - (Optional) Days since the date set in the customTime metadata for the object.<br> # - days_since_noncurrent_time - (Optional) Relevant only for versioned objects. Number of days elapsed since the noncurrent timestamp of an object.<br> # - noncurrent_time_before - (Optional) Relevant only for versioned objects. The date in RFC 3339 (e.g. 2017-06-13) when the object became nonconcurrent.<br> condition = object({<br> age = optional(number)<br> send_age_if_zero = optional(bool)<br> created_before = optional(string)<br> with_state = optional(string)<br> matches_storage_class = optional(string)<br> matches_prefix = optional(string)<br> matches_suffix = optional(string)<br> num_newer_versions = optional(number)<br> custom_time_before = optional(string)<br> days_since_custom_time = optional(number)<br> days_since_noncurrent_time = optional(number)<br> noncurrent_time_before = optional(string)<br> })<br> }))</pre> | `[]` | no |
| location | The location of the bucket. See https://cloud.google.com/storage/docs/locations. | `string` | n/a | yes |
Expand Down
22 changes: 22 additions & 0 deletions modules/simple_bucket/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,28 @@ resource "google_storage_bucket" "bucket" {
retention_duration_seconds = lookup(soft_delete_policy.value, "retention_duration_seconds", null)
}
}

dynamic "ip_filter" {
for_each = var.ip_filter == null ? [] : [var.ip_filter]
content {
mode = ip_filter.value.mode
allow_cross_org_vpcs = ip_filter.value.allow_cross_org_vpcs
allow_all_service_agent_access = ip_filter.value.allow_all_service_agent_access
dynamic "public_network_source" {
for_each = ip_filter.value.public_network_source != null ? [ip_filter.value.public_network_source] : []
content {
allowed_ip_cidr_ranges = public_network_source.value.allowed_ip_cidr_ranges
}
}
dynamic "vpc_network_sources" {
for_each = ip_filter.value.vpc_network_sources != null ? ip_filter.value.vpc_network_sources : []
content {
network = vpc_network_sources.value.network
allowed_ip_cidr_ranges = vpc_network_sources.value.allowed_ip_cidr_ranges
}
}
}
}
}

resource "google_storage_bucket_iam_member" "members" {
Expand Down
45 changes: 44 additions & 1 deletion modules/simple_bucket/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,49 @@ spec:
key_rotation_period = optional(string, "7776000s")
})
defaultValue: {}
- name: ip_filter
description: |
The IP filter configuration for the bucket. Restricts access based on source IP addresses.

- mode: "Enabled" or "Disabled"
- public_network_source: (Optional) Configure allowed public internet IP ranges
- vpc_network_sources: (Optional) Configure allowed VPC networks and IP ranges
- allow_cross_org_vpcs: (Optional) Allow VPC networks from different organizations
- allow_all_service_agent_access: (Optional) Allow Google Cloud service agents to access the bucket regardless of IP filtering

Both public_network_source and vpc_network_sources can be configured together.

Example:
```
ip_filter = {
mode = "Enabled"
public_network_source = {
allowed_ip_cidr_ranges = ["203.0.113.0/24"]
}
vpc_network_sources = [{
network = "projects/my-project/global/networks/my-vpc"
allowed_ip_cidr_ranges = ["10.0.0.0/8"]
}]
allow_cross_org_vpcs = true
allow_all_service_agent_access = true
}
```

Limits: Max 200 IP CIDR blocks, 25 VPC networks. May block some Google Cloud services.
See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#ip_filter-1
varType: |-
object({
mode = string
public_network_source = optional(object({
allowed_ip_cidr_ranges = list(string)
}))
vpc_network_sources = optional(list(object({
network = string
allowed_ip_cidr_ranges = list(string)
})))
allow_cross_org_vpcs = optional(bool)
allow_all_service_agent_access = optional(bool)
})
outputs:
- name: apphub_service_uri
description: URI in CAIS style to be used by Apphub.
Expand Down Expand Up @@ -361,4 +404,4 @@ spec:
- storage.googleapis.com
providerVersions:
- source: hashicorp/google
version: ">= 6.9.0, < 7"
version: ">= 6.37.0, < 8"
46 changes: 46 additions & 0 deletions modules/simple_bucket/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,49 @@ variable "internal_encryption_config" {
})
default = {}
}

variable "ip_filter" {
description = <<EOT
The IP filter configuration for the bucket. Restricts access based on source IP addresses.

- mode: "Enabled" or "Disabled"
- public_network_source: (Optional) Configure allowed public internet IP ranges
- vpc_network_sources: (Optional) Configure allowed VPC networks and IP ranges
- allow_cross_org_vpcs: (Optional) Allow VPC networks from different organizations
- allow_all_service_agent_access: (Optional) Allow Google Cloud service agents to access the bucket regardless of IP filtering

Both public_network_source and vpc_network_sources can be configured together.

Example:
```
ip_filter = {
mode = "Enabled"
public_network_source = {
allowed_ip_cidr_ranges = ["203.0.113.0/24"]
}
vpc_network_sources = [{
network = "projects/my-project/global/networks/my-vpc"
allowed_ip_cidr_ranges = ["10.0.0.0/8"]
}]
allow_cross_org_vpcs = true
allow_all_service_agent_access = true
}
```

Limits: Max 200 IP CIDR blocks, 25 VPC networks. May block some Google Cloud services.
See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#ip_filter-1
EOT
type = object({
mode = string
public_network_source = optional(object({
allowed_ip_cidr_ranges = list(string)
}))
vpc_network_sources = optional(list(object({
network = string
allowed_ip_cidr_ranges = list(string)
})))
allow_cross_org_vpcs = optional(bool)
allow_all_service_agent_access = optional(bool)
})
default = null
}
2 changes: 1 addition & 1 deletion modules/simple_bucket/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ terraform {

google = {
source = "hashicorp/google"
version = ">= 6.9.0, < 8"
version = ">= 6.37.0, < 8"
}
}

Expand Down
Loading