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 for importing service accounts #377

Merged
merged 3 commits into from
Mar 29, 2019

Conversation

wjam
Copy link
Contributor

@wjam wjam commented Mar 26, 2019

This implements importing of service accounts using the behaviour implemented in source code of the Kubernetes service account controller to discover the default service account token. This PR also adds support for updating the automount_service_account_token attribute when it changes.

This implements importing of service accounts using the behaviour implemented in source code of the Kubernetes service account controller to discover the default service account token. This PR also adds support for updating the `automount_service_account_token` attribute when it changes.
@wjam
Copy link
Contributor Author

wjam commented Mar 26, 2019

This would fix #268


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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind wrapping these errors before returning them? The idea being to make it obvious that the error happened during import processing, since these can also occur during a normal Read.

return "", fmt.Errorf("Unable to find any service accounts tokens which could have been the default one")
}

if len(serviceAccountTokens) > 1 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the goal is to find exactly one, then finding the first ones means it's done.
You could just return it when you find it rather than running the list of secrets all the way to the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thought was to be as conservative as possible and just fail if the assumptions used to find the default service account aren't correct

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll refactor it so that is less conservative

@@ -169,6 +169,10 @@ func resourceKubernetesServiceAccountRead(d *schema.ResourceData, meta interface
if err != nil {
return err
}
err = d.Set("automount_service_account_token", *svcAcc.AutomountServiceAccountToken)
Copy link
Member

@alexsomesan alexsomesan Mar 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This crashes with a panic if svcAcc.AutomountServiceAccountToken is nil.
It should be checked for nil before using it, as with all pointer attributes.

Copy link
Member

@alexsomesan alexsomesan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good overall.
I've left some comments below on spot issues.
On top of that, could you please remove the default value from automount_service_account_token attribute. It's not part of the Kubernetes spec and it also causes a diff after importing a new which doesn't have it set.

@alexsomesan
Copy link
Member

Thanks for the updates @wjam.
Please don't forget to remove the default value from automount_service_account_token like I mentioned earlier. It causes an unexpected diff otherwise.

Copy link
Member

@alexsomesan alexsomesan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@alexsomesan alexsomesan merged commit 3743fb9 into hashicorp:master Mar 29, 2019
@pdecat
Copy link
Contributor

pdecat commented Apr 5, 2019

FYI, I've just tested the importation of four service accounts building from master and this works perfectly, thanks!

@pdecat
Copy link
Contributor

pdecat commented Apr 9, 2019

Also, this will be worth mentioning in the release notes as I thought this was already supported in the last release:

This PR also adds support for updating the automount_service_account_token attribute when it changes.

@wjam wjam deleted the support-importing-service-accounts branch June 5, 2019 16:26
@mstrejczek
Copy link

It doesn't work (reliably) for me because Secret is sometimes created >1 seconds after ServiceAccount.
I'm using EKS (K8S version 1.14) and Terraform Kubernetes Provider 1.9.0. EKS cluster was provisioned by Terraform.

In my case:
Secret has creationTimestamp: "2019-10-09T17:50:03Z"
ServiceAccount has creationTimestamp: "2019-10-09T17:50:01Z"

The outcome of "terraform import kubernetes_service_account.kube-system_aws-node kube-system/aws-node" is:
kubernetes_service_account.kube-system_aws-node: Importing from ID "kube-system/aws-node"...
2019-10-09T20:16:56.604+0200 [DEBUG] plugin.terraform-provider-kubernetes_v1.9.0_x4: 2019/10/09 20:16:56 [DEBUG] Skipping aws-node-token-xh7fr as it wasn't created at the same time as the service account
2019/10/09 20:16:56 [ERROR] <root>: eval: *terraform.EvalImportState, err: Failed to discover the default service account token: Unable to find any service accounts tokens which could have been the default one
2019/10/09 20:16:56 [ERROR] <root>: eval: *terraform.EvalSequence, err: Failed to discover the default service account token: Unable to find any service accounts tokens which could have been the default one

therc added a commit to therc/terraform-provider-kubernetes that referenced this pull request Jan 27, 2020
Importing service accounts isn't always working on EKS clusters, which sometimes see secrets created more than one second after the service account, as reported in hashicorp#377 (comment) and hashicorp#268 (comment) 

With some fields removed for clarity:
```
 {
  "kind": "ServiceAccount",
  "metadata": {
   "name": "coredns",
   "uid": "e2885307-37d7-11ea-9db3-1211528e452b",
   "resourceVersion": "201",
   "creationTimestamp": "2020-01-15T20:44:54Z",
  },
  "secrets": [ { "name": "coredns-token-8tdpj" } ]
 }
 {
  "kind": "Secret",
  "metadata": {
   "name": "coredns-token-8tdpj",
   "resourceVersion": "196",
   "creationTimestamp": "2020-01-15T20:44:56Z",
   "annotations": {
    "kubernetes.io/service-account.name": "coredns",
    "kubernetes.io/service-account.uid": "e2885307-37d7-11ea-9db3-1211528e452b"
   }
  },
  "type": "kubernetes.io/service-account-token"                                                                              
 }
```

It's not clear what could be causing this. In our case, the cluster was brand new at the time the account was created, as can be seen in the relatively low resourceVersions. Maybe it's load, maybe it's clock drift between API servers (where creationTimestamp is injected, AFAIK). No matter the cause, this is a real problem and it's stopping imports.
This is the simplest fix. A more comprehensive one could also double check that the annotations for SA name and the UID on the secret match with the account's. If more than one secret matches all criteria, perhaps the oldest one could be picked. But that's all better addressed separately.
alexsomesan pushed a commit that referenced this pull request Jan 30, 2020
Importing service accounts isn't always working on EKS clusters, which sometimes see secrets created more than one second after the service account, as reported in #377 (comment) and #268 (comment) 

With some fields removed for clarity:
```
 {
  "kind": "ServiceAccount",
  "metadata": {
   "name": "coredns",
   "uid": "e2885307-37d7-11ea-9db3-1211528e452b",
   "resourceVersion": "201",
   "creationTimestamp": "2020-01-15T20:44:54Z",
  },
  "secrets": [ { "name": "coredns-token-8tdpj" } ]
 }
 {
  "kind": "Secret",
  "metadata": {
   "name": "coredns-token-8tdpj",
   "resourceVersion": "196",
   "creationTimestamp": "2020-01-15T20:44:56Z",
   "annotations": {
    "kubernetes.io/service-account.name": "coredns",
    "kubernetes.io/service-account.uid": "e2885307-37d7-11ea-9db3-1211528e452b"
   }
  },
  "type": "kubernetes.io/service-account-token"                                                                              
 }
```

It's not clear what could be causing this. In our case, the cluster was brand new at the time the account was created, as can be seen in the relatively low resourceVersions. Maybe it's load, maybe it's clock drift between API servers (where creationTimestamp is injected, AFAIK). No matter the cause, this is a real problem and it's stopping imports.
This is the simplest fix. A more comprehensive one could also double check that the annotations for SA name and the UID on the secret match with the account's. If more than one secret matches all criteria, perhaps the oldest one could be picked. But that's all better addressed separately.
@ghost ghost locked and limited conversation to collaborators Apr 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants