Repository: Shopify/kubeaudit (go)

Issue:
kubeaudit doesn't support initContainers
<!-- Please erase any parts of this template not applicable to your issue. -->

##### ISSUE TYPE
 - [x] Bug Report
 - [ ] Feature Idea

# BUG REPORT

##### SUMMARY
<!-- Briefly describe the problem/enhancement. -->

As pointed out by @thriqon in https://github.com/Shopify/kubeaudit/issues/285#issuecomment-891289275, kubeaudit audits `containers` but not `initContainers`. This is specifically problematic for the `apparmor` auditor which warns if an apparmor annotation refers to a container that doesn't exist and will remove that annotation in `autofix`. Since it ignores `initContainers` this would mean that an apparmor annotation which correctly refers to an `initContainer` would be removed by kubeaudit. In general though, we should add support for kubeaudit to add security controls to `initContainers` the same way it does for `containers`.

##### ENVIRONMENT
See https://github.com/Shopify/kubeaudit/issues/285#issuecomment-891894619

##### STEPS TO REPRODUCE

See https://github.com/Shopify/kubeaudit/issues/285#issuecomment-891894619

##### EXPECTED RESULTS

Kubeaudit should audit `initContainers` the same way it audits `containers`.

##### ACTUAL RESULTS

Kubeaudit ignores `initContainers` and removes apparmor annotations that refer to `initContainers`

##### ADDITIONAL INFORMATION

See https://github.com/Shopify/kubeaudit/issues/285#issuecomment-891894619


Pull request description:
pkg/k8s: add support for initContainer
<!-- Please erase any parts of this template not applicable to your Pull Request. -->

<!-- All code PR must be labeled with :bug: (patch fixes), :sparkles: (backwards-compatible features), or :warning: (breaking changes) -->

##### Description

Adds support for `initContainers`. Current state is as follows and as described [here](https://github.com/Shopify/kubeaudit/issues/355#issue-959191623):

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      annotations:
        container.apparmor.security.beta.kubernetes.io/nginx: runtime/default
        container.apparmor.security.beta.kubernetes.io/bb: runtime/default
    spec:
      initContainers:
      - image: busybox
        name: bb
        command:
          - /bin/echo
          - hello
      containers:
      - image: nginx
        name: nginx
```

```
$ kubeaudit apparmor -f deploy.yaml 

---------------- Results for ---------------

  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx

--------------------------------------------

-- [error] AppArmorInvalidAnnotation
   Message: AppArmor annotation key refers to a container that doesn't exist. Remove the annotation 'container.apparmor.security.beta.kubernetes.io/bb: runtime/default'.
   Metadata:
      Container: bb
      Annotation: container.apparmor.security.beta.kubernetes.io/bb: runtime/default

```

<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. -->

Fixes #355 

##### Type of change

<!-- Please delete options that are not relevant. --->
- [x] Bug fix :bug:
- [ ] New feature :sparkles:
- [ ] This change requires a documentation update :book:
- [ ] Breaking changes :warning:
##### How Has This Been Tested?

The tests are failing on the current main with the following error:
```
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
namespace/pod configured
Error from server (Forbidden): error when creating "../../internal/test/fixtures/all_resources/pod.yml": pods "pod" is forbidden: error looking up service account pod/default: serviceaccount "default" not found
```
Although I've tested my changes as part of this too by both removing the change (while keeping the fixtures) and vice versa. I'll take some time to look into the above error though.

##### Checklist:

- [x] I have :tophat: my changes (A 🎩 specifically includes pulling down changes, setting them up, and manually testing the changed features and potential side effects to make sure nothing is broken)
- [x] I have performed a self-review of my own code
- [ ] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] The test coverage did not decrease
- [x] I have signed the appropriate [Contributor License Agreement](https://cla.shopify.com/)


Patch:
diff --git a/auditors/apparmor/fixtures/apparmor-annotation-init-container-enabled.yml b/auditors/apparmor/fixtures/apparmor-annotation-init-container-enabled.yml
new file mode 100644
index 0000000..8a05260
--- /dev/null
+++ b/auditors/apparmor/fixtures/apparmor-annotation-init-container-enabled.yml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod
+  namespace: apparmor-annotation-init-container-enabled
+  annotations:
+    container.apparmor.security.beta.kubernetes.io/container: localhost/someval
+    container.apparmor.security.beta.kubernetes.io/init-container: localhost/someval
+spec:
+  initContainers:
+  - name: init-container
+    image: scratch
+  containers:
+    - name: container
+      image: scratch
diff --git a/auditors/apparmor/fixtures/apparmor-annotation-init-container-missing.yml b/auditors/apparmor/fixtures/apparmor-annotation-init-container-missing.yml
new file mode 100644
index 0000000..072a68c
--- /dev/null
+++ b/auditors/apparmor/fixtures/apparmor-annotation-init-container-missing.yml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod
+  namespace: apparmor-annotation-init-container-missing
+  annotations:
+    container.apparmor.security.beta.kubernetes.io/container: localhost/someval
+spec:
+  initContainers:
+  - name: init-container
+    image: scratch
+  containers:
+    - name: container
+      image: scratch
diff --git a/pkg/k8s/helpers.go b/pkg/k8s/helpers.go
index c4329d2..1b8cf07 100644
--- a/pkg/k8s/helpers.go
+++ b/pkg/k8s/helpers.go
@@ -17,9 +17,26 @@ func GetContainers(resource Resource) []*ContainerV1 {
 		return nil
 	}
 
-	containers := make([]*ContainerV1, len(podSpec.Containers))
+	var containers []*ContainerV1
 	for i := range podSpec.Containers {
-		containers[i] = &podSpec.Containers[i]
+		containers = append(containers, &podSpec.Containers[i])
+	}
+
+	if len(podSpec.InitContainers) > 0 {
+		containers = append(containers, GetInitContainers(resource)...)
+	}
+	return containers
+}
+
+func GetInitContainers(resource Resource) []*ContainerV1 {
+	podSpec := GetPodSpec(resource)
+	if podSpec == nil {
+		return nil
+	}
+
+	containers := make([]*ContainerV1, len(podSpec.InitContainers))
+	for i := range podSpec.InitContainers {
+		containers[i] = &podSpec.InitContainers[i]
 	}
 	return containers
 }


Test patch:
diff --git a/auditors/apparmor/apparmor_test.go b/auditors/apparmor/apparmor_test.go
index dd51cfc..a59d47b 100644
--- a/auditors/apparmor/apparmor_test.go
+++ b/auditors/apparmor/apparmor_test.go
@@ -19,6 +19,8 @@ func TestAuditAppArmor(t *testing.T) {
 	}{
 		{"apparmor-enabled.yml", nil, true},
 		{"apparmor-annotation-missing.yml", []string{AppArmorAnnotationMissing}, true},
+		{"apparmor-annotation-init-container-enabled.yml", nil, true},
+		{"apparmor-annotation-init-container-missing.yml", []string{AppArmorAnnotationMissing}, true},
 		// These are invalid manifests so we should only test it in manifest mode as kubernetes will fail to apply it
 		{"apparmor-disabled.yml", []string{AppArmorDisabled}, false},
 		{"apparmor-invalid-annotation.yml", []string{AppArmorInvalidAnnotation}, false},