mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-09-28 22:16:04 +00:00
New datasource: service account and service account key (#1535)
This commit is contained in:
parent
c71ab3f62f
commit
8f31fec857
70
google/data_source_google_service_account.go
Normal file
70
google/data_source_google_service_account.go
Normal file
@ -0,0 +1,70 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func dataSourceGoogleServiceAccount() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceGoogleServiceAccountRead,
|
||||
Schema: map[string]*schema.Schema{
|
||||
"account_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ValidateFunc: validateRFC1035Name(6, 30),
|
||||
},
|
||||
"project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"email": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"unique_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"display_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceGoogleServiceAccountRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
// Get the project from the resource or fallback to the project
|
||||
// in the provider configuration
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the service account as a fully qualified name
|
||||
serviceAccountName := serviceAccountFQN(d.Get("account_id").(string), project)
|
||||
|
||||
sa, err := config.clientIAM.Projects.ServiceAccounts.Get(serviceAccountName).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Service Account %q", serviceAccountName))
|
||||
}
|
||||
|
||||
d.SetId(sa.Name)
|
||||
d.Set("email", sa.Email)
|
||||
d.Set("unique_id", sa.UniqueId)
|
||||
d.Set("project", sa.ProjectId)
|
||||
d.Set("account_id", strings.Split(sa.Email, "@")[0])
|
||||
d.Set("name", sa.Name)
|
||||
d.Set("display_name", sa.DisplayName)
|
||||
|
||||
return nil
|
||||
}
|
74
google/data_source_google_service_account_key.go
Normal file
74
google/data_source_google_service_account_key.go
Normal file
@ -0,0 +1,74 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
)
|
||||
|
||||
func dataSourceGoogleServiceAccountKey() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceGoogleServiceAccountKeyRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"service_account_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"public_key_type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Default: "TYPE_X509_PEM_FILE",
|
||||
Optional: true,
|
||||
ValidateFunc: validation.StringInSlice([]string{"TYPE_NONE", "TYPE_X509_PEM_FILE", "TYPE_RAW_PUBLIC_KEY"}, false),
|
||||
},
|
||||
"project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
// Computed
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"key_algorithm": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"public_key": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceGoogleServiceAccountKeyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
// Get the project from the resource or fallback to the project
|
||||
// in the provider configuration
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the service account as the fully qualified name
|
||||
serviceAccountName := serviceAccountFQN(d.Get("service_account_id").(string), project)
|
||||
|
||||
publicKeyType := d.Get("public_key_type").(string)
|
||||
|
||||
// Confirm the service account key exists
|
||||
sak, err := config.clientIAM.Projects.ServiceAccounts.Keys.Get(serviceAccountName).PublicKeyType(publicKeyType).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, fmt.Sprintf("Service Account Key %q", serviceAccountName))
|
||||
}
|
||||
|
||||
d.SetId(sak.Name)
|
||||
|
||||
d.Set("name", sak.Name)
|
||||
d.Set("key_algorithm", sak.KeyAlgorithm)
|
||||
d.Set("public_key", sak.PublicKeyData)
|
||||
|
||||
return nil
|
||||
}
|
56
google/data_source_google_service_account_key_test.go
Normal file
56
google/data_source_google_service_account_key_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccDatasourceGoogleServiceAccountKey_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
resourceName := "data.google_service_account_key.acceptance"
|
||||
account := acctest.RandomWithPrefix("tf-test")
|
||||
serviceAccountName := fmt.Sprintf(
|
||||
"projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com",
|
||||
getTestProjectFromEnv(),
|
||||
account,
|
||||
getTestProjectFromEnv(),
|
||||
)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDatasourceGoogleServiceAccountKey(account),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleServiceAccountKeyExists(resourceName),
|
||||
// Check that the 'name' starts with the service account name
|
||||
resource.TestMatchResourceAttr(resourceName, "name", regexp.MustCompile(serviceAccountName)),
|
||||
resource.TestCheckResourceAttrSet(resourceName, "key_algorithm"),
|
||||
resource.TestCheckResourceAttrSet(resourceName, "public_key"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccDatasourceGoogleServiceAccountKey(account string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_service_account" "acceptance" {
|
||||
account_id = "%s"
|
||||
}
|
||||
|
||||
resource "google_service_account_key" "acceptance" {
|
||||
service_account_id = "${google_service_account.acceptance.name}"
|
||||
public_key_type = "TYPE_X509_PEM_FILE"
|
||||
}
|
||||
|
||||
data "google_service_account_key" "acceptance" {
|
||||
service_account_id = "${google_service_account_key.acceptance.id}"
|
||||
}`, account)
|
||||
}
|
48
google/data_source_google_service_account_test.go
Normal file
48
google/data_source_google_service_account_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccDatasourceGoogleServiceAccount_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
resourceName := "data.google_service_account.acceptance"
|
||||
account := acctest.RandomWithPrefix("tf-test")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckGoogleServiceAccount_basic(account),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckGoogleServiceAccountExists(resourceName),
|
||||
resource.TestCheckResourceAttr(
|
||||
resourceName, "id", fmt.Sprintf("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com", getTestProjectFromEnv(), account, getTestProjectFromEnv())),
|
||||
resource.TestCheckResourceAttrSet(resourceName, "email"),
|
||||
resource.TestCheckResourceAttrSet(resourceName, "unique_id"),
|
||||
resource.TestCheckResourceAttrSet(resourceName, "name"),
|
||||
resource.TestCheckResourceAttrSet(resourceName, "display_name"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckGoogleServiceAccount_basic(account string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_service_account" "acceptance" {
|
||||
account_id = "%s"
|
||||
display_name = "Testing Account"
|
||||
}
|
||||
|
||||
data "google_service_account" "acceptance" {
|
||||
account_id = "${google_service_account.acceptance.account_id}"
|
||||
}
|
||||
`, account)
|
||||
}
|
@ -88,6 +88,8 @@ func Provider() terraform.ResourceProvider {
|
||||
"google_kms_secret": dataSourceGoogleKmsSecret(),
|
||||
"google_folder": dataSourceGoogleFolder(),
|
||||
"google_organization": dataSourceGoogleOrganization(),
|
||||
"google_service_account": dataSourceGoogleServiceAccount(),
|
||||
"google_service_account_key": dataSourceGoogleServiceAccountKey(),
|
||||
"google_storage_object_signed_url": dataSourceGoogleSignedUrl(),
|
||||
"google_storage_project_service_account": dataSourceGoogleStorageProjectServiceAccount(),
|
||||
"google_compute_backend_service": dataSourceGoogleComputeBackendService(),
|
||||
|
@ -2,7 +2,6 @@ package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/encryption"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
@ -88,17 +87,21 @@ func resourceGoogleServiceAccountKey() *schema.Resource {
|
||||
func resourceGoogleServiceAccountKeyCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
serviceAccount := d.Get("service_account_id").(string)
|
||||
if !strings.HasPrefix(serviceAccount, "projects/") {
|
||||
serviceAccount = "projects/-/serviceAccounts/" + serviceAccount
|
||||
// Get the project from the resource or fallback to the project
|
||||
// in the provider configuration
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serviceAccountName := serviceAccountFQN(d.Get("service_account_id").(string), project)
|
||||
|
||||
r := &iam.CreateServiceAccountKeyRequest{
|
||||
KeyAlgorithm: d.Get("key_algorithm").(string),
|
||||
PrivateKeyType: d.Get("private_key_type").(string),
|
||||
}
|
||||
|
||||
sak, err := config.clientIAM.Projects.ServiceAccounts.Keys.Create(serviceAccount, r).Do()
|
||||
sak, err := config.clientIAM.Projects.ServiceAccounts.Keys.Create(serviceAccountName, r).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating service account key: %s", err)
|
||||
}
|
||||
|
@ -360,3 +360,19 @@ func lockedCall(lockKey string, f func() error) error {
|
||||
|
||||
return f()
|
||||
}
|
||||
|
||||
// serviceAccountFQN will attempt to generate the fully qualified name in the format of:
|
||||
// "projects/(-|<project_name>)/serviceAccounts/<service_account_id>@<project_name>.iam.gserviceaccount.com"
|
||||
func serviceAccountFQN(serviceAccount, project string) string {
|
||||
// If the service account id isn't already the fully qualified name
|
||||
if !strings.HasPrefix(serviceAccount, "projects/") {
|
||||
// If the service account id is an email
|
||||
if strings.Contains(serviceAccount, "@") {
|
||||
serviceAccount = "projects/-/serviceAccounts/" + serviceAccount
|
||||
} else {
|
||||
// If the service account id doesn't contain the email, build it
|
||||
serviceAccount = fmt.Sprintf("projects/-/serviceAccounts/%s@%s.iam.gserviceaccount.com", serviceAccount, project)
|
||||
}
|
||||
}
|
||||
return serviceAccount
|
||||
}
|
||||
|
@ -444,3 +444,30 @@ func TestEmptyOrDefaultStringSuppress(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceAccountFQN(t *testing.T) {
|
||||
// Every test case should produce this fully qualified service account name
|
||||
serviceAccountExpected := "projects/-/serviceAccounts/test-service-account@test-project.iam.gserviceaccount.com"
|
||||
cases := map[string]struct {
|
||||
serviceAccount string
|
||||
project string
|
||||
}{
|
||||
"service account fully qualified name from account id": {
|
||||
serviceAccount: "test-service-account",
|
||||
project: "test-project",
|
||||
},
|
||||
"service account fully qualified name from account email": {
|
||||
serviceAccount: "test-service-account@test-project.iam.gserviceaccount.com",
|
||||
},
|
||||
"service account fully qualified name from account name": {
|
||||
serviceAccount: "projects/-/serviceAccounts/test-service-account@test-project.iam.gserviceaccount.com",
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range cases {
|
||||
serviceAccountName := serviceAccountFQN(tc.serviceAccount, tc.project)
|
||||
if serviceAccountName != serviceAccountExpected {
|
||||
t.Errorf("bad: %s, expected '%s' but returned '%s", tn, serviceAccountExpected, serviceAccountName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,13 @@ package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -0,0 +1,63 @@
|
||||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_service_account"
|
||||
sidebar_current: "docs-google-datasource-service-account"
|
||||
description: |-
|
||||
Get the service account from a project.
|
||||
---
|
||||
|
||||
# google\_service\_account
|
||||
|
||||
Get the service account from a project. For more information see
|
||||
the official [API](https://cloud.google.com/compute/docs/access/service-accounts) documentation.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```hcl
|
||||
data "google_service_account" "object_viewer" {
|
||||
account_id = "object-viewer"
|
||||
}
|
||||
```
|
||||
|
||||
## Example Usage, save key in Kubernetes secret
|
||||
```hcl
|
||||
data "google_service_account" "myaccount" {
|
||||
account_id = "myaccount-id"
|
||||
}
|
||||
|
||||
resource "google_service_account_key" "mykey" {
|
||||
service_account_id = "${data.google_service_account.myaccount.name}"
|
||||
}
|
||||
|
||||
resource "kubernetes_secret" "google-application-credentials" {
|
||||
metadata {
|
||||
name = "google-application-credentials"
|
||||
}
|
||||
data {
|
||||
credentials.json = "${base64decode(google_service_account_key.mykey.private_key)}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `account_id` - (Required) The Service account id.
|
||||
|
||||
* `project` - (Optional) The ID of the project that the service account will be created in.
|
||||
Defaults to the provider project configuration.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
In addition to the arguments listed above, the following computed attributes are
|
||||
exported:
|
||||
|
||||
* `email` - The e-mail address of the service account. This value
|
||||
should be referenced from any `google_iam_policy` data sources
|
||||
that would grant the service account privileges.
|
||||
|
||||
* `unique_id` - The unique id of the service account.
|
||||
|
||||
* `name` - The fully-qualified name of the service account.
|
||||
|
||||
* `display_name` - The display name for the service account.
|
@ -0,0 +1,50 @@
|
||||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_service_account_key"
|
||||
sidebar_current: "docs-google-datasource-service-account-key"
|
||||
description: |-
|
||||
Get a Google Cloud Platform service account Public Key
|
||||
---
|
||||
|
||||
# google\_service\_account\_key
|
||||
|
||||
Get service account public key. For more information, see [the official documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) and [API](https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts.keys/get).
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```hcl
|
||||
data "google_service_account" "myaccount" {
|
||||
account_id = "myaccount"
|
||||
}
|
||||
|
||||
data "google_service_account_key" "mykey" {
|
||||
service_account_id = "${data.google_service_account.myaccount.name}"
|
||||
public_key_type = "TYPE_X509_PEM_FILE"
|
||||
}
|
||||
|
||||
output "mykey_public_key" {
|
||||
value = "${data.google_service_account_key.mykey.public_key}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `service_account_id` - (Required) The Service account id of the Key Pair. This can be a string in the format
|
||||
`{ACCOUNT}` or `projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}`, where `{ACCOUNT}` is the email address or
|
||||
unique id of the service account. If the `{ACCOUNT}` syntax is used, the project will be inferred from the account.
|
||||
|
||||
* `project` - (Optional) The ID of the project that the service account will be created in.
|
||||
Defaults to the provider project configuration.
|
||||
|
||||
* `public_key_type` (Optional) The output format of the public key requested. X509_PEM is the default output format.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported in addition to the arguments listed above:
|
||||
|
||||
* `name` - The name used for this key pair
|
||||
|
||||
* `public_key` - The public key, base64 encoded
|
@ -40,7 +40,6 @@
|
||||
<li<%= sidebar_current("docs-google-datasource-compute-network") %>>
|
||||
<a href="/docs/providers/google/d/datasource_compute_network.html">google_compute_network</a>
|
||||
</li>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-datasource-project") %>>
|
||||
<a href="/docs/providers/google/d/google_project.html">google_project</a>
|
||||
</li>
|
||||
@ -98,6 +97,12 @@
|
||||
<li<%= sidebar_current("docs-google-datasource-folder") %>>
|
||||
<a href="/docs/providers/google/d/google_folder.html">google_folder</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-datasource-service-account") %>>
|
||||
<a href="/docs/providers/google/d/datasource_google_service_account.html">google_service_account</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-datasource-service-account-key") %>>
|
||||
<a href="/docs/providers/google/d/datasource_google_service_account_key.html">google_service_account_key</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-datasource-signed_url") %>>
|
||||
<a href="/docs/providers/google/d/signed_url.html">google_storage_object_signed_url</a>
|
||||
</li>
|
||||
|
Loading…
Reference in New Issue
Block a user