Skip to content

Commit f060f7e

Browse files
committed
Fix: Define behavior for containers without RootCA store
1 parent e71f302 commit f060f7e

File tree

4 files changed

+109
-24
lines changed

4 files changed

+109
-24
lines changed

cmd/main.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ package main
2020
import (
2121
"context"
2222
"crypto/tls"
23-
"crypto/x509"
2423
"flag"
2524
"fmt"
2625
"net/http"
@@ -49,6 +48,7 @@ import (
4948

5049
infrastructurev1alpha1 "github.com/ionos-cloud/cluster-api-provider-proxmox/api/v1alpha1"
5150
"github.com/ionos-cloud/cluster-api-provider-proxmox/internal/controller"
51+
"github.com/ionos-cloud/cluster-api-provider-proxmox/internal/tlshelper"
5252
"github.com/ionos-cloud/cluster-api-provider-proxmox/internal/webhook"
5353
capmox "github.com/ionos-cloud/cluster-api-provider-proxmox/pkg/proxmox"
5454
"github.com/ionos-cloud/cluster-api-provider-proxmox/pkg/proxmox/goproxmox"
@@ -195,21 +195,9 @@ func setupProxmoxClient(ctx context.Context, logger logr.Logger) (capmox.Client,
195195
return nil, nil
196196
}
197197

198-
rootCerts, err := x509.SystemCertPool()
198+
rootCerts, err := tlshelper.SystemRootsWithFile(proxmoxRootCertFile)
199199
if err != nil {
200-
return nil, fmt.Errorf("loading system cert pool: %w", err)
201-
}
202-
203-
if proxmoxRootCertFile != "" {
204-
// There is a custom root cert, we need to load it
205-
pemBlock, err := os.ReadFile(proxmoxRootCertFile) //#nosec:G304 // File provided by system operator
206-
if err != nil {
207-
return nil, fmt.Errorf("reading proxmox-root-cert-file: %w", err)
208-
}
209-
210-
if !rootCerts.AppendCertsFromPEM(pemBlock) {
211-
return nil, fmt.Errorf("failure adding cert to root cert list")
212-
}
200+
return nil, fmt.Errorf("loading cert pool: %w", err)
213201
}
214202

215203
tr := &http.Transport{

internal/tlshelper/roots.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Package tlshelper wraps loading and modifying the root-CA store for
2+
// use in tls.Config
3+
package tlshelper
4+
5+
import (
6+
"crypto/x509"
7+
"fmt"
8+
"os"
9+
)
10+
11+
// SystemRootsWithFile reads the pemBlock for SystemRootsWithCert from
12+
// the given file and then calls SystemRootsWithCert.
13+
func SystemRootsWithFile(filepath string) (*x509.CertPool, error) {
14+
if len(filepath) == 0 {
15+
// No filename given, we fall back to default behavior: returning
16+
// nil and letting Go itself take care of everything
17+
return nil, nil
18+
}
19+
20+
pemBlock, err := os.ReadFile(filepath) //#nosec:G304 // Intended to read the given file
21+
if err != nil {
22+
return nil, fmt.Errorf("loading certificate file: %w", err)
23+
}
24+
25+
return SystemRootsWithCert(pemBlock)
26+
}
27+
28+
// SystemRootsWithCert tries to load the system root store and to
29+
// append the given certificate from a PEM encoded block into it. In
30+
// case there is no pool an empty pool is used to add the certificate.
31+
func SystemRootsWithCert(pemBlock []byte) (*x509.CertPool, error) {
32+
if len(pemBlock) == 0 {
33+
// Zero length / nil, we fall back to default behavior: returning
34+
// nil and letting Go itself take care of everything
35+
return nil, nil
36+
}
37+
38+
rootCerts, err := x509.SystemCertPool()
39+
if err != nil && !os.IsNotExist(err) {
40+
return nil, fmt.Errorf("loading system cert pool: %w", err)
41+
}
42+
43+
if os.IsNotExist(err) {
44+
// The system pool is not available but that's fine as we are
45+
// supposed to add one own cert
46+
rootCerts = x509.NewCertPool()
47+
}
48+
49+
if !rootCerts.AppendCertsFromPEM(pemBlock) {
50+
return nil, fmt.Errorf("certificate was not appended")
51+
}
52+
53+
return rootCerts, nil
54+
}

internal/tlshelper/roots_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package tlshelper
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
// This block contains a 100Y valid self-signed ECDSA CA with key no
11+
// longer existent.
12+
const exampleRootCA = `-----BEGIN CERTIFICATE-----
13+
MIIB6DCCAY+gAwIBAgIUIgQxz/rn8WLH3zyHICHh8Us552AwCgYIKoZIzj0EAwIw
14+
STELMAkGA1UEBhMCREUxEDAOBgNVBAgMB0hhbWJ1cmcxEzARBgNVBAoMCkV4YW1w
15+
bGUgQ0ExEzARBgNVBAMMCkV4YW1wbGUgQ0EwIBcNMjQxMTI4MTExMzM3WhgPMjEy
16+
NDExMDQxMTEzMzdaMEkxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdIYW1idXJnMRMw
17+
EQYDVQQKDApFeGFtcGxlIENBMRMwEQYDVQQDDApFeGFtcGxlIENBMFkwEwYHKoZI
18+
zj0CAQYIKoZIzj0DAQcDQgAEvQIYmiX4z2sv8sVqyC/eQ7e2JH1WQgIRuSWYVEOL
19+
YKEQDHwMg1KKu3+McgHXLiZ0af0JDyd00em/g7k39RzNhqNTMFEwHQYDVR0OBBYE
20+
FPDaKA2+m5nRhWESuw+61HdvmZiGMB8GA1UdIwQYMBaAFPDaKA2+m5nRhWESuw+6
21+
1HdvmZiGMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgQtj0ZhXK
22+
RYrWwHMzIHXqggsU3NhnOUa/yeeQOExDVbMCIAFDdaz3v5jOmWm7LR5BwQwLRWhO
23+
37ky2VQr/1GhU42q
24+
-----END CERTIFICATE-----`
25+
26+
func TestRootPoolLoading(t *testing.T) {
27+
// Empty file
28+
roots, err := SystemRootsWithFile("")
29+
require.NoError(t, err)
30+
assert.Nil(t, roots)
31+
32+
// Empty pemBlock
33+
roots, err = SystemRootsWithCert(nil)
34+
require.NoError(t, err)
35+
assert.Nil(t, roots)
36+
37+
// CA from system plus PEM
38+
roots, err = SystemRootsWithCert([]byte(exampleRootCA))
39+
require.NoError(t, err)
40+
assert.NotNil(t, roots)
41+
42+
// Error from broken file
43+
_, err = SystemRootsWithFile("/tmp/this/file/will/never/exist.notexist")
44+
require.Error(t, err)
45+
46+
// Error from broken PEM
47+
_, err = SystemRootsWithCert([]byte("I'm certainly not a PEM block"))
48+
require.Error(t, err)
49+
}

pkg/scope/cluster.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ package scope
2020
import (
2121
"context"
2222
"crypto/tls"
23-
"crypto/x509"
2423
"fmt"
2524
"net/http"
2625

@@ -38,6 +37,7 @@ import (
3837
"sigs.k8s.io/controller-runtime/pkg/log"
3938

4039
infrav1alpha1 "github.com/ionos-cloud/cluster-api-provider-proxmox/api/v1alpha1"
40+
"github.com/ionos-cloud/cluster-api-provider-proxmox/internal/tlshelper"
4141
"github.com/ionos-cloud/cluster-api-provider-proxmox/pkg/kubernetes/ipam"
4242
capmox "github.com/ionos-cloud/cluster-api-provider-proxmox/pkg/proxmox"
4343
"github.com/ionos-cloud/cluster-api-provider-proxmox/pkg/proxmox/goproxmox"
@@ -156,15 +156,9 @@ func (s *ClusterScope) setupProxmoxClient(ctx context.Context) (capmox.Client, e
156156
tlsInsecure := string(secret.Data["insecure"]) != "false"
157157
tlsRootCA := secret.Data["root_ca"]
158158

159-
rootCerts, err := x509.SystemCertPool()
159+
rootCerts, err := tlshelper.SystemRootsWithCert(tlsRootCA)
160160
if err != nil {
161-
return nil, fmt.Errorf("loading system cert pool: %w", err)
162-
}
163-
164-
if len(tlsRootCA) > 0 {
165-
if !rootCerts.AppendCertsFromPEM(tlsRootCA) {
166-
return nil, fmt.Errorf("failure adding cert to root cert list")
167-
}
161+
return nil, fmt.Errorf("loading cert pool: %w", err)
168162
}
169163

170164
tr := &http.Transport{

0 commit comments

Comments
 (0)