-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add google_impersonated_credential datasource (#1597)
Merged PR #1597.
- Loading branch information
1 parent
65c466e
commit e582f0a
Showing
10 changed files
with
247 additions
and
9 deletions.
There are no files selected for viewing
Submodule terraform
updated
from 4d2ade to 6121d5
Submodule terraform-beta
updated
from a57ed2 to b59c93
Submodule terraform-mapper
updated
5 files
79 changes: 79 additions & 0 deletions
79
third_party/terraform/resources/data_source_google_service_account_access_token.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"strings" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
iamcredentials "google.golang.org/api/iamcredentials/v1" | ||
) | ||
|
||
func dataSourceGoogleServiceAccountAccessToken() *schema.Resource { | ||
|
||
return &schema.Resource{ | ||
Read: dataSourceGoogleServiceAccountAccessTokenRead, | ||
Schema: map[string]*schema.Schema{ | ||
"target_service_account": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ValidateFunc: validateRegexp("(" + strings.Join(PossibleServiceAccountNames, "|") + ")"), | ||
}, | ||
"access_token": { | ||
Type: schema.TypeString, | ||
Sensitive: true, | ||
Computed: true, | ||
}, | ||
"scopes": { | ||
Type: schema.TypeSet, | ||
Required: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
StateFunc: func(v interface{}) string { | ||
return canonicalizeServiceScope(v.(string)) | ||
}, | ||
}, | ||
// ValidateFunc is not yet supported on lists or sets. | ||
}, | ||
"delegates": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
ValidateFunc: validateRegexp(ServiceAccountLinkRegex), | ||
}, | ||
}, | ||
"lifetime": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ValidateFunc: validateDuration(), // duration <=3600s; TODO: support validteDuration(min,max) | ||
Default: "3600s", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceGoogleServiceAccountAccessTokenRead(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
log.Printf("[INFO] Acquire Service Account AccessToken for %s", d.Get("target_service_account").(string)) | ||
|
||
service := config.clientIamCredentials | ||
|
||
name := fmt.Sprintf("projects/-/serviceAccounts/%s", d.Get("target_service_account").(string)) | ||
tokenRequest := &iamcredentials.GenerateAccessTokenRequest{ | ||
Lifetime: d.Get("lifetime").(string), | ||
Delegates: convertStringSet(d.Get("delegates").(*schema.Set)), | ||
Scope: canonicalizeServiceScopes(convertStringSet(d.Get("scopes").(*schema.Set))), | ||
} | ||
at, err := service.Projects.ServiceAccounts.GenerateAccessToken(name, tokenRequest).Do() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(time.Now().UTC().String()) | ||
d.Set("access_token", at.AccessToken) | ||
|
||
return nil | ||
} |
66 changes: 66 additions & 0 deletions
66
third_party/terraform/resources/data_source_google_service_account_access_token_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package google | ||
|
||
import ( | ||
"testing" | ||
|
||
"fmt" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func testAccCheckServiceAccountAccessTokenValue(name, value string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
ms := s.RootModule() | ||
rs, ok := ms.Outputs[name] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", name) | ||
} | ||
|
||
// TODO: validate the token belongs to the service account | ||
if rs.Value == "" { | ||
return fmt.Errorf("%s Cannot be empty", name) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func TestAccDataSourceGoogleServiceAccountAccessToken_basic(t *testing.T) { | ||
t.Parallel() | ||
|
||
resourceName := "data.google_service_account_access_token.default" | ||
|
||
targetServiceAccountEmail := getTestServiceAccountFromEnv(t) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckGoogleServiceAccountAccessToken_datasource(targetServiceAccountEmail), | ||
Destroy: true, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(resourceName, "target_service_account", targetServiceAccountEmail), | ||
testAccCheckServiceAccountAccessTokenValue("access_token", targetServiceAccountEmail), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckGoogleServiceAccountAccessToken_datasource(targetServiceAccountID string) string { | ||
|
||
return fmt.Sprintf(` | ||
data "google_service_account_access_token" "default" { | ||
target_service_account = "%s" | ||
scopes = ["userinfo-email", "https://www.googleapis.com/auth/cloud-platform"] | ||
lifetime = "30s" | ||
} | ||
output "access_token" { | ||
value = "${data.google_service_account_access_token.default.access_token}" | ||
} | ||
`, targetServiceAccountID) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
...orm/website/docs/d/datasource_google_service_account_access_token.html.markdown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
--- | ||
layout: "google" | ||
page_title: "Google: google_service_account_access_token" | ||
sidebar_current: "docs-google-service-account-access-token" | ||
description: |- | ||
Produces access_token for impersonated service accounts | ||
--- | ||
|
||
# google\_service\_account\_access\_token | ||
|
||
This data source provides a google `oauth2` `access_token` for a different service account than the one initially running the script. | ||
|
||
For more information see | ||
[the official documentation](https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials) as well as [iamcredentials.generateAccessToken()](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken) | ||
|
||
## Example Usage | ||
|
||
To allow `service_A` to impersonate `service_B`, grant the [Service Account Token Creator](https://cloud.google.com/iam/docs/service-accounts#the_service_account_token_creator_role) on B to A. | ||
|
||
In the IAM policy below, `service_A` is given the Token Creator role impersonate `service_B` | ||
|
||
```sh | ||
resource "google_service_account_iam_binding" "token-creator-iam" { | ||
service_account_id = "projects/-/serviceAccounts/[email protected]" | ||
role = "roles/iam.serviceAccountTokenCreator" | ||
members = [ | ||
"serviceAccount:[email protected]", | ||
] | ||
} | ||
``` | ||
|
||
Once the IAM permissions are set, you can apply the new token to a provider bootstrapped with it. Any resources that references the aliased provider will run as the new identity. | ||
|
||
In the example below, `google_project` will run as `service_B`. | ||
|
||
```hcl | ||
provider "google" {} | ||
data "google_client_config" "default" { | ||
provider = "google" | ||
} | ||
data "google_service_account_access_token" "default" { | ||
provider = "google" | ||
target_service_account = "[email protected]" | ||
scopes = ["userinfo-email", "cloud-platform"] | ||
lifetime = "300s" | ||
} | ||
provider "google" { | ||
alias = "impersonated" | ||
access_token = "${data.google_service_account_access_token.default.access_token}" | ||
} | ||
data "google_client_openid_userinfo" "me" { | ||
provider = "google.impersonated" | ||
} | ||
output "target-email" { | ||
value = "${data.google_client_openid_userinfo.me.email}" | ||
} | ||
``` | ||
|
||
> *Note*: the generated token is non-refreshable and can have a maximum `lifetime` of `3600` seconds. | ||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `target_service_account` (Required) - The service account _to_ impersonate (e.g. `[email protected]`) | ||
* `scopes` (Required) - The scopes the new credential should have (e.g. `["storage-ro", "cloud-platform"]`) | ||
* `delegates` (Optional) - Deegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name. (e.g. `["projects/-/serviceAccounts/[email protected]"]`) | ||
* `lifetime` (Optional) Lifetime of the impersonated token (defaults to its max: `3600s`). | ||
|
||
## Attributes Reference | ||
|
||
The following attribute is exported: | ||
|
||
* `access_token` - The `access_token` representing the new generated identity. |