Skip to content

Commit

Permalink
TLS certificate rotation tests (#7103)
Browse files Browse the repository at this point in the history
Fixes #7039

<!-- Please include the 'why' behind your changes if no issue exists -->

## Proposed Changes

<!-- Please categorize your changes:
- 🎁 Add new feature
- 🐛 Fix bug
- 🧹 Update or clean up current behavior
- 🗑️ Remove feature or internal logic
-->

- Test broker ingress TLS key pair rotation
- Test IMC dispatcher TLS key pair rotation

### Pre-review Checklist

<!-- If these boxes are not checked, you will be asked to complete these
requirements or explain why they do not apply to your PR. -->

- [ ] **At least 80% unit test coverage**
- [ ] **E2E tests** for any new behavior
- [ ] **Docs PR** for any user-facing impact
- [ ] **Spec PR** for any new API feature
- [ ] **Conformance test** for any change to the spec

**Release Note**

<!--
📄 If this change has user-visible impact, write a release
note in the block
below. Include the string "action required" if additional action is
required of
users switching to the new release, for example in case of a breaking
change.

Write as if you are speaking to users, not other Knative contributors.
If this
change has no user-visible impact, no release note is needed.
-->

```release-note

```


**Docs**

<!--
📖 If this change has user-visible impact, link to an issue or PR in
https://github.com/knative/docs.
-->

---------

Signed-off-by: Pierangelo Di Pilato <[email protected]>
  • Loading branch information
pierDipi authored Aug 3, 2023
1 parent bfba6fd commit 8a90e40
Show file tree
Hide file tree
Showing 17 changed files with 599 additions and 6 deletions.
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

0 comments on commit 8a90e40

Please sign in to comment.