Skip to content

Commit 8f2f1e9

Browse files
perdasilvaPer G. da Silva
and
Per G. da Silva
authored
Add openshift-serviceca certificate provider (#1969)
Signed-off-by: Per G. da Silva <pegoncal@redhat.com> Co-authored-by: Per G. da Silva <pegoncal@redhat.com>
1 parent c9df915 commit 8f2f1e9

File tree

4 files changed

+209
-4
lines changed

4 files changed

+209
-4
lines changed

cmd/operator-controller/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ func run() error {
431431
if features.OperatorControllerFeatureGate.Enabled(features.WebhookProviderCertManager) {
432432
certProvider = certproviders.CertManagerCertificateProvider{}
433433
isWebhookSupportEnabled = true
434+
} else if features.OperatorControllerFeatureGate.Enabled(features.WebhookProviderOpenshiftServiceCA) {
435+
certProvider = certproviders.OpenshiftServiceCaCertificateProvider{}
436+
isWebhookSupportEnabled = true
434437
}
435438

436439
// now initialize the helmApplier, assigning the potentially nil preAuth

internal/operator-controller/features/features.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ import (
1111
const (
1212
// Add new feature gates constants (strings)
1313
// Ex: SomeFeature featuregate.Feature = "SomeFeature"
14-
PreflightPermissions featuregate.Feature = "PreflightPermissions"
15-
SingleOwnNamespaceInstallSupport featuregate.Feature = "SingleOwnNamespaceInstallSupport"
16-
SyntheticPermissions featuregate.Feature = "SyntheticPermissions"
17-
WebhookProviderCertManager featuregate.Feature = "WebhookProviderCertManager"
14+
PreflightPermissions featuregate.Feature = "PreflightPermissions"
15+
SingleOwnNamespaceInstallSupport featuregate.Feature = "SingleOwnNamespaceInstallSupport"
16+
SyntheticPermissions featuregate.Feature = "SyntheticPermissions"
17+
WebhookProviderCertManager featuregate.Feature = "WebhookProviderCertManager"
18+
WebhookProviderOpenshiftServiceCA featuregate.Feature = "WebhookProviderOpenshiftServiceCA"
1819
)
1920

2021
var operatorControllerFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
@@ -52,6 +53,16 @@ var operatorControllerFeatureGates = map[featuregate.Feature]featuregate.Feature
5253
PreRelease: featuregate.Alpha,
5354
LockToDefault: false,
5455
},
56+
57+
// WebhookProviderCertManager enables support for installing
58+
// registry+v1 cluster extensions that include validating,
59+
// mutating, and/or conversion webhooks with Openshift Service CA
60+
// as the certificate provider.
61+
WebhookProviderOpenshiftServiceCA: {
62+
Default: false,
63+
PreRelease: featuregate.Alpha,
64+
LockToDefault: false,
65+
},
5566
}
5667

5768
var OperatorControllerFeatureGate featuregate.MutableFeatureGate = featuregate.NewFeatureGate()
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package certproviders
2+
3+
import (
4+
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
5+
corev1 "k8s.io/api/core/v1"
6+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
7+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8+
"sigs.k8s.io/controller-runtime/pkg/client"
9+
10+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render"
11+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/util"
12+
)
13+
14+
const (
15+
openshiftServiceCAServingCertNameAnnotation = "service.beta.openshift.io/serving-cert-secret-name"
16+
openshiftServiceCAInjectCABundleAnnotation = "service.beta.openshift.io/inject-cabundle"
17+
)
18+
19+
var _ render.CertificateProvider = (*OpenshiftServiceCaCertificateProvider)(nil)
20+
21+
type OpenshiftServiceCaCertificateProvider struct{}
22+
23+
func (p OpenshiftServiceCaCertificateProvider) InjectCABundle(obj client.Object, cfg render.CertificateProvisionerConfig) error {
24+
switch obj.(type) {
25+
case *admissionregistrationv1.ValidatingWebhookConfiguration:
26+
p.addInjectCABundleAnnotation(obj)
27+
case *admissionregistrationv1.MutatingWebhookConfiguration:
28+
p.addInjectCABundleAnnotation(obj)
29+
case *apiextensionsv1.CustomResourceDefinition:
30+
p.addInjectCABundleAnnotation(obj)
31+
case *corev1.Service:
32+
p.addServingCertSecretNameAnnotation(obj, cfg.CertName)
33+
}
34+
return nil
35+
}
36+
37+
func (p OpenshiftServiceCaCertificateProvider) AdditionalObjects(_ render.CertificateProvisionerConfig) ([]unstructured.Unstructured, error) {
38+
return nil, nil
39+
}
40+
41+
func (p OpenshiftServiceCaCertificateProvider) GetCertSecretInfo(cfg render.CertificateProvisionerConfig) render.CertSecretInfo {
42+
return render.CertSecretInfo{
43+
SecretName: cfg.CertName,
44+
PrivateKeyKey: "tls.key",
45+
CertificateKey: "tls.crt",
46+
}
47+
}
48+
49+
func (p OpenshiftServiceCaCertificateProvider) addServingCertSecretNameAnnotation(obj client.Object, certName string) {
50+
injectionAnnotation := map[string]string{
51+
openshiftServiceCAServingCertNameAnnotation: certName,
52+
}
53+
obj.SetAnnotations(util.MergeMaps(obj.GetAnnotations(), injectionAnnotation))
54+
}
55+
56+
func (p OpenshiftServiceCaCertificateProvider) addInjectCABundleAnnotation(obj client.Object) {
57+
injectionAnnotation := map[string]string{
58+
openshiftServiceCAInjectCABundleAnnotation: "true",
59+
}
60+
obj.SetAnnotations(util.MergeMaps(obj.GetAnnotations(), injectionAnnotation))
61+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package certproviders_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
8+
corev1 "k8s.io/api/core/v1"
9+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
13+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render"
14+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render/certproviders"
15+
)
16+
17+
func Test_OpenshiftServiceCAProvider_InjectCABundle(t *testing.T) {
18+
for _, tc := range []struct {
19+
name string
20+
obj client.Object
21+
cfg render.CertificateProvisionerConfig
22+
expectedObj client.Object
23+
}{
24+
{
25+
name: "injects inject-cabundle annotation in validating webhook configuration",
26+
obj: &admissionregistrationv1.ValidatingWebhookConfiguration{},
27+
cfg: render.CertificateProvisionerConfig{
28+
WebhookServiceName: "webhook-service",
29+
Namespace: "namespace",
30+
CertName: "cert-name",
31+
},
32+
expectedObj: &admissionregistrationv1.ValidatingWebhookConfiguration{
33+
ObjectMeta: metav1.ObjectMeta{
34+
Annotations: map[string]string{
35+
"service.beta.openshift.io/inject-cabundle": "true",
36+
},
37+
},
38+
},
39+
},
40+
{
41+
name: "injects inject-cabundle annotation in mutating webhook configuration",
42+
obj: &admissionregistrationv1.MutatingWebhookConfiguration{},
43+
cfg: render.CertificateProvisionerConfig{
44+
WebhookServiceName: "webhook-service",
45+
Namespace: "namespace",
46+
CertName: "cert-name",
47+
},
48+
expectedObj: &admissionregistrationv1.MutatingWebhookConfiguration{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Annotations: map[string]string{
51+
"service.beta.openshift.io/inject-cabundle": "true",
52+
},
53+
},
54+
},
55+
},
56+
{
57+
name: "injects inject-cabundle annotation in custom resource definition",
58+
obj: &apiextensionsv1.CustomResourceDefinition{},
59+
cfg: render.CertificateProvisionerConfig{
60+
WebhookServiceName: "webhook-service",
61+
Namespace: "namespace",
62+
CertName: "cert-name",
63+
},
64+
expectedObj: &apiextensionsv1.CustomResourceDefinition{
65+
ObjectMeta: metav1.ObjectMeta{
66+
Annotations: map[string]string{
67+
"service.beta.openshift.io/inject-cabundle": "true",
68+
},
69+
},
70+
},
71+
},
72+
{
73+
name: "injects serving-cert-secret-name annotation in service resource referencing the certificate name",
74+
obj: &corev1.Service{},
75+
cfg: render.CertificateProvisionerConfig{
76+
WebhookServiceName: "webhook-service",
77+
Namespace: "namespace",
78+
CertName: "cert-name",
79+
},
80+
expectedObj: &corev1.Service{
81+
ObjectMeta: metav1.ObjectMeta{
82+
Annotations: map[string]string{
83+
"service.beta.openshift.io/serving-cert-secret-name": "cert-name",
84+
},
85+
},
86+
},
87+
},
88+
{
89+
name: "ignores other objects",
90+
obj: &corev1.Secret{},
91+
cfg: render.CertificateProvisionerConfig{
92+
WebhookServiceName: "webhook-service",
93+
Namespace: "namespace",
94+
CertName: "cert-name",
95+
},
96+
expectedObj: &corev1.Secret{},
97+
},
98+
} {
99+
t.Run(tc.name, func(t *testing.T) {
100+
certProvider := certproviders.OpenshiftServiceCaCertificateProvider{}
101+
require.NoError(t, certProvider.InjectCABundle(tc.obj, tc.cfg))
102+
require.Equal(t, tc.expectedObj, tc.obj)
103+
})
104+
}
105+
}
106+
107+
func Test_OpenshiftServiceCAProvider_AdditionalObjects(t *testing.T) {
108+
certProvider := certproviders.OpenshiftServiceCaCertificateProvider{}
109+
objs, err := certProvider.AdditionalObjects(render.CertificateProvisionerConfig{
110+
WebhookServiceName: "webhook-service",
111+
Namespace: "namespace",
112+
CertName: "cert-name",
113+
})
114+
require.NoError(t, err)
115+
require.Nil(t, objs)
116+
}
117+
118+
func Test_OpenshiftServiceCAProvider_GetCertSecretInfo(t *testing.T) {
119+
certProvider := certproviders.OpenshiftServiceCaCertificateProvider{}
120+
certInfo := certProvider.GetCertSecretInfo(render.CertificateProvisionerConfig{
121+
WebhookServiceName: "webhook-service",
122+
Namespace: "namespace",
123+
CertName: "cert-name",
124+
})
125+
require.Equal(t, render.CertSecretInfo{
126+
SecretName: "cert-name",
127+
PrivateKeyKey: "tls.key",
128+
CertificateKey: "tls.crt",
129+
}, certInfo)
130+
}

0 commit comments

Comments
 (0)