diff --git a/deploy/charts/trust-manager/templates/crd-trust.cert-manager.io_bundles.yaml b/deploy/charts/trust-manager/templates/crd-trust.cert-manager.io_bundles.yaml index 59d75332..60deb804 100644 --- a/deploy/charts/trust-manager/templates/crd-trust.cert-manager.io_bundles.yaml +++ b/deploy/charts/trust-manager/templates/crd-trust.cert-manager.io_bundles.yaml @@ -391,6 +391,9 @@ spec: - key type: object type: object + useCACertsOnly: + description: Use only CAs certificates in a resulting Bundle + type: boolean required: - sources type: object diff --git a/deploy/crds/trust-manager.io_clusterbundles.yaml b/deploy/crds/trust-manager.io_clusterbundles.yaml index 259d9538..46f8847a 100644 --- a/deploy/crds/trust-manager.io_clusterbundles.yaml +++ b/deploy/crds/trust-manager.io_clusterbundles.yaml @@ -419,6 +419,9 @@ spec: - message: 'any of the following fields must be provided: [configMap, secret]' rule: '[has(self.configMap), has(self.secret)].exists(x,x)' + useCACertsOnly: + description: Use only CAs certificates in a resulting Bundle + type: boolean type: object status: description: Status of the Bundle. This is set and managed automatically. diff --git a/deploy/crds/trust.cert-manager.io_bundles.yaml b/deploy/crds/trust.cert-manager.io_bundles.yaml index 0e14dbed..c54667fe 100644 --- a/deploy/crds/trust.cert-manager.io_bundles.yaml +++ b/deploy/crds/trust.cert-manager.io_bundles.yaml @@ -409,6 +409,9 @@ spec: - key type: object type: object + useCACertsOnly: + description: Use only CAs certificates in a resulting Bundle + type: boolean required: - sources type: object diff --git a/pkg/apis/trust/v1alpha1/types_bundle.go b/pkg/apis/trust/v1alpha1/types_bundle.go index afe22fec..4a527aaa 100644 --- a/pkg/apis/trust/v1alpha1/types_bundle.go +++ b/pkg/apis/trust/v1alpha1/types_bundle.go @@ -68,6 +68,10 @@ type BundleSpec struct { // Target is the target location in all namespaces to sync source data to. // +optional Target BundleTarget `json:"target,omitzero"` + + // Use only CAs certificates in a resulting Bundle + // +optional + UseCACertsOnly *bool `json:"useCACertsOnly,omitempty"` } // BundleSource is the set of sources whose data will be appended and synced to diff --git a/pkg/apis/trust/v1alpha1/zz_generated.conversion.go b/pkg/apis/trust/v1alpha1/zz_generated.conversion.go index 964774b7..b3d040e2 100644 --- a/pkg/apis/trust/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/trust/v1alpha1/zz_generated.conversion.go @@ -138,6 +138,7 @@ func autoConvert_v1alpha1_BundleSpec_To_v1alpha2_BundleSpec(in *BundleSpec, out if err := Convert_v1alpha1_BundleTarget_To_v1alpha2_BundleTarget(&in.Target, &out.Target, s); err != nil { return err } + out.UseCACertsOnly = (*bool)(unsafe.Pointer(in.UseCACertsOnly)) return nil } @@ -163,6 +164,7 @@ func autoConvert_v1alpha2_BundleSpec_To_v1alpha1_BundleSpec(in *v1alpha2.BundleS if err := Convert_v1alpha2_BundleTarget_To_v1alpha1_BundleTarget(&in.Target, &out.Target, s); err != nil { return err } + out.UseCACertsOnly = (*bool)(unsafe.Pointer(in.UseCACertsOnly)) return nil } diff --git a/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go index 8a012d70..41c87d26 100644 --- a/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go @@ -155,6 +155,11 @@ func (in *BundleSpec) DeepCopyInto(out *BundleSpec) { } } in.Target.DeepCopyInto(&out.Target) + if in.UseCACertsOnly != nil { + in, out := &in.UseCACertsOnly, &out.UseCACertsOnly + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSpec. diff --git a/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go b/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go index 60a3c6ad..b9a2202f 100644 --- a/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go +++ b/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go @@ -84,6 +84,10 @@ type BundleSpec struct { // Target is the target location in all namespaces to sync source data to. // +optional Target BundleTarget `json:"target,omitzero"` + + // Use only CAs certificates in a resulting Bundle + // +optional + UseCACertsOnly *bool `json:"useCACertsOnly,omitempty"` } // BundleSource is the set of sources whose data will be appended and synced to diff --git a/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go index ea9248ad..b2981000 100644 --- a/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go @@ -62,6 +62,11 @@ func (in *BundleSpec) DeepCopyInto(out *BundleSpec) { **out = **in } in.Target.DeepCopyInto(&out.Target) + if in.UseCACertsOnly != nil { + in, out := &in.UseCACertsOnly, &out.UseCACertsOnly + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSpec. diff --git a/pkg/applyconfigurations/trust/v1alpha1/bundlespec.go b/pkg/applyconfigurations/trust/v1alpha1/bundlespec.go index cf618499..330e0027 100644 --- a/pkg/applyconfigurations/trust/v1alpha1/bundlespec.go +++ b/pkg/applyconfigurations/trust/v1alpha1/bundlespec.go @@ -26,6 +26,8 @@ type BundleSpecApplyConfiguration struct { Sources []BundleSourceApplyConfiguration `json:"sources,omitempty"` // Target is the target location in all namespaces to sync source data to. Target *BundleTargetApplyConfiguration `json:"target,omitempty"` + // Use only CAs certificates in a resulting Bundle + UseCACertsOnly *bool `json:"useCACertsOnly,omitempty"` } // BundleSpecApplyConfiguration constructs a declarative configuration of the BundleSpec type for use with @@ -54,3 +56,11 @@ func (b *BundleSpecApplyConfiguration) WithTarget(value *BundleTargetApplyConfig b.Target = value return b } + +// WithUseCACertsOnly sets the UseCACertsOnly field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UseCACertsOnly field is set to the value of the last call. +func (b *BundleSpecApplyConfiguration) WithUseCACertsOnly(value bool) *BundleSpecApplyConfiguration { + b.UseCACertsOnly = &value + return b +} diff --git a/pkg/applyconfigurations/trustmanager/v1alpha2/bundlespec.go b/pkg/applyconfigurations/trustmanager/v1alpha2/bundlespec.go index 6cae1b03..5dc34748 100644 --- a/pkg/applyconfigurations/trustmanager/v1alpha2/bundlespec.go +++ b/pkg/applyconfigurations/trustmanager/v1alpha2/bundlespec.go @@ -37,6 +37,8 @@ type BundleSpecApplyConfiguration struct { InLineCAs *string `json:"inLineCAs,omitempty"` // Target is the target location in all namespaces to sync source data to. Target *BundleTargetApplyConfiguration `json:"target,omitempty"` + // Use only CAs certificates in a resulting Bundle + UseCACertsOnly *bool `json:"useCACertsOnly,omitempty"` } // BundleSpecApplyConfiguration constructs a declarative configuration of the BundleSpec type for use with @@ -81,3 +83,11 @@ func (b *BundleSpecApplyConfiguration) WithTarget(value *BundleTargetApplyConfig b.Target = value return b } + +// WithUseCACertsOnly sets the UseCACertsOnly field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UseCACertsOnly field is set to the value of the last call. +func (b *BundleSpecApplyConfiguration) WithUseCACertsOnly(value bool) *BundleSpecApplyConfiguration { + b.UseCACertsOnly = &value + return b +} diff --git a/pkg/bundle/bundle.go b/pkg/bundle/bundle.go index 9e982664..72ab9b1d 100644 --- a/pkg/bundle/bundle.go +++ b/pkg/bundle/bundle.go @@ -105,7 +105,7 @@ func (b *bundle) reconcileBundle(ctx context.Context, req ctrl.Request) (statusP statusPatch = &trustapi.BundleStatus{ DefaultCAPackageVersion: bundle.Status.DefaultCAPackageVersion, } - resolvedBundle, err := b.bundleBuilder.BuildBundle(ctx, bundle.Spec.Sources) + resolvedBundle, err := b.bundleBuilder.BuildBundle(ctx, bundle.Spec) if err != nil { var reason, message string diff --git a/pkg/bundle/internal/source/source.go b/pkg/bundle/internal/source/source.go index 172998d1..d606de5f 100644 --- a/pkg/bundle/internal/source/source.go +++ b/pkg/bundle/internal/source/source.go @@ -23,6 +23,7 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -55,14 +56,19 @@ type BundleBuilder struct { DefaultPackage *fspkg.Package controller.Options + + // Use only CAs certificates + UseCACertsOnly bool } // BuildBundle retrieves and concatenates all source bundle data for this Bundle object. // Each source data is validated and pruned to ensure that all certificates within are valid. -func (b *BundleBuilder) BuildBundle(ctx context.Context, sources []trustapi.BundleSource) (BundleData, error) { +func (b *BundleBuilder) BuildBundle(ctx context.Context, bundle trustapi.BundleSpec) (BundleData, error) { var resolvedBundle BundleData + var sources = bundle.Sources resolvedBundle.CertPool = util.NewCertPool( util.WithFilteredExpiredCerts(b.FilterExpiredCerts), + util.WithCACertsOnly(ptr.Deref(bundle.UseCACertsOnly, false)), util.WithLogger(logf.FromContext(ctx).WithName("cert-pool")), ) diff --git a/pkg/bundle/internal/source/source_test.go b/pkg/bundle/internal/source/source_test.go index 6f979140..6633031b 100644 --- a/pkg/bundle/internal/source/source_test.go +++ b/pkg/bundle/internal/source/source_test.go @@ -339,7 +339,10 @@ func Test_BuildBundle(t *testing.T) { Options: controller.Options{FilterExpiredCerts: tt.filterExpired}, } - resolvedBundle, err := b.BuildBundle(t.Context(), tt.sources) + bundle := trustapi.BundleSpec{ + Sources: tt.sources, + } + resolvedBundle, err := b.BuildBundle(t.Context(), bundle) if (err != nil) != tt.expError { t.Errorf("unexpected error, exp=%t got=%v", tt.expError, err) diff --git a/pkg/util/cert_pool.go b/pkg/util/cert_pool.go index f736e2c9..cff2b1f6 100644 --- a/pkg/util/cert_pool.go +++ b/pkg/util/cert_pool.go @@ -37,6 +37,8 @@ type CertPool struct { filterExpired bool logger logr.Logger + + useCACertsOnly bool } type Option func(*CertPool) @@ -53,6 +55,12 @@ func WithLogger(logger logr.Logger) Option { } } +func WithCACertsOnly(useCACertsOnly bool) Option { + return func(cp *CertPool) { + cp.useCACertsOnly = useCACertsOnly + } +} + // NewCertPool returns a new, empty CertPool. // It will deduplicate certificates based on their SHA256 hash. // Optionally, it can filter out expired certificates. @@ -142,6 +150,11 @@ func (cp *CertPool) AddCert(certificate *x509.Certificate) bool { return false } + if cp.useCACertsOnly && !certificate.IsCA { + cp.logger.Info("ignoring non-CA certificate", "certificate", certificate.Subject) + return false + } + hash := sha256.Sum256(certificate.Raw) cp.certificates[hash] = certificate return true diff --git a/pkg/util/cert_pool_test.go b/pkg/util/cert_pool_test.go index f8b74516..c520b64e 100644 --- a/pkg/util/cert_pool_test.go +++ b/pkg/util/cert_pool_test.go @@ -92,3 +92,46 @@ func TestAppendCertFromPEM(t *testing.T) { }) } } + +// CA certificates only +func TestAppendCACertFromPEM(t *testing.T) { + tests := map[string]struct { + pemData string + filterExpired bool + expError string + expEmpty bool + useCACertsOnly bool + CACertsCount int + }{ + "if multiple certificates, should return": { + pemData: dummy.JoinCerts(dummy.TestCertificate1, dummy.TestCertificateNonCA1, dummy.TestCertificate2, dummy.TestCertificate3, dummy.TestCertificateNonCA2), + CACertsCount: 3, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + t.Parallel() + + certPool := NewCertPool(WithCACertsOnly(true)) + + err := certPool.AddCertsFromPEM([]byte(test.pemData)) + if test.expError != "" { + assert.Error(t, err, test.expError) + } else { + assert.NoError(t, err) + } + + CACertsList := certPool.Certificates() + if len(CACertsList) != test.CACertsCount { + t.Fatalf("The number of CA certificates isn't equal to expected one: given %d, expected %d", len(CACertsList), test.CACertsCount) + } + + for _, cert := range CACertsList { + if !cert.IsCA { + t.Fatalf("there are nonCA certificates in the certificates list") + } + } + }) + } +} diff --git a/test/dummy/certificates.go b/test/dummy/certificates.go index 7cd6d01b..b2ad0bde 100644 --- a/test/dummy/certificates.go +++ b/test/dummy/certificates.go @@ -477,6 +477,130 @@ PQ5qEvRB3rGmtpvWu/p8z4AlMSWFb9C+Qp4NiU2jiPgw0t1DL/vdrvLcYb/ExyJx /+ZA+ONCt347Do/oMXy8iT4cmNOe28pHLYHkhkbP5d2ajpjSwqH2Q8Gr8AiMM5OO HYjDRRens0uEsJFTfFBq0YbGiIAHZ1ESs/ipdisdgmLkIDjF8UKRNoBacodAsghV z40l74JcR+GvcFZWz7/jmJq95YMZ7LawLAr1CaAXxCwsoLbJpbgg4lVo6odACzY= +-----END CERTIFICATE-----` + + // Certificate: + // Data: + // Version: 3 (0x2) + // Serial Number: + // 67:bc:27:4c:38:bd:86:8e:64:64:b9:bc:e7:96:c6:fa:4e:78:57:a4 + // Signature Algorithm: sha256WithRSAEncryption + // Issuer: C=US, L=Default City, O=Internet Security Research Group, CN=www.example.com + // Validity + // Not Before: Dec 20 15:32:26 2025 GMT + // Not After : Dec 18 15:32:26 2035 GMT + // Subject: C=US, L=Default City, O=Internet Security Research Group, CN=www.example.com + // Subject Public Key Info: + // Public Key Algorithm: rsaEncryption + // Public-Key: (4096 bit) + // Modulus: + // 00:a9:7c:2d:2a:b1:67:0e:90:f8:37:db:c4:d7:7b: + // 7b:00:40:72:8e:d9:44:70:b0:96:38:4c:4f:91:9f: + // ... + // 56:c9:bc:07:0f:87:f3:10:75:0e:3d:3a:1e:83:cc: + // 61:4d:fb + // Exponent: 65537 (0x10001) + // X509v3 extensions: + // X509v3 Subject Key Identifier: + // 6F:F8:A7:F7:66:75:D9:EB:02:25:05:A4:4E:62:C5:D9:85:53:F9:0B + // X509v3 Authority Key Identifier: + // 6F:F8:A7:F7:66:75:D9:EB:02:25:05:A4:4E:62:C5:D9:85:53:F9:0B + // X509v3 Basic Constraints: + // CA:FALSE + TestCertificateNonCA1 = `-----BEGIN CERTIFICATE----- +MIIFrTCCA5WgAwIBAgIUZ7wnTDi9ho5kZLm855bG+k54V6QwDQYJKoZIhvcNAQEL +BQAwaTELMAkGA1UEBhMCVVMxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEpMCcGA1UE +CgwgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxGDAWBgNVBAMMD3d3 +dy5leGFtcGxlLmNvbTAeFw0yNTEyMjAxNTMyMjZaFw0zNTEyMTgxNTMyMjZaMGkx +CzAJBgNVBAYTAlVTMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxKTAnBgNVBAoMIElu +dGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRgwFgYDVQQDDA93d3cuZXhh +bXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpfC0qsWcO +kPg328TXe3sAQHKO2URwsJY4TE+Rn99jMHtMwHtgmxPQ/sMlljrhPk5vdf55i0R9 +iWm9sEvRynhv2hejr2hV0RAM7Q2+Q4We9Qmn8Bh9+sN60I5YVM1lOmVKUbxDQTFm +D1WrC3NMLuAhnkoJKE1ElAN3f6TWihWhlg4lmN8qbFcZIsGMXmEKXiPPFLqTn0h7 +G5HTo0SCOqQnG4qdIW4hdOXVb3dIeX5/yVeKwQJcUWrIcOSONG5SAfbwvUFExp7d +10g/j5r4wWGvvzm9pJzpMLgGCwMoATxHdM7k2twSbIIrulfmCgiqzqqmctUEP3c4 +AYbPr/LDtlRqEGxFHlfmnpT9nDETF44enBEeQ75tsj7sguqNOay+/lemM42SnfSt +mrcm14LAvZtpV5+zeyxA4ujczsUybWuWM6jtmRaBbQ4MtPCG3q+GMyroMtJ+AXYH +1sM67AppyTNaxYf5bns+mdCKce9BrOM1Uqqh8R0hikoVTW65WhDdh+iJHU9DAbvC +mIW5NDeyevs/utI3hppLZZ1dyhrQ5U1CjrWZ63sEjy0InCF4OJg8Ck4d8HYe1Ipk +I16pRBe9FAd0AvOZgUXE18o5si6LOOEWkAkf9aw3+CeUs3ijRmsg2vFWgivoz4uE +w8L7+b2cQFbJvAcPh/MQdQ49Oh6DzGFN+wIDAQABo00wSzAdBgNVHQ4EFgQUb/in +92Z12esCJQWkTmLF2YVT+QswHwYDVR0jBBgwFoAUb/in92Z12esCJQWkTmLF2YVT ++QswCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAgEAfgAjHMI8Kt7uVxvRWo8W +DzmYT7FJYWxBGEng7DJcvb346C9o3Bo/4HDG4t0G/COwpbO5k/7GY9WmOCTi7hD9 +s5itXH2Oxvnn2Vmnyf0ZcbzFnJWN7sHHvqB7HBCVCmJdzp1etjr7klXUalIRPp9w +Xpv6XUKBCRAWDVvIiZOfeTHrmF1GHcsbBiSZKn/sD7HbgOY4eHFbwWjEtOynW3i4 +YBDmd7IZlUnxUJEGFq+8wuFt1QpjtzZp+zD2ZLKE2hdzoUmIWNPPWtrplvP68yTY +KGtggpbG4rTmaq4C7Y2g56hAbWARgtwa52keGl42vBeIoY6uDuByQG1+uxJlkRhh +vKKL8Nv1Bvv1QBpFZa3WckRbe+vUl+4lWQsaHWjydrv//rxTpKw7NO+y2O5YYwgz +kX7dbrSluYP9KjvawopYqaN362QA+ZDkq17u2jF0H3l78IMoVTEszEME5VF9GuP6 +EeuzMl8ttrIwZig/t7TSpVzGyxbNAE2CJQ5Ydt22AaLnZX2BXiBRCNxmi58j/fBH +1dIomzU1yZwcXZwUCga0j9+xEhdG8gdr77G4O0P1BO8Tui6WeNU3DAWWWiuBLWT6 +K6WVn0GVZR2gMUZs6Fdi1f5pguIQE10be9VM+m2ei9Cy3rjZLnAKN87D2JJJPm8C +plNZGnaNc9ms+ZvMgFUOQOQ= +-----END CERTIFICATE-----` + + // Certificate: + // Data: + // Version: 3 (0x2) + // Serial Number: + // 26:0f:0c:cd:09:53:87:27:55:51:74:7b:d9:4e:c4:e1:ea:cd:6d:2c + // Signature Algorithm: sha256WithRSAEncryption + // Issuer: C=US, L=Default City, O=Internet Security Research Group, CN=mail.example.com + // Validity + // Not Before: Dec 20 15:36:45 2025 GMT + // Not After : Dec 18 15:36:45 2035 GMT + // Subject: C=US, L=Default City, O=Internet Security Research Group, CN=mail.example.com + // Subject Public Key Info: + // Public Key Algorithm: rsaEncryption + // Public-Key: (4096 bit) + // Modulus: + // 00:b6:81:5f:a9:f3:19:1f:a6:71:56:61:e6:53:e9: + // 8f:24:f4:05:4f:06:25:a9:8b:f3:4f:b3:82:9a:dd: + // ... + // c8:d1:ca:45:84:69:8e:f6:1d:bb:e0:43:24:73:7c: + // 2f:08:bd + // Exponent: 65537 (0x10001) + // X509v3 extensions: + // X509v3 Subject Key Identifier: + // 43:3E:01:3D:F9:34:CE:19:31:8A:F1:2F:82:68:CD:1D:F5:A8:61:87 + // X509v3 Authority Key Identifier: + // 43:3E:01:3D:F9:34:CE:19:31:8A:F1:2F:82:68:CD:1D:F5:A8:61:87 + // X509v3 Basic Constraints: + // CA:FALSE + TestCertificateNonCA2 = `-----BEGIN CERTIFICATE----- +MIIFrzCCA5egAwIBAgIUJg8MzQlThydVUXR72U7E4erNbSwwDQYJKoZIhvcNAQEL +BQAwajELMAkGA1UEBhMCVVMxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEpMCcGA1UE +CgwgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxGTAXBgNVBAMMEG1h +aWwuZXhhbXBsZS5jb20wHhcNMjUxMjIwMTUzNjQ1WhcNMzUxMjE4MTUzNjQ1WjBq +MQswCQYDVQQGEwJVUzEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MSkwJwYDVQQKDCBJ +bnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEZMBcGA1UEAwwQbWFpbC5l +eGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALaBX6nz +GR+mcVZh5lPpjyT0BU8GJamL80+zgprdJ/Xq1aMB709asF3o/gWlHVMke2JIX+lr +kvQLoSxr0AB7eOwaz+8KfWH3BLw399j9c88Lo+ZAot8CgpUz7YaeETOUveEGJVSb +PP/k0bmNxqBPnP3ba20xTRlW5MFnTXHxNJ5TghRC98FfeGwEkN8tb5YdFzoRKM/m +FSRevS4rcHBIwpU4l9xNIBfgI7P/Ib/UlrXTITVdAMriypU3AkNn25cUECa4sJ5a +YVvI/bv4r63x8gscFVwhleM5Ms9eENoAF/BbZq2Fc/la2DwZANkaq1WOz0us5NS2 +UzIIhKM9OU/+FbPs1x2UiAjGLa5X/HVE2Y0HJx0JzAEb4jMaDHn1KoE2HImWCp5F +RdS2VEAJKoH0Dv6toP//exK/uQoQs3c/V668Dm4yRERWJ42ipeSHrVNkkwUSKgvp +qD2oaaE8CGgXunraE5hbKb4zOy/xBiw6FVdOZ3fyNGlWZ38lvUDLVjyK4GdKEWN5 +b6T098qmUfl4vflAxvL0NeGb8zvT2n12REWbtSpPFjp2Tq+fBcPCq1OE3zDsca4d +hwiVNJ33O5VVhqnVd20VlAo+IxHi+IhdIotMhHnhXi0+86i/aRTTiUO2/h/BoHWK +zYp6VSKAFUu2yNHKRYRpjvYdu+BDJHN8Lwi9AgMBAAGjTTBLMB0GA1UdDgQWBBRD +PgE9+TTOGTGK8S+CaM0d9ahhhzAfBgNVHSMEGDAWgBRDPgE9+TTOGTGK8S+CaM0d +9ahhhzAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQA12GwhzZfNQBWbWmk1 +2E6JdQFrsRIcgkHo54eyhoIjLsHKrwP99DcHTTFrOfJPrGRk5b/C8mnNlcQOey+I +qmpRrwvpvW4njxPR5bUzt4UsOrG7k+GsA4ovQzjvDCAdjLcvoFFYrMvoQ18rvxEH +NuJeRoqc5bnSO0k+B5lc9TCsfHQwLkw7s6K8l2scdJj7X0vg2KTn0FDRMQlvWcBK +lxbfHTDGK2+N841TIABalhT1ljMlhnfdDiVQGqRnmVdrTM4diJ1CaRm7CW36CwCE +yeYLc5Q/hdNd3AlsZo4Wu9xnjW5ozeoOKveJrm1KSl+BylkF+bHWFaq1w7EDQkVC +uv0BEdFyXcFL7sI3OsblXJibSqZJsZn/SeJja3LAvm5M5FIjoZ1uZzzdc0Hx1tzb +OdjK0cgXqcyz/stQ22kKnadZOi0lMoVUmP8TLo+2B6LvAYHClStEIhBet2W80wDe +PwfVKfLQ98Fpt7QHzpzcwje2I3dfyI1WHNPptJcryFdXcJHLHksv1rk+tbcaHN8K +rsE6P1NCjsAFn43+Kicmlj14IR1UZ54MmK+KXlr1I2/MAXvI86rXhTXC7xI+uS5v +/qf5aom1SWBJAQmexwbC+viyH/obwSNAygLNTyUBOx9TSPlsEazQ8TV+9OaWkbsh +rtDOMVCUoMGIbAJRLwKLL7djlw== -----END CERTIFICATE-----` ) diff --git a/test/integration/bundle/suite.go b/test/integration/bundle/suite.go index 4b336f26..b497bc90 100644 --- a/test/integration/bundle/suite.go +++ b/test/integration/bundle/suite.go @@ -727,6 +727,30 @@ var _ = Describe("Integration", func() { Expect(configMap.Annotations).To(HaveKeyWithValue("test1", "test1"), "Ensuring target contains additional annotations") } }) + + It("should update all targets with CA certificates only", func() { + configMap := corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "new-bundle-source", + Namespace: opts.Namespace, + }, + Data: map[string]string{ + "new-source-key": dummy.JoinCerts(dummy.TestCertificateNonCA1), + }, + } + + Expect(cl.Create(ctx, &configMap)).NotTo(HaveOccurred()) + + Expect(komega.Update(testBundle, func() { + testBundle.Spec.UseCACertsOnly = ptr.To(true) + testBundle.Spec.Sources = append(testBundle.Spec.Sources, trustapi.BundleSource{ + ConfigMap: &trustapi.SourceObjectKeySelector{Name: "new-bundle-source", Key: "new-source-key"}, + }) + })()).To(Succeed()) + + expectedData := dummy.JoinCerts(dummy.TestCertificate2, dummy.TestCertificate1, dummy.TestCertificate3) + testenv.EventuallyBundleHasSyncedAllNamespaces(ctx, cl, testBundle.Name, expectedData) + }) }) func writeDefaultPackage() (string, error) {