diff --git a/e2e/imagepuller-auth/imagepuller-auth_test.go b/e2e/imagepuller-auth/imagepuller-auth_test.go index ad9e7a86ad..e1c0d39572 100644 --- a/e2e/imagepuller-auth/imagepuller-auth_test.go +++ b/e2e/imagepuller-auth/imagepuller-auth_test.go @@ -7,9 +7,7 @@ package imagepullerauth import ( "context" - "encoding/base64" "flag" - "fmt" "os" "testing" "time" @@ -18,7 +16,6 @@ import ( "github.com/edgelesssys/contrast/internal/kuberesource" "github.com/edgelesssys/contrast/internal/manifest" "github.com/edgelesssys/contrast/internal/platforms" - "github.com/pelletier/go-toml/v2" "github.com/stretchr/testify/require" ) @@ -27,26 +24,13 @@ func TestImagepullerAuth(t *testing.T) { require.NoError(t, err) ct := contrasttest.New(t) - token := os.Getenv("CONTRAST_GHCR_READ") - require.NotEmpty(t, token, "environment variable CONTRAST_GHCR_READ must be set with a ghcr token") - cfg := map[string]any{ - "registries": map[string]any{ - "ghcr.io.": map[string]string{ - "auth": base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "user-not-required-here:%s", token)), - }, - }, - } - imagePullerConfig, err := toml.Marshal(cfg) - require.NoError(t, err) - ct.NodeInstallerImagePullerConfig = imagePullerConfig - runtimeHandler, err := manifest.RuntimeHandler(platform) require.NoError(t, err) resources := kuberesource.CoordinatorBundle() deploymentName := "auth-test" - authTester := kuberesource.AuthenticatedPullTester(deploymentName, token) - resources = append(resources, authTester...) + authTester := kuberesource.AuthenticatedPullTester(deploymentName) + resources = append(resources, authTester) resources = kuberesource.PatchRuntimeHandlers(resources, runtimeHandler) resources = kuberesource.AddPortForwarders(resources) diff --git a/e2e/internal/contrasttest/contrasttest.go b/e2e/internal/contrasttest/contrasttest.go index e22589fd72..4fc871c6c6 100644 --- a/e2e/internal/contrasttest/contrasttest.go +++ b/e2e/internal/contrasttest/contrasttest.go @@ -10,6 +10,7 @@ import ( "context" "crypto/rand" "crypto/x509" + "encoding/base64" "encoding/json" "errors" "flag" @@ -32,6 +33,7 @@ import ( "github.com/edgelesssys/contrast/internal/platforms" "github.com/edgelesssys/contrast/internal/userapi" "github.com/edgelesssys/contrast/sdk" + "github.com/pelletier/go-toml/v2" "github.com/spf13/cobra" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -74,6 +76,7 @@ type ContrastTest struct { RuntimeClassName string NodeInstallerTargetConfType string NodeInstallerImagePullerConfig []byte + GHCRToken string Kubeclient *kubeclient.Kubeclient // outputs of contrast subcommands @@ -91,15 +94,29 @@ func New(t *testing.T) *ContrastTest { runtimeClass, err := kuberesource.ContrastRuntimeClass(platform) require.NoError(err) + token := os.Getenv("CONTRAST_GHCR_READ") + require.NotEmpty(t, token, "environment variable CONTRAST_GHCR_READ must be set with a ghcr token") + cfg := map[string]any{ + "registries": map[string]any{ + "ghcr.io.": map[string]string{ + "auth": base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "user-not-required-here:%s", token)), + }, + }, + } + imagePullerConfig, err := toml.Marshal(cfg) + require.NoError(err) + return &ContrastTest{ - Namespace: MakeNamespace(t, Flags.NamespaceSuffix), - WorkDir: t.TempDir(), - ImageReplacementsFile: Flags.ImageReplacementsFile, - Platform: platform, - NamespaceFile: Flags.NamespaceFile, - RuntimeClassName: *runtimeClass.Handler, - Kubeclient: kubeclient.NewForTest(t), - NodeInstallerTargetConfType: Flags.NodeInstallerTargetConfType, + Namespace: MakeNamespace(t, Flags.NamespaceSuffix), + WorkDir: t.TempDir(), + ImageReplacementsFile: Flags.ImageReplacementsFile, + Platform: platform, + NamespaceFile: Flags.NamespaceFile, + RuntimeClassName: *runtimeClass.Handler, + Kubeclient: kubeclient.NewForTest(t), + NodeInstallerTargetConfType: Flags.NodeInstallerTargetConfType, + GHCRToken: token, + NodeInstallerImagePullerConfig: imagePullerConfig, } } @@ -151,6 +168,7 @@ func (ct *ContrastTest) Init(t *testing.T, resources []any) { // Prepare resources resources = kuberesource.PatchImages(resources, ct.ImageReplacements) + resources = kuberesource.PatchDockerSecrets(resources, ct.Namespace, ct.GHCRToken) resources = kuberesource.PatchNamespaces(resources, ct.Namespace) resources = kuberesource.PatchCoordinatorMetrics(resources) resources = kuberesource.AddLogging(resources, "debug", "*") diff --git a/internal/kuberesource/mutators.go b/internal/kuberesource/mutators.go index da97b9ecfd..be9714223d 100644 --- a/internal/kuberesource/mutators.go +++ b/internal/kuberesource/mutators.go @@ -4,6 +4,7 @@ package kuberesource import ( + "encoding/base64" "fmt" "log" "slices" @@ -551,6 +552,37 @@ func PatchCoordinatorMetrics(resources []any) []any { return resources } +// PatchDockerSecrets adds a docker pull secret and references it in each PodSpec. +func PatchDockerSecrets(resources []any, namespace, token string) []any { + if token == "" { + return resources + } + + auth := base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "user-not-required-here:%s", token)) + content := fmt.Sprintf(`{"auths":{"ghcr.io":{"auth":%q}}}`, auth) + name := "ghcr-pull-secret" + + secret := applycorev1.Secret(name, namespace). + WithType(corev1.SecretTypeDockerConfigJson). + WithData(map[string][]byte{ + ".dockerconfigjson": []byte(content), + }) + + var out []any + for _, resource := range resources { + out = append(out, MapPodSpec(resource, func(spec *applycorev1.PodSpecApplyConfiguration) *applycorev1.PodSpecApplyConfiguration { + if spec == nil { + return spec + } + spec = spec.WithImagePullSecrets(applycorev1.LocalObjectReference().WithName(name)) + return spec + })) + } + + out = append(out, secret) + return out +} + // MapPodSpecWithMeta applies a function to a PodSpec in a Kubernetes resource, // and its corresponding object metadata. func MapPodSpecWithMeta( diff --git a/internal/kuberesource/sets.go b/internal/kuberesource/sets.go index 3ef9e2150d..0e0ae439d1 100644 --- a/internal/kuberesource/sets.go +++ b/internal/kuberesource/sets.go @@ -4,7 +4,6 @@ package kuberesource import ( - "encoding/base64" "fmt" "github.com/edgelesssys/contrast/internal/platforms" @@ -1010,7 +1009,7 @@ func MemDumpTester() []any { } // AuthenticatedPullTester returns the resources for the imagepuller-auth test. -func AuthenticatedPullTester(name, token string) []any { +func AuthenticatedPullTester(name string) any { deployment := Deployment(name, ""). WithSpec(DeploymentSpec(). WithReplicas(1). @@ -1020,7 +1019,6 @@ func AuthenticatedPullTester(name, token string) []any { WithTemplate(PodTemplateSpec(). WithLabels(map[string]string{"app.kubernetes.io/name": name}). WithSpec(PodSpec(). - WithImagePullSecrets(applycorev1.LocalObjectReference().WithName(name)). WithContainers( Container(). WithName("my-image-is-private"). @@ -1034,16 +1032,7 @@ func AuthenticatedPullTester(name, token string) []any { ), ) - auth := base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "user-not-required-here:%s", token)) - content := fmt.Sprintf(`{"auths":{"ghcr.io":{"auth":%q}}}`, auth) - - secret := applycorev1.Secret(name, ""). - WithType(corev1.SecretTypeDockerConfigJson). - WithData(map[string][]byte{ - ".dockerconfigjson": []byte(content), - }) - - return []any{deployment, secret} + return deployment } // Containerd11644ReproducerTesters returns the resources for the reproducer test for containerd issue #11644.