Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support impersonated_credentials #3215

Closed
salrashid123 opened this issue Mar 11, 2019 · 8 comments
Closed

Add support impersonated_credentials #3215

salrashid123 opened this issue Mar 11, 2019 · 8 comments

Comments

@salrashid123
Copy link
Contributor

GCP allows for impersonated_credentials which allows one service account to impersonate another.

The usecase is to grant temp access to a resource that is a service account with access instead of explict grant on the target resource

Basically,

  • i run terrafrom in projectA with svcA.
  • svcA does not have any permissions on your projectB
  • you create a svcB and provide it permissions on your resources in projectB
  • you grant serviceA the ability to impersonate B
  • now the terraform i run has temp access to create/modify the resource in projectB in addition to whatever i had on projectA
  • (vs you granting individual permissions on resources in projectB to svcA)

I had an offline chat with the google team and this isn't the best practice in how terraform is used. I'm still filing this FR to document this process and see if anyone has legit usecases for this (also because the PR below was almost ready to go and works!)

#3211

(i'll cancel this PR out but revive it if there are legit uscases and need)


ref:

@yhuang
Copy link

yhuang commented Mar 11, 2019

@rileykarson @ndmckinley : The workflow we are trying to enhance is this one. Right now GCP users can set the environment variable GOOGLE_OAUTH_ACCESS_TOKEN to enable a Terraform workflow that leverages the short-lived OAuth token; however, we would still need to provision a long-term key for GCS backend authentication, since the OAuth token support is not extended there. GCP service accounts map very well to AWS roles, so for your multi-cloud customers who assume specific roles in order to run high-impact operations in Terraform, service account impersonation may be a good way to go.

@chrisst
Copy link
Contributor

chrisst commented Mar 12, 2019

I'm going to try and summarize to see if I'm understanding you correctly: this is a workflow that allows an SRE to impersonate a more powerful service account temporarily so that they can run terraform commands locally under the scope of the service account? This would give them the ability to troubleshoot why a particular command is failing during an automated run of CI by tweak a config locally. The user will have access to a low privilege service account to be able to use a config with remote state and then use that account to request an expiring oauth token from the high privilege account. You would then capture the output into the local environment variable GOOGLE_OAUTH_ACCESS_TOKEN in order to run commands.

If that isn't what you're trying to accomplish let me know, otherwise my follow up questions are:

  • If you could use gcloud to pull the temporary credentials does Terraform provide any benefit?
  • Would you need this workflow if a user could impersonate without using the first service account and the oauth credentials gave access to the remote state?

@rileykarson
Copy link
Collaborator

rileykarson commented Mar 12, 2019

Thinking out loud, I'd imagine that if we support this we'd support it inside of the provider block rather than exporting an access token in a resource? I'm not sure what my thoughts on the feature are though, since users with complex logins such as this can feed an access token in directly.

@salrashid123
Copy link
Contributor Author

salrashid123 commented Mar 12, 2019

@rileykarson : correct, i 'd much rather have some way to not recreate a provider and just pass an access_token in directly. I started looking to see if there was anyway terraform allowed property overrides that were inherited (eg, from the provider). i didnt find that but did come across this stuff about setting it directly to a provider (it isnt' as clean as i'd like but it worked).

@chrisst The idea is really to control the capabiity of the terraform service account thats doing the management. Suppose Terraform runs as service_account A to do management on Projects (A,B,C). I own projectZ but i dont' want to grant service_account_A permanent access and even if i do, restrict access in my project to Resource R1,R2. What i'd do is create a service_account_Z and grant impersonation to service_accoount_A for 2hours at 1->3pm (for example). Then the terraform script will only have access to do stuff on my project under strict conditions i set.

provider "google" {}

data "google_client_config" "default" {
  provider = "google"
}

data "google_impersonated_credential" "default" {
 provider = "google"
 target_service_account = "[email protected]"
 scopes = ["devstorage.read_only", "cloud-platform"]
 lifetime = "300s"
}

provider "google" {
   alias  = "impersonated"
   access_token = "${data.google_impersonated_credential.default.access_token}"
}

data "google_project" "project" {
  provider = "google.impersonated"
  project_id = "target-project"
}

/cc @yhuang

@chrisst
Copy link
Contributor

chrisst commented Mar 15, 2019

This has sparked a lot of conversation on the team which is why we've taken a bit of time to get back to you, but I'll try and summarize our stance at this point.

We are hesitant to add this functionality because at first glance it feels like it adds an additional layer of security but when implemented frivolously it doesn't provide any extra security. It could also be implemented in a way that terraform would be unable to manage the resources that it has provisioned adequately leading to infrastructure drift. If somebody is looking to add security to their Terraform installations then there are other options which have fewer sharp edges such as using Vault to manage credential access.

However we acknowledge that when used judiciously this can provide a benefit and isn't explicitly wrong. We know we won't be able to anticipate all real world use cases so we're ok with providing functionality that could be used poorly as long as we provide guidance on what the better solutions are for individuals who stumble across it.

I'll review the PR when I get some cycles and we'll try and get it merged in when it's passing builds/tests.

@bcadiot
Copy link
Contributor

bcadiot commented Mar 15, 2019

It's a much needed functionality ! I have been waiting such a thing for a long time.
Currently managing credentials is a pain because you can't rely on gcloud authentication (not all apis are supported), and using a keyfile from an authorized service account leads to share the same key for everyone (which is very problematic when someone leave the team).

To solve this the options I used to is (tell me if you you see another) :

  • Using a bastion which hold credentials
  • Using a sharing solution like Atlantis
  • Using Vault to generate temporary credentials
  • Create a custom script to generate impersonated credentials

Adding this last option directly in the provider can solve many problems and provide the same mechanism than AWS AssumeRole.

By the way, concerning the proposed implementation I would prefer (if possible) a single provider declaration instead of the declaration of an intermediary datasource between the first and the second provider.
For example in AWS we can simply configure the provider to assume an elevated role :

provider "aws" {
  region  = "eu-west-3"
  version = "~> 1.60"

  assume_role {
    role_arn     = "arn:aws:iam::${var.account_id}:role/OrgAdmin"
  }
}

In the same way can we integrate the impersonation directly in the GCP provider ?

provider "google" {
  region  = "europe-west1"
  version = "~> 2.0"

  impersonation {
    target_service_account = "[email protected]"
    scopes = ["devstorage.read_only", "cloud-platform"]
    lifetime = "300s"
  }
}

@chrisst
Copy link
Contributor

chrisst commented Apr 3, 2019

Fixed by #3357

@chrisst chrisst closed this as completed Apr 3, 2019
@ghost
Copy link

ghost commented May 4, 2019

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks!

@ghost ghost locked and limited conversation to collaborators May 4, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants