Skip to content

Commit

Permalink
Add limited support for importing service accounts
Browse files Browse the repository at this point in the history
Partially fixes hashicorp#268
  • Loading branch information
wjam committed Feb 18, 2019
1 parent 114667b commit fc8fb0e
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
50 changes: 50 additions & 0 deletions kubernetes/resource_kubernetes_service_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ func resourceKubernetesServiceAccount() *schema.Resource {
Update: resourceKubernetesServiceAccountUpdate,
Delete: resourceKubernetesServiceAccountDelete,

// This only allows the importing of ServiceAccounts which have a single service account token secret on them
// The reasoning for this is due to the complexity around calculating the `default_secret_name` if there are
// multiple service account tokens attached to service account.
Importer: &schema.ResourceImporter{
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
conn := meta.(*kubernetes.Clientset)

namespace, name, err := idParts(d.Id())
if err != nil {
return nil, err
}

sa, err := conn.CoreV1().ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
if err != nil {
return nil, err
}
defaultSecret, err := findDefaultServiceAccount(namespace, name, conn)
if err != nil {
return nil, err
}

d.Set("default_secret_name", defaultSecret)
d.SetId(buildId(sa.ObjectMeta))

return []*schema.ResourceData{d}, nil
},
},

// This resource is not importable because the API doesn't offer
// any way to differentiate between default & user-defined secret
// after the account was created.
Expand Down Expand Up @@ -254,3 +282,25 @@ func resourceKubernetesServiceAccountExists(d *schema.ResourceData, meta interfa
}
return true, err
}

func findDefaultServiceAccount(namespace, name string, conn *kubernetes.Clientset) (string, error) {
resp, err := conn.CoreV1().ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
secretList, err := conn.CoreV1().Secrets(namespace).List(metav1.ListOptions{})
var svcAccTokens []api.Secret
for _, secret := range secretList.Items {
for _, svcSecret := range resp.Secrets {
if secret.Name != svcSecret.Name {
break
}
if secret.Type == api.SecretTypeServiceAccountToken {
svcAccTokens = append(svcAccTokens, secret)
}
}
}

if len(svcAccTokens) > 1 {
return "", fmt.Errorf("Expected 1 generated service account token, %d found: %s", len(svcAccTokens), err)
}

return svcAccTokens[0].Name, nil
}
22 changes: 22 additions & 0 deletions kubernetes/resource_kubernetes_service_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,28 @@ func TestAccKubernetesServiceAccount_generatedName(t *testing.T) {
})
}

func TestAccKubernetesServiceAccount_importBasic(t *testing.T) {
resourceName := "kubernetes_service_account.test"
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckKubernetesPodDestroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesServiceAccountConfig_noAttributes(name),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"metadata.0.resource_version", "automount_service_account_token"},
},
},
})
}

func testAccCheckServiceAccountImagePullSecrets(m *api.ServiceAccount, expected []*regexp.Regexp) resource.TestCheckFunc {
return func(s *terraform.State) error {
if len(expected) == 0 && len(m.ImagePullSecrets) == 0 {
Expand Down
11 changes: 11 additions & 0 deletions website/docs/r/service_account.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,14 @@ In addition to the arguments listed above, the following computed attributes are
exported:

* `default_secret_name` - Name of the default secret, containing service account token, created & managed by the service.

## Import

kubernetes_service_account can be imported using its namespace and name, e.g.

```
$ terraform import kubernetes_service_account.example default/sa-name
```

Note that only service accounts with a single service account token can be imported, due to difficulty in discovering
the name of the default secret name.

0 comments on commit fc8fb0e

Please sign in to comment.