audit.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /*
  2. Copyright 2017 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 auth
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "strings"
  18. "time"
  19. apps "k8s.io/api/apps/v1"
  20. apiv1 "k8s.io/api/core/v1"
  21. apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
  22. apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
  23. "k8s.io/apiextensions-apiserver/test/integration/fixtures"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. "k8s.io/apimachinery/pkg/types"
  26. "k8s.io/apimachinery/pkg/util/wait"
  27. auditinternal "k8s.io/apiserver/pkg/apis/audit"
  28. auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
  29. clientset "k8s.io/client-go/kubernetes"
  30. restclient "k8s.io/client-go/rest"
  31. "k8s.io/kubernetes/test/e2e/framework"
  32. "k8s.io/kubernetes/test/e2e/framework/auth"
  33. e2edeploy "k8s.io/kubernetes/test/e2e/framework/deployment"
  34. e2elog "k8s.io/kubernetes/test/e2e/framework/log"
  35. "k8s.io/kubernetes/test/utils"
  36. imageutils "k8s.io/kubernetes/test/utils/image"
  37. jsonpatch "github.com/evanphx/json-patch"
  38. "github.com/onsi/ginkgo"
  39. )
  40. var (
  41. watchTestTimeout int64 = 1
  42. auditTestUser = "kubecfg"
  43. crd = fixtures.NewRandomNameCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
  44. crdName = strings.SplitN(crd.Name, ".", 2)[0]
  45. crdNamespace = strings.SplitN(crd.Name, ".", 2)[1]
  46. watchOptions = metav1.ListOptions{TimeoutSeconds: &watchTestTimeout}
  47. patch, _ = json.Marshal(jsonpatch.Patch{})
  48. )
  49. // TODO: Get rid of [DisabledForLargeClusters] when feature request #53455 is ready.
  50. // Marked as flaky until a reliable method for collecting server-side audit logs is available. See http://issue.k8s.io/74745#issuecomment-474052439
  51. var _ = SIGDescribe("Advanced Audit [DisabledForLargeClusters][Flaky]", func() {
  52. f := framework.NewDefaultFramework("audit")
  53. var namespace string
  54. ginkgo.BeforeEach(func() {
  55. framework.SkipUnlessProviderIs("gce")
  56. namespace = f.Namespace.Name
  57. })
  58. ginkgo.It("should audit API calls to create, get, update, patch, delete, list, watch pods.", func() {
  59. pod := &apiv1.Pod{
  60. ObjectMeta: metav1.ObjectMeta{
  61. Name: "audit-pod",
  62. },
  63. Spec: apiv1.PodSpec{
  64. Containers: []apiv1.Container{{
  65. Name: "pause",
  66. Image: imageutils.GetPauseImageName(),
  67. }},
  68. },
  69. }
  70. updatePod := func(pod *apiv1.Pod) {}
  71. f.PodClient().CreateSync(pod)
  72. _, err := f.PodClient().Get(pod.Name, metav1.GetOptions{})
  73. framework.ExpectNoError(err, "failed to get audit-pod")
  74. podChan, err := f.PodClient().Watch(watchOptions)
  75. framework.ExpectNoError(err, "failed to create watch for pods")
  76. podChan.Stop()
  77. f.PodClient().Update(pod.Name, updatePod)
  78. _, err = f.PodClient().List(metav1.ListOptions{})
  79. framework.ExpectNoError(err, "failed to list pods")
  80. _, err = f.PodClient().Patch(pod.Name, types.JSONPatchType, patch)
  81. framework.ExpectNoError(err, "failed to patch pod")
  82. f.PodClient().DeleteSync(pod.Name, &metav1.DeleteOptions{}, framework.DefaultPodDeletionTimeout)
  83. expectEvents(f, []utils.AuditEvent{
  84. {
  85. Level: auditinternal.LevelRequestResponse,
  86. Stage: auditinternal.StageResponseComplete,
  87. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods", namespace),
  88. Verb: "create",
  89. Code: 201,
  90. User: auditTestUser,
  91. Resource: "pods",
  92. Namespace: namespace,
  93. RequestObject: true,
  94. ResponseObject: true,
  95. AuthorizeDecision: "allow",
  96. }, {
  97. Level: auditinternal.LevelRequest,
  98. Stage: auditinternal.StageResponseComplete,
  99. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods/audit-pod", namespace),
  100. Verb: "get",
  101. Code: 200,
  102. User: auditTestUser,
  103. Resource: "pods",
  104. Namespace: namespace,
  105. RequestObject: false,
  106. ResponseObject: false,
  107. AuthorizeDecision: "allow",
  108. }, {
  109. Level: auditinternal.LevelRequest,
  110. Stage: auditinternal.StageResponseComplete,
  111. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods", namespace),
  112. Verb: "list",
  113. Code: 200,
  114. User: auditTestUser,
  115. Resource: "pods",
  116. Namespace: namespace,
  117. RequestObject: false,
  118. ResponseObject: false,
  119. AuthorizeDecision: "allow",
  120. }, {
  121. Level: auditinternal.LevelRequest,
  122. Stage: auditinternal.StageResponseStarted,
  123. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  124. Verb: "watch",
  125. Code: 200,
  126. User: auditTestUser,
  127. Resource: "pods",
  128. Namespace: namespace,
  129. RequestObject: false,
  130. ResponseObject: false,
  131. AuthorizeDecision: "allow",
  132. }, {
  133. Level: auditinternal.LevelRequest,
  134. Stage: auditinternal.StageResponseComplete,
  135. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  136. Verb: "watch",
  137. Code: 200,
  138. User: auditTestUser,
  139. Resource: "pods",
  140. Namespace: namespace,
  141. RequestObject: false,
  142. ResponseObject: false,
  143. AuthorizeDecision: "allow",
  144. }, {
  145. Level: auditinternal.LevelRequestResponse,
  146. Stage: auditinternal.StageResponseComplete,
  147. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods/audit-pod", namespace),
  148. Verb: "update",
  149. Code: 200,
  150. User: auditTestUser,
  151. Resource: "pods",
  152. Namespace: namespace,
  153. RequestObject: true,
  154. ResponseObject: true,
  155. AuthorizeDecision: "allow",
  156. }, {
  157. Level: auditinternal.LevelRequestResponse,
  158. Stage: auditinternal.StageResponseComplete,
  159. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods/audit-pod", namespace),
  160. Verb: "patch",
  161. Code: 200,
  162. User: auditTestUser,
  163. Resource: "pods",
  164. Namespace: namespace,
  165. RequestObject: true,
  166. ResponseObject: true,
  167. AuthorizeDecision: "allow",
  168. }, {
  169. Level: auditinternal.LevelRequestResponse,
  170. Stage: auditinternal.StageResponseComplete,
  171. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods/audit-pod", namespace),
  172. Verb: "delete",
  173. Code: 200,
  174. User: auditTestUser,
  175. Resource: "pods",
  176. Namespace: namespace,
  177. RequestObject: true,
  178. ResponseObject: true,
  179. AuthorizeDecision: "allow",
  180. },
  181. })
  182. })
  183. ginkgo.It("should audit API calls to create, get, update, patch, delete, list, watch deployments.", func() {
  184. podLabels := map[string]string{"name": "audit-deployment-pod"}
  185. d := e2edeploy.NewDeployment("audit-deployment", int32(1), podLabels, "redis", imageutils.GetE2EImage(imageutils.Redis), apps.RecreateDeploymentStrategyType)
  186. _, err := f.ClientSet.AppsV1().Deployments(namespace).Create(d)
  187. framework.ExpectNoError(err, "failed to create audit-deployment")
  188. _, err = f.ClientSet.AppsV1().Deployments(namespace).Get(d.Name, metav1.GetOptions{})
  189. framework.ExpectNoError(err, "failed to get audit-deployment")
  190. deploymentChan, err := f.ClientSet.AppsV1().Deployments(namespace).Watch(watchOptions)
  191. framework.ExpectNoError(err, "failed to create watch for deployments")
  192. deploymentChan.Stop()
  193. _, err = f.ClientSet.AppsV1().Deployments(namespace).Update(d)
  194. framework.ExpectNoError(err, "failed to update audit-deployment")
  195. _, err = f.ClientSet.AppsV1().Deployments(namespace).Patch(d.Name, types.JSONPatchType, patch)
  196. framework.ExpectNoError(err, "failed to patch deployment")
  197. _, err = f.ClientSet.AppsV1().Deployments(namespace).List(metav1.ListOptions{})
  198. framework.ExpectNoError(err, "failed to create list deployments")
  199. err = f.ClientSet.AppsV1().Deployments(namespace).Delete("audit-deployment", &metav1.DeleteOptions{})
  200. framework.ExpectNoError(err, "failed to delete deployments")
  201. expectEvents(f, []utils.AuditEvent{
  202. {
  203. Level: auditinternal.LevelRequestResponse,
  204. Stage: auditinternal.StageResponseComplete,
  205. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments", namespace),
  206. Verb: "create",
  207. Code: 201,
  208. User: auditTestUser,
  209. Resource: "deployments",
  210. Namespace: namespace,
  211. RequestObject: true,
  212. ResponseObject: true,
  213. AuthorizeDecision: "allow",
  214. }, {
  215. Level: auditinternal.LevelRequest,
  216. Stage: auditinternal.StageResponseComplete,
  217. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments/audit-deployment", namespace),
  218. Verb: "get",
  219. Code: 200,
  220. User: auditTestUser,
  221. Resource: "deployments",
  222. Namespace: namespace,
  223. RequestObject: false,
  224. ResponseObject: false,
  225. AuthorizeDecision: "allow",
  226. }, {
  227. Level: auditinternal.LevelRequest,
  228. Stage: auditinternal.StageResponseComplete,
  229. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments", namespace),
  230. Verb: "list",
  231. Code: 200,
  232. User: auditTestUser,
  233. Resource: "deployments",
  234. Namespace: namespace,
  235. RequestObject: false,
  236. ResponseObject: false,
  237. AuthorizeDecision: "allow",
  238. }, {
  239. Level: auditinternal.LevelRequest,
  240. Stage: auditinternal.StageResponseStarted,
  241. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  242. Verb: "watch",
  243. Code: 200,
  244. User: auditTestUser,
  245. Resource: "deployments",
  246. Namespace: namespace,
  247. RequestObject: false,
  248. ResponseObject: false,
  249. AuthorizeDecision: "allow",
  250. }, {
  251. Level: auditinternal.LevelRequest,
  252. Stage: auditinternal.StageResponseComplete,
  253. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  254. Verb: "watch",
  255. Code: 200,
  256. User: auditTestUser,
  257. Resource: "deployments",
  258. Namespace: namespace,
  259. RequestObject: false,
  260. ResponseObject: false,
  261. AuthorizeDecision: "allow",
  262. }, {
  263. Level: auditinternal.LevelRequestResponse,
  264. Stage: auditinternal.StageResponseComplete,
  265. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments/audit-deployment", namespace),
  266. Verb: "update",
  267. Code: 200,
  268. User: auditTestUser,
  269. Resource: "deployments",
  270. Namespace: namespace,
  271. RequestObject: true,
  272. ResponseObject: true,
  273. AuthorizeDecision: "allow",
  274. }, {
  275. Level: auditinternal.LevelRequestResponse,
  276. Stage: auditinternal.StageResponseComplete,
  277. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments/audit-deployment", namespace),
  278. Verb: "patch",
  279. Code: 200,
  280. User: auditTestUser,
  281. Resource: "deployments",
  282. Namespace: namespace,
  283. RequestObject: true,
  284. ResponseObject: true,
  285. AuthorizeDecision: "allow",
  286. }, {
  287. Level: auditinternal.LevelRequestResponse,
  288. Stage: auditinternal.StageResponseComplete,
  289. RequestURI: fmt.Sprintf("/apis/apps/v1/namespaces/%s/deployments/audit-deployment", namespace),
  290. Verb: "delete",
  291. Code: 200,
  292. User: auditTestUser,
  293. Resource: "deployments",
  294. Namespace: namespace,
  295. RequestObject: true,
  296. ResponseObject: true,
  297. AuthorizeDecision: "allow",
  298. },
  299. })
  300. })
  301. ginkgo.It("should audit API calls to create, get, update, patch, delete, list, watch configmaps.", func() {
  302. configMap := &apiv1.ConfigMap{
  303. ObjectMeta: metav1.ObjectMeta{
  304. Name: "audit-configmap",
  305. },
  306. Data: map[string]string{
  307. "map-key": "map-value",
  308. },
  309. }
  310. _, err := f.ClientSet.CoreV1().ConfigMaps(namespace).Create(configMap)
  311. framework.ExpectNoError(err, "failed to create audit-configmap")
  312. _, err = f.ClientSet.CoreV1().ConfigMaps(namespace).Get(configMap.Name, metav1.GetOptions{})
  313. framework.ExpectNoError(err, "failed to get audit-configmap")
  314. configMapChan, err := f.ClientSet.CoreV1().ConfigMaps(namespace).Watch(watchOptions)
  315. framework.ExpectNoError(err, "failed to create watch for config maps")
  316. configMapChan.Stop()
  317. _, err = f.ClientSet.CoreV1().ConfigMaps(namespace).Update(configMap)
  318. framework.ExpectNoError(err, "failed to update audit-configmap")
  319. _, err = f.ClientSet.CoreV1().ConfigMaps(namespace).Patch(configMap.Name, types.JSONPatchType, patch)
  320. framework.ExpectNoError(err, "failed to patch configmap")
  321. _, err = f.ClientSet.CoreV1().ConfigMaps(namespace).List(metav1.ListOptions{})
  322. framework.ExpectNoError(err, "failed to list config maps")
  323. err = f.ClientSet.CoreV1().ConfigMaps(namespace).Delete(configMap.Name, &metav1.DeleteOptions{})
  324. framework.ExpectNoError(err, "failed to delete audit-configmap")
  325. expectEvents(f, []utils.AuditEvent{
  326. {
  327. Level: auditinternal.LevelMetadata,
  328. Stage: auditinternal.StageResponseComplete,
  329. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps", namespace),
  330. Verb: "create",
  331. Code: 201,
  332. User: auditTestUser,
  333. Resource: "configmaps",
  334. Namespace: namespace,
  335. RequestObject: false,
  336. ResponseObject: false,
  337. AuthorizeDecision: "allow",
  338. }, {
  339. Level: auditinternal.LevelMetadata,
  340. Stage: auditinternal.StageResponseComplete,
  341. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps/audit-configmap", namespace),
  342. Verb: "get",
  343. Code: 200,
  344. User: auditTestUser,
  345. Resource: "configmaps",
  346. Namespace: namespace,
  347. RequestObject: false,
  348. ResponseObject: false,
  349. AuthorizeDecision: "allow",
  350. }, {
  351. Level: auditinternal.LevelMetadata,
  352. Stage: auditinternal.StageResponseComplete,
  353. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps", namespace),
  354. Verb: "list",
  355. Code: 200,
  356. User: auditTestUser,
  357. Resource: "configmaps",
  358. Namespace: namespace,
  359. RequestObject: false,
  360. ResponseObject: false,
  361. AuthorizeDecision: "allow",
  362. }, {
  363. Level: auditinternal.LevelMetadata,
  364. Stage: auditinternal.StageResponseStarted,
  365. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  366. Verb: "watch",
  367. Code: 200,
  368. User: auditTestUser,
  369. Resource: "configmaps",
  370. Namespace: namespace,
  371. RequestObject: false,
  372. ResponseObject: false,
  373. AuthorizeDecision: "allow",
  374. }, {
  375. Level: auditinternal.LevelMetadata,
  376. Stage: auditinternal.StageResponseComplete,
  377. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  378. Verb: "watch",
  379. Code: 200,
  380. User: auditTestUser,
  381. Resource: "configmaps",
  382. Namespace: namespace,
  383. RequestObject: false,
  384. ResponseObject: false,
  385. AuthorizeDecision: "allow",
  386. }, {
  387. Level: auditinternal.LevelMetadata,
  388. Stage: auditinternal.StageResponseComplete,
  389. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps/audit-configmap", namespace),
  390. Verb: "update",
  391. Code: 200,
  392. User: auditTestUser,
  393. Resource: "configmaps",
  394. Namespace: namespace,
  395. RequestObject: false,
  396. ResponseObject: false,
  397. AuthorizeDecision: "allow",
  398. }, {
  399. Level: auditinternal.LevelMetadata,
  400. Stage: auditinternal.StageResponseComplete,
  401. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps/audit-configmap", namespace),
  402. Verb: "patch",
  403. Code: 200,
  404. User: auditTestUser,
  405. Resource: "configmaps",
  406. Namespace: namespace,
  407. RequestObject: false,
  408. ResponseObject: false,
  409. AuthorizeDecision: "allow",
  410. }, {
  411. Level: auditinternal.LevelMetadata,
  412. Stage: auditinternal.StageResponseComplete,
  413. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/configmaps/audit-configmap", namespace),
  414. Verb: "delete",
  415. Code: 200,
  416. User: auditTestUser,
  417. Resource: "configmaps",
  418. Namespace: namespace,
  419. RequestObject: false,
  420. ResponseObject: false,
  421. AuthorizeDecision: "allow",
  422. },
  423. })
  424. })
  425. ginkgo.It("should audit API calls to create, get, update, patch, delete, list, watch secrets.", func() {
  426. secret := &apiv1.Secret{
  427. ObjectMeta: metav1.ObjectMeta{
  428. Name: "audit-secret",
  429. },
  430. Data: map[string][]byte{
  431. "top-secret": []byte("foo-bar"),
  432. },
  433. }
  434. _, err := f.ClientSet.CoreV1().Secrets(namespace).Create(secret)
  435. framework.ExpectNoError(err, "failed to create audit-secret")
  436. _, err = f.ClientSet.CoreV1().Secrets(namespace).Get(secret.Name, metav1.GetOptions{})
  437. framework.ExpectNoError(err, "failed to get audit-secret")
  438. secretChan, err := f.ClientSet.CoreV1().Secrets(namespace).Watch(watchOptions)
  439. framework.ExpectNoError(err, "failed to create watch for secrets")
  440. secretChan.Stop()
  441. _, err = f.ClientSet.CoreV1().Secrets(namespace).Update(secret)
  442. framework.ExpectNoError(err, "failed to update audit-secret")
  443. _, err = f.ClientSet.CoreV1().Secrets(namespace).Patch(secret.Name, types.JSONPatchType, patch)
  444. framework.ExpectNoError(err, "failed to patch secret")
  445. _, err = f.ClientSet.CoreV1().Secrets(namespace).List(metav1.ListOptions{})
  446. framework.ExpectNoError(err, "failed to list secrets")
  447. err = f.ClientSet.CoreV1().Secrets(namespace).Delete(secret.Name, &metav1.DeleteOptions{})
  448. framework.ExpectNoError(err, "failed to delete audit-secret")
  449. expectEvents(f, []utils.AuditEvent{
  450. {
  451. Level: auditinternal.LevelMetadata,
  452. Stage: auditinternal.StageResponseComplete,
  453. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets", namespace),
  454. Verb: "create",
  455. Code: 201,
  456. User: auditTestUser,
  457. Resource: "secrets",
  458. Namespace: namespace,
  459. RequestObject: false,
  460. ResponseObject: false,
  461. AuthorizeDecision: "allow",
  462. }, {
  463. Level: auditinternal.LevelMetadata,
  464. Stage: auditinternal.StageResponseComplete,
  465. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets/audit-secret", namespace),
  466. Verb: "get",
  467. Code: 200,
  468. User: auditTestUser,
  469. Resource: "secrets",
  470. Namespace: namespace,
  471. RequestObject: false,
  472. ResponseObject: false,
  473. AuthorizeDecision: "allow",
  474. }, {
  475. Level: auditinternal.LevelMetadata,
  476. Stage: auditinternal.StageResponseComplete,
  477. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets", namespace),
  478. Verb: "list",
  479. Code: 200,
  480. User: auditTestUser,
  481. Resource: "secrets",
  482. Namespace: namespace,
  483. RequestObject: false,
  484. ResponseObject: false,
  485. AuthorizeDecision: "allow",
  486. }, {
  487. Level: auditinternal.LevelMetadata,
  488. Stage: auditinternal.StageResponseStarted,
  489. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  490. Verb: "watch",
  491. Code: 200,
  492. User: auditTestUser,
  493. Resource: "secrets",
  494. Namespace: namespace,
  495. RequestObject: false,
  496. ResponseObject: false,
  497. AuthorizeDecision: "allow",
  498. }, {
  499. Level: auditinternal.LevelMetadata,
  500. Stage: auditinternal.StageResponseComplete,
  501. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets?timeout=%ds&timeoutSeconds=%d&watch=true", namespace, watchTestTimeout, watchTestTimeout),
  502. Verb: "watch",
  503. Code: 200,
  504. User: auditTestUser,
  505. Resource: "secrets",
  506. Namespace: namespace,
  507. RequestObject: false,
  508. ResponseObject: false,
  509. AuthorizeDecision: "allow",
  510. }, {
  511. Level: auditinternal.LevelMetadata,
  512. Stage: auditinternal.StageResponseComplete,
  513. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets/audit-secret", namespace),
  514. Verb: "update",
  515. Code: 200,
  516. User: auditTestUser,
  517. Resource: "secrets",
  518. Namespace: namespace,
  519. RequestObject: false,
  520. ResponseObject: false,
  521. AuthorizeDecision: "allow",
  522. }, {
  523. Level: auditinternal.LevelMetadata,
  524. Stage: auditinternal.StageResponseComplete,
  525. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets/audit-secret", namespace),
  526. Verb: "patch",
  527. Code: 200,
  528. User: auditTestUser,
  529. Resource: "secrets",
  530. Namespace: namespace,
  531. RequestObject: false,
  532. ResponseObject: false,
  533. AuthorizeDecision: "allow",
  534. }, {
  535. Level: auditinternal.LevelMetadata,
  536. Stage: auditinternal.StageResponseComplete,
  537. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/secrets/audit-secret", namespace),
  538. Verb: "delete",
  539. Code: 200,
  540. User: auditTestUser,
  541. Resource: "secrets",
  542. Namespace: namespace,
  543. RequestObject: false,
  544. ResponseObject: false,
  545. AuthorizeDecision: "allow",
  546. },
  547. })
  548. })
  549. ginkgo.It("should audit API calls to create and delete custom resource definition.", func() {
  550. config, err := framework.LoadConfig()
  551. framework.ExpectNoError(err, "failed to load config")
  552. apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
  553. framework.ExpectNoError(err, "failed to initialize apiExtensionClient")
  554. crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, f.DynamicClient)
  555. framework.ExpectNoError(err, "failed to create custom resource definition")
  556. err = fixtures.DeleteCustomResourceDefinition(crd, apiExtensionClient)
  557. framework.ExpectNoError(err, "failed to delete custom resource definition")
  558. expectEvents(f, []utils.AuditEvent{
  559. {
  560. Level: auditinternal.LevelRequestResponse,
  561. Stage: auditinternal.StageResponseComplete,
  562. RequestURI: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions",
  563. Verb: "create",
  564. Code: 201,
  565. User: auditTestUser,
  566. Resource: "customresourcedefinitions",
  567. RequestObject: true,
  568. ResponseObject: true,
  569. AuthorizeDecision: "allow",
  570. }, {
  571. Level: auditinternal.LevelMetadata,
  572. Stage: auditinternal.StageResponseComplete,
  573. RequestURI: fmt.Sprintf("/apis/%s/v1beta1/%s", crdNamespace, crdName),
  574. Verb: "create",
  575. Code: 201,
  576. User: auditTestUser,
  577. Resource: crdName,
  578. RequestObject: false,
  579. ResponseObject: false,
  580. AuthorizeDecision: "allow",
  581. }, {
  582. Level: auditinternal.LevelRequestResponse,
  583. Stage: auditinternal.StageResponseComplete,
  584. RequestURI: fmt.Sprintf("/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/%s", crd.Name),
  585. Verb: "delete",
  586. Code: 200,
  587. User: auditTestUser,
  588. Resource: "customresourcedefinitions",
  589. RequestObject: false,
  590. ResponseObject: true,
  591. AuthorizeDecision: "allow",
  592. }, {
  593. Level: auditinternal.LevelMetadata,
  594. Stage: auditinternal.StageResponseComplete,
  595. RequestURI: fmt.Sprintf("/apis/%s/v1beta1/%s/setup-instance", crdNamespace, crdName),
  596. Verb: "delete",
  597. Code: 200,
  598. User: auditTestUser,
  599. Resource: crdName,
  600. RequestObject: false,
  601. ResponseObject: false,
  602. AuthorizeDecision: "allow",
  603. },
  604. })
  605. })
  606. // test authorizer annotations, RBAC is required.
  607. ginkgo.It("should audit API calls to get a pod with unauthorized user.", func() {
  608. if !auth.IsRBACEnabled(f.ClientSet.RbacV1beta1()) {
  609. framework.Skipf("RBAC not enabled.")
  610. }
  611. ginkgo.By("Creating a kubernetes client that impersonates an unauthorized anonymous user")
  612. config, err := framework.LoadConfig()
  613. framework.ExpectNoError(err)
  614. config.Impersonate = restclient.ImpersonationConfig{
  615. UserName: "system:anonymous",
  616. Groups: []string{"system:unauthenticated"},
  617. }
  618. anonymousClient, err := clientset.NewForConfig(config)
  619. framework.ExpectNoError(err)
  620. _, err = anonymousClient.CoreV1().Pods(namespace).Get("another-audit-pod", metav1.GetOptions{})
  621. expectForbidden(err)
  622. expectEvents(f, []utils.AuditEvent{
  623. {
  624. Level: auditinternal.LevelRequest,
  625. Stage: auditinternal.StageResponseComplete,
  626. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods/another-audit-pod", namespace),
  627. Verb: "get",
  628. Code: 403,
  629. User: auditTestUser,
  630. ImpersonatedUser: "system:anonymous",
  631. ImpersonatedGroups: "system:unauthenticated",
  632. Resource: "pods",
  633. Namespace: namespace,
  634. RequestObject: false,
  635. ResponseObject: false,
  636. AuthorizeDecision: "forbid",
  637. },
  638. })
  639. })
  640. ginkgo.It("should list pods as impersonated user.", func() {
  641. ginkgo.By("Creating a kubernetes client that impersonates an authorized user")
  642. config, err := framework.LoadConfig()
  643. framework.ExpectNoError(err)
  644. config.Impersonate = restclient.ImpersonationConfig{
  645. UserName: "superman",
  646. Groups: []string{"system:masters"},
  647. }
  648. impersonatedClient, err := clientset.NewForConfig(config)
  649. framework.ExpectNoError(err)
  650. _, err = impersonatedClient.CoreV1().Pods(namespace).List(metav1.ListOptions{})
  651. framework.ExpectNoError(err, "failed to list pods")
  652. expectEvents(f, []utils.AuditEvent{
  653. {
  654. Level: auditinternal.LevelRequest,
  655. Stage: auditinternal.StageResponseComplete,
  656. RequestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods", namespace),
  657. Verb: "list",
  658. Code: 200,
  659. User: auditTestUser,
  660. ImpersonatedUser: "superman",
  661. ImpersonatedGroups: "system:masters",
  662. Resource: "pods",
  663. Namespace: namespace,
  664. RequestObject: false,
  665. ResponseObject: false,
  666. AuthorizeDecision: "allow",
  667. },
  668. })
  669. })
  670. })
  671. func expectEvents(f *framework.Framework, expectedEvents []utils.AuditEvent) {
  672. // The default flush timeout is 30 seconds, therefore it should be enough to retry once
  673. // to find all expected events. However, we're waiting for 5 minutes to avoid flakes.
  674. pollingInterval := 30 * time.Second
  675. pollingTimeout := 5 * time.Minute
  676. err := wait.Poll(pollingInterval, pollingTimeout, func() (bool, error) {
  677. // Fetch the log stream.
  678. stream, err := f.ClientSet.CoreV1().RESTClient().Get().AbsPath("/logs/kube-apiserver-audit.log").Stream()
  679. if err != nil {
  680. return false, err
  681. }
  682. defer stream.Close()
  683. missingReport, err := utils.CheckAuditLines(stream, expectedEvents, auditv1.SchemeGroupVersion)
  684. if err != nil {
  685. e2elog.Logf("Failed to observe audit events: %v", err)
  686. } else if len(missingReport.MissingEvents) > 0 {
  687. e2elog.Logf(missingReport.String())
  688. }
  689. return len(missingReport.MissingEvents) == 0, nil
  690. })
  691. framework.ExpectNoError(err, "after %v failed to observe audit events", pollingTimeout)
  692. }