From c8e7e7660f344e03f09b68098b413a45cbb1c3f9 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Mon, 3 Feb 2020 13:01:40 +0000 Subject: [PATCH] Create apm-service account for the APM Server when running on OCP --- test/e2e/cmd/run/run.go | 1 + test/e2e/test/apmserver/builder.go | 21 +++++++++++++++--- test/e2e/test/apmserver/steps_creation.go | 26 +++++++++++++++++++++++ test/e2e/test/context.go | 2 ++ test/e2e/test/default.go | 24 +++++++++++++++++++-- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/test/e2e/cmd/run/run.go b/test/e2e/cmd/run/run.go index 5dba4f48aa..68bc416c58 100644 --- a/test/e2e/cmd/run/run.go +++ b/test/e2e/cmd/run/run.go @@ -149,6 +149,7 @@ func (h *helper) initTestContext() error { TestRun: h.testRunName, TestTimeout: h.testTimeout, IgnoreWebhookFailures: h.ignoreWebhookFailures, + OcpCluster: h.kubectl("get", "clusterversion") == nil, } for i, ns := range h.managedNamespaces { diff --git a/test/e2e/test/apmserver/builder.go b/test/e2e/test/apmserver/builder.go index f0e0fd2566..92e8d36628 100644 --- a/test/e2e/test/apmserver/builder.go +++ b/test/e2e/test/apmserver/builder.go @@ -17,6 +17,7 @@ import ( // Builder to create APM Servers type Builder struct { ApmServer apmv1.ApmServer + ServiceAccount corev1.ServiceAccount } var _ test.Builder = Builder{} @@ -34,7 +35,16 @@ func newBuilder(name, randSuffix string) Builder { Name: name, Namespace: test.Ctx().ManagedNamespace(0), } + + sa := metav1.ObjectMeta{ + Name: name, + Namespace: test.Ctx().ManagedNamespace(0), + } + return Builder{ + ServiceAccount: corev1.ServiceAccount{ + ObjectMeta: sa, + }, ApmServer: apmv1.ApmServer{ ObjectMeta: meta, Spec: apmv1.ApmServerSpec{ @@ -47,7 +57,8 @@ func newBuilder(name, randSuffix string) Builder { }, PodTemplate: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ - SecurityContext: test.DefaultSecurityContext(), + ServiceAccountName: name, + SecurityContext: test.APMDefaultSecurityContext(), }, }, }, @@ -58,16 +69,20 @@ func newBuilder(name, randSuffix string) Builder { func (b Builder) WithSuffix(suffix string) Builder { if suffix != "" { b.ApmServer.ObjectMeta.Name = b.ApmServer.ObjectMeta.Name + "-" + suffix + b.ServiceAccount.ObjectMeta.Name = b.ApmServer.ObjectMeta.GetName() + b.ApmServer.Spec.PodTemplate.Spec.ServiceAccountName = b.ServiceAccount.GetName() } return b } func (b Builder) WithRestrictedSecurityContext() Builder { - b.ApmServer.Spec.PodTemplate.Spec.SecurityContext = test.DefaultSecurityContext() + b.ApmServer.Spec.PodTemplate.Spec.ServiceAccountName = b.ServiceAccount.GetName() + b.ApmServer.Spec.PodTemplate.Spec.SecurityContext = test.APMDefaultSecurityContext() return b } func (b Builder) WithNamespace(namespace string) Builder { + b.ServiceAccount.ObjectMeta.Namespace = namespace b.ApmServer.ObjectMeta.Namespace = namespace return b } @@ -113,7 +128,7 @@ func (b Builder) WithHTTPCfg(cfg commonv1.HTTPConfig) Builder { // -- Helper functions func (b Builder) RuntimeObjects() []runtime.Object { - return []runtime.Object{&b.ApmServer} + return []runtime.Object{&b.ServiceAccount, &b.ApmServer} } func (b Builder) RUMEnabled() bool { diff --git a/test/e2e/test/apmserver/steps_creation.go b/test/e2e/test/apmserver/steps_creation.go index 3467287d2f..337d958112 100644 --- a/test/e2e/test/apmserver/steps_creation.go +++ b/test/e2e/test/apmserver/steps_creation.go @@ -5,8 +5,13 @@ package apmserver import ( + "fmt" "testing" + "sigs.k8s.io/controller-runtime/pkg/client/config" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + secv1client "github.com/openshift/client-go/security/clientset/versioned/typed/security/v1" + apmv1 "github.com/elastic/cloud-on-k8s/pkg/apis/apm/v1" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" "github.com/elastic/cloud-on-k8s/test/e2e/test" @@ -25,6 +30,27 @@ func (b Builder) CreationTestSteps(k *test.K8sClient) test.StepList { } }, }, + { + Name: "Add apm-server service account to anyuid (OpenShift Only)", + Test: func(t *testing.T) { + if !test.Ctx().OcpCluster { + return + } + + cfg, err := config.GetConfig() + require.NoError(t, err) + + secClient := secv1client.NewForConfigOrDie(cfg) + require.NoError(t, err) + + scc, err := secClient.SecurityContextConstraints().Get("anyuid", metav1.GetOptions{}) + require.NoError(t, err) + + scc.Users = append(scc.Users, fmt.Sprintf("system:serviceaccount:%s:%s", b.ServiceAccount.GetNamespace(), b.ServiceAccount.GetName())) + scc, err = secClient.SecurityContextConstraints().Update(scc) + require.NoError(t, err) + }, + }, { Name: "APM Server should be created", Test: func(t *testing.T) { diff --git a/test/e2e/test/context.go b/test/e2e/test/context.go index ebaac94391..60bcb58366 100644 --- a/test/e2e/test/context.go +++ b/test/e2e/test/context.go @@ -76,6 +76,7 @@ func defaultContext() Context { ManagedNamespaces: []string{"mercury", "venus"}, }, TestRun: "e2e-default", + OcpCluster: false, } } @@ -97,6 +98,7 @@ type Context struct { AutoPortForwarding bool `json:"auto_port_forwarding"` Local bool `json:"local"` IgnoreWebhookFailures bool `json:"ignore_webhook_failures"` + OcpCluster bool `json:"ocp_cluster"` } // ManagedNamespace returns the nth managed namespace. diff --git a/test/e2e/test/default.go b/test/e2e/test/default.go index ffc447a07d..1d134d536b 100644 --- a/test/e2e/test/default.go +++ b/test/e2e/test/default.go @@ -12,10 +12,30 @@ import ( // Values should be inherited and checked against a PSP, but we provide some // default values if pods are started outside E2E tests, by a developer for example. func DefaultSecurityContext() *corev1.PodSecurityContext { + dscc := &corev1.PodSecurityContext{ + RunAsNonRoot: BoolPtr(true), + } + + if !Ctx().OcpCluster { + defaultUserID := int64(1000) + dscc.RunAsUser = &defaultUserID + dscc.FSGroup = &defaultUserID + } + + return dscc +} + +// It's currently not possible to run APM using OpenShift's +// restricted SCC. Therefore, we are forcing the required UID +// and fsGroup for APM's security context. A dedicated ServiceAccount +// with special permissions is created by APM test's builder +// so that this can work. +func APMDefaultSecurityContext() *corev1.PodSecurityContext { defaultUserID := int64(1000) + return &corev1.PodSecurityContext{ RunAsNonRoot: BoolPtr(true), - RunAsUser: &defaultUserID, - FSGroup: &defaultUserID, + RunAsUser: &defaultUserID, + FSGroup: &defaultUserID, } }