audit.go 29 KB

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