Skip to content

Commit 3331e5e

Browse files
committed
feat(storage): add samples and system tests for GCS bucket IP filtering operations
1 parent e29c4b7 commit 3331e5e

6 files changed

Lines changed: 336 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
function main(bucketName = 'my-bucket') {
18+
// [START storage_delete_ip_filtering_rules]
19+
/**
20+
* TODO(developer): Uncomment the following lines before running the sample.
21+
*/
22+
// The ID of your GCS bucket
23+
// const bucketName = 'your-unique-bucket-name';
24+
25+
// Imports the Google Cloud client library
26+
const {Storage} = require('@google-cloud/storage');
27+
28+
// Creates a client
29+
const storage = new Storage();
30+
31+
async function deleteBucketIpFilterRules() {
32+
// Note: To delete specific rules, you fetch the existing config, filter out the rules, and update.
33+
const [metadata] = await storage.bucket(bucketName).getMetadata();
34+
35+
if (!metadata.ipFilter) {
36+
console.log(`No IP Filter configuration found for bucket ${bucketName}.`);
37+
return;
38+
}
39+
40+
const updatedIpRanges = (
41+
metadata.ipFilter.publicNetworkSource?.allowedIpCidrRanges || []
42+
).filter(range => range !== '8.8.8.8/32');
43+
44+
const updatedIpFilter = {
45+
...metadata.ipFilter,
46+
publicNetworkSource: {
47+
allowedIpCidrRanges: updatedIpRanges,
48+
},
49+
};
50+
51+
const [updatedMetadata] = await storage.bucket(bucketName).setMetadata({
52+
ipFilter: updatedIpFilter,
53+
});
54+
55+
console.log(`Specific IP Filter rules deleted for bucket ${bucketName}.`);
56+
console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2));
57+
}
58+
59+
deleteBucketIpFilterRules().catch(console.error);
60+
// [END storage_delete_ip_filtering_rules]
61+
}
62+
63+
main(...process.argv.slice(2));

storage/disableBucketIpFilter.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
function main(bucketName = 'my-bucket') {
18+
// [START storage_disable_ip_filtering]
19+
/**
20+
* TODO(developer): Uncomment the following lines before running the sample.
21+
*/
22+
// The ID of your GCS bucket
23+
// const bucketName = 'your-unique-bucket-name';
24+
25+
// Imports the Google Cloud client library
26+
const {Storage} = require('@google-cloud/storage');
27+
28+
// Creates a client
29+
const storage = new Storage();
30+
31+
async function disableBucketIpFilter() {
32+
const ipFilter = {
33+
mode: 'Disabled',
34+
};
35+
36+
const [updatedMetadata] = await storage.bucket(bucketName).setMetadata({
37+
ipFilter,
38+
});
39+
40+
console.log(`IP Filter disabled for bucket ${bucketName}.`);
41+
console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2));
42+
}
43+
44+
disableBucketIpFilter().catch(console.error);
45+
// [END storage_disable_ip_filtering]
46+
}
47+
48+
main(...process.argv.slice(2));

storage/enableBucketIpFilter.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
function main(bucketName = 'my-bucket', filterMode = 'Enabled') {
18+
// [START storage_enable_ip_filtering]
19+
/**
20+
* TODO(developer): Uncomment the following lines before running the sample.
21+
*/
22+
// The ID of your GCS bucket
23+
// const bucketName = 'your-unique-bucket-name';
24+
25+
// Imports the Google Cloud client library
26+
const {Storage} = require('@google-cloud/storage');
27+
28+
// Creates a client
29+
const storage = new Storage();
30+
31+
async function enableBucketIpFilter() {
32+
// Note: IP Filter configurations cannot be partially updated.
33+
// We must fetch the existing configuration and modify it, or set a completely new one.
34+
const [metadata] = await storage.bucket(bucketName).getMetadata();
35+
const existingIpFilter = metadata.ipFilter || {
36+
mode: filterMode,
37+
publicNetworkSource: {allowedIpCidrRanges: ['0.0.0.0/0']},
38+
allowCrossOrgVpcs: false,
39+
allowAllServiceAgentAccess: false,
40+
};
41+
42+
// Add a new IP range to publicNetworkSource
43+
const updatedIpRanges =
44+
existingIpFilter.publicNetworkSource?.allowedIpCidrRanges || [];
45+
if (!updatedIpRanges.includes('8.8.8.8/32')) {
46+
updatedIpRanges.push('8.8.8.8/32');
47+
}
48+
49+
const updatedIpFilter = {
50+
...existingIpFilter,
51+
publicNetworkSource: {
52+
allowedIpCidrRanges: updatedIpRanges,
53+
},
54+
};
55+
56+
const [updatedMetadata] = await storage.bucket(bucketName).setMetadata({
57+
ipFilter: updatedIpFilter,
58+
});
59+
60+
console.log(`IP Filter enabled for bucket ${bucketName}.`);
61+
console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2));
62+
}
63+
64+
enableBucketIpFilter().catch(console.error);
65+
// [END storage_enable_ip_filtering]
66+
}
67+
68+
main(...process.argv.slice(2));

storage/getBucketIpFilter.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
function main(bucketName = 'my-bucket') {
18+
// [START storage_get_ip_filtering]
19+
/**
20+
* TODO(developer): Uncomment the following lines before running the sample.
21+
*/
22+
// The ID of your GCS bucket
23+
// const bucketName = 'your-unique-bucket-name';
24+
25+
// Imports the Google Cloud client library
26+
const {Storage} = require('@google-cloud/storage');
27+
28+
// Creates a client
29+
const storage = new Storage();
30+
31+
async function getBucketIpFilter() {
32+
const [metadata] = await storage.bucket(bucketName).getMetadata();
33+
34+
if (metadata.ipFilter) {
35+
console.log(`IP Filter Mode: ${metadata.ipFilter.mode}`);
36+
console.log('IP Filter Configuration:');
37+
console.log(JSON.stringify(metadata.ipFilter, null, 2));
38+
} else {
39+
console.log(`No IP Filter configuration found for bucket ${bucketName}.`);
40+
}
41+
}
42+
43+
getBucketIpFilter().catch(console.error);
44+
// [END storage_get_ip_filtering]
45+
}
46+
47+
main(...process.argv.slice(2));

storage/listBucketIpFilters.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
function main(projectId = 'my-project-id') {
18+
// [START storage_list_buckets_ip_filtering]
19+
/**
20+
* TODO(developer): Uncomment the following lines before running the sample.
21+
*/
22+
// The ID of the project to which the service account belongs
23+
// const projectId = 'my-project-id';
24+
25+
// Imports the Google Cloud client library
26+
const {Storage} = require('@google-cloud/storage');
27+
28+
// Creates a client
29+
const storage = new Storage({projectId});
30+
31+
async function listBucketsIpFiltering() {
32+
const [buckets] = await storage.getBuckets();
33+
34+
for (const bucket of buckets) {
35+
if (bucket.metadata.ipFilter) {
36+
try {
37+
const [metadata] = await storage.bucket(bucket.name).getMetadata();
38+
const ipFilter = metadata.ipFilter;
39+
console.log(`${bucket.name}: IP Filter Mode - ${ipFilter.mode}`);
40+
41+
const publicNetworkSource = ipFilter.publicNetworkSource;
42+
if (publicNetworkSource && publicNetworkSource.allowedIpCidrRanges) {
43+
console.log(' Public Network Allowed IP Ranges:');
44+
publicNetworkSource.allowedIpCidrRanges.forEach(range => {
45+
console.log(` - ${range}`);
46+
});
47+
}
48+
49+
const vpcNetworkSources = ipFilter.vpcNetworkSources;
50+
if (vpcNetworkSources && vpcNetworkSources.length > 0) {
51+
console.log(' VPC Network Sources:');
52+
vpcNetworkSources.forEach(source => {
53+
console.log(` - Network: ${source.network}`);
54+
if (source.allowedIpCidrRanges) {
55+
source.allowedIpCidrRanges.forEach(range => {
56+
console.log(` - ${range}`);
57+
});
58+
}
59+
});
60+
}
61+
} catch (err) {
62+
console.log(
63+
`${bucket.name}: Error fetching IP filter - ${err.message}`
64+
);
65+
}
66+
}
67+
}
68+
}
69+
70+
listBucketsIpFiltering().catch(console.error);
71+
// [END storage_list_buckets_ip_filtering]
72+
}
73+
74+
main(...process.argv.slice(2));

storage/system-test/buckets.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,39 @@ it('should update and then remove bucket encryption enforcement configuration',
141141
const [metadata] = await bucket.getMetadata();
142142
assert.ok(!metadata.encryption);
143143
});
144+
145+
it('should enable the bucket IP filter', () => {
146+
const output = execSync(
147+
`node enableBucketIpFilter.js ${bucketName} Disabled`
148+
);
149+
assert.include(output, `IP Filter enabled for bucket ${bucketName}.`);
150+
assert.include(output, '8.8.8.8/32');
151+
});
152+
153+
it('should get the bucket IP filter', () => {
154+
const output = execSync(`node getBucketIpFilter.js ${bucketName}`);
155+
assert.include(output, 'IP Filter Mode: Disabled');
156+
assert.include(output, '8.8.8.8/32');
157+
});
158+
159+
it('should list the bucket IP filters', () => {
160+
const projectId = process.env.GCLOUD_PROJECT;
161+
const output = execSync(`node listBucketIpFilters.js ${projectId}`);
162+
assert.include(output, `${bucketName}: IP Filter Mode - Disabled`);
163+
assert.include(output, 'Public Network Allowed IP Ranges:');
164+
assert.include(output, '- 8.8.8.8/32');
165+
});
166+
167+
it('should delete specific bucket IP filter rules', () => {
168+
const output = execSync(`node deleteBucketIpFilterRules.js ${bucketName}`);
169+
assert.include(
170+
output,
171+
`Specific IP Filter rules deleted for bucket ${bucketName}.`
172+
);
173+
});
174+
175+
it('should disable the bucket IP filter', () => {
176+
const output = execSync(`node disableBucketIpFilter.js ${bucketName}`);
177+
assert.include(output, `IP Filter disabled for bucket ${bucketName}.`);
178+
assert.include(output, '"mode": "Disabled"');
179+
});

0 commit comments

Comments
 (0)