Skip to content

Commit 0bb6cae

Browse files
authored
feat: Add support for allowUnauthenticated and custom IAM definitions
(PR #219)
1 parent ad8cf16 commit 0bb6cae

File tree

2 files changed

+501
-0
lines changed

2 files changed

+501
-0
lines changed

package/lib/compileFunctions.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module.exports = {
2424
validateHandlerProperty(funcObject, functionName);
2525
validateEventsProperty(funcObject, functionName);
2626
validateVpcConnectorProperty(funcObject, functionName);
27+
validateIamProperty(funcObject, functionName);
2728

2829
const funcTemplate = getFunctionTemplate(
2930
funcObject,
@@ -51,6 +52,11 @@ module.exports = {
5152
_.get(this, 'serverless.service.provider.environment'),
5253
funcObject.environment // eslint-disable-line comma-dangle
5354
);
55+
funcTemplate.accessControl.gcpIamPolicy.bindings = _.unionBy(
56+
_.get(funcObject, 'iam.bindings'),
57+
_.get(this, 'serverless.service.provider.iam.bindings'),
58+
'role'
59+
);
5460

5561
if (!funcTemplate.properties.serviceAccountEmail) {
5662
delete funcTemplate.properties.serviceAccountEmail;
@@ -83,6 +89,14 @@ module.exports = {
8389

8490
funcTemplate.properties.httpsTrigger = {};
8591
funcTemplate.properties.httpsTrigger.url = url;
92+
93+
if (funcObject.allowUnauthenticated) {
94+
funcTemplate.accessControl.gcpIamPolicy.bindings = _.unionBy(
95+
[{ role: 'roles/cloudfunctions.invoker', members: ['allUsers'] }],
96+
funcTemplate.accessControl.gcpIamPolicy.bindings,
97+
'role'
98+
);
99+
}
86100
}
87101
if (eventType === 'event') {
88102
const type = funcObject.events[0].event.eventType;
@@ -95,6 +109,10 @@ module.exports = {
95109
funcTemplate.properties.eventTrigger.resource = resource;
96110
}
97111

112+
if (!funcTemplate.accessControl.gcpIamPolicy.bindings.length) {
113+
delete funcTemplate.accessControl;
114+
}
115+
98116
this.serverless.service.provider.compiledConfigurationTemplate.resources.push(funcTemplate);
99117
});
100118

@@ -157,6 +175,29 @@ const validateVpcConnectorProperty = (funcObject, functionName) => {
157175
}
158176
};
159177

178+
const validateIamProperty = (funcObject, functionName) => {
179+
if (_.get(funcObject, 'iam.bindings') && funcObject.iam.bindings.length > 0) {
180+
funcObject.iam.bindings.forEach((binding) => {
181+
if (!binding.role) {
182+
const errorMessage = [
183+
`The function "${functionName}" has no role specified for an IAM binding.`,
184+
' Each binding requires a role. For details on supported roles, see the documentation',
185+
' at: https://cloud.google.com/iam/docs/understanding-roles',
186+
].join('');
187+
throw new Error(errorMessage);
188+
}
189+
if (!Array.isArray(binding.members) || !binding.members.length) {
190+
const errorMessage = [
191+
`The function "${functionName}" has no members specified for an IAM binding.`,
192+
' Each binding requires at least one member to be assigned. See the IAM documentation',
193+
' for details on configuring members: https://cloud.google.com/iam/docs/overview',
194+
].join('');
195+
throw new Error(errorMessage);
196+
}
197+
});
198+
}
199+
};
200+
160201
const getFunctionTemplate = (funcObject, projectName, region, sourceArchiveUrl) => {
161202
//eslint-disable-line
162203
return {
@@ -171,5 +212,10 @@ const getFunctionTemplate = (funcObject, projectName, region, sourceArchiveUrl)
171212
function: funcObject.name,
172213
sourceArchiveUrl,
173214
},
215+
accessControl: {
216+
gcpIamPolicy: {
217+
bindings: [],
218+
},
219+
},
174220
};
175221
};

0 commit comments

Comments
 (0)