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

TLS certificate rotation tests #7103

Merged
merged 20 commits into from
Aug 3, 2023
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
24 changes: 24 additions & 0 deletions test/config-transport-encryption/features.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2021 The Knative Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: ConfigMap
metadata:
name: config-features
namespace: knative-eventing
labels:
knative.dev/config-propagation: original
knative.dev/config-category: eventing
data:
transport-encryption: "strict"
12 changes: 9 additions & 3 deletions test/e2e-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ readonly CONFIG_TRACING_CONFIG="test/config/config-tracing.yaml"
readonly KNATIVE_EVENTING_MONITORING_YAML="test/config/monitoring.yaml"

# The number of controlplane replicas to run.
readonly REPLICAS=3
readonly REPLICAS=${REPLICAS:-3}

# Should deploy a Knative Monitoring as well
readonly DEPLOY_KNATIVE_MONITORING="${DEPLOY_KNATIVE_MONITORING:-1}"
Expand All @@ -76,15 +76,15 @@ UNINSTALL_LIST=()

# Setup the Knative environment for running tests.
function knative_setup() {
install_cert_manager || fail_test "Could not install Cert Manager"

install_knative_eventing "HEAD"

install_mt_broker || fail_test "Could not install MT Channel Based Broker"

enable_sugar || fail_test "Could not enable Sugar Controller Injection"

unleash_duck || fail_test "Could not unleash the chaos duck"

install_cert_manager || fail_test "Could not install Cert Manager"
}

function scale_controlplane() {
Expand Down Expand Up @@ -147,6 +147,12 @@ function install_knative_eventing() {
-f "${EVENTING_CORE_NAME}" || return 1
UNINSTALL_LIST+=( "${EVENTING_CORE_NAME}" )

local EVENTING_TLS_NAME=${TMP_DIR}/${EVENTING_TLS_YAML##*/}
sed "s/namespace: ${KNATIVE_DEFAULT_NAMESPACE}/namespace: ${SYSTEM_NAMESPACE}/g" ${EVENTING_TLS_YAML} > ${EVENTING_TLS_NAME}
kubectl apply \
-f "${EVENTING_TLS_NAME}" || return 1
UNINSTALL_LIST+=( "${EVENTING_TLS_NAME}" )

kubectl patch horizontalpodautoscalers.autoscaling -n ${SYSTEM_NAMESPACE} eventing-webhook -p '{"spec": {"minReplicas": '${REPLICAS}'}}' || return 1

else
Expand Down
6 changes: 6 additions & 0 deletions test/e2e-rekt-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,10 @@ echo "Running E2E Reconciler Tests"

go_test_e2e -timeout=1h ./test/rekt || fail_test

echo "Running E2E Reconciler Tests with strict transport encryption"

kubectl apply -Rf "$(dirname "$0")/config-transport-encryption"

go_test_e2e -timeout=1h ./test/rekt -run TLS || fail_test

success
3 changes: 1 addition & 2 deletions test/e2e-upgrade-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ source "$(dirname "${BASH_SOURCE[0]}")/e2e-common.sh"
# Overrides

function knative_setup {
# Nothing to do at setup
true
install_cert_manager || return $?
}

function install_test_resources {
Expand Down
17 changes: 17 additions & 0 deletions test/rekt/broker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"knative.dev/pkg/system"
_ "knative.dev/pkg/system/testing"
"knative.dev/reconciler-test/pkg/environment"
"knative.dev/reconciler-test/pkg/eventshub"
"knative.dev/reconciler-test/pkg/k8s"
"knative.dev/reconciler-test/pkg/knative"
"knative.dev/reconciler-test/pkg/tracing"
Expand Down Expand Up @@ -230,3 +231,19 @@ func TestBrokerDeliverLongResponseMessage(t *testing.T) {

env.TestSet(ctx, t, broker.BrokerDeliverLongResponseMessage())
}

func TestMTChannelBrokerRotateTLSCertificates(t *testing.T) {
t.Parallel()

ctx, env := global.Environment(
knative.WithKnativeNamespace(system.Namespace()),
knative.WithLoggingConfig,
knative.WithTracingConfig,
k8s.WithEventListener,
environment.Managed(t),
eventshub.WithTLS(t),
environment.WithPollTimings(5*time.Second, 4*time.Minute),
)

env.Test(ctx, t, broker.RotateMTChannelBrokerTLSCertificates())
}
18 changes: 18 additions & 0 deletions test/rekt/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ package rekt

import (
"testing"
"time"

"github.com/cloudevents/sdk-go/v2/binding"
duckv1 "knative.dev/pkg/apis/duck/v1"
"knative.dev/pkg/system"
_ "knative.dev/pkg/system/testing"
"knative.dev/reconciler-test/pkg/environment"
"knative.dev/reconciler-test/pkg/eventshub"
"knative.dev/reconciler-test/pkg/k8s"
"knative.dev/reconciler-test/pkg/knative"
"knative.dev/reconciler-test/pkg/manifest"
Expand Down Expand Up @@ -318,3 +320,19 @@ func TestChannelDeadLetterSinkExtensions(t *testing.T) {

env.TestSet(ctx, t, channel.ChannelDeadLetterSinkExtensions(createSubscriberFn))
}

func TestInMemoryChannelRotateIngressTLSCertificate(t *testing.T) {
t.Parallel()

ctx, env := global.Environment(
knative.WithKnativeNamespace(system.Namespace()),
knative.WithLoggingConfig,
knative.WithTracingConfig,
k8s.WithEventListener,
environment.Managed(t),
eventshub.WithTLS(t),
environment.WithPollTimings(5*time.Second, 4*time.Minute),
)

env.Test(ctx, t, channel.RotateDispatcherTLSCertificate())
}
105 changes: 105 additions & 0 deletions test/rekt/features/broker/eventing_tls_feature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright 2023 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package broker

import (
"context"
"time"

cetest "github.com/cloudevents/sdk-go/v2/test"
"github.com/google/uuid"
"k8s.io/apimachinery/pkg/types"
"knative.dev/pkg/system"
"knative.dev/reconciler-test/pkg/eventshub"
"knative.dev/reconciler-test/pkg/eventshub/assert"
"knative.dev/reconciler-test/pkg/feature"
"knative.dev/reconciler-test/pkg/resources/service"
"knative.dev/reconciler-test/resources/certificate"

"knative.dev/eventing/test/rekt/features/featureflags"
"knative.dev/eventing/test/rekt/resources/addressable"
"knative.dev/eventing/test/rekt/resources/broker"
"knative.dev/eventing/test/rekt/resources/trigger"
)

func RotateMTChannelBrokerTLSCertificates() *feature.Feature {
ingressCertificateName := "mt-broker-ingress-server-tls"
ingressSecretName := "mt-broker-ingress-server-tls"

filterCertificateName := "mt-broker-filter-server-tls"

brokerName := feature.MakeRandomK8sName("broker")
triggerName := feature.MakeRandomK8sName("trigger")
sink := feature.MakeRandomK8sName("sink")
source := feature.MakeRandomK8sName("source")

f := feature.NewFeatureNamed("Rotate MTChannelBroker TLS certificate")

f.Prerequisite("transport encryption is strict", featureflags.TransportEncryptionStrict())
f.Prerequisite("should not run when Istio is enabled", featureflags.IstioDisabled())

f.Setup("Rotate ingress certificate", certificate.Rotate(certificate.RotateCertificate{
Certificate: types.NamespacedName{
Namespace: system.Namespace(),
Name: ingressCertificateName,
},
}))
// We cannot externally verify this certificate rotation
f.Setup("Rotate filter certificate", certificate.Rotate(certificate.RotateCertificate{
Certificate: types.NamespacedName{
Namespace: system.Namespace(),
Name: filterCertificateName,
},
}))

f.Setup("install sink", eventshub.Install(sink, eventshub.StartReceiverTLS))
f.Setup("install broker", broker.Install(brokerName, broker.WithEnvConfig()...))
f.Setup("Broker is ready", broker.IsReady(brokerName))
f.Setup("install trigger", func(ctx context.Context, t feature.T) {
d := service.AsDestinationRef(sink)
d.CACerts = eventshub.GetCaCerts(ctx)
trigger.Install(triggerName, brokerName, trigger.WithSubscriberFromDestination(d))(ctx, t)
})
f.Setup("trigger is ready", trigger.IsReady(triggerName))
f.Setup("Broker has HTTPS address", broker.ValidateAddress(brokerName, addressable.AssertHTTPSAddress))

event := cetest.FullEvent()
event.SetID(uuid.New().String())

f.Requirement("install source", eventshub.Install(source,
eventshub.StartSenderToResourceTLS(broker.GVR(), brokerName, nil),
eventshub.InputEvent(event),
// Send multiple events so that we take into account that the certificate rotation might
// be detected by the server after some time.
eventshub.SendMultipleEvents(100, 3*time.Second),
))

f.Assert("Event sent", assert.OnStore(source).
MatchSentEvent(cetest.HasId(event.ID())).
AtLeast(1),
)
f.Assert("Event received", assert.OnStore(sink).
MatchReceivedEvent(cetest.HasId(event.ID())).
AtLeast(1),
)
f.Assert("Source match updated peer certificate", assert.OnStore(source).
MatchPeerCertificatesReceived(assert.MatchPeerCertificatesFromSecret(system.Namespace(), ingressSecretName, "tls.crt")).
AtLeast(1),
)

return f
}
98 changes: 98 additions & 0 deletions test/rekt/features/channel/eventing_tls_feature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
Copyright 2023 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package channel

import (
"context"
"time"

cetest "github.com/cloudevents/sdk-go/v2/test"
"github.com/google/uuid"
"k8s.io/apimachinery/pkg/types"
"knative.dev/pkg/system"
"knative.dev/reconciler-test/pkg/eventshub"
"knative.dev/reconciler-test/pkg/eventshub/assert"
"knative.dev/reconciler-test/pkg/feature"
"knative.dev/reconciler-test/pkg/resources/service"
"knative.dev/reconciler-test/resources/certificate"

"knative.dev/eventing/test/rekt/features/featureflags"
"knative.dev/eventing/test/rekt/resources/addressable"
"knative.dev/eventing/test/rekt/resources/channel_impl"
"knative.dev/eventing/test/rekt/resources/subscription"
)

func RotateDispatcherTLSCertificate() *feature.Feature {
certificateName := "imc-dispatcher-server-tls"
secretName := "imc-dispatcher-server-tls"

channelName := feature.MakeRandomK8sName("channel")
subscriptionName := feature.MakeRandomK8sName("sub")
sink := feature.MakeRandomK8sName("sink")
source := feature.MakeRandomK8sName("source")

f := feature.NewFeatureNamed("Rotate " + certificateName + " certificate")

f.Prerequisite("transport encryption is strict", featureflags.TransportEncryptionStrict())
f.Prerequisite("should not run when Istio is enabled", featureflags.IstioDisabled())

f.Setup("Rotate certificate", certificate.Rotate(certificate.RotateCertificate{
Certificate: types.NamespacedName{
Namespace: system.Namespace(),
Name: certificateName,
},
}))

f.Setup("install sink", eventshub.Install(sink, eventshub.StartReceiverTLS))
f.Setup("install channel", channel_impl.Install(channelName))
f.Setup("channel is ready", channel_impl.IsReady(channelName))
f.Setup("install subscription", func(ctx context.Context, t feature.T) {
d := service.AsDestinationRef(sink)
d.CACerts = eventshub.GetCaCerts(ctx)
subscription.Install(subscriptionName,
subscription.WithChannel(channel_impl.AsRef(channelName)),
subscription.WithSubscriberFromDestination(d))(ctx, t)
})
f.Setup("subscription is ready", subscription.IsReady(subscriptionName))
f.Setup("Channel has HTTPS address", channel_impl.ValidateAddress(channelName, addressable.AssertHTTPSAddress))

event := cetest.FullEvent()
event.SetID(uuid.New().String())

f.Requirement("install source", eventshub.Install(source,
eventshub.StartSenderToResourceTLS(channel_impl.GVR(), channelName, nil),
eventshub.InputEvent(event),
// Send multiple events so that we take into account that the certificate rotation might
// be detected by the server after some time.
eventshub.SendMultipleEvents(100, 3*time.Second),
))

f.Assert("Event sent", assert.OnStore(source).
MatchSentEvent(cetest.HasId(event.ID())).
AtLeast(1),
)
f.Assert("Event received", assert.OnStore(sink).
MatchReceivedEvent(cetest.HasId(event.ID())).
AtLeast(1),
)
f.Assert("Source match updated peer certificate", assert.OnStore(source).
MatchPeerCertificatesReceived(assert.MatchPeerCertificatesFromSecret(system.Namespace(), secretName, "tls.crt")).
AtLeast(1),
)

return f
}
14 changes: 14 additions & 0 deletions test/rekt/features/featureflags/featureflags.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ func TransportEncryptionPermissiveOrStrict() feature.ShouldRun {
}
}

func TransportEncryptionStrict() feature.ShouldRun {
return func(ctx context.Context, t feature.T) (feature.PrerequisiteResult, error) {
flags, err := getFeatureFlags(ctx, "config-features")
if err != nil {
return feature.PrerequisiteResult{}, err
}

return feature.PrerequisiteResult{
ShouldRun: flags.IsStrictTransportEncryption(),
Reason: flags.String(),
}, nil
}
}

func IstioDisabled() feature.ShouldRun {
return func(ctx context.Context, t feature.T) (feature.PrerequisiteResult, error) {
flags, err := getFeatureFlags(ctx, "config-features")
Expand Down
Loading