Skip to content

Commit 59c889f

Browse files
authored
handle CA bundle for k8s platform (#135)
Signed-off-by: Riccardo Piccoli <rpiccoli@redhat.com>
1 parent 51a99db commit 59c889f

File tree

10 files changed

+1932
-37
lines changed

10 files changed

+1932
-37
lines changed

Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform
169169
generate-published-manifests: build-installer
170170
cp $(DIST_DIR)/controlplane_install.yaml controlplane-components.yaml
171171
cp $(DIST_DIR)/bootstrap_install.yaml bootstrap-components.yaml
172+
cp $(DIST_DIR)/controlplane_install.yaml test/e2e/manifests/capcoa/controlplane_install.yaml
173+
cp $(DIST_DIR)/bootstrap_install.yaml test/e2e/manifests/capboa/bootstrap_install.yaml
174+
172175

173176
.PHONY: build-installer
174177
build-installer:

assistedinstaller/client.go

+55-13
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"context"
55
"crypto/tls"
66
"crypto/x509"
7+
"errors"
78
"fmt"
89
"net/http"
10+
"strings"
911

1012
corev1 "k8s.io/api/core/v1"
1113
"k8s.io/apimachinery/pkg/types"
@@ -17,27 +19,39 @@ func GetAssistedHTTPClient(config ServiceConfig, c client.Client) (*http.Client,
1719
return &http.Client{}, nil
1820
}
1921
if config.AssistedCABundleName == "" || config.AssistedCABundleNamespace == "" {
20-
return nil, fmt.Errorf("ASSISTED_CA_BUNDLE_NAME and ASSISTED_CA_BUNDLE_NAMESPACE must either both be set or unset")
22+
return nil, errors.New("ASSISTED_CA_BUNDLE_NAME and ASSISTED_CA_BUNDLE_NAMESPACE must either both be set or unset")
23+
}
24+
if config.AssistedCABundleResource != "secret" && config.AssistedCABundleResource != "configmap" {
25+
return nil, errors.New("ASSISTED_CA_BUNDLE_RESOURCE must be either configmap or secret")
2126
}
2227

23-
cmNSName := types.NamespacedName{
28+
caCertPool, err := x509.SystemCertPool()
29+
if err != nil {
30+
return nil, fmt.Errorf("failed to obtain system cert pool: %w", err)
31+
}
32+
33+
namespacedName := types.NamespacedName{
2434
Name: config.AssistedCABundleName,
2535
Namespace: config.AssistedCABundleNamespace,
2636
}
27-
cm := &corev1.ConfigMap{}
28-
if err := c.Get(context.Background(), cmNSName, cm); err != nil {
29-
return nil, err
30-
}
31-
bundlePEM, present := cm.Data[config.AssistedCABundleKey]
32-
if !present {
33-
return nil, fmt.Errorf("key %s not found in configmap %s", config.AssistedCABundleKey, cmNSName)
37+
var bundlePEM []byte
38+
39+
if strings.EqualFold(config.AssistedCABundleResource, "secret") {
40+
var secretErr error
41+
bundlePEM, secretErr = getBundlePEMFromSecret(namespacedName, config.AssistedCABundleKey, c)
42+
if secretErr != nil {
43+
return nil, fmt.Errorf("failed to retrieve cert from secret %s: %w", namespacedName, secretErr)
44+
}
3445
}
3546

36-
caCertPool, err := x509.SystemCertPool()
37-
if err != nil {
38-
return nil, fmt.Errorf("failed to obtain system cert pool: %w", err)
47+
if strings.EqualFold(config.AssistedCABundleResource, "configmap") {
48+
var configmapErr error
49+
bundlePEM, configmapErr = getBundlePEMFromConfigmap(namespacedName, config.AssistedCABundleKey, c)
50+
if configmapErr != nil {
51+
return nil, fmt.Errorf("failed to retrieve cert from configmap %s: %w", namespacedName, configmapErr)
52+
}
3953
}
40-
if !caCertPool.AppendCertsFromPEM([]byte(bundlePEM)) {
54+
if bundlePEM == nil || !caCertPool.AppendCertsFromPEM(bundlePEM) {
4155
return nil, fmt.Errorf("failed to append additional certificates")
4256
}
4357

@@ -52,3 +66,31 @@ func GetAssistedHTTPClient(config ServiceConfig, c client.Client) (*http.Client,
5266

5367
return &http.Client{Transport: transport}, nil
5468
}
69+
70+
func getBundlePEMFromConfigmap(namespacedName types.NamespacedName, certKey string, c client.Client) ([]byte, error) {
71+
configmap := &corev1.ConfigMap{}
72+
73+
if err := c.Get(context.Background(), namespacedName, configmap); err != nil {
74+
return nil, fmt.Errorf("failed to get configmap %s: %w", namespacedName, err)
75+
}
76+
77+
bundlePEM, present := configmap.Data[certKey]
78+
if !present {
79+
return nil, fmt.Errorf("key %s not found in configmap %s", certKey, namespacedName)
80+
}
81+
return []byte(bundlePEM), nil
82+
}
83+
84+
func getBundlePEMFromSecret(namespacedName types.NamespacedName, certKey string, c client.Client) ([]byte, error) {
85+
secret := &corev1.Secret{}
86+
87+
if err := c.Get(context.Background(), namespacedName, secret); err != nil {
88+
return nil, fmt.Errorf("failed to get secret %s: %w", namespacedName, err)
89+
}
90+
91+
bundlePEMBytes, present := secret.Data[certKey]
92+
if !present {
93+
return nil, fmt.Errorf("key %s not found in secret %s", certKey, namespacedName)
94+
}
95+
return bundlePEMBytes, nil
96+
}

assistedinstaller/client_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@ var _ = Describe("GetAssistedHTTPClient", func() {
6868
Expect(err).ToNot(BeNil())
6969
})
7070

71+
It("fails when the referenced resource is not valid", func() {
72+
cm := &corev1.ConfigMap{
73+
ObjectMeta: metav1.ObjectMeta{
74+
Name: "test-cm-name",
75+
Namespace: "test-cm-namespace",
76+
},
77+
Data: map[string]string{
78+
"bundle.crt": testCert,
79+
},
80+
}
81+
Expect(c.Create(context.Background(), cm)).To(Succeed())
82+
83+
config := ServiceConfig{
84+
AssistedCABundleName: "test-cm-name",
85+
AssistedCABundleNamespace: "test-cm-namespace",
86+
AssistedCABundleKey: "bundle.crt",
87+
AssistedCABundleResource: "deployment",
88+
}
89+
_, err := GetAssistedHTTPClient(config, c)
90+
Expect(err).ToNot(BeNil())
91+
})
92+
7193
It("fails when the referenced CM key is not present", func() {
7294
cm := &corev1.ConfigMap{
7395
ObjectMeta: metav1.ObjectMeta{
@@ -84,6 +106,7 @@ var _ = Describe("GetAssistedHTTPClient", func() {
84106
AssistedCABundleName: "test-cm-name",
85107
AssistedCABundleNamespace: "test-cm-namespace",
86108
AssistedCABundleKey: "bundle.crt",
109+
AssistedCABundleResource: "secret",
87110
}
88111
_, err := GetAssistedHTTPClient(config, c)
89112
Expect(err).ToNot(BeNil())
@@ -105,6 +128,29 @@ var _ = Describe("GetAssistedHTTPClient", func() {
105128
AssistedCABundleName: "test-cm-name",
106129
AssistedCABundleNamespace: "test-cm-namespace",
107130
AssistedCABundleKey: "bundle.crt",
131+
AssistedCABundleResource: "configmap",
132+
}
133+
_, err := GetAssistedHTTPClient(config, c)
134+
Expect(err).To(BeNil())
135+
})
136+
137+
It("creates a client using the referenced certs with secret", func() {
138+
cm := &corev1.Secret{
139+
ObjectMeta: metav1.ObjectMeta{
140+
Name: "test-cm-name",
141+
Namespace: "test-cm-namespace",
142+
},
143+
Data: map[string][]byte{
144+
"bundle.crt": []byte(testCert),
145+
},
146+
}
147+
Expect(c.Create(context.Background(), cm)).To(Succeed())
148+
149+
config := ServiceConfig{
150+
AssistedCABundleName: "test-cm-name",
151+
AssistedCABundleNamespace: "test-cm-namespace",
152+
AssistedCABundleKey: "bundle.crt",
153+
AssistedCABundleResource: "secret",
108154
}
109155
_, err := GetAssistedHTTPClient(config, c)
110156
Expect(err).To(BeNil())

assistedinstaller/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type ServiceConfig struct {
1616
// Name and namespace of a configmap containing the CA bundle to trust when querying assisted-service
1717
AssistedCABundleNamespace string `envconfig:"ASSISTED_CA_BUNDLE_NAMESPACE"`
1818
AssistedCABundleName string `envconfig:"ASSISTED_CA_BUNDLE_NAME"`
19+
AssistedCABundleResource string `envconfig:"ASSISTED_CA_BUNDLE_RESOURCE" default:"configmap"`
1920
// Key name to reference in the CA bundle configmap where the cert bundle is stored
2021
AssistedCABundleKey string `envconfig:"ASSISTED_CA_BUNDLE_KEY" default:"ca-bundle.crt"`
2122
}

0 commit comments

Comments
 (0)