Skip to content

Commit b093afd

Browse files
committed
add filepath tls server source in webhook init
1 parent 192a723 commit b093afd

3 files changed

Lines changed: 79 additions & 20 deletions

File tree

cmd/crossplane/core/init.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package core
1919
import (
2020
"context"
2121
"fmt"
22+
"path/filepath"
2223

2324
admv1 "k8s.io/api/admissionregistration/v1"
2425
"k8s.io/apimachinery/pkg/runtime"
@@ -53,6 +54,9 @@ type initCommand struct {
5354
TLSCASecretName string `env:"TLS_CA_SECRET_NAME" help:"The name of the Secret that the initializer will fill with TLS CA certificate."`
5455
TLSServerSecretName string `env:"TLS_SERVER_SECRET_NAME" help:"The name of the Secret that the initializer will fill with TLS server certificates."`
5556
TLSClientSecretName string `env:"TLS_CLIENT_SECRET_NAME" help:"The name of the Secret that the initializer will fill with TLS client certificates."`
57+
58+
WebhookTLSCertDir string `env:"WEBHOOK_TLS_CERT_DIR" help:"Directory containing TLS certificates for webhooks. When set, certificates are read from files instead of Secrets."`
59+
WebhookTLSCACert string `default:"ca.crt" env:"WEBHOOK_TLS_CA_CERT" help:"Filename of the CA certificate within the TLS cert directory."`
5660
}
5761

5862
// Run starts the initialization process.
@@ -91,18 +95,28 @@ func (c *initCommand) Run(s *runtime.Scheme, log logging.Logger) error {
9195
),
9296
)
9397

94-
nn := types.NamespacedName{
95-
Name: c.TLSServerSecretName,
96-
Namespace: c.Namespace,
97-
}
9898
svc := admv1.ServiceReference{
9999
Name: c.WebhookServiceName,
100100
Namespace: c.WebhookServiceNamespace,
101101
Port: &c.WebhookServicePort,
102102
}
103-
steps = append(steps,
104-
initializer.NewCoreCRDs(c.CRDsPath, s, initializer.WithWebhookTLSSecretRef(nn)),
105-
initializer.NewWebhookConfigurations(c.WebhookConfigurationsPath, s, nn, svc))
103+
104+
var caProvider initializer.WebhookCAProvider
105+
if c.WebhookTLSCertDir != "" {
106+
caProvider = &initializer.FileCAProvider{Path: filepath.Join(c.WebhookTLSCertDir, c.WebhookTLSCACert)}
107+
steps = append(steps,
108+
initializer.NewCoreCRDs(c.CRDsPath, s),
109+
initializer.NewWebhookConfigurations(c.WebhookConfigurationsPath, s, caProvider, svc))
110+
} else {
111+
nn := types.NamespacedName{
112+
Name: c.TLSServerSecretName,
113+
Namespace: c.Namespace,
114+
}
115+
caProvider = &initializer.SecretCAProvider{SecretRef: nn}
116+
steps = append(steps,
117+
initializer.NewCoreCRDs(c.CRDsPath, s, initializer.WithWebhookTLSSecretRef(nn)),
118+
initializer.NewWebhookConfigurations(c.WebhookConfigurationsPath, s, caProvider, svc))
119+
}
106120
} else {
107121
log.Info("Warning: Webhooks are disabled, so deprecated ValidatingWebhookConfigurations will not be automatically deleted.")
108122
steps = append(steps,

internal/initializer/webhook_configurations.go

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package initializer
1818

1919
import (
2020
"context"
21+
"os"
2122

2223
"github.com/spf13/afero"
2324
admv1 "k8s.io/api/admissionregistration/v1"
@@ -35,8 +36,51 @@ import (
3536
const (
3637
errApplyWebhookConfiguration = "cannot apply webhook configuration"
3738
errGetWebhookSecret = "cannot get webhook secret"
39+
errReadCABundleFile = "cannot read CA bundle file"
40+
errEmptyCABundleFile = "CA bundle file is empty"
3841
)
3942

43+
// WebhookCAProvider provides a CA bundle for webhook configurations.
44+
type WebhookCAProvider interface {
45+
GetCABundle(ctx context.Context, kube client.Client) ([]byte, error)
46+
}
47+
48+
// SecretCAProvider loads the CA bundle from a Kubernetes Secret.
49+
type SecretCAProvider struct {
50+
SecretRef types.NamespacedName
51+
}
52+
53+
func (p *SecretCAProvider) GetCABundle(ctx context.Context, kube client.Client) ([]byte, error) {
54+
s := &corev1.Secret{}
55+
if err := kube.Get(ctx, p.SecretRef, s); err != nil {
56+
return nil, errors.Wrap(err, errGetWebhookSecret)
57+
}
58+
59+
if len(s.Data["tls.crt"]) == 0 {
60+
return nil, errors.Errorf(errFmtNoTLSCrtInSecret, p.SecretRef.String())
61+
}
62+
63+
return s.Data["tls.crt"], nil
64+
}
65+
66+
// FileCAProvider loads the CA bundle from a file.
67+
type FileCAProvider struct {
68+
Path string
69+
}
70+
71+
func (p *FileCAProvider) GetCABundle(ctx context.Context, kube client.Client) ([]byte, error) {
72+
data, err := os.ReadFile(p.Path)
73+
if err != nil {
74+
return nil, errors.Wrap(err, errReadCABundleFile)
75+
}
76+
77+
if len(data) == 0 {
78+
return nil, errors.New(errEmptyCABundleFile)
79+
}
80+
81+
return data, nil
82+
}
83+
4084
// WithWebhookConfigurationsFs is used to configure the filesystem the CRDs will
4185
// be read from. Its default is afero.OsFs.
4286
func WithWebhookConfigurationsFs(fs afero.Fs) WebhookConfigurationsOption {
@@ -45,15 +89,22 @@ func WithWebhookConfigurationsFs(fs afero.Fs) WebhookConfigurationsOption {
4589
}
4690
}
4791

92+
// WithWebhookCAProvider sets the CA provider for webhook configurations.
93+
func WithWebhookCAProvider(provider WebhookCAProvider) WebhookConfigurationsOption {
94+
return func(c *WebhookConfigurations) {
95+
c.caProvider = provider
96+
}
97+
}
98+
4899
// WebhookConfigurationsOption configures WebhookConfigurations step.
49100
type WebhookConfigurationsOption func(*WebhookConfigurations)
50101

51102
// NewWebhookConfigurations returns a new *WebhookConfigurations.
52-
func NewWebhookConfigurations(path string, s *runtime.Scheme, tlsSecretRef types.NamespacedName, svc admv1.ServiceReference, opts ...WebhookConfigurationsOption) *WebhookConfigurations {
103+
func NewWebhookConfigurations(path string, s *runtime.Scheme, caProvider WebhookCAProvider, svc admv1.ServiceReference, opts ...WebhookConfigurationsOption) *WebhookConfigurations {
53104
c := &WebhookConfigurations{
54105
Path: path,
55106
Scheme: s,
56-
TLSSecretRef: tlsSecretRef,
107+
caProvider: caProvider,
57108
ServiceReference: svc,
58109
fs: afero.NewOsFs(),
59110
}
@@ -69,7 +120,7 @@ func NewWebhookConfigurations(path string, s *runtime.Scheme, tlsSecretRef types
69120
type WebhookConfigurations struct {
70121
Path string
71122
Scheme *runtime.Scheme
72-
TLSSecretRef types.NamespacedName
123+
caProvider WebhookCAProvider
73124
ServiceReference admv1.ServiceReference
74125

75126
fs afero.Fs
@@ -78,17 +129,11 @@ type WebhookConfigurations struct {
78129
// Run applies all webhook ValidatingWebhookConfigurations and
79130
// MutatingWebhookConfiguration in the given directory.
80131
func (c *WebhookConfigurations) Run(ctx context.Context, kube client.Client) error {
81-
s := &corev1.Secret{}
82-
if err := kube.Get(ctx, c.TLSSecretRef, s); err != nil {
83-
return errors.Wrap(err, errGetWebhookSecret)
84-
}
85-
86-
if len(s.Data["tls.crt"]) == 0 {
87-
return errors.Errorf(errFmtNoTLSCrtInSecret, c.TLSSecretRef.String())
132+
caBundle, err := c.caProvider.GetCABundle(ctx, kube)
133+
if err != nil {
134+
return err
88135
}
89136

90-
caBundle := s.Data["tls.crt"]
91-
92137
r, err := parser.NewFsBackend(c.fs,
93138
parser.FsDir(c.Path),
94139
parser.FsFilters(

internal/initializer/webhook_configurations_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func TestWebhookConfigurations(t *testing.T) {
189189
err := NewWebhookConfigurations(
190190
"/webhooks",
191191
sch,
192-
types.NamespacedName{},
192+
&SecretCAProvider{SecretRef: types.NamespacedName{}},
193193
tc.args.svc,
194194
tc.opts...).Run(context.TODO(), tc.kube)
195195
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {

0 commit comments

Comments
 (0)