Skip to content

Commit

Permalink
test: add e2e tests for multi-tenancy
Browse files Browse the repository at this point in the history
  • Loading branch information
binbin-li committed May 2, 2024
1 parent ce2415f commit a6d87b7
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 103 deletions.
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,17 @@ delete-ratify:

.PHONY: deploy-demo-constraints
deploy-demo-constraints:
kubectl apply -f ./library/default/template.yaml
kubectl apply -f ./library/default/samples/constraint.yaml
kubectl apply -f ./library/multi-tenancy-validation/template.yaml
kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml

.PHONY: delete-demo-constraints
delete-demo-constraints:
kubectl delete -f ./library/default/template.yaml
kubectl delete -f ./library/default/samples/constraint.yaml
kubectl delete -f ./library/multi-tenancy-validation/template.yaml
kubectl delete -f ./library/multi-tenancy-validation/samples/constraint.yaml

.PHONY: deploy-rego-policy
deploy-rego-policy:
kubectl apply -f ./config/samples/clustered/policy/config_v1beta1_policy_rego.yaml
kubectl replace -f ./config/samples/clustered/policy/config_v1beta1_policy_rego.yaml

.PHONY: deploy-gatekeeper
deploy-gatekeeper:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ spec:
scopes:
- "*"
keys:
- provider: ratify-cosign-inline-key-0
- provider: default/ratify-cosign-inline-key-0
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ spec:
parameters:
verificationCertStores:
certs:
- ratify-notation-inline-cert-0
- default/ratify-notation-inline-cert-0
trustPolicyDoc:
version: "1.0"
trustPolicies:
Expand Down
8 changes: 4 additions & 4 deletions internal/context/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ import (

type contextKey string

const contextKeyNamespace = contextKey("namespace")
const ContextKeyNamespace = contextKey("namespace")

// SetContextWithNamespace embeds namespace to the context.
func SetContextWithNamespace(ctx context.Context, namespace string) context.Context {
return context.WithValue(ctx, contextKeyNamespace, namespace)
return context.WithValue(ctx, ContextKeyNamespace, namespace)
}

// GetNamespace returns the embedded namespace from the context.
func GetNamespace(ctx context.Context) string {
namespace := ctx.Value(contextKeyNamespace)
namespace := ctx.Value(ContextKeyNamespace)
if namespace == nil {
return ""
}
Expand All @@ -40,7 +40,7 @@ func GetNamespace(ctx context.Context) string {

// CreateCacheKey creates a new cache key prefixed with embedded namespace.
func CreateCacheKey(ctx context.Context, key string) string {
namespace := ctx.Value(contextKeyNamespace)
namespace := ctx.Value(ContextKeyNamespace)
if namespace == nil {
return key
}
Expand Down
2 changes: 1 addition & 1 deletion internal/context/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
func TestSetContext(t *testing.T) {
ctx := context.Background()
ctx = SetContextWithNamespace(ctx, testNamespace)
namespace := ctx.Value(contextKeyNamespace).(string)
namespace := ctx.Value(ContextKeyNamespace).(string)
if namespace != testNamespace {
t.Fatalf("expected namespace %s, got %s", testNamespace, namespace)
}
Expand Down
2 changes: 2 additions & 0 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

logstash "github.com/bshuster-repo/logrus-logstash-hook"
re "github.com/deislabs/ratify/errors"
icontext "github.com/deislabs/ratify/internal/context"
dcontext "github.com/docker/distribution/context"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -93,6 +94,7 @@ func InitContext(ctx context.Context, r *http.Request) context.Context {

// GetLogger returns a logger with provided values.
func GetLogger(ctx context.Context, opt Option) dcontext.Logger {
ctx = dcontext.WithLogger(ctx, dcontext.GetLogger(ctx, icontext.ContextKeyNamespace))
ctx = context.WithValue(ctx, ContextKeyComponentType, opt.ComponentType)
return dcontext.GetLogger(ctx, ContextKeyComponentType)
}
Expand Down
11 changes: 11 additions & 0 deletions library/multi-tenancy-validation/samples/constraint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: RatifyVerification
metadata:
name: ratify-constraint
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["default", "new-namespace"]
48 changes: 48 additions & 0 deletions library/multi-tenancy-validation/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: ratifyverification
spec:
crd:
spec:
names:
kind: RatifyVerification
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package ratifyverification
# Get data from Ratify
remote_data := response {
images := [img | img = concat("", ["[",input.review.object.metadata.namespace,"]",input.review.object.spec.containers[_].image])]
images_init := [img | img = concat("", ["[",input.review.object.metadata.namespace,"]",input.review.object.spec.initContainers[_].image])]
images_ephemeral := [img | img = concat("", ["[",input.review.object.metadata.namespace,"]",input.review.object.spec.ephemeralContainers[_].image])]
other_images := array.concat(images_init, images_ephemeral)
all_images := array.concat(other_images, images)
response := external_data({"provider": "ratify-provider", "keys": all_images})
}
# Base Gatekeeper violation
violation[{"msg": msg}] {
general_violation[{"result": msg}]
}
# Check if there are any system errors
general_violation[{"result": result}] {
err := remote_data.system_error
err != ""
result := sprintf("System error calling external data provider: %s", [err])
}
# Check if there are errors for any of the images
general_violation[{"result": result}] {
count(remote_data.errors) > 0
result := sprintf("Error validating one or more images: %s", remote_data.errors)
}
# Check if the success criteria is true
general_violation[{"result": result}] {
subject_validation := remote_data.responses[_]
subject_validation[1].isSuccess == false
result := sprintf("Subject failed verification: %s", [subject_validation[0]])
}
58 changes: 29 additions & 29 deletions test/bats/azure-test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ SLEEP_TIME=1

# ensure that the chart deployment is reset to a clean state for other tests
teardown() {
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-dynamic --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-dynamic --ignore-not-found=true'
pod=$(kubectl -n gatekeeper-system get pod -l=app.kubernetes.io/name=ratify --sort-by=.metadata.creationTimestamp -o=name | tail -n 1)
helm upgrade --atomic --namespace gatekeeper-system --reuse-values --set featureFlags.RATIFY_EXPERIMENTAL_DYNAMIC_PLUGINS=false ratify ./charts/ratify
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl -n gatekeeper-system delete $pod --force --grace-period=0'
Expand Down Expand Up @@ -54,9 +54,9 @@ SLEEP_TIME=1
}

# configure the default template/constraint
run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success

# verify that the image can be run with a root cert, root verification cert should have been configured on deployment
Expand Down Expand Up @@ -87,10 +87,10 @@ SLEEP_TIME=1
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod demo1 --namespace default --force --ignore-not-found=true'
}

run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5
run kubectl run demo --namespace default --image=${TEST_REGISTRY}/notation:signed
Expand All @@ -106,10 +106,10 @@ SLEEP_TIME=1
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod cosign-demo2 --namespace default --force --ignore-not-found=true'
}

run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5
run kubectl apply -f ./test/bats/tests/config/config_v1beta1_verifier_cosign_akv.yaml
Expand All @@ -127,13 +127,13 @@ SLEEP_TIME=1
echo "cleaning up"
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod license-checker --namespace default --force --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod license-checker2 --namespace default --force --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-license-checker --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-license-checker --ignore-not-found=true'
}

run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5

Expand All @@ -156,10 +156,10 @@ SLEEP_TIME=1
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod sbom2 --namespace default --force --ignore-not-found=true'
}

run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5

Expand All @@ -179,17 +179,17 @@ SLEEP_TIME=1
@test "schemavalidator verifier test" {
teardown() {
echo "cleaning up"
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-license-checker --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-sbom --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-schemavalidator --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-license-checker --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-sbom --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-schemavalidator --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod schemavalidator --namespace default --force --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod schemavalidator2 --namespace default --force --ignore-not-found=true'
}

run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5

Expand All @@ -209,17 +209,17 @@ SLEEP_TIME=1
@test "sbom/notary/cosign/licensechecker/schemavalidator verifiers test" {
teardown() {
echo "cleaning up"
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-license-checker --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-sbom --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-schemavalidator --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-cosign --namespace default --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-license-checker --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-sbom --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-schemavalidator --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete verifiers.config.ratify.deislabs.io/verifier-cosign --ignore-not-found=true'
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod all-in-one --namespace default --force --ignore-not-found=true'
}

run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5

Expand Down Expand Up @@ -262,23 +262,23 @@ SLEEP_TIME=1

@test "configmap update test" {
skip "Skipping test for now as we are no longer watching for configfile update in a K8s environment.This test ensures we are watching config file updates in a non-kub scenario"
run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5
run kubectl run demo2 --image=${TEST_REGISTRY}/notation:signed
assert_success

run kubectl get configmaps ratify-configuration --namespace=gatekeeper-system -o yaml >currentConfig.yaml
run kubectl delete -f ./library/default/samples/constraint.yaml
run kubectl delete -f ./library/multi-tenancy-validation/samples/constraint.yaml

wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl replace --namespace=gatekeeper-system -f ${BATS_TESTS_DIR}/configmap/invalidconfigmap.yaml"
echo "Waiting for 150 second for configuration update"
sleep 150

run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
run kubectl run demo3 --image=${TEST_REGISTRY}/notation:signed
echo "Current time after validate : $(date +"%T")"
Expand Down Expand Up @@ -307,10 +307,10 @@ SLEEP_TIME=1
echo "cleaning up"
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod mutate-demo --namespace default --ignore-not-found=true'
}
run kubectl apply -f ./library/default/template.yaml
run kubectl apply -f ./library/multi-tenancy-validation/template.yaml
assert_success
sleep 5
run kubectl apply -f ./library/default/samples/constraint.yaml
run kubectl apply -f ./library/multi-tenancy-validation/samples/constraint.yaml
assert_success
sleep 5
run kubectl run mutate-demo --namespace default --image=${TEST_REGISTRY}/notation:signed
Expand Down
Loading

0 comments on commit a6d87b7

Please sign in to comment.