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

[release-1.1] Add TSA to upgrade test #757

Merged
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
320 changes: 51 additions & 269 deletions test/e2e/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,29 @@ import (
"strings"
"time"

"github.com/securesign/operator/test/e2e/support/tas/ctlog"
"github.com/securesign/operator/test/e2e/support/tas/fulcio"
"github.com/securesign/operator/test/e2e/support/tas/rekor"
"github.com/securesign/operator/test/e2e/support/tas/securesign"
"github.com/securesign/operator/test/e2e/support/tas/trillian"
"github.com/securesign/operator/test/e2e/support/tas/tsa"
"github.com/securesign/operator/test/e2e/support/tas/tuf"

"github.com/blang/semver/v4"
"github.com/onsi/ginkgo/v2/dsl/core"
"github.com/onsi/gomega/matchers"
v12 "github.com/operator-framework/api/pkg/operators/v1"
tasv1alpha "github.com/securesign/operator/api/v1alpha1"
"github.com/securesign/operator/internal/controller/common/utils"
"github.com/securesign/operator/internal/controller/constants"
ctl "github.com/securesign/operator/internal/controller/ctlog/actions"
fulcioAction "github.com/securesign/operator/internal/controller/fulcio/actions"
rekorAction "github.com/securesign/operator/internal/controller/rekor/actions"
"github.com/securesign/operator/internal/controller/securesign/actions"
trillianAction "github.com/securesign/operator/internal/controller/trillian/actions"
tsaAction "github.com/securesign/operator/internal/controller/tsa/actions"
tufAction "github.com/securesign/operator/internal/controller/tuf/actions"
"github.com/securesign/operator/test/e2e/support/tas"
clients "github.com/securesign/operator/test/e2e/support/tas/cli"
"github.com/securesign/operator/test/e2e/support/tas/rekor"
"github.com/securesign/operator/test/e2e/support/tas/securesign"
v13 "k8s.io/api/apps/v1"

. "github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
"github.com/operator-framework/api/pkg/operators/v1alpha1"
"github.com/securesign/operator/test/e2e/support"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
runtimeCli "sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -57,10 +50,7 @@ var _ = Describe("Operator upgrade", Ordered, func() {
baseCatalogImage, targetedCatalogImage string
base, updated semver.Version
securesignDeployment *tasv1alpha.Securesign
rfulcio *tasv1alpha.Fulcio
rrekor *tasv1alpha.Rekor
rtuf *tasv1alpha.Tuf
oidcToken string
prevImageName, newImageName string
openshift bool
)
Expand Down Expand Up @@ -222,49 +212,54 @@ var _ = Describe("Operator upgrade", Ordered, func() {
Trillian: tasv1alpha.TrillianSpec{Db: tasv1alpha.TrillianDB{
Create: utils.Pointer(true),
}},
TimestampAuthority: &tasv1alpha.TimestampAuthoritySpec{
ExternalAccess: tasv1alpha.ExternalAccess{
Enabled: true,
},
Signer: tasv1alpha.TimestampAuthoritySigner{
CertificateChain: tasv1alpha.CertificateChain{
RootCA: &tasv1alpha.TsaCertificateAuthority{
OrganizationName: "MyOrg",
OrganizationEmail: "[email protected]",
CommonName: "tsa.hostname",
},
IntermediateCA: []*tasv1alpha.TsaCertificateAuthority{
{
OrganizationName: "MyOrg",
OrganizationEmail: "[email protected]",
CommonName: "tsa.hostname",
},
},
LeafCA: &tasv1alpha.TsaCertificateAuthority{
OrganizationName: "MyOrg",
OrganizationEmail: "[email protected]",
CommonName: "tsa.hostname",
},
},
},
NTPMonitoring: tasv1alpha.NTPMonitoring{
Enabled: true,
Config: &tasv1alpha.NtpMonitoringConfig{
RequestAttempts: 3,
RequestTimeout: 5,
NumServers: 4,
ServerThreshold: 3,
MaxTimeDelta: 6,
Period: 60,
Servers: []string{"time.apple.com", "time.google.com", "time-a-b.nist.gov", "time-b-b.nist.gov", "gbg1.ntp.se"},
},
},
},
},
}

gomega.Expect(cli.Create(ctx, securesignDeployment)).To(gomega.Succeed())

securesign.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
fulcio.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
rekor.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
trillian.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name, true)
ctlog.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
tuf.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
rekor.VerifySearchUI(ctx, cli, securesignDeployment.Namespace)
tas.VerifyAllComponents(ctx, cli, securesignDeployment, true)
})

It("Sign image with cosign cli", func() {
rfulcio = fulcio.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(rfulcio).ToNot(gomega.BeNil())

rrekor = rekor.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(rrekor).ToNot(gomega.BeNil())

rtuf = tuf.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(rtuf).ToNot(gomega.BeNil())

var err error
oidcToken, err = support.OidcToken(ctx)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(oidcToken).ToNot(gomega.BeEmpty())

// sleep for a while to be sure everything has settled down
time.Sleep(time.Duration(10) * time.Second)

gomega.Expect(clients.Execute("cosign", "initialize", "--mirror="+rtuf.Status.Url, "--root="+rtuf.Status.Url+"/root.json")).To(gomega.Succeed())

gomega.Expect(clients.Execute(
"cosign", "sign", "-y",
"--fulcio-url="+rfulcio.Status.Url,
"--rekor-url="+rrekor.Status.Url,
"--oidc-issuer="+support.OidcIssuerUrl(),
"--oidc-client-id="+support.OidcClientID(),
"--identity-token="+oidcToken,
prevImageName,
)).To(gomega.Succeed())
tas.VerifyByCosign(ctx, cli, securesignDeployment, prevImageName)
})

It("Upgrade operator", func() {
Expand Down Expand Up @@ -309,6 +304,7 @@ var _ = Describe("Operator upgrade", Ordered, func() {
rekorAction.SearchUiDeploymentName: constants.RekorSearchUiImage,
trillianAction.LogsignerDeploymentName: constants.TrillianLogSignerImage,
trillianAction.LogserverDeploymentName: constants.TrillianServerImage,
tsaAction.DeploymentName: constants.TimestampAuthorityImage,
} {
gomega.Eventually(func(g gomega.Gomega) string {
d := &v13.Deployment{}
Expand All @@ -321,239 +317,25 @@ var _ = Describe("Operator upgrade", Ordered, func() {
}).Should(gomega.Equal(v), fmt.Sprintf("Expected %s deployment image to be equal to %s", k, v))
}

securesign.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
fulcio.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
rekor.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
trillian.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name, true)
ctlog.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
tuf.Verify(ctx, cli, securesignDeployment.Namespace, securesignDeployment.Name)
rekor.VerifySearchUI(ctx, cli, securesignDeployment.Namespace)
tas.VerifyAllComponents(ctx, cli, securesignDeployment, true)
})

It("Verify image signature after upgrade", func() {
rrekor = rekor.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(rrekor).ToNot(gomega.BeNil())

gomega.Expect(clients.Execute(
"cosign", "verify",
"--rekor-url="+rrekor.Status.Url,
"--timestamp-certificate-chain=ts_chain.pem",
"--certificate-identity-regexp", ".*@redhat",
"--certificate-oidc-issuer-regexp", ".*keycloak.*",
prevImageName,
)).To(gomega.Succeed())
})

It("Sign and Verify new image after upgrade", func() {
gomega.Expect(clients.Execute(
"cosign", "sign", "-y",
"--fulcio-url="+rfulcio.Status.Url,
"--rekor-url="+rrekor.Status.Url,
"--oidc-issuer="+support.OidcIssuerUrl(),
"--oidc-client-id="+support.OidcClientID(),
"--identity-token="+oidcToken,
newImageName,
)).To(gomega.Succeed())

gomega.Expect(clients.Execute(
"cosign", "verify",
"--rekor-url="+rrekor.Status.Url,
"--certificate-identity-regexp", ".*@redhat",
"--certificate-oidc-issuer-regexp", ".*keycloak.*",
newImageName,
)).To(gomega.Succeed())
})

It("Install Timestamp Authority after upgrade", func() {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())
gomega.Expect(meta.FindStatusCondition(s.GetConditions(), actions.TSACondition).Reason).To(gomega.Equal(constants.NotDefined))

s.Spec.TimestampAuthority = &tasv1alpha.TimestampAuthoritySpec{
ExternalAccess: tasv1alpha.ExternalAccess{
Enabled: true,
},
Signer: tasv1alpha.TimestampAuthoritySigner{
CertificateChain: tasv1alpha.CertificateChain{
RootCA: &tasv1alpha.TsaCertificateAuthority{
OrganizationName: "MyOrg",
OrganizationEmail: "[email protected]",
CommonName: "tsa.hostname",
},
IntermediateCA: []*tasv1alpha.TsaCertificateAuthority{
{
OrganizationName: "MyOrg",
OrganizationEmail: "[email protected]",
CommonName: "tsa.hostname",
},
},
LeafCA: &tasv1alpha.TsaCertificateAuthority{
OrganizationName: "MyOrg",
OrganizationEmail: "[email protected]",
CommonName: "tsa.hostname",
},
},
},
NTPMonitoring: tasv1alpha.NTPMonitoring{
Enabled: true,
Config: &tasv1alpha.NtpMonitoringConfig{
RequestAttempts: 3,
RequestTimeout: 5,
NumServers: 4,
ServerThreshold: 3,
MaxTimeDelta: 6,
Period: 60,
Servers: []string{"time.apple.com", "time.google.com", "time-a-b.nist.gov", "time-b-b.nist.gov", "gbg1.ntp.se"},
},
},
}
gomega.Expect(cli.Update(ctx, s)).Should(gomega.Succeed())
})

It("tsa should reach a ready state", func() {
gomega.Eventually(func() string {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())
return meta.FindStatusCondition(s.Status.Conditions, actions.TSACondition).Reason
}).Should(gomega.Equal(constants.Ready))
})

It("operator should generate TSA secret", func() {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())
tsa := tsa.Get(ctx, cli, namespace.Name, s.Name)()

gomega.Eventually(func() *v1.Secret {
scr := &v1.Secret{}
gomega.Expect(cli.Get(ctx, types.NamespacedName{Namespace: namespace.Name, Name: tsa.Status.Signer.File.PrivateKeyRef.Name}, scr)).To(gomega.Succeed())
return scr
}).Should(
gomega.WithTransform(func(secret *v1.Secret) map[string][]byte { return secret.Data },
gomega.And(
&matchers.HaveKeyMatcher{Key: "rootPrivateKey"},
&matchers.HaveKeyMatcher{Key: "rootPrivateKeyPassword"},
&matchers.HaveKeyMatcher{Key: "interPrivateKey-0"},
&matchers.HaveKeyMatcher{Key: "interPrivateKeyPassword-0"},
&matchers.HaveKeyMatcher{Key: "leafPrivateKey"},
&matchers.HaveKeyMatcher{Key: "leafPrivateKeyPassword"},
&matchers.HaveKeyMatcher{Key: "certificateChain"},
)))
})

It("tsa is running with operator generated certs and keys", func() {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())
t := tsa.Get(ctx, cli, namespace.Name, s.Name)()
server := tsa.GetServerPod(ctx, cli, namespace.Name)()

gomega.Expect(server).NotTo(gomega.BeNil())
gomega.Expect(server.Spec.Volumes).To(
gomega.ContainElement(
gomega.WithTransform(func(volume v1.Volume) string {
if volume.VolumeSource.Secret != nil {
return volume.VolumeSource.Secret.SecretName
}
return ""
}, gomega.Equal(t.Status.Signer.CertificateChain.CertificateChainRef.Name))),
)
gomega.Expect(server.Spec.Volumes).To(
gomega.ContainElement(
gomega.WithTransform(func(volume v1.Volume) string {
if volume.VolumeSource.Secret != nil {
return volume.VolumeSource.Secret.SecretName
}
return ""
}, gomega.Equal(t.Status.Signer.File.PrivateKeyRef.Name))),
)
})

It("ntp monitoring config created", func() {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())
t := tsa.Get(ctx, cli, namespace.Name, s.Name)()

server := tsa.GetServerPod(ctx, cli, namespace.Name)()
gomega.Expect(server).NotTo(gomega.BeNil())
gomega.Expect(server.Spec.Volumes).To(
gomega.ContainElement(
gomega.WithTransform(func(volume v1.Volume) string {
if volume.VolumeSource.ConfigMap != nil {
return volume.VolumeSource.ConfigMap.Name
}
return ""
}, gomega.Equal(t.Status.NTPMonitoring.Config.NtpConfigRef.Name))),
)
})

It("Update tuf root with tsa certificate chain", func() {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())

s.Spec.Tuf.Keys = append(s.Spec.Tuf.Keys, tasv1alpha.TufKey{Name: "tsa.certchain.pem"})
gomega.Expect(cli.Update(ctx, s)).To(gomega.Succeed())
gomega.Eventually(func() string {
t := tuf.Get(ctx, cli, namespace.Name, s.Name)()
return meta.FindStatusCondition(t.Status.Conditions, constants.Ready).Reason
}).Should(gomega.Equal(constants.Ready))
})

It("Trillian components are Ready", func() {
gomega.Eventually(func(g gomega.Gomega) {
t := trillian.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
g.Expect(t).ToNot(gomega.BeNil())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, trillianAction.DbCondition)).To(gomega.BeTrue())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, trillianAction.ServerCondition)).To(gomega.BeTrue())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, trillianAction.SignerCondition)).To(gomega.BeTrue())
}).Should(gomega.Succeed())
})

It("Rekor components are Ready", func() {
gomega.Eventually(func(g gomega.Gomega) {
t := rekor.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
g.Expect(t).ToNot(gomega.BeNil())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, rekorAction.ServerCondition)).To(gomega.BeTrue())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, rekorAction.SignerCondition)).To(gomega.BeTrue())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, rekorAction.UICondition)).To(gomega.BeTrue())
g.Expect(meta.IsStatusConditionTrue(t.Status.Conditions, rekorAction.RedisCondition)).To(gomega.BeTrue())
}).Should(gomega.Succeed())
})

It("Sign and Verify image after tsa install", func() {
s := securesign.Get(ctx, cli, namespace.Name, securesignDeployment.Name)()
gomega.Expect(s).ToNot(gomega.BeNil())
t := tsa.Get(ctx, cli, namespace.Name, s.Name)()

gomega.Expect(t).ToNot(gomega.BeNil())

gomega.Eventually(func() error {
return tsa.GetCertificateChain(ctx, cli, t.Namespace, t.Name, t.Status.Url)
}).Should(gomega.Succeed())

gomega.Expect(clients.Execute("cosign", "initialize", "--mirror="+rtuf.Status.Url, "--root="+rtuf.Status.Url+"/root.json")).To(gomega.Succeed())

gomega.Expect(clients.Execute(
"cosign", "verify",
"--rekor-url="+rrekor.Status.Url,
"--certificate-identity-regexp", ".*@redhat",
"--certificate-oidc-issuer-regexp", ".*keycloak.*",
prevImageName,
)).To(gomega.Succeed())

gomega.Expect(clients.Execute(
"cosign", "sign", "-y",
"--fulcio-url="+rfulcio.Status.Url,
"--rekor-url="+rrekor.Status.Url,
"--timestamp-server-url="+t.Status.Url+"/api/v1/timestamp",
"--oidc-issuer="+support.OidcIssuerUrl(),
"--oidc-client-id="+support.OidcClientID(),
"--identity-token="+oidcToken,
newImageName,
)).To(gomega.Succeed())

gomega.Expect(clients.Execute(
"cosign", "verify",
"--rekor-url="+rrekor.Status.Url,
"--timestamp-certificate-chain=ts_chain.pem",
"--certificate-identity-regexp", ".*@redhat",
"--certificate-oidc-issuer-regexp", ".*keycloak.*",
newImageName,
)).To(gomega.Succeed())
tas.VerifyByCosign(ctx, cli, securesignDeployment, newImageName)
})

It("Make sure securesign can be deleted after upgrade", func() {
Expand Down
Loading