diff --git a/package/googlePackage.js b/package/googlePackage.js
index 7fbb0a7..566d34b 100644
--- a/package/googlePackage.js
+++ b/package/googlePackage.js
@@ -10,6 +10,7 @@ const prepareDeployment = require('./lib/prepareDeployment');
 const saveCreateTemplateFile = require('./lib/writeFilesToDisk');
 const mergeServiceResources = require('./lib/mergeServiceResources');
 const generateArtifactDirectoryName = require('./lib/generateArtifactDirectoryName');
+const createIamRoles = require('./lib/createIamRoles');
 const compileFunctions = require('./lib/compileFunctions');
 const saveUpdateTemplateFile = require('./lib/writeFilesToDisk');
 
@@ -54,6 +55,7 @@ class GooglePackage {
       prepareDeployment,
       saveCreateTemplateFile,
       generateArtifactDirectoryName,
+      createIamRoles,
       compileFunctions,
       mergeServiceResources,
       saveUpdateTemplateFile
@@ -72,7 +74,9 @@ class GooglePackage {
           .then(this.saveCreateTemplateFile),
 
       'before:package:compileFunctions': () =>
-        BbPromise.bind(this).then(this.generateArtifactDirectoryName),
+        BbPromise.bind(this)
+          .then(this.generateArtifactDirectoryName)
+          .then(this.createIamRoles),
 
       'package:compileFunctions': () => BbPromise.bind(this).then(this.compileFunctions),
 
diff --git a/package/lib/createIamRoles.js b/package/lib/createIamRoles.js
new file mode 100644
index 0000000..ccf9a20
--- /dev/null
+++ b/package/lib/createIamRoles.js
@@ -0,0 +1,153 @@
+'use strict';
+
+const _ = require('lodash');
+
+module.exports = {
+  createIamRoles() {
+    const provider = this.serverless.service.provider;
+    const iamConfig = provider.iam;
+    if (!iamConfig || !iamConfig.permissions) return;
+
+    if (provider.serviceAccountEmail) {
+      throw new Error('Cannot set both iam permissions and serviceAccountEmail on provider')
+    }
+
+    const projectId = provider.project;
+    const serviceName = `${this.serverless.service.service}-${this.options.stage}`;
+    const serviceAccountName = `sls-${serviceName}`;
+    const serviceAccountEmail = `${serviceAccountName}@${projectId}.iam.gserviceaccount.com`;
+
+    provider.serviceAccountEmail = serviceAccountEmail;
+
+    const deploymentResources =
+      this.serverless.service.provider.compiledConfigurationTemplate.resources;
+
+    // Create Cloud Function identity service account to assign custom IAM roles to
+    deploymentResources.push({
+      type: 'iam.v1.serviceAccount',
+      name: serviceAccountName,
+      properties: {
+        accountId: serviceAccountName,
+        displayName: serviceAccountName,
+        description: `Generated service account for Serverless project ${serviceName}`,
+      },
+    });
+
+    // Collect all permissions that don't apply to a specific resource
+    const [permissions, resourceSpecificRoles] = _.partition(
+      iamConfig.permissions,
+      (item) => typeof item === 'string'
+    );
+
+    // Create and assign custom role for permissions without a resource
+    if (permissions.length > 0) {
+      const iamObject = { permissions, projectId };
+      const role = getCustomRoleTemplate(projectId, serviceName, iamObject);
+      deploymentResources.push(role);
+      deploymentResources.push(
+        getIamMemberTemplate(projectId, serviceAccountEmail, role, iamObject)
+      );
+    }
+
+    // Create and assign custom role(s) for each specific resource
+    resourceSpecificRoles.forEach((iamObject) => {
+      const role = getCustomRoleTemplate(projectId, serviceName, iamObject);
+      deploymentResources.push(role);
+      deploymentResources.push(
+        getIamMemberTemplate(projectId, serviceAccountEmail, role, iamObject)
+      );
+    });
+  },
+};
+
+const ROLE_NAME_MAX_LENGTH = 64;
+const getCustomRoleTemplate = (project, serviceName, config) => {
+  const namePrefix = serviceName.slice(0, 48).replaceAll('-', '_');
+  const nameSuffix = getResourceRoleSuffix(config)
+    .replace(/[^a-zA-Z_]/g, '')
+    .slice(0, ROLE_NAME_MAX_LENGTH - namePrefix.length);
+  const name = `${namePrefix}${nameSuffix}`;
+
+  return {
+    type: 'gcp-types/iam-v1:projects.roles',
+    name,
+    properties: {
+      parent: `projects/${project}`,
+      roleId: name,
+      role: {
+        title: name,
+        description: `Generated IAM role for Serverless project ${serviceName}`,
+        stage: 'GA',
+        includedPermissions: config.permissions,
+      },
+    },
+  };
+};
+
+const getIamMemberTemplate = (project, serviceAccountEmail, role, config) => {
+  const { type, resource } = getIamMembershipResourceType(config);
+
+  return {
+    type,
+    name: `${role.name}_members`,
+    properties: {
+      ...resource,
+      role: `projects/${project}/roles/${role.properties.roleId}`,
+      member: `serviceAccount:${serviceAccountEmail}`,
+    },
+  };
+};
+
+const getResourceRoleSuffix = (config) => {
+  if (config.bucket) return `gcs_${config.bucket}`;
+  if (config.organizationId) return `org_${config.organizationId}`;
+  if (config.folderId) return `fol_${config.folderId}`;
+  if (config.projectId) return `pro_${config.projectId}`;
+  if (config.cloudFunction) return `gcf_${config.cloudFunction}`;
+  return '';
+};
+
+const getIamMembershipResourceType = (config) => {
+  if (config.bucket) {
+    return {
+      type: 'gcp-types/storage-v1:virtual.buckets.iamMemberBinding',
+      resource: {
+        bucket: config.bucket,
+      },
+    };
+  }
+  if (config.organizationId) {
+    return {
+      type: 'gcp-types/cloudresourcemanager-v1:virtual.organizations.iamMemberBinding',
+      resource: {
+        resource: config.organizationId,
+      },
+    };
+  }
+  if (config.folderId) {
+    return {
+      type: 'gcp-types/cloudresourcemanager-v2:virtual.folders.iamMemberBinding',
+      resource: {
+        resource: config.folderId,
+      },
+    };
+  }
+  if (config.projectId) {
+    return {
+      type: 'gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding',
+      resource: {
+        resource: config.projectId,
+      },
+    };
+  }
+  if (config.cloudFunction) {
+    return {
+      type: 'gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding',
+      resource: {
+        resource: config.cloudFunction,
+      },
+    };
+  }
+
+  throw new Error('IAM resource type not supported');
+};
diff --git a/provider/googleProvider.js b/provider/googleProvider.js
index 00bbd85..b0ce62c 100644
--- a/provider/googleProvider.js
+++ b/provider/googleProvider.js
@@ -130,8 +130,50 @@ class GoogleProvider {
           },
           additionalProperties: false,
         },
+        iamCustomRoles: {
+          type: 'object',
+          properties: {
+            permissions: {
+              type: 'array',
+              items: {
+                anyOf: [
+                  {
+                    $ref: '#/definitions/iamPermissionsOnResource',
+                  },
+                  {
+                    type: 'string',
+                  },
+                ],
+              },
+            },
+          },
+          additionalProperties: false,
+        },
+        iamPermissionsOnResource: {
+          type: 'object',
+          properties: {
+            bucket: { type: 'string' },
+            organizationId: { type: 'string' },
+            folderId: { type: 'string' },
+            projectId: { type: 'string' },
+            cloudFunction: { type: 'string' },
+            permissions: {
+              type: 'array',
+              items: {
+                type: 'string',
+              },
+            },
+          },
+          additionalProperties: false,
+          oneOf: [
+            { required: ['bucket', 'permissions'] },
+            { required: ['organizationId', 'permissions'] },
+            { required: ['folderId', 'permissions'] },
+            { required: ['projectId', 'permissions'] },
+            { required: ['cloudFunction', 'permissions'] },
+          ]
+        },
       },
-
       provider: {
         properties: {
           credentials: { type: 'string' },
@@ -146,6 +188,7 @@ class GoogleProvider {
           vpc: { type: 'string' }, // Can be overridden by function configuration
           vpcEgress: { $ref: '#/definitions/cloudFunctionVpcEgress' }, // Can be overridden by function configuration
           labels: { $ref: '#/definitions/resourceManagerLabels' }, // Can be overridden by function configuration
+          iam: { $ref: '#/definitions/iamCustomRoles' },
         },
       },
       function: {