44package apiserver
55
66import (
7+ "bytes"
78 "context"
89 "fmt"
910 "net"
@@ -35,6 +36,7 @@ import (
3536 "k8s.io/client-go/discovery"
3637 "k8s.io/client-go/kubernetes"
3738 "k8s.io/client-go/rest"
39+ "k8s.io/client-go/util/retry"
3840 apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
3941 aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
4042)
@@ -49,6 +51,8 @@ const (
4951 kappctrlSVCEnvKey = "KAPPCTRL_SYSTEM_SERVICE"
5052
5153 apiServiceName = "v1alpha1.data.packaging.carvel.dev"
54+
55+ apiServiceReconcileInterval = 30 * time .Second
5256)
5357
5458var (
@@ -107,7 +111,7 @@ func NewAPIServer(clientConfig *rest.Config, coreClient kubernetes.Interface, kc
107111 return nil , fmt .Errorf ("building aggregation client: %v" , err )
108112 }
109113
110- config , err := newServerConfig (aggClient , opts )
114+ config , caContentProvider , err := newServerConfig (aggClient , opts )
111115 if err != nil {
112116 return nil , err
113117 }
@@ -117,6 +121,29 @@ func NewAPIServer(clientConfig *rest.Config, coreClient kubernetes.Interface, kc
117121 return nil , err
118122 }
119123
124+ // Register the PostStartHook to reconcile the CA Bundle
125+ if err := server .AddPostStartHook ("apiservice-ca-reconciler" , func (hookContext genericapiserver.PostStartHookContext ) error {
126+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
127+ defer cancel ()
128+ if err := updateAPIService (ctx , opts .Logger , aggClient , caContentProvider ); err != nil {
129+ opts .Logger .Error (err , "Initial APIService CA sync failed" )
130+ return err
131+ }
132+
133+ // Background Reconciliation
134+ go wait .Until (func () {
135+ ctx , syncCancel := context .WithTimeout (context .Background (), 10 * time .Second )
136+ defer syncCancel ()
137+ if err := updateAPIService (ctx , opts .Logger , aggClient , caContentProvider ); err != nil {
138+ opts .Logger .Error (err , "Background APIService CA reconciliation failed" )
139+ }
140+ }, apiServiceReconcileInterval , hookContext .StopCh )
141+
142+ return nil
143+ }); err != nil {
144+ return nil , fmt .Errorf ("error registering APIService CA reconciler hook: %v" , err )
145+ }
146+
120147 packageMetadatasStorage := packagerest .NewPackageMetadataCRDREST (kcClient , coreClient , opts .GlobalNamespace )
121148 packageStorage := packagerest .NewPackageCRDREST (kcClient , coreClient , opts .GlobalNamespace , opts .Logger )
122149
@@ -168,7 +195,7 @@ func (as *APIServer) isReady() (bool, error) {
168195 return false , nil
169196}
170197
171- func newServerConfig (aggClient aggregatorclient.Interface , opts NewAPIServerOpts ) (* genericapiserver.RecommendedConfig , error ) {
198+ func newServerConfig (aggClient aggregatorclient.Interface , opts NewAPIServerOpts ) (* genericapiserver.RecommendedConfig , * dynamiccertificates. DynamicFileCAContent , error ) {
172199
173200 recommendedOptions := genericoptions .NewRecommendedOptions ("" , Codecs .LegacyCodec (v1alpha1 .SchemeGroupVersion ))
174201 recommendedOptions .Etcd = nil
@@ -180,26 +207,22 @@ func newServerConfig(aggClient aggregatorclient.Interface, opts NewAPIServerOpts
180207
181208 // ports below 1024 are probably the wrong port, see https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports
182209 if opts .BindPort < 1024 {
183- return nil , fmt .Errorf ("error initializing API Port to %v - try passing a port above 1023" , opts .BindPort )
210+ return nil , nil , fmt .Errorf ("error initializing API Port to %v - try passing a port above 1023" , opts .BindPort )
184211 }
185212 recommendedOptions .SecureServing .BindPort = opts .BindPort
186213
187214 if err := recommendedOptions .SecureServing .MaybeDefaultWithSelfSignedCerts ("kapp-controller" , []string {apiServiceEndoint ()}, []net.IP {net .ParseIP ("127.0.0.1" )}); err != nil {
188- return nil , fmt .Errorf ("error creating self-signed certificates: %v" , err )
215+ return nil , nil , fmt .Errorf ("error creating self-signed certificates: %v" , err )
189216 }
190217
191218 caContentProvider , err := dynamiccertificates .NewDynamicCAContentFromFile ("self-signed cert" , recommendedOptions .SecureServing .ServerCert .CertKey .CertFile )
192219 if err != nil {
193- return nil , fmt .Errorf ("error reading self-signed CA certificate: %v" , err )
194- }
195-
196- if err := updateAPIService (opts .Logger , aggClient , caContentProvider ); err != nil {
197- return nil , fmt .Errorf ("error updating api service with generated certs: %v" , err )
220+ return nil , nil , fmt .Errorf ("error reading self-signed CA certificate: %v" , err )
198221 }
199222
200223 serverVersion , err := getServerVersion (aggClient .Discovery ())
201224 if err != nil {
202- return nil , err
225+ return nil , nil , err
203226 }
204227
205228 // this feature gate is not enabled in k8s <1.29 as the
@@ -208,7 +231,7 @@ func newServerConfig(aggClient aggregatorclient.Interface, opts NewAPIServerOpts
208231 // so the best we can do for older k8s clusters is to allow it to be disabled.
209232 minSupportedVersionForAPF , err := semver .New ("1.29.0" )
210233 if err != nil {
211- return nil , err
234+ return nil , nil , err
212235 }
213236 isServerVerLTminSupportedVer := serverVersion .LT (* minSupportedVersionForAPF )
214237 if ! opts .EnableAPIPriorityAndFairness || isServerVerLTminSupportedVer {
@@ -223,7 +246,7 @@ func newServerConfig(aggClient aggregatorclient.Interface, opts NewAPIServerOpts
223246 // However, we will still run namespaceLifecycle, mutatingAdmissionWebhook and validatingAdmissionWebhooks.
224247 minSupportedVersionForValidatingAdmissionPolicy , err := semver .New ("1.30.0" )
225248 if err != nil {
226- return nil , err
249+ return nil , nil , err
227250 }
228251 isServerVerLTminSupportedVer = serverVersion .LT (* minSupportedVersionForValidatingAdmissionPolicy )
229252 if isServerVerLTminSupportedVer {
@@ -248,10 +271,10 @@ func newServerConfig(aggClient aggregatorclient.Interface, opts NewAPIServerOpts
248271 serverConfig .OpenAPIConfig .Info .Version = "v1alpha1"
249272
250273 if err := recommendedOptions .ApplyTo (serverConfig ); err != nil {
251- return nil , err
274+ return nil , nil , err
252275 }
253276
254- return serverConfig , nil
277+ return serverConfig , caContentProvider , nil
255278}
256279
257280func getServerVersion (discoveryClient discovery.DiscoveryInterface ) (semver.Version , error ) {
@@ -268,14 +291,23 @@ func getServerVersion(discoveryClient discovery.DiscoveryInterface) (semver.Vers
268291 return retv , nil
269292}
270293
271- func updateAPIService (logger logr.Logger , client aggregatorclient.Interface , caProvider dynamiccertificates.CAContentProvider ) error {
272- logger .Info ("Syncing CA certificate with APIServices" )
273- apiService , err := client .ApiregistrationV1 ().APIServices ().Get (context .TODO (), apiServiceName , metav1.GetOptions {})
274- if err != nil {
275- return fmt .Errorf ("error getting APIService %s: %v" , apiServiceName , err )
276- }
277- apiService .Spec .CABundle = caProvider .CurrentCABundleContent ()
278- if _ , err := client .ApiregistrationV1 ().APIServices ().Update (context .TODO (), apiService , metav1.UpdateOptions {}); err != nil {
294+ func updateAPIService (ctx context.Context , logger logr.Logger , client aggregatorclient.Interface , caProvider dynamiccertificates.CAContentProvider ) error {
295+ if err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
296+ apiService , err := client .ApiregistrationV1 ().APIServices ().Get (ctx , apiServiceName , metav1.GetOptions {})
297+ if err != nil {
298+ return fmt .Errorf ("error getting APIService %s: %v" , apiServiceName , err )
299+ }
300+
301+ caBundle := caProvider .CurrentCABundleContent ()
302+ if bytes .Equal (apiService .Spec .CABundle , caBundle ) {
303+ return nil
304+ }
305+
306+ logger .Info ("Syncing CA certificate with APIServices" )
307+ apiService .Spec .CABundle = caBundle
308+ _ , err = client .ApiregistrationV1 ().APIServices ().Update (ctx , apiService , metav1.UpdateOptions {})
309+ return err
310+ }); err != nil {
279311 return fmt .Errorf ("error updating kapp-controller CA cert of APIService %s: %v" , apiServiceName , err )
280312 }
281313 return nil
0 commit comments