Support service accounts on GCE instances
Update the Google Compute Engine provider to add support for service accounts on `google_compute_instance`. Both gcloud shorthand (`compute-ro`, `storage-ro`, etc.) and OAuth2 API endpoints are supported. This feature is currently limited to a single service account (supporting multiple scopes) and an automatically-generated service account email.
This commit is contained in:
parent
f61b7af815
commit
d3081e0da8
|
@ -124,6 +124,33 @@ func resourceComputeInstance() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"service_account": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"email": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"scopes": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
StateFunc: func(v interface{}) string {
|
||||||
|
return canonicalizeServiceScope(v.(string))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"tags": &schema.Schema{
|
"tags": &schema.Schema{
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeSet,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
@ -259,6 +286,26 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
||||||
networks = append(networks, &iface)
|
networks = append(networks, &iface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serviceAccountsCount := d.Get("service_account.#").(int)
|
||||||
|
serviceAccounts := make([]*compute.ServiceAccount, 0, serviceAccountsCount)
|
||||||
|
for i := 0; i < serviceAccountsCount; i++ {
|
||||||
|
prefix := fmt.Sprintf("service_account.%d", i)
|
||||||
|
|
||||||
|
scopesCount := d.Get(prefix + ".scopes.#").(int)
|
||||||
|
scopes := make([]string, 0, scopesCount)
|
||||||
|
for j := 0; j < scopesCount; j++ {
|
||||||
|
scope := d.Get(fmt.Sprintf(prefix + ".scopes.%d", j)).(string)
|
||||||
|
scopes = append(scopes, canonicalizeServiceScope(scope))
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceAccount := &compute.ServiceAccount {
|
||||||
|
Email: "default",
|
||||||
|
Scopes: scopes,
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceAccounts = append(serviceAccounts, serviceAccount)
|
||||||
|
}
|
||||||
|
|
||||||
// Create the instance information
|
// Create the instance information
|
||||||
instance := compute.Instance{
|
instance := compute.Instance{
|
||||||
CanIpForward: d.Get("can_ip_forward").(bool),
|
CanIpForward: d.Get("can_ip_forward").(bool),
|
||||||
|
@ -269,18 +316,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
||||||
Name: d.Get("name").(string),
|
Name: d.Get("name").(string),
|
||||||
NetworkInterfaces: networks,
|
NetworkInterfaces: networks,
|
||||||
Tags: resourceInstanceTags(d),
|
Tags: resourceInstanceTags(d),
|
||||||
/*
|
ServiceAccounts: serviceAccounts,
|
||||||
ServiceAccounts: []*compute.ServiceAccount{
|
|
||||||
&compute.ServiceAccount{
|
|
||||||
Email: "default",
|
|
||||||
Scopes: []string{
|
|
||||||
"https://www.googleapis.com/auth/userinfo.email",
|
|
||||||
"https://www.googleapis.com/auth/compute",
|
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Requesting instance creation")
|
log.Printf("[INFO] Requesting instance creation")
|
||||||
|
@ -339,6 +375,16 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
|
||||||
|
|
||||||
d.Set("can_ip_forward", instance.CanIpForward)
|
d.Set("can_ip_forward", instance.CanIpForward)
|
||||||
|
|
||||||
|
// Set the service accounts
|
||||||
|
for i, serviceAccount := range instance.ServiceAccounts {
|
||||||
|
prefix := fmt.Sprintf("service_account.%d", i)
|
||||||
|
d.Set(prefix + ".email", serviceAccount.Email)
|
||||||
|
d.Set(prefix + ".scopes.#", len(serviceAccount.Scopes))
|
||||||
|
for j, scope := range serviceAccount.Scopes {
|
||||||
|
d.Set(fmt.Sprintf("%s.scopes.%d", prefix, j), scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set the networks
|
// Set the networks
|
||||||
externalIP := ""
|
externalIP := ""
|
||||||
for i, iface := range instance.NetworkInterfaces {
|
for i, iface := range instance.NetworkInterfaces {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
func canonicalizeServiceScope(scope string) string {
|
||||||
|
// This is a convenience map of short names used by the gcloud tool
|
||||||
|
// to the GCE auth endpoints they alias to.
|
||||||
|
scopeMap := map[string]string{
|
||||||
|
"bigquery": "https://www.googleapis.com/auth/bigquery",
|
||||||
|
"compute-ro": "https://www.googleapis.com/auth/compute.readonly",
|
||||||
|
"compute-rw": "https://www.googleapis.com/auth/compute",
|
||||||
|
"datastore": "https://www.googleapis.com/auth/datastore",
|
||||||
|
"sql": "https://www.googleapis.com/auth/sqlservice",
|
||||||
|
"sql-admin": "https://www.googleapis.com/auth/sqlservice.admin",
|
||||||
|
"storage-full": "https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
|
"storage-ro": "https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
|
"storage-rw": "https://www.googleapis.com/auth/devstorage.read_write",
|
||||||
|
"taskqueue": "https://www.googleapis.com/auth/taskqueue",
|
||||||
|
"userinfo-email": "https://www.googleapis.com/auth/userinfo.email",
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchedUrl, ok := scopeMap[scope]; ok {
|
||||||
|
return matchedUrl
|
||||||
|
} else {
|
||||||
|
return scope
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,10 @@ resource "google_compute_instance" "default" {
|
||||||
metadata {
|
metadata {
|
||||||
foo = "bar"
|
foo = "bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
service_account {
|
||||||
|
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -60,6 +64,8 @@ The following arguments are supported:
|
||||||
specified multiple times for multiple networks. Structure is documented
|
specified multiple times for multiple networks. Structure is documented
|
||||||
below.
|
below.
|
||||||
|
|
||||||
|
* `service_account` - (Optional) Service account to attach to the instance.
|
||||||
|
|
||||||
* `tags` - (Optional) Tags to attach to the instance.
|
* `tags` - (Optional) Tags to attach to the instance.
|
||||||
|
|
||||||
The `disk` block supports:
|
The `disk` block supports:
|
||||||
|
@ -82,6 +88,11 @@ The `network` block supports:
|
||||||
* `address` - (Optional) The IP address of a reserved IP address to assign
|
* `address` - (Optional) The IP address of a reserved IP address to assign
|
||||||
to this interface.
|
to this interface.
|
||||||
|
|
||||||
|
The `service_account` block supports:
|
||||||
|
|
||||||
|
* `scopes` - (Required) A list of service scopes. Both OAuth2 URLs and gcloud
|
||||||
|
short names are supported.
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
|
Loading…
Reference in New Issue