Skip to content

Commit 5d39f27

Browse files
Merge pull request #1030 from LalatenduMohanty/custom-signature-stores
OCPBUGS-24700: Add support for Custom Certificate Authorities for custom signature stores
2 parents 0b3f507 + 6f95e1f commit 5d39f27

File tree

4 files changed

+92
-57
lines changed

4 files changed

+92
-57
lines changed

pkg/customsignaturestore/customsignaturestore.go

Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,46 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"net/http"
89
"net/url"
910
"strings"
1011
"sync"
1112

13+
configv1 "github.com/openshift/api/config/v1"
1214
configv1listers "github.com/openshift/client-go/config/listers/config/v1"
1315
"github.com/openshift/library-go/pkg/verify/store"
1416
"github.com/openshift/library-go/pkg/verify/store/parallel"
1517
"github.com/openshift/library-go/pkg/verify/store/sigstore"
18+
utilerrors "k8s.io/apimachinery/pkg/util/errors"
19+
"k8s.io/klog/v2"
1620
)
1721

1822
type Store struct {
1923
// Name is the name of the ClusterVersion object that configures this store.
2024
Name string
2125

22-
// Lister allows the store to fetch the current ClusterVersion configuration.
23-
Lister configv1listers.ClusterVersionLister
26+
// ClusterVersionLister allows the store to fetch the current ClusterVersion configuration.
27+
ClusterVersionLister configv1listers.ClusterVersionLister
2428

25-
// HTTPClient is called once for each Signatures call to ensure
26-
// requests are made with the currently-recommended parameters.
27-
HTTPClient sigstore.HTTPClient
29+
// HTTPClient construct which respects the customstore CA certs and cluster proxy configuration
30+
HTTPClient func(string) (*http.Client, error)
2831

2932
// lock allows the store to be locked while mutating or accessing internal state.
3033
lock sync.Mutex
3134

32-
// customURIs tracks the most-recently retrieved ClusterVersion configuration.
33-
customURIs []*url.URL
35+
// customStores tracks the most-recently retrieved ClusterVersion configuration.
36+
customStores []configv1.SignatureStore
3437
}
3538

3639
// Signatures fetches signatures for the provided digest.
3740
func (s *Store) Signatures(ctx context.Context, name string, digest string, fn store.Callback) error {
38-
uris, err := s.refreshConfiguration(ctx)
41+
customStores, err := s.refreshConfiguration()
3942
if err != nil {
4043
return err
41-
}
42-
43-
if uris == nil {
44+
} else if customStores == nil {
4445
return nil
45-
}
46-
47-
if len(uris) == 0 {
48-
return errors.New("ClusterVersion spec.signatureStores is an empty array. Unset signatureStores entirely if you want to to enable the default signature stores.")
46+
} else if len(customStores) == 0 {
47+
return errors.New("ClusterVersion spec.signatureStores is an empty array. Unset signatureStores entirely if you want to enable the default signature stores")
4948
}
5049

5150
allDone := false
@@ -58,44 +57,66 @@ func (s *Store) Signatures(ctx context.Context, name string, digest string, fn s
5857
return done, err
5958
}
6059

61-
stores := make([]store.Store, 0, len(uris))
62-
for i := range uris {
63-
uri := *uris[i]
60+
var errs []error
61+
stores := make([]store.Store, 0, len(customStores))
62+
for _, customStore := range customStores {
63+
uri, err := url.Parse(customStore.URL)
64+
if err != nil {
65+
errs = append(errs, fmt.Errorf("failed to parse the ClusterVersion spec.signatureStores %w", err))
66+
continue
67+
}
68+
newHttpClient, err := s.HTTPClient(customStore.CA.Name)
69+
if err != nil {
70+
errs = append(errs, fmt.Errorf("failed to process the ClusterVersion spec.signatureStores %w", err))
71+
continue
72+
}
73+
6474
stores = append(stores, &sigstore.Store{
65-
URI: &uri,
66-
HTTPClient: s.HTTPClient,
67-
})
75+
URI: uri,
76+
HTTPClient: func() (*http.Client, error) { return newHttpClient, nil }})
77+
}
78+
79+
if len(stores) == 0 {
80+
return utilerrors.NewAggregate(errs)
6881
}
6982
store := &parallel.Store{Stores: stores}
70-
if err := store.Signatures(ctx, name, digest, wrapper); err != nil || allDone {
71-
return err
83+
if err := store.Signatures(ctx, name, digest, wrapper); allDone {
84+
if len(errs) > 0 {
85+
klog.V(2).Infof("%s", utilerrors.NewAggregate(errs))
86+
}
87+
return nil
88+
} else if err != nil {
89+
errs = append(errs, err)
90+
return utilerrors.NewAggregate(errs)
7291
}
73-
return errors.New("ClusterVersion spec.signatureStores exhausted without finding a valid signature.")
92+
93+
errs = append(errs, errors.New("ClusterVersion spec.signatureStores exhausted without finding a valid signature"))
94+
return utilerrors.NewAggregate(errs)
7495
}
7596

76-
func (s *Store) refreshConfiguration(ctx context.Context) ([]*url.URL, error) {
77-
config, err := s.Lister.Get(s.Name)
97+
// refreshConfiguration retrieves the latest configuration from the ClusterVersionLister
98+
// and updates the customStores with the URL and CA information from the retrieved configuration.
99+
// It returns the updated customStores slice and any error encountered during the retrieval process.
100+
func (s *Store) refreshConfiguration() ([]configv1.SignatureStore, error) {
101+
102+
config, err := s.ClusterVersionLister.Get(s.Name)
78103
if err != nil {
79104
return nil, err
80105
}
81106

82-
var uris []*url.URL
107+
var customStores = make([]configv1.SignatureStore, 0, len(config.Spec.SignatureStores))
83108
if config.Spec.SignatureStores != nil {
84-
uris = make([]*url.URL, 0, len(config.Spec.SignatureStores))
85109
for _, store := range config.Spec.SignatureStores {
86-
uri, err := url.Parse(store.URL)
87-
if err != nil {
88-
return uris, err
89-
}
90-
91-
uris = append(uris, uri)
110+
url := store.URL
111+
caCert := store.CA
112+
customStores = append(customStores, configv1.SignatureStore{URL: url, CA: caCert})
92113
}
93114
}
94115

95116
s.lock.Lock()
96117
defer s.lock.Unlock()
97-
s.customURIs = uris
98-
return uris, nil
118+
s.customStores = customStores
119+
return customStores, nil
99120
}
100121

101122
// String returns a description of where this store finds
@@ -104,14 +125,14 @@ func (s *Store) String() string {
104125
s.lock.Lock()
105126
defer s.lock.Unlock()
106127

107-
if s.customURIs == nil {
108-
return "ClusterVersion signatureStores unset, falling back to default stores"
109-
} else if len(s.customURIs) == 0 {
128+
if s.customStores == nil {
129+
return "ClusterVersion signatureStores not set, falling back to default stores"
130+
} else if len(s.customStores) == 0 {
110131
return "0 ClusterVersion signatureStores"
111132
}
112-
uris := make([]string, 0, len(s.customURIs))
113-
for _, uri := range s.customURIs {
114-
uris = append(uris, uri.String())
133+
customStores := make([]string, 0, len(s.customStores))
134+
for _, customStore := range s.customStores {
135+
customStores = append(customStores, customStore.URL)
115136
}
116-
return fmt.Sprintf("ClusterVersion signatureStores: %s", strings.Join(uris, ", "))
137+
return fmt.Sprintf("ClusterVersion signatureStores: %s", strings.Join(customStores, ", "))
117138
}

pkg/cvo/availableupdates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (optr *Operator) syncAvailableUpdates(ctx context.Context, config *configv1
9393
}
9494

9595
if needFreshFetch {
96-
transport, err := optr.getTransport()
96+
transport, err := optr.getTransport("")
9797
if err != nil {
9898
return err
9999
}

pkg/cvo/cvo.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,16 +294,16 @@ func (optr *Operator) LoadInitialPayload(ctx context.Context, startingRequiredFe
294294
if err != nil {
295295
return nil, fmt.Errorf("the local release contents are invalid - no current version can be determined from disk: %v", err)
296296
}
297-
httpClientConstructor := sigstore.NewCachedHTTPClientConstructor(optr.HTTPClient, nil)
297+
httpClientConstructor := sigstore.NewCachedHTTPClientConstructor(func() (*http.Client, error) { return optr.HTTPClient("") }, nil)
298298
configClient, err := coreclientsetv1.NewForConfig(restConfig)
299299
if err != nil {
300300
return nil, fmt.Errorf("unable to create a configuration client: %v", err)
301301
}
302302

303303
customSignatureStore := &customsignaturestore.Store{
304-
Lister: optr.cvLister,
305-
Name: optr.name,
306-
HTTPClient: httpClientConstructor.HTTPClient,
304+
Name: optr.name,
305+
ClusterVersionLister: optr.cvLister,
306+
HTTPClient: optr.HTTPClient,
307307
}
308308

309309
// attempt to load a verifier as defined in the payload
@@ -980,8 +980,8 @@ func (optr *Operator) defaultPreconditionChecks() precondition.List {
980980

981981
// HTTPClient provides a method for generating an HTTP client
982982
// with the proxy and trust settings, if set in the cluster.
983-
func (optr *Operator) HTTPClient() (*http.Client, error) {
984-
transportOption, err := optr.getTransport()
983+
func (optr *Operator) HTTPClient(caConfigMap string) (*http.Client, error) {
984+
transportOption, err := optr.getTransport(caConfigMap)
985985
if err != nil {
986986
return nil, err
987987
}

pkg/cvo/egress.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
"golang.org/x/net/http/httpproxy"
1212
apierrors "k8s.io/apimachinery/pkg/api/errors"
1313

14+
"github.com/openshift/cluster-version-operator/pkg/internal"
1415
"github.com/openshift/cluster-version-operator/pkg/version"
16+
corev1 "k8s.io/api/core/v1"
1517
)
1618

1719
// Returns a User-Agent to be used for outgoing HTTP requests.
@@ -25,7 +27,7 @@ func (optr *Operator) getUserAgent() string {
2527

2628
// getTransport constructs an HTTP transport configuration, including
2729
// any custom proxy configuration.
28-
func (optr *Operator) getTransport() (*http.Transport, error) {
30+
func (optr *Operator) getTransport(caConfigMap string) (*http.Transport, error) {
2931
transport := &http.Transport{}
3032

3133
proxyConfig, err := optr.getProxyConfig()
@@ -41,7 +43,7 @@ func (optr *Operator) getTransport() (*http.Transport, error) {
4143
}
4244
}
4345

44-
tlsConfig, err := optr.getTLSConfig()
46+
tlsConfig, err := optr.getTLSConfig(caConfigMap)
4547
if err != nil {
4648
return transport, err
4749
} else if tlsConfig != nil {
@@ -70,8 +72,20 @@ func (optr *Operator) getProxyConfig() (*httpproxy.Config, error) {
7072
}, nil
7173
}
7274

73-
func (optr *Operator) getTLSConfig() (*tls.Config, error) {
74-
cm, err := optr.cmConfigManagedLister.Get("trusted-ca-bundle")
75+
func (optr *Operator) getTLSConfig(caConfigMap string) (*tls.Config, error) {
76+
var namespace, key string
77+
var cm *corev1.ConfigMap
78+
var err error
79+
if caConfigMap == "" {
80+
namespace = internal.ConfigManagedNamespace
81+
caConfigMap = "trusted-ca-bundle"
82+
key = "ca-bundle.crt"
83+
cm, err = optr.cmConfigManagedLister.Get(caConfigMap)
84+
} else {
85+
namespace = internal.ConfigNamespace
86+
key = "ca.crt"
87+
cm, err = optr.cmConfigLister.Get(caConfigMap)
88+
}
7589
if apierrors.IsNotFound(err) {
7690
return nil, nil
7791
}
@@ -81,9 +95,9 @@ func (optr *Operator) getTLSConfig() (*tls.Config, error) {
8195

8296
certPool := x509.NewCertPool()
8397

84-
if cm.Data["ca-bundle.crt"] != "" {
85-
if ok := certPool.AppendCertsFromPEM([]byte(cm.Data["ca-bundle.crt"])); !ok {
86-
return nil, fmt.Errorf("unable to add ca-bundle.crt certificates")
98+
if cm.Data[key] != "" {
99+
if ok := certPool.AppendCertsFromPEM([]byte(cm.Data[key])); !ok {
100+
return nil, fmt.Errorf("unable to add %s certificates from the %s ConfigMap in the %s namespace", key, caConfigMap, namespace)
87101
}
88102
} else {
89103
return nil, nil

0 commit comments

Comments
 (0)