Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

e2e: allow usage of different PatchManifestFunc + add test for equal WorkloadSecretID #1104

Merged
merged 2 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 46 additions & 37 deletions e2e/internal/contrasttest/contrasttest.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,52 +179,61 @@ func (ct *ContrastTest) Generate(t *testing.T) {
require.NoError(err)
require.NotEmpty(hash, "expected apply to fill coordinator policy hash")

ct.patchReferenceValues(t, ct.Platform)
ct.PatchManifest(t, patchReferenceValues(ct.Platform))
}

// patchReferenceValues modifies the manifest to contain multiple reference values for testing
// cases with multiple validators, as well as filling in bare-metal SNP-specific values.
func (ct *ContrastTest) patchReferenceValues(t *testing.T, platform platforms.Platform) {
// PatchManifestFunc defines a function type allowing the given manifest to be modified.
type PatchManifestFunc func(manifest.Manifest) manifest.Manifest

// PatchManifest modifies the current manifest by executing a provided PatchManifestFunc on it.
func (ct *ContrastTest) PatchManifest(t *testing.T, patchFn PatchManifestFunc) {
manifestBytes, err := os.ReadFile(ct.WorkDir + "/manifest.json")
require.NoError(t, err)
var m manifest.Manifest
require.NoError(t, json.Unmarshal(manifestBytes, &m))
patchedManifest := patchFn(m)
manifestBytes, err = json.Marshal(patchedManifest)
require.NoError(t, err)
require.NoError(t, os.WriteFile(ct.WorkDir+"/manifest.json", manifestBytes, 0o644))
}

switch platform {
case platforms.AKSCloudHypervisorSNP:
// Duplicate the reference values to test multiple validators by having at least 2.
m.ReferenceValues.SNP = append(m.ReferenceValues.SNP, m.ReferenceValues.SNP[len(m.ReferenceValues.SNP)-1])

// Make the last set of reference values invalid by changing the SVNs.
m.ReferenceValues.SNP[len(m.ReferenceValues.SNP)-1].MinimumTCB = manifest.SNPTCB{
BootloaderVersion: toPtr(manifest.SVN(255)),
TEEVersion: toPtr(manifest.SVN(255)),
SNPVersion: toPtr(manifest.SVN(255)),
MicrocodeVersion: toPtr(manifest.SVN(255)),
}
case platforms.MetalQEMUSNP, platforms.K3sQEMUSNP:
// The generate command doesn't fill in all required fields when
// generating a manifest for baremetal SNP. Do that now.
for i, snp := range m.ReferenceValues.SNP {
snp.MinimumTCB.BootloaderVersion = toPtr(manifest.SVN(0))
snp.MinimumTCB.TEEVersion = toPtr(manifest.SVN(0))
snp.MinimumTCB.SNPVersion = toPtr(manifest.SVN(0))
snp.MinimumTCB.MicrocodeVersion = toPtr(manifest.SVN(0))
m.ReferenceValues.SNP[i] = snp
}
case platforms.MetalQEMUTDX, platforms.K3sQEMUTDX, platforms.RKE2QEMUTDX:
// The generate command doesn't fill in all required fields when
// generating a manifest for baremetal TDX. Do that now.
for i, tdx := range m.ReferenceValues.TDX {
tdx.MinimumTeeTcbSvn = manifest.HexString("04010200000000000000000000000000")
tdx.MrSeam = manifest.HexString("1cc6a17ab799e9a693fac7536be61c12ee1e0fabada82d0c999e08ccee2aa86de77b0870f558c570e7ffe55d6d47fa04")
m.ReferenceValues.TDX[i] = tdx
// patchReferenceValues returns a PatchManifestFunc which modifies a manifest to contain multiple reference values for testing
// cases with multiple validators, as well as filling in bare-metal SNP-specific values.
func patchReferenceValues(platform platforms.Platform) PatchManifestFunc {
return func(m manifest.Manifest) manifest.Manifest {
switch platform {
case platforms.AKSCloudHypervisorSNP:
// Duplicate the reference values to test multiple validators by having at least 2.
m.ReferenceValues.SNP = append(m.ReferenceValues.SNP, m.ReferenceValues.SNP[len(m.ReferenceValues.SNP)-1])

// Make the last set of reference values invalid by changing the SVNs.
m.ReferenceValues.SNP[len(m.ReferenceValues.SNP)-1].MinimumTCB = manifest.SNPTCB{
BootloaderVersion: toPtr(manifest.SVN(255)),
TEEVersion: toPtr(manifest.SVN(255)),
SNPVersion: toPtr(manifest.SVN(255)),
MicrocodeVersion: toPtr(manifest.SVN(255)),
}
jmxnzo marked this conversation as resolved.
Show resolved Hide resolved
case platforms.MetalQEMUSNP, platforms.K3sQEMUSNP:
// The generate command doesn't fill in all required fields when
// generating a manifest for baremetal SNP. Do that now.
for i, snp := range m.ReferenceValues.SNP {
snp.MinimumTCB.BootloaderVersion = toPtr(manifest.SVN(0))
snp.MinimumTCB.TEEVersion = toPtr(manifest.SVN(0))
snp.MinimumTCB.SNPVersion = toPtr(manifest.SVN(0))
snp.MinimumTCB.MicrocodeVersion = toPtr(manifest.SVN(0))
m.ReferenceValues.SNP[i] = snp
}
case platforms.MetalQEMUTDX, platforms.K3sQEMUTDX, platforms.RKE2QEMUTDX:
// The generate command doesn't fill in all required fields when
// generating a manifest for baremetal TDX. Do that now.
for i, tdx := range m.ReferenceValues.TDX {
tdx.MinimumTeeTcbSvn = manifest.HexString("04010200000000000000000000000000")
tdx.MrSeam = manifest.HexString("1cc6a17ab799e9a693fac7536be61c12ee1e0fabada82d0c999e08ccee2aa86de77b0870f558c570e7ffe55d6d47fa04")
m.ReferenceValues.TDX[i] = tdx
}
}
return m
}

manifestBytes, err = json.Marshal(m)
require.NoError(t, err)
require.NoError(t, os.WriteFile(ct.WorkDir+"/manifest.json", manifestBytes, 0o644))
}

// Apply the generated resources to the Kubernetes test environment.
Expand Down
38 changes: 38 additions & 0 deletions e2e/workloadsecret/workloadsecret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,44 @@ func TestWorkloadSecrets(t *testing.T) {
require.Len(emojiWorkloadSecretBytes, constants.SecretSeedSize)
require.NotEqual(webWorkloadSecretBytes, emojiWorkloadSecretBytes)
})

t.Run("workload secrets seeds can be set to be equal for different deployments", func(t *testing.T) {
require := require.New(t)
ctx, cancel := context.WithTimeout(context.Background(), ct.FactorPlatformTimeout(60*time.Second))
defer cancel()

ct.PatchManifest(t, patchWorkloadSecretID("web", "emoji"))

t.Run("set", ct.Set)
require.NoError(ct.Kubeclient.Restart(ctx, kubeclient.Deployment{}, ct.Namespace, "web"))
require.NoError(ct.Kubeclient.WaitFor(ctx, kubeclient.Ready, kubeclient.Deployment{}, ct.Namespace, "web"))

webPods, err = ct.Kubeclient.PodsFromDeployment(ctx, ct.Namespace, "web")
require.NoError(err)
require.Len(webPods, 2, "pod not found: %s/%s", ct.Namespace, "web")

stdout, stderr, err := ct.Kubeclient.Exec(ctx, ct.Namespace, webPods[0].Name, []string{"/bin/sh", "-c", "cat /contrast/secrets/workload-secret-seed"})
require.NoError(err, "stderr: %q", stderr)
require.NotEmpty(stdout)
webWorkloadSecretBytes, err = hex.DecodeString(stdout)
require.NoError(err)
require.Len(webWorkloadSecretBytes, constants.SecretSeedSize)
require.Equal(webWorkloadSecretBytes, emojiWorkloadSecretBytes)
})
}

// patchWorkloadSecretID returns a PatchManifestFunc which overwrites the expectedWorkloadSecretID with the patchWorkloadSecretID
// in a manifest.
func patchWorkloadSecretID(expectedWorkloadSecretID string, patchWorkloadSecretID string) contrasttest.PatchManifestFunc {
return func(m manifest.Manifest) manifest.Manifest {
for key, policy := range m.Policies {
if policy.WorkloadSecretID == expectedWorkloadSecretID {
policy.WorkloadSecretID = patchWorkloadSecretID
m.Policies[key] = policy
}
}
return m
}
}

func TestMain(m *testing.M) {
Expand Down