-
Notifications
You must be signed in to change notification settings - Fork 208
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds a test case for L7 policy with TLS
This adds a test to check if HTTPS traffic can get inspected in a CNP. To enable this it adds new helper functions to provision secrets, certificates and a public CA bundle into the test setup. Signed-off-by: Maartje Eyskens <[email protected]>
- Loading branch information
Showing
8 changed files
with
3,685 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package check | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
"fmt" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
"github.com/cilium/cilium-cli/k8s" | ||
) | ||
|
||
// addSecrets adds one or more secret(s) resources to the test. | ||
func (t *Test) addSecrets(secrets ...*corev1.Secret) error { | ||
if t.secrets == nil { | ||
t.secrets = make(map[string]*corev1.Secret) | ||
} | ||
|
||
for _, s := range secrets { | ||
if s == nil { | ||
return errors.New("cannot add nil Secret to test") | ||
} | ||
if s.Name == "" { | ||
return fmt.Errorf("adding Secret with empty name to test: %v", s) | ||
} | ||
if _, ok := t.secrets[s.Name]; ok { | ||
return fmt.Errorf("Secret with name %s already in test scope", s.Name) | ||
} | ||
|
||
t.secrets[s.Name] = s | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// applySecrets applies all the test's registered secrets. | ||
func (t *Test) applySecrets(ctx context.Context) error { | ||
if len(t.secrets) == 0 { | ||
return nil | ||
} | ||
|
||
for _, secret := range t.secrets { | ||
for _, client := range t.Context().clients.clients() { | ||
t.Infof("📜 Applying secret '%s' to namespace '%s'..", secret.Name, secret.Namespace) | ||
if _, err := updateOrCreateSecret(ctx, client, secret); err != nil { | ||
return fmt.Errorf("secret application failed: %w", err) | ||
} | ||
} | ||
} | ||
|
||
// Register a finalizer with the Test immediately to enable cleanup. | ||
t.finalizers = append(t.finalizers, func() error { | ||
// Use a detached context to make sure this call is not affected by | ||
// context cancellation. This deletion needs to happen event when the | ||
// user interrupted the program. | ||
if err := t.deleteSecrets(context.TODO()); err != nil { | ||
t.ciliumLogs(ctx) | ||
return err | ||
} | ||
|
||
return nil | ||
}) | ||
|
||
t.Debugf("📜 Successfully applied %d secret(s)", len(t.secrets)) | ||
|
||
return nil | ||
} | ||
|
||
// deleteSecrets deletes a given set of secrets from the cluster. | ||
func (t *Test) deleteSecrets(ctx context.Context) error { | ||
if len(t.secrets) == 0 { | ||
return nil | ||
} | ||
|
||
// Delete all the Test's secrers from all clients. | ||
for _, secret := range t.secrets { | ||
t.Infof("📜 Deleting secret '%s' from namespace '%s'..", secret.Name, secret.Namespace) | ||
for _, client := range t.Context().clients.clients() { | ||
if err := deleteSecret(ctx, client, secret); err != nil { | ||
return fmt.Errorf("deleting secret: %w", err) | ||
} | ||
} | ||
} | ||
|
||
t.Debugf("📜 Successfully deleted %d secret(s)", len(t.secrets)) | ||
|
||
return nil | ||
} | ||
|
||
func updateOrCreateSecret(ctx context.Context, client *k8s.Client, secret *corev1.Secret) (bool, error) { | ||
mod := false | ||
|
||
if existing, err := client.GetSecret(ctx, secret.Namespace, secret.Name, metav1.GetOptions{}); err == nil { | ||
// compare data map | ||
if len(existing.Data) != len(secret.Data) { | ||
mod = true | ||
} else { | ||
for k, v := range existing.Data { | ||
if v2, ok := secret.Data[k]; !ok || !bytes.Equal(v, v2) { | ||
mod = true | ||
break | ||
} | ||
} | ||
} | ||
|
||
_, err = client.UpdateSecret(ctx, secret.Namespace, secret, metav1.UpdateOptions{}) | ||
return mod, err | ||
} | ||
|
||
// Creating, so a resource will definitely be modified. | ||
mod = true | ||
_, err := client.CreateSecret(ctx, secret.Namespace, secret, metav1.CreateOptions{}) | ||
return mod, err | ||
} | ||
|
||
func deleteSecret(ctx context.Context, client *k8s.Client, secret *corev1.Secret) error { | ||
if err := client.DeleteSecret(ctx, secret.Namespace, secret.Name, metav1.DeleteOptions{}); err != nil { | ||
return fmt.Errorf("%s/%s/%s secret delete failed: %w", client.ClusterName(), secret.Namespace, secret.Name, err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
apiVersion: "cilium.io/v2" | ||
kind: CiliumNetworkPolicy | ||
metadata: | ||
name: "l7-policy-tls" | ||
specs: | ||
- description: "L7 policy with TLS" | ||
endpointSelector: | ||
matchLabels: | ||
kind: client | ||
egress: | ||
# Allow DNS | ||
- toPorts: | ||
- ports: | ||
- port: "53" | ||
protocol: ANY | ||
rules: | ||
dns: | ||
- matchPattern: "*" | ||
# Allow HTTPS when X-Very-Secret-Token is set | ||
- toFQDNs: | ||
- matchName: "{{.ExternalTarget}}" | ||
toPorts: | ||
- ports: | ||
- port: "443" | ||
protocol: "TCP" | ||
terminatingTLS: | ||
secret: | ||
namespace: "{{.TestNamespace}}" | ||
name: externaltarget-tls # internal certificate to terminate in cluster | ||
originatingTLS: | ||
secret: | ||
namespace: "{{.TestNamespace}}" | ||
name: cabundle # public CA bundle to validate external target | ||
rules: | ||
http: | ||
- method: "GET" | ||
path: "/" | ||
headers: | ||
- "X-Very-Secret-Token: 42" |
Oops, something went wrong.