Cannot deploy public api on Cloud Run using Terraform - google-cloud-platform

Terraform now supports cloud run as documented here,
and I'm trying the example code below.
resource "google_cloud_run_service" "default" {
name = "tftest-cloudrun"
location = "us-central1"
provider = "google-beta"
metadata {
namespace = "my-project-name"
}
spec {
containers {
image = "gcr.io/cloudrun/hello"
}
}
}
Although it deploys the sample hello service with no error, when I access to the auto-generated URL, it returns 403(Forbidden) response.
Is it possible to create public cloud run api using terraform?
(When I'm creating the same service using GUI, GCP provides "Allow unauthenticated invocations" option under "Authentication" section, but there seems to be no equivalent option in terraform document...)

Just add the following code to your terraform script, which will make it publicly accessable
data "google_iam_policy" "noauth" {
binding {
role = "roles/run.invoker"
members = [
"allUsers",
]
}
}
resource "google_cloud_run_service_iam_policy" "noauth" {
location = google_cloud_run_service.default.location
project = google_cloud_run_service.default.project
service = google_cloud_run_service.default.name
policy_data = data.google_iam_policy.noauth.policy_data
}
You can also find this here

Here the deployment is only based on Knative serving spec. Cloud Run managed implements these specs but have its own internal behavior, like role check linked with IAM (not possible with Knative and a K8S cluster, this is replaced by Private/Public service). The namespace on Cloud Run managed is the projectId, a workaround to identify the project for example, not a real K8S namespace.
So, the latest news that I have from Google (I'm Cloud Run Alpha Tester) which tells they are working with Deployment Manager and Terraform for integrating Cloud Run in them. I don't have deadline, sorry.

Related

Clarification Around "Duality" of Service Accounts

I have two Cloud Run services. Service U has Unauthenticated access open to all users. Service R I want the access Restricted so that only Service A can invoke it.
This gist has a pretty succinct implementation using the CLI. My services are configured with Terraform and I'm trying to translate, but also understand:
Based on this I thought I could allow Service R access by Service U by adding U's service account (I added service_account: service-u-sa#abcdefg.iam.gserviceaccount.com to Service U's google_cloud_run_service.spec.service_account_name) in the same way I open up access to all users. Here is allUsers:
resource "google_cloud_run_service" "service_r" {
name = local.service_name
# ... rest of the service definition
}
resource "google_cloud_run_service_iam_member" "run_all_users" {
service = google_cloud_run_service.service_r.name
location = google_cloud_run_service.service_r.location
role = "roles/run.invoker"
member = "allUsers"
depends_on = [
google_cloud_run_service.service_r,
]
}
And I amended it to be for just one service account with:
resource "google_cloud_run_service_iam_member" "run_all_users" {
service = google_cloud_run_service.service_r.name
location = google_cloud_run_service.service_r.location
role = "roles/run.invoker"
member = "serviceAccount:service-u-sa#abcdefg.iam.gserviceaccount.com
depends_on = [
google_cloud_run_service.service_b,
]
}
This does not seem to work.
However, adding a data source that creates a policy does seem to work:
data "google_iam_policy" "access_policy" {
binding {
role = "roles/run.invoker"
members = [
"serviceAccount:service-u-sa#abcdefg.iam.gserviceaccount.com",
]
}
}
resource "google_cloud_run_service_iam_policy" "cloud_run_policy" {
location = google_cloud_run_service.service_r.location
project = google_cloud_run_service.service_r.project
service = google_cloud_run_service.service_r.name
policy_data = data.google_iam_policy.access_policy.policy_data
}
I've read on this SO answer (and elsewhere) that service accounts are identities as well as resources. Is that what is happening here? That is, rather than using the service account service-b-sa#abcdefg.iam.gserviceaccount.com as an identity, I am attaching it to Service R as a "resource"? Is that what a "policy" is in this context? And is there anywhere in the GCR UI where I can see these relationships?
Ok, I will try to clarify the wording and the situation, even if I didn't catch what changed between your 2 latest piece of code.
Duality
Yes, Service Account have duality: they are identity AND resources. And because they are a resource, you can grant on identity on it (especially to perform impersonation).
Access Policy
It's simply a binding between an identity and a role. Then you have to apply that binding to a resource to grant the identity the role on the resource. This trio is an IAM authorization policy, or policy in short.
Service and Service Account
Your question is hard to understand because you mix the Cloud Run service, and the service account.
A Cloud Run service has an identity: the runtime service account.
A Cloud Run service CAN'T have access to another Cloud Run service. But the identity of a Cloud Run service can access another Cloud Run service.
That being said, there is no difference between your 2 latest piece of code. In fact yes, there is a difference but the second definition is much more restrictive than the first one.
In the latest one, you use ....._iam_policy. It means you REPLACE all the policies. In other word, the "access_policy" override all the existing permissions.
In the case before, you use ....._iam_member. It means you simply add a policy to the current resource, without changing the existing ones.
That's why, the result is the same: service-u has the role Invoker on the service_r.
Can you try again? the issue is somewhere else.

(Terraform) Error 403: Cloud Run Admin API has not been used in project 905986752003 before or it is disabled. Enable it by visiting https://console.d

On GCP, I applied this Terraform code below to run the Cloud Run service "renderer":
resource "google_cloud_run_service" "renderer" {
name = "renderer"
location = "asia-northeast1"
template {
spec {
containers {
image = "gcr.io/${var.project_id}/renderer:latest"
}
}
}
}
But I got this error:
Error creating Service: googleapi: Error 403: Cloud Run Admin API has
not been used in project 905986752003 before or it is disabled. Enable
it by visiting
https://console.developers.google.com/apis/api/run.googleapis.com/overview?project=905986752003
then retry. If you enabled this API recently, wait a few minutes for
the action to propagate to our systems and retry.
So, I went to the url https://console.developers.google.com/apis/api/run.googleapis.com/overview?project=905986752003 shown in this error above:
Then, enabled Cloud Run API:
Then, applied this Terraform code again:
resource "google_cloud_run_service" "renderer" {
name = "renderer"
location = "asia-northeast1"
template {
spec {
containers {
image = "gcr.io/${var.project_id}/renderer:latest"
}
}
}
}
Finally, I could run the Cloud Run service "renderer":
Now, I want to enable Cloud Run API with Terraform code:
Is it possible to enable Cloud Run API with Terraform code and if it's possible, how do I enable Cloud Run API with Terraform code?
Yes, it's possible to enable Cloud Run API with Terraform code. So, you need to add this Terraform code:
resource "google_project_service" "cloud_run_api" {
service = "run.googleapis.com"
}
Then, you also need to add "depends_on" block with "google_project_service.cloud_run_api" to wait for Cloud Run API to be enabled:
resource "google_cloud_run_service" "renderer" {
name = "renderer"
location = "asia-northeast1"
template {
spec {
containers {
image = "gcr.io/${var.project_id}/renderer:latest"
}
}
}
depends_on = [ // Here
google_project_service.cloud_run_api
]
}
Otherwise, you will get the same error:
Error creating Service: googleapi: Error 403: Cloud Run Admin API has
not been used in project 905986752003 before or it is disabled. Enable
it by visiting
https://console.developers.google.com/apis/api/run.googleapis.com/overview?project=905986752003
then retry. If you enabled this API recently, wait a few minutes for
the action to propagate to our systems and retry.
This is the full Terrafrom code:
resource "google_project_service" "cloud_run_api" {
service = "run.googleapis.com"
}
resource "google_cloud_run_service" "renderer" {
name = "renderer"
location = "asia-northeast1"
template {
spec {
containers {
image = "gcr.io/${var.project_id}/renderer:latest"
}
}
}
depends_on = [
google_project_service.cloud_run_api
]
}
In addition, you can find the Service name "run.googleapis.com" in the page redirected to after you enable Cloud Run API:
resource "google_project_service" "cloud_run_api" {
service = "run.googleapis.com" // Service name
}
So, after you enable Cloud Run API:
You are redirected to this page:
Then, you can find the Service name "run.googleapis.com" in Details section:

How can I create a project in gcp via terraform?

I am planning to use terraform to deploy to GCP and I have read the instruction on how to set it up:
provider "google" {
project = "{{YOUR GCP PROJECT}}"
region = "us-central1"
zone = "us-central1-c"
}
it requires a project name in the provider configuration. But I am planning to create the project via terraform like below code:
resource "google_project" "my_project" {
name = "My Project"
project_id = "your-project-id"
org_id = "1234567"
}
how can I use terraform without a pre-created project?
Take a look on this tutorial (from Community):
Creating Google Cloud projects with Terraform
This tutorial assumes that you already have a Google Cloud account set up for your organization and that you are allowed to make organization-level changes in the account
First step,for example, is to setup your ENV variables with your Organization ID and your billing account ID which will allow you to create the projects using terraform:
export TF_VAR_org_id=YOUR_ORG_ID
export TF_VAR_billing_account=YOUR_BILLING_ACCOUNT_ID
export TF_ADMIN=${USER}-terraform-admin
export TF_CREDS=~/.config/gcloud/${USER}-terraform-admin.json

Using AWS Terraform How to enable s3 backend authentication with assumed role MFA credentials

I provision AWS resources using Terraform using a python script that call terraform via shell
os.system('terraform apply')
The only way I found to enable terraform authentication, after enabling MFA and assuming a role, is to publish these environment variables:
os.system('export ASSUMED_ROLE="<>:botocore-session-123";
export AWS_ACCESS_KEY_ID="vfdgdsfg";
export AWS_SECRET_ACCESS_KEY="fgbdzf";
export AWS_SESSION_TOKEN="fsrfserfgs";
export AWS_SECURITY_TOKEN="fsrfserfgs"; terraform apply')
This worked OK until I configured s3 as backend, terraform action is performed but before the state can be stored in the bucket I get the standard (very confusing) exception:
Error: error configuring S3 Backend: Error creating AWS session: AssumeRoleTokenProviderNotSetError: assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.
I read this excellent answer explaining that for security and other reasons backend configuration is separate.
Since I don't want to add actual secret keys to source code (as suggested by the post) I tried adding a reference to the profile and when it failed I added the actual keys just to see if it would work, which it didn't.
My working theory is that behind the scenes terraform starts another process which doesn't access or inherit the credential e environment variables.
How do I use s3 backend, with an MFA assumed role?
One must point the backend to the desired profile. In my case the same profile used for the provisioning itself.
Here is a minimal POC
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
backend "s3" {
bucket = "unique-terraform-state-dev"
key = "test"
region = "us-east-2"
profile = "the_role_assumed_in_aws_credentials"
}
}
provider "aws" {
version = "~> 3.0"
region = var.region
}
resource "aws_s3_bucket" "s3_bucket" {
bucket = var.bucket_name
}
I'm reminding that it's run by shell which has these environment variables:
os.system('export ASSUMED_ROLE="<>:botocore-session-123";
export AWS_ACCESS_KEY_ID="vfdgdsfg";
export AWS_SECRET_ACCESS_KEY="fgbdzf";
export AWS_SESSION_TOKEN="fsrfserfgs";
export AWS_SECURITY_TOKEN="fsrfserfgs"; terraform apply')

Need clarification on using Terraform to manage Google Cloud projects

I read this article on using Terraform with GCP:
https://cloud.google.com/community/tutorials/managing-gcp-projects-with-terraform
I almost have it working, but I ran into some issues and wanted some clarification.
I made a terraform admin project, and made a service account in that project with the roles/viewer and roles/storage.admin roles. I then made a bucket in the admin project and use that as the terraform backend storage.
terraform {
backend "gcs" {
bucket = "test-terraform-admin-1"
prefix = "terraform/state"
credentials = "service-account.json"
}
}
I then use that service account to create another project and provision resources in that project:
provider "google" {
alias = "company_a"
credentials = "./service-account.json"
region = "us-east4"
zone = "us-east4-c"
version = "~> 2.12"
}
resource "google_project" "project" {
name = var.project_name
project_id = "${random_id.id.hex}"
billing_account = "${var.billing_account}"
org_id = "${var.org_id}"
}
I thought that it would be sufficient to enable services for the project created with terraform like this:
resource "google_project_service" "container_service" {
project = "${google_project.project.project_id}"
service = "container.googleapis.com"
}
However, I got an error when terraform tried to create my gke cluster:
resource "google_container_cluster" "primary" {
project = "${google_project.project.project_id}"
name = "main-gke-cluster"
node_pool {
....
}
network = "${google_compute_network.vpc_network.self_link}"
}
It said that the container service was not enabled yet for my project, and it referenced the terraform admin project ID (not the project created with the google_project resource!). It seems that I have to enable the services on the terraform admin project in order for the service account to access those services on any projects created by the service account.
In fact, I can get it working without ever enabling the container, servicenetworking, etc. services on the create project as long as they are enabled on the terraform admin project.
Is there some parent/child relationship between the projects where services in one project are inherited by projects created from a service account in the parent project? This seems to be the case, but I cannot find any documentation about this anywhere.
Thanks for listening!
In my company, we created a folder and a service account in this folder. Then, we created a project for terraform and each terraform job use the folder level service account for creating projects and resources into this folder.
As the role and permission are inherited from folder to lower level (folders or projects) we don't have issue to create resources.
I don't if it helps your specific issue, but for us, it solved a lot and simplify the service account management.