From e2c43cd98c2f232db5f777c8e79fe0026bad4a86 Mon Sep 17 00:00:00 2001 From: Patrick Decat Date: Fri, 7 Dec 2018 19:32:51 +0100 Subject: [PATCH 1/2] Add run_as_group property to container and pod security contexts, update documentation and acceptance tests --- kubernetes/resource_kubernetes_deployment_test.go | 4 ++++ kubernetes/resource_kubernetes_pod_test.go | 2 ++ .../resource_kubernetes_replication_controller_test.go | 2 ++ kubernetes/schema_container.go | 5 +++++ kubernetes/schema_pod_spec.go | 5 +++++ kubernetes/structures_container.go | 6 ++++++ kubernetes/structures_pod.go | 6 ++++++ website/docs/r/deployment.html.markdown | 2 ++ website/docs/r/pod.html.markdown | 2 ++ 9 files changed, 34 insertions(+) diff --git a/kubernetes/resource_kubernetes_deployment_test.go b/kubernetes/resource_kubernetes_deployment_test.go index 45c00b2553..124617fd33 100644 --- a/kubernetes/resource_kubernetes_deployment_test.go +++ b/kubernetes/resource_kubernetes_deployment_test.go @@ -185,6 +185,7 @@ func TestAccKubernetesDeployment_with_security_context(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKubernetesDeploymentExists(deploymentTestResourceName, &conf), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.fs_group", "100"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.run_as_group", "100"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.run_as_non_root", "true"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.run_as_user", "101"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.supplemental_groups.#", "1"), @@ -340,6 +341,7 @@ func TestAccKubernetesDeployment_with_container_security_context(t *testing.T) { resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.drop.0", "all"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.privileged", "true"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.read_only_root_filesystem", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_group", "200"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_non_root", "true"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_user", "201"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.se_linux_options.#", "1"), @@ -932,6 +934,7 @@ resource "kubernetes_deployment" "test" { spec { security_context { fs_group = 100 + run_as_group = 100 run_as_non_root = true run_as_user = 101 supplemental_groups = [101] @@ -1202,6 +1205,7 @@ resource "kubernetes_deployment" "test" { privileged = true read_only_root_filesystem = true + run_as_group = 200 run_as_non_root = true run_as_user = 201 diff --git a/kubernetes/resource_kubernetes_pod_test.go b/kubernetes/resource_kubernetes_pod_test.go index 54460c5a77..4b422d28a0 100644 --- a/kubernetes/resource_kubernetes_pod_test.go +++ b/kubernetes/resource_kubernetes_pod_test.go @@ -282,6 +282,7 @@ func TestAccKubernetesPod_with_pod_security_context(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKubernetesPodExists("kubernetes_pod.test", &conf), resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.fs_group", "100"), + resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.run_as_group", "100"), resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.run_as_non_root", "true"), resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.run_as_user", "101"), resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.supplemental_groups.#", "1"), @@ -845,6 +846,7 @@ resource "kubernetes_pod" "test" { spec { security_context { fs_group = 100 + run_as_group = 100 run_as_non_root = true run_as_user = 101 supplemental_groups = [101] diff --git a/kubernetes/resource_kubernetes_replication_controller_test.go b/kubernetes/resource_kubernetes_replication_controller_test.go index 8fe01bf62d..ae1c90a8c2 100644 --- a/kubernetes/resource_kubernetes_replication_controller_test.go +++ b/kubernetes/resource_kubernetes_replication_controller_test.go @@ -205,6 +205,7 @@ func TestAccKubernetesReplicationController_with_security_context(t *testing.T) Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKubernetesReplicationControllerExists("kubernetes_replication_controller.test", &conf), resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.fs_group", "100"), + resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.run_as_group", "100"), resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.run_as_non_root", "true"), resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.run_as_user", "101"), resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.supplemental_groups.#", "1"), @@ -739,6 +740,7 @@ resource "kubernetes_replication_controller" "test" { spec { security_context { fs_group = 100 + run_as_group = 100 run_as_non_root = true run_as_user = 101 supplemental_groups = [101] diff --git a/kubernetes/schema_container.go b/kubernetes/schema_container.go index 593a5ddc6f..9a3d15eb45 100644 --- a/kubernetes/schema_container.go +++ b/kubernetes/schema_container.go @@ -627,6 +627,11 @@ func securityContextSchema() *schema.Resource { Default: false, Description: "Whether this container has a read-only root filesystem. Default is false.", }, + "run_as_group": { + Type: schema.TypeInt, + Description: "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", + Optional: true, + }, "run_as_non_root": { Type: schema.TypeBool, Description: "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", diff --git a/kubernetes/schema_pod_spec.go b/kubernetes/schema_pod_spec.go index 3395530938..62f803ade2 100644 --- a/kubernetes/schema_pod_spec.go +++ b/kubernetes/schema_pod_spec.go @@ -203,6 +203,11 @@ func podSpecFields(isUpdatable, isDeprecated, isComputed bool) map[string]*schem Description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume.", Optional: true, }, + "run_as_group": { + Type: schema.TypeInt, + Description: "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.", + Optional: true, + }, "run_as_non_root": { Type: schema.TypeBool, Description: "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", diff --git a/kubernetes/structures_container.go b/kubernetes/structures_container.go index 6b43adaed9..53a8c5400f 100644 --- a/kubernetes/structures_container.go +++ b/kubernetes/structures_container.go @@ -30,6 +30,9 @@ func flattenContainerSecurityContext(in *v1.SecurityContext) []interface{} { if in.ReadOnlyRootFilesystem != nil { att["read_only_root_filesystem"] = *in.ReadOnlyRootFilesystem } + if in.RunAsGroup != nil { + att["run_as_group"] = *in.RunAsGroup + } if in.RunAsNonRoot != nil { att["run_as_non_root"] = *in.RunAsNonRoot } @@ -554,6 +557,9 @@ func expandContainerSecurityContext(l []interface{}) *v1.SecurityContext { if v, ok := in["read_only_root_filesystem"]; ok { obj.ReadOnlyRootFilesystem = ptrToBool(v.(bool)) } + if v, ok := in["run_as_group"]; ok { + obj.RunAsGroup = ptrToInt64(int64(v.(int))) + } if v, ok := in["run_as_non_root"]; ok { obj.RunAsNonRoot = ptrToBool(v.(bool)) } diff --git a/kubernetes/structures_pod.go b/kubernetes/structures_pod.go index dcd6a93281..1f204b365e 100644 --- a/kubernetes/structures_pod.go +++ b/kubernetes/structures_pod.go @@ -127,6 +127,9 @@ func flattenPodSecurityContext(in *v1.PodSecurityContext) []interface{} { if in.FSGroup != nil { att["fs_group"] = *in.FSGroup } + if in.RunAsGroup != nil { + att["run_as_group"] = *in.RunAsGroup + } if in.RunAsNonRoot != nil { att["run_as_non_root"] = *in.RunAsNonRoot } @@ -529,6 +532,9 @@ func expandPodSecurityContext(l []interface{}) *v1.PodSecurityContext { if v, ok := in["fs_group"].(int); ok { obj.FSGroup = ptrToInt64(int64(v)) } + if v, ok := in["run_as_group"].(int); ok { + obj.RunAsGroup = ptrToInt64(int64(v)) + } if v, ok := in["run_as_non_root"].(bool); ok { obj.RunAsNonRoot = ptrToBool(v) } diff --git a/website/docs/r/deployment.html.markdown b/website/docs/r/deployment.html.markdown index 9d8ca35ecd..6f0dddbc3a 100644 --- a/website/docs/r/deployment.html.markdown +++ b/website/docs/r/deployment.html.markdown @@ -588,6 +588,7 @@ The `items` block supports the following: * `capabilities` - (Optional) The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. * `privileged` - (Optional) Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. * `read_only_root_filesystem` - (Optional) Whether this container has a read-only root filesystem. Default is false. +* `run_as_group` - (Optional) The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `run_as_non_root` - (Optional) Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `run_as_user` - (Optional) The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `se_linux_options` - (Optional) The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. @@ -604,6 +605,7 @@ The `items` block supports the following: #### Arguments * `fs_group` - (Optional) A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume. +* `run_as_group` - (Optional) The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. * `run_as_non_root` - (Optional) Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `run_as_user` - (Optional) The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. * `se_linux_options` - (Optional) The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. diff --git a/website/docs/r/pod.html.markdown b/website/docs/r/pod.html.markdown index b1710d9eec..29258f9d04 100644 --- a/website/docs/r/pod.html.markdown +++ b/website/docs/r/pod.html.markdown @@ -544,6 +544,7 @@ The `items` block supports the following: * `capabilities` - (Optional) The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. * `privileged` - (Optional) Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. * `read_only_root_filesystem` - (Optional) Whether this container has a read-only root filesystem. Default is false. +* `run_as_group` - (Optional) The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `run_as_non_root` - (Optional) Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `run_as_user` - (Optional) The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `se_linux_options` - (Optional) The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. @@ -560,6 +561,7 @@ The `items` block supports the following: #### Arguments * `fs_group` - (Optional) A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume. +* `run_as_group` - (Optional) The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. * `run_as_non_root` - (Optional) Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. * `run_as_user` - (Optional) The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. * `se_linux_options` - (Optional) The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. From 3a5d885eeead292939347401605c77c8614cc941 Mon Sep 17 00:00:00 2001 From: Patrick Decat Date: Fri, 26 Apr 2019 20:34:04 +0200 Subject: [PATCH 2/2] Skip security_context acceptance test cases with run_as_group if kubernetes version is < 1.14.0 --- kubernetes/provider_test.go | 23 +++ .../resource_kubernetes_deployment_test.go | 181 +++++++++++++++++- kubernetes/resource_kubernetes_pod_test.go | 54 ++++++ ..._kubernetes_replication_controller_test.go | 68 +++++++ 4 files changed, 325 insertions(+), 1 deletion(-) diff --git a/kubernetes/provider_test.go b/kubernetes/provider_test.go index b0210d7ba8..af93a1ffbc 100644 --- a/kubernetes/provider_test.go +++ b/kubernetes/provider_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + gversion "github.com/hashicorp/go-version" "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" @@ -224,6 +225,28 @@ func skipIfNotRunningInGke(t *testing.T) { } } +func skipIfUnsupportedSecurityContextRunAsGroup(t *testing.T) { + meta := testAccProvider.Meta() + if meta == nil { + t.Fatal("Provider not initialized, unable to check cluster capabilities") + } + conn := meta.(*kubernetes.Clientset) + serverVersion, err := conn.ServerVersion() + if err != nil { + t.Fatal(err) + } + + k8sVersion, err := gversion.NewVersion(serverVersion.String()) + if err != nil { + t.Fatal(err) + } + + v1_14_0, _ := gversion.NewVersion("1.14.0") + if k8sVersion.LessThan(v1_14_0) { + t.Skip("The Kubernetes version must be 1.14.0 or newer for this test to run - skipping") + } +} + func isRunningInMinikube() (bool, error) { node, err := getFirstNode() if err != nil { diff --git a/kubernetes/resource_kubernetes_deployment_test.go b/kubernetes/resource_kubernetes_deployment_test.go index 124617fd33..1b9dc69be4 100644 --- a/kubernetes/resource_kubernetes_deployment_test.go +++ b/kubernetes/resource_kubernetes_deployment_test.go @@ -182,6 +182,32 @@ func TestAccKubernetesDeployment_with_security_context(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccKubernetesDeploymentConfigWithSecurityContext(rcName, imageName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKubernetesDeploymentExists(deploymentTestResourceName, &conf), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.fs_group", "100"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.run_as_non_root", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.run_as_user", "101"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.supplemental_groups.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.supplemental_groups.988695518", "101"), + ), + }, + }, + }) +} + +func TestAccKubernetesDeployment_with_security_context_run_as_group(t *testing.T) { + var conf api.Deployment + + rcName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) + imageName := "redis:5.0.2" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); skipIfUnsupportedSecurityContextRunAsGroup(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckKubernetesDeploymentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccKubernetesDeploymentConfigWithSecurityContextRunAsGroup(rcName, imageName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKubernetesDeploymentExists(deploymentTestResourceName, &conf), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.security_context.0.fs_group", "100"), @@ -341,7 +367,6 @@ func TestAccKubernetesDeployment_with_container_security_context(t *testing.T) { resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.drop.0", "all"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.privileged", "true"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.read_only_root_filesystem", "true"), - resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_group", "200"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_non_root", "true"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_user", "201"), resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.se_linux_options.#", "1"), @@ -352,6 +377,46 @@ func TestAccKubernetesDeployment_with_container_security_context(t *testing.T) { }) } +func TestAccKubernetesDeployment_with_container_security_context_run_as_group(t *testing.T) { + var conf api.Deployment + + rcName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) + imageName := "redis:5.0.2" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); skipIfUnsupportedSecurityContextRunAsGroup(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckKubernetesDeploymentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccKubernetesDeploymentConfigWithContainerSecurityContextRunAsGroup(rcName, imageName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKubernetesDeploymentExists(deploymentTestResourceName, &conf), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.#", "2"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.0.security_context.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.0.security_context.0.capabilities.#", "0"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.0.security_context.0.privileged", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.0.security_context.0.se_linux_options.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.0.security_context.0.se_linux_options.0.level", "s0:c123,c456"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.allow_privilege_escalation", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.add.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.add.0", "NET_BIND_SERVICE"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.drop.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.capabilities.0.drop.0", "all"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.privileged", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.read_only_root_filesystem", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_group", "200"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_non_root", "true"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.run_as_user", "201"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.se_linux_options.#", "1"), + resource.TestCheckResourceAttr(deploymentTestResourceName, "spec.0.template.0.spec.0.container.1.security_context.0.se_linux_options.0.level", "s0:c123,c789"), + ), + }, + }, + }) +} func TestAccKubernetesDeployment_with_volume_mount(t *testing.T) { var conf api.Deployment @@ -917,6 +982,50 @@ resource "kubernetes_deployment" "test" { } } + spec { + selector { + match_labels = { + Test = "TfAcceptanceTest" + } + } + + template { + metadata { + labels = { + Test = "TfAcceptanceTest" + } + } + + spec { + security_context { + fs_group = 100 + run_as_non_root = true + run_as_user = 101 + supplemental_groups = [101] + } + + container { + image = "%s" + name = "containername" + } + } + } + } +} +`, rcName, imageName) +} + +func testAccKubernetesDeploymentConfigWithSecurityContextRunAsGroup(rcName, imageName string) string { + return fmt.Sprintf(` +resource "kubernetes_deployment" "test" { + metadata { + name = "%s" + + labels = { + Test = "TfAcceptanceTest" + } + } + spec { selector { match_labels = { @@ -1161,6 +1270,76 @@ resource "kubernetes_deployment" "test" { } } + spec { + selector { + match_labels = { + Test = "TfAcceptanceTest" + } + } + + template { + metadata { + labels = { + Test = "TfAcceptanceTest" + } + } + + spec { + container { + image = "%s" + name = "containername" + + security_context { + privileged = true + run_as_user = 1 + + se_linux_options { + level = "s0:c123,c456" + } + } + } + + container { + image = "gcr.io/google_containers/liveness" + name = "containername2" + args = ["/server"] + + security_context { + allow_privilege_escalation = true + + capabilities { + drop = ["all"] + add = ["NET_BIND_SERVICE"] + } + + privileged = true + read_only_root_filesystem = true + run_as_non_root = true + run_as_user = 201 + + se_linux_options { + level = "s0:c123,c789" + } + } + } + } + } + } +} +`, rcName, imageName) +} + +func testAccKubernetesDeploymentConfigWithContainerSecurityContextRunAsGroup(rcName, imageName string) string { + return fmt.Sprintf(` +resource "kubernetes_deployment" "test" { + metadata { + name = "%s" + + labels = { + Test = "TfAcceptanceTest" + } + } + spec { selector { match_labels = { diff --git a/kubernetes/resource_kubernetes_pod_test.go b/kubernetes/resource_kubernetes_pod_test.go index 4b422d28a0..2737bd4934 100644 --- a/kubernetes/resource_kubernetes_pod_test.go +++ b/kubernetes/resource_kubernetes_pod_test.go @@ -279,6 +279,32 @@ func TestAccKubernetesPod_with_pod_security_context(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccKubernetesPodConfigWithSecurityContext(podName, imageName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKubernetesPodExists("kubernetes_pod.test", &conf), + resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.fs_group", "100"), + resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.run_as_non_root", "true"), + resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.run_as_user", "101"), + resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.supplemental_groups.#", "1"), + resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.supplemental_groups.988695518", "101"), + ), + }, + }, + }) +} + +func TestAccKubernetesPod_with_pod_security_context_run_as_group(t *testing.T) { + var conf api.Pod + + podName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) + imageName := "nginx:1.7.9" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); skipIfUnsupportedSecurityContextRunAsGroup(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckKubernetesPodDestroy, + Steps: []resource.TestStep{ + { + Config: testAccKubernetesPodConfigWithSecurityContextRunAsGroup(podName, imageName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKubernetesPodExists("kubernetes_pod.test", &conf), resource.TestCheckResourceAttr("kubernetes_pod.test", "spec.0.security_context.0.fs_group", "100"), @@ -843,6 +869,34 @@ resource "kubernetes_pod" "test" { name = "%s" } + spec { + security_context { + fs_group = 100 + run_as_non_root = true + run_as_user = 101 + supplemental_groups = [101] + } + + container { + image = "%s" + name = "containername" + } + } +} +`, podName, imageName) +} + +func testAccKubernetesPodConfigWithSecurityContextRunAsGroup(podName, imageName string) string { + return fmt.Sprintf(` +resource "kubernetes_pod" "test" { + metadata { + labels = { + app = "pod_label" + } + + name = "%s" + } + spec { security_context { fs_group = 100 diff --git a/kubernetes/resource_kubernetes_replication_controller_test.go b/kubernetes/resource_kubernetes_replication_controller_test.go index ae1c90a8c2..6dc15a3acd 100644 --- a/kubernetes/resource_kubernetes_replication_controller_test.go +++ b/kubernetes/resource_kubernetes_replication_controller_test.go @@ -202,6 +202,32 @@ func TestAccKubernetesReplicationController_with_security_context(t *testing.T) Steps: []resource.TestStep{ { Config: testAccKubernetesReplicationControllerConfigWithSecurityContext(rcName, imageName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKubernetesReplicationControllerExists("kubernetes_replication_controller.test", &conf), + resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.fs_group", "100"), + resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.run_as_non_root", "true"), + resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.run_as_user", "101"), + resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.supplemental_groups.#", "1"), + resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.supplemental_groups.988695518", "101"), + ), + }, + }, + }) +} + +func TestAccKubernetesReplicationController_with_security_context_run_as_group(t *testing.T) { + var conf api.ReplicationController + + rcName := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) + imageName := "nginx:1.7.9" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); skipIfUnsupportedSecurityContextRunAsGroup(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckKubernetesReplicationControllerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccKubernetesReplicationControllerConfigWithSecurityContextRunAsGroup(rcName, imageName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKubernetesReplicationControllerExists("kubernetes_replication_controller.test", &conf), resource.TestCheckResourceAttr("kubernetes_replication_controller.test", "spec.0.template.0.spec.0.security_context.0.fs_group", "100"), @@ -725,6 +751,48 @@ resource "kubernetes_replication_controller" "test" { } } + spec { + selector = { + Test = "TfAcceptanceTest" + } + + template { + metadata { + labels = { + Test = "TfAcceptanceTest" + } + } + + spec { + security_context { + fs_group = 100 + run_as_non_root = true + run_as_user = 101 + supplemental_groups = [101] + } + + container { + image = "%s" + name = "containername" + } + } + } + } +} +`, rcName, imageName) +} + +func testAccKubernetesReplicationControllerConfigWithSecurityContextRunAsGroup(rcName, imageName string) string { + return fmt.Sprintf(` +resource "kubernetes_replication_controller" "test" { + metadata { + name = "%s" + + labels = { + Test = "TfAcceptanceTest" + } + } + spec { selector = { Test = "TfAcceptanceTest"