GoogleCloudPlatform / cloud-run-button

Let anyone deploy your GitHub repos to Google Cloud Run with a single click
https://cloud.run
Apache License 2.0
527 stars 92 forks source link

Allow app.json to list required IAM roles #33

Open ahmetb opened 5 years ago

ahmetb commented 5 years ago

This feature would allow users to run with non-default service accounts created just for that application.

@mchmarny said that the default Run app identity doesn't have enough permissions to create a PubSub topic to one-click-deploy his app. (Ideally it should, since GCE default svc account has Editor role, so I'll investigate that separately).

But if we needed this someday, the strawman design would be like:

app.json:

{ 
  "roles": [
     "roles/storage.objectAdmin",
     "roles/pubsub.subscriber"
  ]
}

When this field specifies, we should prompt the user with a confirmation saying a "service account with permissions [..., ...] will be created or re-used by the deployed application".

Then we would create a Cloud IAM Service Account that has the same name as the Run app name. (It would assign the listed roles on the project-level to that service account. It wouldn't remove extra role bindings that are already there, as they may be added by the user.)

If the account exists, we should have a way of verifying it was created by cloud-run-button (somehow through a marker). If so, we can reuse it (by making sure the role bindings listed in app.json exist).

But I'm not sure if we need this feature just yet, since technically GCE Default Service Account is an Editor and it should be able to bootstrap its needs just fine.

mchmarny commented 5 years ago

I was able to confirm that the default GCE service account has sufficient rights to create pubsub topics. Enabling declarative permission requests ala Android is still a good idea though

jlandure commented 4 years ago

Hi @ahmetb 👋

This feature is exactly what I'm looking for. 👍

I wrote a short tutorial on "How to backup your Firestore data automatically" and it uses Cloud Run to perform the task with Cloud Scheduler.

I've investigated to implement the Cloud Run Button to facilitate the setup but it still requires a manual step to create an IAM compatible service account and transform the JSON private key into a base64 env var.

How can I help?

ahmetb commented 4 years ago

I think we can implement this if there's more demand. You don't need to add any private keys to your Cloud Run environment, you just need to set the --service-account while deploying.

Mainly the involved design here would be signaling a new service account should be generated (or use an existing one) and how to signal that in the app.json file. Similarly we need a way to reuse the same service account upon redeployment (clicking the button again).

How do you envision Cloud Run Button should ask (1) in the app.json file for a service account (2) how would it ask the deploying user about it (or would it just go create that account and use it automatically without even asking).

ahmetb commented 4 years ago

Since we now have post-{deploy,create} scripts, I'm inclined to defer the "role assignment" responsibility to the scripts, for now. (The main reason for this is that the design can easily cover project-level broad roles, but it can't handle per-resource permissions, which are the best practice.)

I'm thinking a much simpler design, app.json listing a field, like:

serviceAccount: {}

this would signal us that the user "wants" a new service account for their application. The flow now would be:

  1. [prompt usual questions]
  2. Prompt for a new service account name (if service is new)
  3. Create service account (using API) with given name (only project Owners can do this by default, I think)
  4. Deploy the Cloud Run Service with this new --service-account
  5. Pass service account email to {pre,post}-{deploy,create} scripts as SERVICE_ACCOUNT_EMAIL environment variable for binding new IAM permissions/roles.

The design wouldn't handle "pick an existing account" for now, but then, most people deploying with the button are likely to provision per-app SA, so I don't think that's a problem yet.

How's that sound @jamesward?

jamesward commented 4 years ago

One quick thought... if we want it to work on mostly existing machinery we could do:

{
    "env": {
        "SERVICE_ACCOUNT_EMAIL": {
            "description": "Service Account Email",
            "value": "$K_SERVICE@$GCP_PROJECT.iam.gserviceaccount.com",
            "required": true
        }
    },
    "hooks": {
        "precreate": {
            "commands": [
                ".gcloud/create_service_account.sh"
            ]
        }
    },
    "options": {
        "service-account": "$SERVICE_ACCOUNT_EMAIL"
    }

The only missing pieces are:

ahmetb commented 4 years ago

Creating a variable evaluation engine wouldn’t be exactly using the existing machinery.. :) It would be non-trivial to do that, can we avoid?

jamesward commented 4 years ago

It's pretty easy with envsubst (which is in the cloud shell base image):

export K_SERVICE=foo; echo "asdf-$K_SERVICE" | envsubst
ahmetb commented 4 years ago

Yeah I guess we can rely on envsubst. Otherwise we'd be dealing with cases like ${FOO_BAR}_QUUX which is harder to implement. It would be good if we call these with env -i so that the scripts don't pick up anything else from env.