service_accounts.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package e2e
  14. import (
  15. "fmt"
  16. "time"
  17. "k8s.io/kubernetes/pkg/api"
  18. apierrors "k8s.io/kubernetes/pkg/api/errors"
  19. "k8s.io/kubernetes/pkg/util/uuid"
  20. "k8s.io/kubernetes/pkg/util/wait"
  21. "k8s.io/kubernetes/pkg/version"
  22. "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount"
  23. "k8s.io/kubernetes/test/e2e/framework"
  24. . "github.com/onsi/ginkgo"
  25. . "github.com/onsi/gomega"
  26. )
  27. var serviceAccountTokenNamespaceVersion = version.MustParse("v1.2.0")
  28. var _ = framework.KubeDescribe("ServiceAccounts", func() {
  29. f := framework.NewDefaultFramework("svcaccounts")
  30. It("should ensure a single API token exists", func() {
  31. // wait for the service account to reference a single secret
  32. var secrets []api.ObjectReference
  33. framework.ExpectNoError(wait.Poll(time.Millisecond*500, time.Second*10, func() (bool, error) {
  34. By("waiting for a single token reference")
  35. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  36. if apierrors.IsNotFound(err) {
  37. framework.Logf("default service account was not found")
  38. return false, nil
  39. }
  40. if err != nil {
  41. framework.Logf("error getting default service account: %v", err)
  42. return false, err
  43. }
  44. switch len(sa.Secrets) {
  45. case 0:
  46. framework.Logf("default service account has no secret references")
  47. return false, nil
  48. case 1:
  49. framework.Logf("default service account has a single secret reference")
  50. secrets = sa.Secrets
  51. return true, nil
  52. default:
  53. return false, fmt.Errorf("default service account has too many secret references: %#v", sa.Secrets)
  54. }
  55. }))
  56. // make sure the reference doesn't flutter
  57. {
  58. By("ensuring the single token reference persists")
  59. time.Sleep(2 * time.Second)
  60. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  61. framework.ExpectNoError(err)
  62. Expect(sa.Secrets).To(Equal(secrets))
  63. }
  64. // delete the referenced secret
  65. By("deleting the service account token")
  66. framework.ExpectNoError(f.Client.Secrets(f.Namespace.Name).Delete(secrets[0].Name))
  67. // wait for the referenced secret to be removed, and another one autocreated
  68. framework.ExpectNoError(wait.Poll(time.Millisecond*500, framework.ServiceAccountProvisionTimeout, func() (bool, error) {
  69. By("waiting for a new token reference")
  70. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  71. if err != nil {
  72. framework.Logf("error getting default service account: %v", err)
  73. return false, err
  74. }
  75. switch len(sa.Secrets) {
  76. case 0:
  77. framework.Logf("default service account has no secret references")
  78. return false, nil
  79. case 1:
  80. if sa.Secrets[0] == secrets[0] {
  81. framework.Logf("default service account still has the deleted secret reference")
  82. return false, nil
  83. }
  84. framework.Logf("default service account has a new single secret reference")
  85. secrets = sa.Secrets
  86. return true, nil
  87. default:
  88. return false, fmt.Errorf("default service account has too many secret references: %#v", sa.Secrets)
  89. }
  90. }))
  91. // make sure the reference doesn't flutter
  92. {
  93. By("ensuring the single token reference persists")
  94. time.Sleep(2 * time.Second)
  95. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  96. framework.ExpectNoError(err)
  97. Expect(sa.Secrets).To(Equal(secrets))
  98. }
  99. // delete the reference from the service account
  100. By("deleting the reference to the service account token")
  101. {
  102. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  103. framework.ExpectNoError(err)
  104. sa.Secrets = nil
  105. _, updateErr := f.Client.ServiceAccounts(f.Namespace.Name).Update(sa)
  106. framework.ExpectNoError(updateErr)
  107. }
  108. // wait for another one to be autocreated
  109. framework.ExpectNoError(wait.Poll(time.Millisecond*500, framework.ServiceAccountProvisionTimeout, func() (bool, error) {
  110. By("waiting for a new token to be created and added")
  111. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  112. if err != nil {
  113. framework.Logf("error getting default service account: %v", err)
  114. return false, err
  115. }
  116. switch len(sa.Secrets) {
  117. case 0:
  118. framework.Logf("default service account has no secret references")
  119. return false, nil
  120. case 1:
  121. framework.Logf("default service account has a new single secret reference")
  122. secrets = sa.Secrets
  123. return true, nil
  124. default:
  125. return false, fmt.Errorf("default service account has too many secret references: %#v", sa.Secrets)
  126. }
  127. }))
  128. // make sure the reference doesn't flutter
  129. {
  130. By("ensuring the single token reference persists")
  131. time.Sleep(2 * time.Second)
  132. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  133. framework.ExpectNoError(err)
  134. Expect(sa.Secrets).To(Equal(secrets))
  135. }
  136. })
  137. It("should mount an API token into pods [Conformance]", func() {
  138. var tokenContent string
  139. var rootCAContent string
  140. // Standard get, update retry loop
  141. framework.ExpectNoError(wait.Poll(time.Millisecond*500, framework.ServiceAccountProvisionTimeout, func() (bool, error) {
  142. By("getting the auto-created API token")
  143. sa, err := f.Client.ServiceAccounts(f.Namespace.Name).Get("default")
  144. if apierrors.IsNotFound(err) {
  145. framework.Logf("default service account was not found")
  146. return false, nil
  147. }
  148. if err != nil {
  149. framework.Logf("error getting default service account: %v", err)
  150. return false, err
  151. }
  152. if len(sa.Secrets) == 0 {
  153. framework.Logf("default service account has no secret references")
  154. return false, nil
  155. }
  156. for _, secretRef := range sa.Secrets {
  157. secret, err := f.Client.Secrets(f.Namespace.Name).Get(secretRef.Name)
  158. if err != nil {
  159. framework.Logf("Error getting secret %s: %v", secretRef.Name, err)
  160. continue
  161. }
  162. if secret.Type == api.SecretTypeServiceAccountToken {
  163. tokenContent = string(secret.Data[api.ServiceAccountTokenKey])
  164. rootCAContent = string(secret.Data[api.ServiceAccountRootCAKey])
  165. return true, nil
  166. }
  167. }
  168. framework.Logf("default service account has no secret references to valid service account tokens")
  169. return false, nil
  170. }))
  171. pod := &api.Pod{
  172. ObjectMeta: api.ObjectMeta{
  173. Name: "pod-service-account-" + string(uuid.NewUUID()),
  174. },
  175. Spec: api.PodSpec{
  176. Containers: []api.Container{
  177. {
  178. Name: "token-test",
  179. Image: "gcr.io/google_containers/mounttest:0.2",
  180. Args: []string{
  181. fmt.Sprintf("--file_content=%s/%s", serviceaccount.DefaultAPITokenMountPath, api.ServiceAccountTokenKey),
  182. },
  183. },
  184. {
  185. Name: "root-ca-test",
  186. Image: "gcr.io/google_containers/mounttest:0.2",
  187. Args: []string{
  188. fmt.Sprintf("--file_content=%s/%s", serviceaccount.DefaultAPITokenMountPath, api.ServiceAccountRootCAKey),
  189. },
  190. },
  191. },
  192. RestartPolicy: api.RestartPolicyNever,
  193. },
  194. }
  195. supportsTokenNamespace, _ := framework.ServerVersionGTE(serviceAccountTokenNamespaceVersion, f.Client)
  196. if supportsTokenNamespace {
  197. pod.Spec.Containers = append(pod.Spec.Containers, api.Container{
  198. Name: "namespace-test",
  199. Image: "gcr.io/google_containers/mounttest:0.2",
  200. Args: []string{
  201. fmt.Sprintf("--file_content=%s/%s", serviceaccount.DefaultAPITokenMountPath, api.ServiceAccountNamespaceKey),
  202. },
  203. })
  204. }
  205. f.TestContainerOutput("consume service account token", pod, 0, []string{
  206. fmt.Sprintf(`content of file "%s/%s": %s`, serviceaccount.DefaultAPITokenMountPath, api.ServiceAccountTokenKey, tokenContent),
  207. })
  208. f.TestContainerOutput("consume service account root CA", pod, 1, []string{
  209. fmt.Sprintf(`content of file "%s/%s": %s`, serviceaccount.DefaultAPITokenMountPath, api.ServiceAccountRootCAKey, rootCAContent),
  210. })
  211. if supportsTokenNamespace {
  212. f.TestContainerOutput("consume service account namespace", pod, 2, []string{
  213. fmt.Sprintf(`content of file "%s/%s": %s`, serviceaccount.DefaultAPITokenMountPath, api.ServiceAccountNamespaceKey, f.Namespace.Name),
  214. })
  215. }
  216. })
  217. })