Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 43e8d85

Browse files
marunbertinatto
authored andcommittedNov 29, 2024
UPSTREAM: <carry>: Ensure service ca is mounted for projected tokens
OpenShift since 3.x has injected the service serving certificate ca (service ca) bundle into service account token secrets. This was intended to ensure that all pods would be able to easily verify connections to endpoints secured with service serving certificates. Since breaking customer workloads is not an option, and there is no way to ensure that customers are not relying on the service ca bundle being mounted at /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt, it is necessary to continue mounting the service ca bundle in the same location in the bound token projected volumes enabled by the BoundServiceAccountTokenVolume feature (enabled by default in 1.21). A new controller is added to create a configmap per namespace that is annotated for service ca injection. The controller is derived from the controller that creates configmaps for the root ca. The service account admission controller is updated to include a source for the new configmap in the default projected volume definition. UPSTREAM: <carry>: <squash> Add unit testing for service ca configmap publishing This commit should be squashed with: UPSTREAM: <carry>: Ensure service ca is mounted for projected tokens OpenShift-Rebase-Source: d69d054 UPSTREAM: <carry>: Ensure service ca is mounted for projected tokens
1 parent 5da1477 commit 43e8d85

File tree

13 files changed

+604
-3
lines changed

13 files changed

+604
-3
lines changed
 

‎cmd/kube-controller-manager/app/certificates.go

+22
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"k8s.io/controller-manager/controller"
3232
"k8s.io/klog/v2"
3333
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
34+
"k8s.io/kubernetes/openshift-kube-controller-manager/servicecacertpublisher"
3435
"k8s.io/kubernetes/pkg/controller/certificates/approver"
3536
"k8s.io/kubernetes/pkg/controller/certificates/cleaner"
3637
ctbpublisher "k8s.io/kubernetes/pkg/controller/certificates/clustertrustbundlepublisher"
@@ -298,3 +299,24 @@ func getKubeAPIServerCAFileContents(controllerContext ControllerContext) ([]byte
298299
return rootCA, nil
299300

300301
}
302+
303+
func newServiceCACertPublisher() *ControllerDescriptor {
304+
return &ControllerDescriptor{
305+
name: names.ServiceCACertificatePublisherController,
306+
aliases: []string{"service-ca-cert-publisher"},
307+
initFunc: startServiceCACertPublisher,
308+
}
309+
}
310+
311+
func startServiceCACertPublisher(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
312+
sac, err := servicecacertpublisher.NewPublisher(
313+
controllerContext.InformerFactory.Core().V1().ConfigMaps(),
314+
controllerContext.InformerFactory.Core().V1().Namespaces(),
315+
controllerContext.ClientBuilder.ClientOrDie("service-ca-cert-publisher"),
316+
)
317+
if err != nil {
318+
return nil, true, fmt.Errorf("error creating service CA certificate publisher: %v", err)
319+
}
320+
go sac.Run(1, ctx.Done())
321+
return nil, true, nil
322+
}

‎cmd/kube-controller-manager/app/controllermanager.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ controller, and serviceaccounts controller.`,
133133
return err
134134
}
135135
cliflag.PrintFlags(cmd.Flags())
136-
136+
137137
if err := SetUpPreferredHostForOpenShift(s); err != nil {
138138
fmt.Fprintf(os.Stderr, "%v\n", err)
139139
os.Exit(1)
@@ -508,9 +508,7 @@ func ControllersDisabledByDefault() []string {
508508
controllersDisabledByDefault = append(controllersDisabledByDefault, name)
509509
}
510510
}
511-
512511
sort.Strings(controllersDisabledByDefault)
513-
514512
return controllersDisabledByDefault
515513
}
516514

@@ -596,6 +594,7 @@ func NewControllerDescriptors() map[string]*ControllerDescriptor {
596594
register(newTTLAfterFinishedControllerDescriptor())
597595
register(newRootCACertificatePublisherControllerDescriptor())
598596
register(newKubeAPIServerSignerClusterTrustBundledPublisherDescriptor())
597+
register(newServiceCACertPublisher())
599598
register(newEphemeralVolumeControllerDescriptor())
600599

601600
// feature gated

‎cmd/kube-controller-manager/app/controllermanager_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func TestControllerNamesDeclaration(t *testing.T) {
9090
names.TTLAfterFinishedController,
9191
names.RootCACertificatePublisherController,
9292
names.KubeAPIServerClusterTrustBundlePublisherController,
93+
names.ServiceCACertificatePublisherController,
9394
names.EphemeralVolumeController,
9495
names.StorageVersionGarbageCollectorController,
9596
names.ResourceClaimController,

‎cmd/kube-controller-manager/names/controller_names.go

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const (
7777
PersistentVolumeProtectionController = "persistentvolume-protection-controller"
7878
TTLAfterFinishedController = "ttl-after-finished-controller"
7979
RootCACertificatePublisherController = "root-ca-certificate-publisher-controller"
80+
ServiceCACertificatePublisherController = "service-ca-certificate-publisher-controller"
8081
KubeAPIServerClusterTrustBundlePublisherController = "kube-apiserver-serving-clustertrustbundle-publisher-controller"
8182
EphemeralVolumeController = "ephemeral-volume-controller"
8283
StorageVersionGarbageCollectorController = "storageversion-garbage-collector-controller"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package servicecacertpublisher
2+
3+
import (
4+
"strconv"
5+
"sync"
6+
"time"
7+
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
9+
"k8s.io/component-base/metrics"
10+
"k8s.io/component-base/metrics/legacyregistry"
11+
)
12+
13+
// ServiceCACertPublisher - subsystem name used by service_ca_cert_publisher
14+
const ServiceCACertPublisher = "service_ca_cert_publisher"
15+
16+
var (
17+
syncCounter = metrics.NewCounterVec(
18+
&metrics.CounterOpts{
19+
Subsystem: ServiceCACertPublisher,
20+
Name: "sync_total",
21+
Help: "Number of namespace syncs happened in service ca cert publisher.",
22+
StabilityLevel: metrics.ALPHA,
23+
},
24+
[]string{"code"},
25+
)
26+
syncLatency = metrics.NewHistogramVec(
27+
&metrics.HistogramOpts{
28+
Subsystem: ServiceCACertPublisher,
29+
Name: "sync_duration_seconds",
30+
Help: "Number of namespace syncs happened in service ca cert publisher.",
31+
Buckets: metrics.ExponentialBuckets(0.001, 2, 15),
32+
StabilityLevel: metrics.ALPHA,
33+
},
34+
[]string{"code"},
35+
)
36+
)
37+
38+
func recordMetrics(start time.Time, ns string, err error) {
39+
code := "500"
40+
if err == nil {
41+
code = "200"
42+
} else if se, ok := err.(*apierrors.StatusError); ok && se.Status().Code != 0 {
43+
code = strconv.Itoa(int(se.Status().Code))
44+
}
45+
syncLatency.WithLabelValues(code).Observe(time.Since(start).Seconds())
46+
syncCounter.WithLabelValues(code).Inc()
47+
}
48+
49+
var once sync.Once
50+
51+
func registerMetrics() {
52+
once.Do(func() {
53+
legacyregistry.MustRegister(syncCounter)
54+
legacyregistry.MustRegister(syncLatency)
55+
})
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package servicecacertpublisher
2+
3+
import (
4+
"errors"
5+
"strings"
6+
"testing"
7+
"time"
8+
9+
corev1 "k8s.io/api/core/v1"
10+
apierrors "k8s.io/apimachinery/pkg/api/errors"
11+
"k8s.io/component-base/metrics/legacyregistry"
12+
"k8s.io/component-base/metrics/testutil"
13+
)
14+
15+
func TestSyncCounter(t *testing.T) {
16+
testCases := []struct {
17+
desc string
18+
err error
19+
metrics []string
20+
want string
21+
}{
22+
{
23+
desc: "nil error",
24+
err: nil,
25+
metrics: []string{
26+
"service_ca_cert_publisher_sync_total",
27+
},
28+
want: `
29+
# HELP service_ca_cert_publisher_sync_total [ALPHA] Number of namespace syncs happened in service ca cert publisher.
30+
# TYPE service_ca_cert_publisher_sync_total counter
31+
service_ca_cert_publisher_sync_total{code="200"} 1
32+
`,
33+
},
34+
{
35+
desc: "kube api error",
36+
err: apierrors.NewNotFound(corev1.Resource("configmap"), "test-configmap"),
37+
metrics: []string{
38+
"service_ca_cert_publisher_sync_total",
39+
},
40+
want: `
41+
# HELP service_ca_cert_publisher_sync_total [ALPHA] Number of namespace syncs happened in service ca cert publisher.
42+
# TYPE service_ca_cert_publisher_sync_total counter
43+
service_ca_cert_publisher_sync_total{code="404"} 1
44+
`,
45+
},
46+
{
47+
desc: "kube api error without code",
48+
err: &apierrors.StatusError{},
49+
metrics: []string{
50+
"service_ca_cert_publisher_sync_total",
51+
},
52+
want: `
53+
# HELP service_ca_cert_publisher_sync_total [ALPHA] Number of namespace syncs happened in service ca cert publisher.
54+
# TYPE service_ca_cert_publisher_sync_total counter
55+
service_ca_cert_publisher_sync_total{code="500"} 1
56+
`,
57+
},
58+
{
59+
desc: "general error",
60+
err: errors.New("test"),
61+
metrics: []string{
62+
"service_ca_cert_publisher_sync_total",
63+
},
64+
want: `
65+
# HELP service_ca_cert_publisher_sync_total [ALPHA] Number of namespace syncs happened in service ca cert publisher.
66+
# TYPE service_ca_cert_publisher_sync_total counter
67+
service_ca_cert_publisher_sync_total{code="500"} 1
68+
`,
69+
},
70+
}
71+
72+
for _, tc := range testCases {
73+
t.Run(tc.desc, func(t *testing.T) {
74+
recordMetrics(time.Now(), "test-ns", tc.err)
75+
defer syncCounter.Reset()
76+
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tc.want), tc.metrics...); err != nil {
77+
t.Fatal(err)
78+
}
79+
})
80+
}
81+
}

0 commit comments

Comments
 (0)
Please sign in to comment.