From 59cacc33bfa24576604d71b8d3de819b0bba82be Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Wed, 8 Jan 2025 17:09:47 +0100 Subject: [PATCH] cli: derive workload secret ID from GVK, namespace and name --- cli/cmd/policies.go | 31 ++++++++++--- cli/cmd/policies_test.go | 21 +++++---- e2e/workloadsecret/workloadsecret_test.go | 56 +++++++++++------------ 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/cli/cmd/policies.go b/cli/cmd/policies.go index b8dd413bd1..8363072368 100644 --- a/cli/cmd/policies.go +++ b/cli/cmd/policies.go @@ -8,13 +8,17 @@ import ( "log/slog" "os" "slices" + "strings" "github.com/edgelesssys/contrast/internal/kubeapi" "github.com/edgelesssys/contrast/internal/manifest" + "k8s.io/apimachinery/pkg/runtime/schema" ) type k8sObject interface { GetName() string + GetNamespace() string + GetObjectKind() schema.ObjectKind } func policiesFromKubeResources(yamlPaths []string) ([]deployment, error) { @@ -38,6 +42,10 @@ func policiesFromKubeResources(yamlPaths []string) ([]deployment, error) { continue } name := meta.GetName() + namespace := orDefault(meta.GetNamespace(), "default") + + gvk := meta.GetObjectKind().GroupVersionKind() + workloadSecretID := strings.Join([]string{orDefault(gvk.Group, "core"), gvk.Version, gvk.Kind, namespace, name}, "/") var annotation, role string switch obj := objAny.(type) { @@ -75,9 +83,10 @@ func policiesFromKubeResources(yamlPaths []string) ([]deployment, error) { return nil, fmt.Errorf("failed to parse policy %s: %w", name, err) } deployments = append(deployments, deployment{ - name: name, - policy: policy, - role: role, + name: name, + policy: policy, + role: role, + workloadSecretID: workloadSecretID, }) } @@ -94,7 +103,7 @@ func manifestPolicyMapFromPolicies(policies []deployment) (map[manifest.HexStrin } continue } - entry := manifest.PolicyEntry{SANs: depl.DNSNames(), WorkloadSecretID: depl.name} + entry := manifest.PolicyEntry{SANs: depl.DNSNames(), WorkloadSecretID: depl.workloadSecretID} policyHashes[depl.policy.Hash()] = entry } return policyHashes, nil @@ -136,11 +145,19 @@ func getCoordinatorPolicyHash(policies []deployment, log *slog.Logger) string { } type deployment struct { - name string - policy manifest.Policy - role string + name string + policy manifest.Policy + role string + workloadSecretID string } func (d deployment) DNSNames() []string { return []string{d.name, "*"} } + +func orDefault(s, d string) string { + if s == "" { + return d + } + return s +} diff --git a/cli/cmd/policies_test.go b/cli/cmd/policies_test.go index 7cce66eafc..b8b8e72704 100644 --- a/cli/cmd/policies_test.go +++ b/cli/cmd/policies_test.go @@ -74,9 +74,10 @@ func TestPoliciesFromKubeResources(t *testing.T) { }, expectedOutput: []deployment{ { - name: "test", - policy: manifest.Policy([]byte(`valid-agent-policy`)), - role: "coordinator", + name: "test", + policy: manifest.Policy([]byte(`valid-agent-policy`)), + role: "coordinator", + workloadSecretID: "apps/v1/Deployment/default/test", }, }, }, @@ -101,14 +102,16 @@ func TestPoliciesFromKubeResources(t *testing.T) { }, expectedOutput: []deployment{ { - name: "test", - policy: manifest.Policy([]byte(`valid-agent-policy`)), - role: "coordinator", + name: "test", + policy: manifest.Policy([]byte(`valid-agent-policy`)), + role: "coordinator", + workloadSecretID: "apps/v1/Deployment/default/test", }, { - name: "another-pod", - policy: manifest.Policy([]byte(`valid-agent-policy`)), - role: "worker", + name: "another-pod", + policy: manifest.Policy([]byte(`valid-agent-policy`)), + role: "worker", + workloadSecretID: "core/v1/Pod/default/another-pod", }, }, }, diff --git a/e2e/workloadsecret/workloadsecret_test.go b/e2e/workloadsecret/workloadsecret_test.go index 6f266055fa..fbff7d5819 100644 --- a/e2e/workloadsecret/workloadsecret_test.go +++ b/e2e/workloadsecret/workloadsecret_test.go @@ -111,7 +111,6 @@ func TestWorkloadSecrets(t *testing.T) { require.Equal(webWorkloadSecretBytes, otherWebWorkloadSecretBytes) }) - var emojiWorkloadSecretBytes []byte t.Run("workload secret seeds differ between deployments by default", func(t *testing.T) { require := require.New(t) @@ -125,7 +124,7 @@ func TestWorkloadSecrets(t *testing.T) { stdout, stderr, err := ct.Kubeclient.Exec(ctx, ct.Namespace, emojiPods[0].Name, []string{"/bin/sh", "-c", "cat /contrast/secrets/workload-secret-seed"}) require.NoError(err, "stderr: %q", stderr) require.NotEmpty(stdout) - emojiWorkloadSecretBytes, err = hex.DecodeString(stdout) + emojiWorkloadSecretBytes, err := hex.DecodeString(stdout) require.NoError(err) require.Len(emojiWorkloadSecretBytes, constants.SecretSeedSize) require.NotEqual(webWorkloadSecretBytes, emojiWorkloadSecretBytes) @@ -136,38 +135,35 @@ func TestWorkloadSecrets(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), ct.FactorPlatformTimeout(60*time.Second)) defer cancel() - ct.PatchManifest(t, patchWorkloadSecretID("web", "emoji")) + ct.PatchManifest(t, func(m manifest.Manifest) manifest.Manifest { + for key, policy := range m.Policies { + policy.WorkloadSecretID = "custom" + m.Policies[key] = policy + } + return m + }) 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 - } + var secrets [][]byte + for _, deploy := range []string{"web", "emoji"} { + require.NoError(ct.Kubeclient.Restart(ctx, kubeclient.Deployment{}, ct.Namespace, deploy)) + require.NoError(ct.Kubeclient.WaitFor(ctx, kubeclient.Ready, kubeclient.Deployment{}, ct.Namespace, deploy)) + + pods, err := ct.Kubeclient.PodsFromDeployment(ctx, ct.Namespace, deploy) + require.NoError(err) + require.GreaterOrEqual(len(pods), 1, "pod not found: %s/%s", ct.Namespace, deploy) + + stdout, stderr, err := ct.Kubeclient.Exec(ctx, ct.Namespace, pods[0].Name, []string{"/bin/sh", "-c", "cat /contrast/secrets/workload-secret-seed"}) + require.NoError(err, "stderr: %q", stderr) + require.NotEmpty(stdout) + secretBytes, err := hex.DecodeString(stdout) + require.NoError(err) + secrets = append(secrets, secretBytes) } - return m - } + require.Len(secrets, 2) + require.Equal(secrets[0], secrets[1]) + }) } func TestMain(m *testing.M) {