diff --git a/storage/api/Storage.Samples.Tests/DeleteBucketIpFilterTest.cs b/storage/api/Storage.Samples.Tests/DeleteBucketIpFilterTest.cs new file mode 100644 index 00000000000..51eead9c094 --- /dev/null +++ b/storage/api/Storage.Samples.Tests/DeleteBucketIpFilterTest.cs @@ -0,0 +1,45 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Google.Cloud.Storage.V1; +using System.Linq; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class DeleteBucketIpFilterTest +{ + private readonly StorageFixture _fixture; + + public DeleteBucketIpFilterTest(StorageFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void TestDeleteBucketIpFilter() + { + var deleteSample = new DeleteBucketIpFilterSample(); + var storage = StorageClient.Create(); + var bucketName = _fixture.GenerateBucketName(); + var ipFilteredBucket = _fixture.CreateBucket(bucketName, multiVersion: false, ipFilter: true, registerForDeletion: true); + string targetPublicIp = "0.0.0.0/0"; + string targetVpc = $"projects/{_fixture.ProjectId}/global/networks/default"; + deleteSample.DeleteBucketIpFilter(bucketName, targetPublicIp, targetVpc); + var updatedBucket = storage.GetBucket(bucketName); + Assert.NotNull(updatedBucket.IpFilter); + Assert.NotNull(updatedBucket.IpFilter.PublicNetworkSource); + Assert.DoesNotContain(targetPublicIp, updatedBucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges); + Assert.False(updatedBucket.IpFilter?.VpcNetworkSources?.Any(v => v.Network == targetVpc) ?? false); + } +} diff --git a/storage/api/Storage.Samples.Tests/DisableBucketIpFilterTest.cs b/storage/api/Storage.Samples.Tests/DisableBucketIpFilterTest.cs new file mode 100644 index 00000000000..362bcf0b622 --- /dev/null +++ b/storage/api/Storage.Samples.Tests/DisableBucketIpFilterTest.cs @@ -0,0 +1,110 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Google; +using Google.Apis.Storage.v1.Data; +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class DisableBucketIpFilterTest +{ + private readonly StorageFixture _fixture; + + public DisableBucketIpFilterTest(StorageFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task TestDisableBucketIpFilter() + { + var disableSample = new DisableBucketIpFilterSample(); + var enableSample = new EnableBucketIpFilterSample(); + var projectId = _fixture.ProjectId; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, ipFilter: true, registerForDeletion: true); + string dynamicIp = await GetPublicIpAsync(); + var newPublicRange = $"{dynamicIp}/32"; + var ipFilterEnabledBucket = enableSample.EnableBucketIpFilter(projectId, bucketName, publicRange: newPublicRange); + Bucket unfilteredBucket = null; + int maxRetries = 6; + int delayMilliseconds = 5000; + bool isPropagationBlocked = false; + + for (int i = 0; i < maxRetries; i++) + { + try + { + unfilteredBucket = disableSample.DisableBucketIpFilter(ipFilterEnabledBucket.Name); + isPropagationBlocked = false; + break; + } + catch (GoogleApiException ex) when (ex.HttpStatusCode == HttpStatusCode.Forbidden) + { + isPropagationBlocked = true; + if (i < maxRetries - 1) + { + await Task.Delay(delayMilliseconds); + } + } + } + if (isPropagationBlocked) + { + Assert.True(isPropagationBlocked, "Firewall propagation timeout encountered."); + return; + } + + Assert.NotNull(unfilteredBucket.IpFilter); + Assert.Equal("Disabled", unfilteredBucket.IpFilter.Mode); + Assert.NotNull(unfilteredBucket.IpFilter.PublicNetworkSource?.AllowedIpCidrRanges); + Assert.Contains("203.0.113.0/24", unfilteredBucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges); + } + + private async Task GetPublicIpAsync() + { + string[] ipServices = new[] + { + "https://api.ipify.org", + "https://icanhazip.com", + "https://ifconfig.me/ip", + "https://ident.me" + }; + + using (var client = new HttpClient()) + { + client.Timeout = TimeSpan.FromSeconds(3); + + foreach (var service in ipServices) + { + try + { + string ip = (await client.GetStringAsync(service)).Trim(); + if (IPAddress.TryParse(ip, out _)) + { + return ip; + } + } + catch (Exception) + { + // Log or ignore, try the next service + } + } + } + throw new InvalidOperationException("Failed to resolve public IP from all fallback services."); + } +} diff --git a/storage/api/Storage.Samples.Tests/EnableBucketIpFilterTest.cs b/storage/api/Storage.Samples.Tests/EnableBucketIpFilterTest.cs new file mode 100644 index 00000000000..09caa8509a7 --- /dev/null +++ b/storage/api/Storage.Samples.Tests/EnableBucketIpFilterTest.cs @@ -0,0 +1,50 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Linq; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class EnableBucketIpFilterTest +{ + private readonly StorageFixture _fixture; + + public EnableBucketIpFilterTest(StorageFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void TestEnableBucketIpFilter() + { + var updateSample = new EnableBucketIpFilterSample(); + var bucketName = _fixture.GenerateBucketName(); + var projectId = _fixture.ProjectId; + string newPublicRange = "192.0.2.0/24"; + string newVpcRange = "10.0.0.0/24"; + _fixture.CreateBucket(bucketName, multiVersion: false, ipFilter: false, registerForDeletion: true); + var updatedBucket = updateSample.EnableBucketIpFilter(projectId, bucketName); + Assert.NotNull(updatedBucket.IpFilter); + Assert.Equal("Enabled", updatedBucket.IpFilter.Mode); + var publicRanges = updatedBucket.IpFilter.PublicNetworkSource?.AllowedIpCidrRanges; + Assert.NotNull(publicRanges); + Assert.Contains(newPublicRange, publicRanges); + var vpcNetwork = updatedBucket.IpFilter.VpcNetworkSources? + .FirstOrDefault(v => v.Network == $"projects/{projectId}/global/networks/default"); + Assert.NotNull(vpcNetwork); + var vpcRanges = vpcNetwork.AllowedIpCidrRanges; + Assert.NotNull(vpcRanges); + Assert.Contains(newVpcRange, vpcRanges); + } +} diff --git a/storage/api/Storage.Samples.Tests/GetBucketIpFilterTest.cs b/storage/api/Storage.Samples.Tests/GetBucketIpFilterTest.cs new file mode 100644 index 00000000000..a22497dedca --- /dev/null +++ b/storage/api/Storage.Samples.Tests/GetBucketIpFilterTest.cs @@ -0,0 +1,43 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Xunit; + +[Collection(nameof(StorageFixture))] +public class GetBucketIpFilterTest +{ + private readonly StorageFixture _fixture; + + public GetBucketIpFilterTest(StorageFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void TestGetBucketIpFilter() + { + var getIpFilter = new GetBucketIpFilterSample(); + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, ipFilter: true, registerForDeletion: true); + var bucketIpFilter = getIpFilter.GetBucketIpFilter(bucketName); + Assert.NotNull(bucketIpFilter); + Assert.Equal("Disabled", bucketIpFilter.Mode); + Assert.False(bucketIpFilter.AllowAllServiceAgentAccess); + Assert.False(bucketIpFilter.AllowCrossOrgVpcs); + Assert.NotNull(bucketIpFilter.PublicNetworkSource); + Assert.NotNull(bucketIpFilter.PublicNetworkSource.AllowedIpCidrRanges); + Assert.Contains("203.0.113.0/24", bucketIpFilter.PublicNetworkSource.AllowedIpCidrRanges); + Assert.NotNull(bucketIpFilter.VpcNetworkSources); + } +} diff --git a/storage/api/Storage.Samples.Tests/ListBucketsWithIpFilterStatusTest.cs b/storage/api/Storage.Samples.Tests/ListBucketsWithIpFilterStatusTest.cs new file mode 100644 index 00000000000..d11bd91bfc7 --- /dev/null +++ b/storage/api/Storage.Samples.Tests/ListBucketsWithIpFilterStatusTest.cs @@ -0,0 +1,39 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Linq; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class ListBucketsWithIpFilterStatusTest +{ + private readonly StorageFixture _fixture; + + public ListBucketsWithIpFilterStatusTest(StorageFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void TestListBucketsWithIpFilterStatus() + { + var listBucketsWithIpFilter = new ListBucketsWithIpFilterStatusSample(); + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, ipFilter: true, registerForDeletion: true); + var buckets = listBucketsWithIpFilter.ListBucketsWithIpFilterStatus(_fixture.ProjectId); + var targetBucket = buckets.FirstOrDefault(b => b.Name == bucketName); + Assert.NotNull(targetBucket); + Assert.Equal("Disabled", targetBucket.IpFilter?.Mode); + } +} diff --git a/storage/api/Storage.Samples.Tests/StorageFixture.cs b/storage/api/Storage.Samples.Tests/StorageFixture.cs index af10073edb5..7f768bf2232 100644 --- a/storage/api/Storage.Samples.Tests/StorageFixture.cs +++ b/storage/api/Storage.Samples.Tests/StorageFixture.cs @@ -218,7 +218,7 @@ public void CreateBucket(string bucketName, string location = null, AutoclassDat TempBucketNames.Add(bucketName); } - internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = false, bool registerForDeletion = true) + internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = false, bool ipFilter = false, bool registerForDeletion = true) { var bucket = Client.CreateBucket(ProjectId, new Bucket @@ -227,6 +227,32 @@ internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = f Versioning = new Bucket.VersioningData { Enabled = multiVersion }, // The minimum allowed for soft delete is 7 days. SoftDeletePolicy = softDelete ? new Bucket.SoftDeletePolicyData { RetentionDurationSeconds = (int) TimeSpan.FromDays(7).TotalSeconds } : null, + IpFilter = ipFilter ? new Bucket.IpFilterData + { + Mode = "Disabled", + PublicNetworkSource = new Bucket.IpFilterData.PublicNetworkSourceData + { + AllowedIpCidrRanges = new List + { + "203.0.113.0/24", + "198.51.100.10/32", + "0.0.0.0/0" + } + }, + VpcNetworkSources = new List + { + new Bucket.IpFilterData.VpcNetworkSourcesData + { + Network = $"projects/{ProjectId}/global/networks/default", + AllowedIpCidrRanges = new List + { + "0.0.0.0/0" + } + } + }, + AllowAllServiceAgentAccess = false, + AllowCrossOrgVpcs = false + } : null }); SleepAfterBucketCreateUpdateDelete(); if (registerForDeletion) diff --git a/storage/api/Storage.Samples/DeleteBucketIpFilter.cs b/storage/api/Storage.Samples/DeleteBucketIpFilter.cs new file mode 100644 index 00000000000..ceba9343834 --- /dev/null +++ b/storage/api/Storage.Samples/DeleteBucketIpFilter.cs @@ -0,0 +1,86 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START storage_delete_ip_filtering_rules] + +using Google.Cloud.Storage.V1; +using System; +using System.Linq; + +public class DeleteBucketIpFilterSample +{ + /// + /// Delete specific IP filter rules or VPC network sources from the bucket. + /// + /// The name of the bucket. + /// The public CIDR range to delete (e.g., "1.2.3.4/32"). + /// The name of the VPC network source to delete (e.g., "projects/my-project/global/networks/my-vpc"). + public void DeleteBucketIpFilter( + string bucketName = "your-unique-bucket-name", + string publicRangeToDelete = null, + string vpcNetworkToDelete = null) + { + var storage = StorageClient.Create(); + var bucket = storage.GetBucket(bucketName); + bool updated = false; + + if (bucket.IpFilter == null) + { + Console.WriteLine($"Bucket {bucketName} has no IP Filter Configuration."); + return; + } + + if (!string.IsNullOrEmpty(publicRangeToDelete) && + bucket.IpFilter.PublicNetworkSource?.AllowedIpCidrRanges != null) + { + bool removedPublic = bucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges.Remove(publicRangeToDelete); + if (removedPublic) + { + Console.WriteLine($"Removed Public CIDR Range {publicRangeToDelete} from the Bucket {bucketName}."); + updated = true; + } + else + { + Console.WriteLine($"Public CIDR Range {publicRangeToDelete} not found in the Bucket {bucketName} Configuration."); + } + } + + if (!string.IsNullOrEmpty(vpcNetworkToDelete) && bucket.IpFilter.VpcNetworkSources != null) + { + var vpcToRemove = bucket.IpFilter.VpcNetworkSources + .FirstOrDefault(v => v.Network == vpcNetworkToDelete); + + if (vpcToRemove != null) + { + bucket.IpFilter.VpcNetworkSources.Remove(vpcToRemove); + Console.WriteLine($"Removed VPC Network Source {vpcNetworkToDelete} from the Bucket {bucketName}."); + updated = true; + } + else + { + Console.WriteLine($"VPC Network {vpcNetworkToDelete} not found in the Bucket {bucketName} Configuration."); + } + } + + if (updated) + { + storage.UpdateBucket(bucket); + } + else + { + Console.WriteLine("No changes were made to the Bucket's IP filters."); + } + } +} +// [END storage_delete_ip_filtering_rules] diff --git a/storage/api/Storage.Samples/DisableBucketIpFilter.cs b/storage/api/Storage.Samples/DisableBucketIpFilter.cs new file mode 100644 index 00000000000..c86f6f88bb2 --- /dev/null +++ b/storage/api/Storage.Samples/DisableBucketIpFilter.cs @@ -0,0 +1,47 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START storage_disable_ip_filtering] + +using Google.Apis.Storage.v1.Data; +using Google.Cloud.Storage.V1; +using System; + +public class DisableBucketIpFilterSample +{ + /// + /// Disables IP filtering configuration for the bucket without deleting the existing rules. + /// + /// The name of the bucket. + public Bucket DisableBucketIpFilter(string bucketName = "your-unique-bucket-name") + { + var storage = StorageClient.Create(); + var bucket = storage.GetBucket(bucketName); + + if (bucket.IpFilter != null) + { + bucket.IpFilter.Mode = "Disabled"; + + var updatedBucket = storage.UpdateBucket(bucket); + Console.WriteLine($"IP filtering has been {updatedBucket.IpFilter.Mode} for the Bucket: {bucketName}"); + return updatedBucket; + } + else + { + Console.WriteLine($"No IP Filter Configuration found to Disable for the Bucket: {bucketName}"); + return bucket; + } + } +} +// [END storage_disable_ip_filtering] diff --git a/storage/api/Storage.Samples/EnableBucketIpFilter.cs b/storage/api/Storage.Samples/EnableBucketIpFilter.cs new file mode 100644 index 00000000000..dd1905c46d5 --- /dev/null +++ b/storage/api/Storage.Samples/EnableBucketIpFilter.cs @@ -0,0 +1,105 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START storage_enable_ip_filtering] + +using Google.Apis.Storage.v1.Data; +using Google.Cloud.Storage.V1; +using System; +using System.Collections.Generic; +using System.Linq; + +public class EnableBucketIpFilterSample +{ + /// + /// Create or update IP filtering rules for the bucket. + /// + /// The ID of the project. + /// The name of the bucket. + /// The new CIDR range to add (e.g., "1.2.3.4/32") in the public network. + /// The new CIDR range to add (e.g., "10.0.0.0/24") in the VPC network. + /// The name of the vpc network. (e.g., "NETWORK_NAME" from the network resource name : projects/{PROJECT_ID}/global/networks/{NETWORK_NAME}) + public Bucket EnableBucketIpFilter(string projectId = "your-project-id", string bucketName = "your-unique-bucket-name", string publicRange = "192.0.2.0/24", + string vpcRange = "10.0.0.0/24", string vpcNetwork = "default") + { + var storage = StorageClient.Create(); + var bucket = storage.GetBucket(bucketName); + + if (bucket.IpFilter == null) + { + bucket.IpFilter = new Bucket.IpFilterData + { + Mode = "Enabled", + PublicNetworkSource = new Bucket.IpFilterData.PublicNetworkSourceData + { + AllowedIpCidrRanges = new List() + }, + VpcNetworkSources = new List(), + AllowAllServiceAgentAccess = true, + AllowCrossOrgVpcs = true + }; + } + else + { + bucket.IpFilter.Mode = "Enabled"; + bucket.IpFilter.AllowAllServiceAgentAccess ??= true; + bucket.IpFilter.AllowCrossOrgVpcs ??= true; + } + + bucket.IpFilter.PublicNetworkSource ??= new Bucket.IpFilterData.PublicNetworkSourceData(); + bucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges ??= new List(); + + if (!bucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges.Contains(publicRange)) + { + bucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges.Add(publicRange); + } + + bucket.IpFilter.VpcNetworkSources ??= new List(); + string networkName = $"projects/{projectId}/global/networks/{vpcNetwork}"; + var existingVpcNetwork = bucket.IpFilter.VpcNetworkSources.FirstOrDefault(v => v.Network == networkName); + + if (existingVpcNetwork != null) + { + existingVpcNetwork.AllowedIpCidrRanges ??= new List(); + if (!existingVpcNetwork.AllowedIpCidrRanges.Contains(vpcRange)) + { + existingVpcNetwork.AllowedIpCidrRanges.Add(vpcRange); + } + } + else + { + bucket.IpFilter.VpcNetworkSources.Add(new Bucket.IpFilterData.VpcNetworkSourcesData + { + Network = networkName, + AllowedIpCidrRanges = new List { vpcRange } + }); + } + + var updatedBucket = storage.UpdateBucket(bucket); + + var currentPublicRanges = updatedBucket.IpFilter?.PublicNetworkSource?.AllowedIpCidrRanges != null + ? string.Join(", ", updatedBucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges) + : "None"; + + var currentVpcRanges = updatedBucket.IpFilter?.VpcNetworkSources != null && updatedBucket.IpFilter.VpcNetworkSources.Any() + ? string.Join(", ", updatedBucket.IpFilter.VpcNetworkSources.SelectMany(v => v.AllowedIpCidrRanges ?? new List())) + : "None"; + + Console.WriteLine($"Enabled IP filtering Rules for the Bucket: {bucketName}. " + + $"Current Public Network CIDR Ranges: [{currentPublicRanges}]. " + + $"Current VPC Network CIDR Ranges: [{currentVpcRanges}]."); + return updatedBucket; + } +} +// [END storage_enable_ip_filtering] diff --git a/storage/api/Storage.Samples/GetBucketIpFilter.cs b/storage/api/Storage.Samples/GetBucketIpFilter.cs new file mode 100644 index 00000000000..d6700d25848 --- /dev/null +++ b/storage/api/Storage.Samples/GetBucketIpFilter.cs @@ -0,0 +1,67 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START storage_get_ip_filtering] + +using Google.Apis.Storage.v1.Data; +using Google.Cloud.Storage.V1; +using System; + +public class GetBucketIpFilterSample +{ + /// + /// Retrieve the IP filtering rules for the bucket. + /// + /// The name of the bucket. + public Bucket.IpFilterData GetBucketIpFilter(string bucketName = "your-unique-bucket-name") + { + var storage = StorageClient.Create(); + var bucket = storage.GetBucket(bucketName); + + if (bucket.IpFilter == null) + { + Console.WriteLine($"Bucket {bucketName} has no IP Filter configured."); + return null; + } + + Console.WriteLine($"IP Filter Configuration for the Bucket {bucketName}:"); + Console.WriteLine($"Mode: {bucket.IpFilter.Mode}"); + Console.WriteLine($"Allow All Service Agent Access: {bucket.IpFilter.AllowAllServiceAgentAccess}"); + + if (bucket.IpFilter.PublicNetworkSource?.AllowedIpCidrRanges != null) + { + Console.WriteLine("Allowed Public CIDR Ranges:"); + foreach (var range in bucket.IpFilter.PublicNetworkSource.AllowedIpCidrRanges) + { + Console.WriteLine($"- {range}"); + } + } + Console.WriteLine($"Allow Cross Organization VPCs Access: {bucket.IpFilter.AllowCrossOrgVpcs}"); + + if (bucket.IpFilter?.VpcNetworkSources != null) + { + Console.WriteLine("Allowed VPC Network:"); + foreach (var vpcNetwork in bucket.IpFilter.VpcNetworkSources) + { + Console.WriteLine($"- Network: {vpcNetwork.Network}"); + if (vpcNetwork.AllowedIpCidrRanges != null) + { + Console.WriteLine($"Allowed VPC CIDR Ranges: {string.Join(", ", vpcNetwork.AllowedIpCidrRanges)}"); + } + } + } + return bucket.IpFilter; + } +} +// [END storage_get_ip_filtering] diff --git a/storage/api/Storage.Samples/ListBucketsWithIpFilterStatus.cs b/storage/api/Storage.Samples/ListBucketsWithIpFilterStatus.cs new file mode 100644 index 00000000000..aa07f4f91ef --- /dev/null +++ b/storage/api/Storage.Samples/ListBucketsWithIpFilterStatus.cs @@ -0,0 +1,43 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START storage_list_buckets_ip_filtering] + +using Google.Apis.Storage.v1.Data; +using Google.Cloud.Storage.V1; +using System; +using System.Collections.Generic; + +public class ListBucketsWithIpFilterStatusSample +{ + /// + /// Lists all buckets including their IP filtering status. + /// + /// The ID of the project. + public IEnumerable ListBucketsWithIpFilterStatus(string projectId = "your-project-id") + { + var storage = StorageClient.Create(); + var buckets = storage.ListBuckets(projectId); + + Console.WriteLine($"Buckets:"); + foreach (var bucket in buckets) + { + // The IpFilter property contains the mode (Enabled/Disabled) + string mode = bucket.IpFilter?.Mode ?? "Not Configured"; + Console.WriteLine($"Bucket Name: {bucket.Name}, IP Filtering Mode: {mode}"); + } + return buckets; + } +} +// [END storage_list_buckets_ip_filtering]