0

I want to have a service account on Google Cloud that can only write objects to a specific storage Cloud Storage bucket. I have already created the service account using deployment manager and now try to create a bucket with the requisite bindings

def GenerateConfig(context):
    """Generate configuration for a cloud storage bucket for experiment data."""
    resources = []
    resources.append({
        'type': 'storage.v1.bucket',
        'name': 'mybucket',
        'properties': {
            'predefinedAcl': 'projectPrivate',
            'projection': 'full',
            'location': 'europe-west2',
            'storageClass': 'STANDARD',
            'bindings': {
                'role': 'roles/storage.objectCreator',
                'member': 'serviceAccount:my-service@my-project.iam.gserviceaccount.com',
                }
            }
        })
    return {'resources': resources}

If I create this deployment using deployment manager I can see the new bucket and I can see the bucket associated with the deployment has the bindings

member: serviceAccount:my-service@my-project.iam.gserviceaccount.com
role: roles/storage.objectCreator

However if I use this service account to write a file to this cloud storage bucket it fails with a 403 as:

    "errors": [
      {
        "message": "my-service@my-project.iam.gserviceaccount.com does not have storage.objects.create access to the Google Cloud Storage object.",
        "domain": "global",
        "reason": "forbidden"
      }
    ]

If I then use the policy analyser to see what permissions this service account has it returns nothing. What have I misunderstood? Is it not possible to create a service account that can only access certain buckets or must it have access to all buckets on a project?

LlamaD
  • 382
  • 6
  • 15

1 Answers1

0

In order to give the service account write permissions on a specific bucket, you could run the following command from the GCP shell:

gsutil iam ch MEMBER_TYPE:MEMBER_NAME:IAM_ROLE gs://BUCKET_NAME

In your case, it would be something like this:

MEMBER_TYPE="serviceAccount"
MEMBER_NAME="service-account-name@project-id.iam.gserviceaccount.com"
IAM_ROLE="roles/storage.objectCreator"
BUCKET_NAME="your-bucket-name"

gsutil iam ch $MEMBER_TYPE:$MEMBER_NAME:$IAM_ROLE gs://$BUCKET_NAME

If you want to create a bucket and assign the mentioned role at the same time, you could do the following steps, taking into account this and this:

vm.yaml

imports:
  - path: service-accounts.py
resources:
- type: storage.v1.bucket
  name: test-bucket
  properties:
    project: your-project

Service-account.py

def GenerateConfig(context):
    project_id = context.env['project']
    service_account = context.properties['service-account']

    resources = [
        {
            'name': service_account,
            'type': 'iam.v1.serviceAccount',
            'properties': {
                'accountId': service_account,
                'displayName': service_account,
                'projectId': project_id
            }
        },
        {
            'name': 'bind-iam-policy',
            'type': 'gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding',
            'properties': {
                'resource': storage.v1.bucket,
                'role': 'roles/storage.objectCreator',
                'member': 'serviceAccount:$(ref.' + service_account + '.email)'
            },
            'metadata': {
                'dependsOn': [service_account]
            }
        }
    ]

    return {'resources': resources}

And then run the gcloud deployment-manager command.

MariCruzR
  • 147
  • 8
  • I only want to give the service account write permission to a specific bucket. I really want to avoid giving it read permissions. I wanted to do this via deployment manager rather than the UI since I want to create an automated deployment for my production environment rather than creating service accounts on an ad-hoc basis. – LlamaD Aug 27 '21 at 10:11
  • Edited the comment, based on "want to give the service account write permission to a specific bucket. I really want to avoid giving it read permissions". Tell me if this has worked for you, and if not, let me continue helping you. – MariCruzR Aug 27 '21 at 10:53
  • This does work but I was wanting to solve the problem using deployment manager. If its simply not possible to do it this way then your answer is likely the best solution. – LlamaD Aug 27 '21 at 12:36
  • Okay! Working on that. – MariCruzR Aug 27 '21 at 12:38
  • Edited! Please, give it a look and tell me if it has helped you. – MariCruzR Aug 27 '21 at 13:03
  • If I wanted to do that binding but to a specific resource (i.e a cloud storage bucket) rather than across a full project would I change the resource value in properties to be the name of the storage bucket rather than the project_id? – LlamaD Aug 27 '21 at 14:05
  • Edited both files, now working as intended! Please, review the changes applied to yaml and py. – MariCruzR Aug 27 '21 at 14:36
  • Looks like it can give some trouble if we specify the bucket name twice on the yaml file. Now that it's been corrected, the execution of the DM command returns this – MariCruzR Aug 27 '21 at 14:39
  • NAME TYPE STATE ERRORS INTENT test-bucket-stackoverflow storage.v1.bucket COMPLETED [] – MariCruzR Aug 27 '21 at 14:39
  • Apologies but I'm not sure how to use the yaml and py in tandem. I'm happy to take a look at the error if you can advise. Thanks for all the help so far. – LlamaD Aug 31 '21 at 12:59