Skip to content

Commit 10951b4

Browse files
marunbertinatto
authored andcommitted
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 18e47bc commit 10951b4

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
@@ -34,6 +34,7 @@ import (
3434
"k8s.io/controller-manager/controller"
3535
"k8s.io/klog/v2"
3636
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
37+
"k8s.io/kubernetes/openshift-kube-controller-manager/servicecacertpublisher"
3738
"k8s.io/kubernetes/pkg/controller/certificates/approver"
3839
"k8s.io/kubernetes/pkg/controller/certificates/cleaner"
3940
ctbpublisher "k8s.io/kubernetes/pkg/controller/certificates/clustertrustbundlepublisher"
@@ -320,3 +321,24 @@ func getKubeAPIServerCAFileContents(controllerContext ControllerContext) ([]byte
320321
return rootCA, nil
321322

322323
}
324+
325+
func newServiceCACertPublisher() *ControllerDescriptor {
326+
return &ControllerDescriptor{
327+
name: names.ServiceCACertificatePublisherController,
328+
aliases: []string{"service-ca-cert-publisher"},
329+
initFunc: startServiceCACertPublisher,
330+
}
331+
}
332+
333+
func startServiceCACertPublisher(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
334+
sac, err := servicecacertpublisher.NewPublisher(
335+
controllerContext.InformerFactory.Core().V1().ConfigMaps(),
336+
controllerContext.InformerFactory.Core().V1().Namespaces(),
337+
controllerContext.ClientBuilder.ClientOrDie("service-ca-cert-publisher"),
338+
)
339+
if err != nil {
340+
return nil, true, fmt.Errorf("error creating service CA certificate publisher: %v", err)
341+
}
342+
go sac.Run(1, ctx.Done())
343+
return nil, true, nil
344+
}

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ controller, and serviceaccounts controller.`,
136136
return err
137137
}
138138
cliflag.PrintFlags(cmd.Flags())
139-
139+
140140
if err := SetUpPreferredHostForOpenShift(s); err != nil {
141141
fmt.Fprintf(os.Stderr, "%v\n", err)
142142
os.Exit(1)
@@ -520,9 +520,7 @@ func ControllersDisabledByDefault() []string {
520520
controllersDisabledByDefault = append(controllersDisabledByDefault, name)
521521
}
522522
}
523-
524523
sort.Strings(controllersDisabledByDefault)
525-
526524
return controllersDisabledByDefault
527525
}
528526

@@ -608,6 +606,7 @@ func NewControllerDescriptors() map[string]*ControllerDescriptor {
608606
register(newTTLAfterFinishedControllerDescriptor())
609607
register(newRootCACertificatePublisherControllerDescriptor())
610608
register(newKubeAPIServerSignerClusterTrustBundledPublisherDescriptor())
609+
register(newServiceCACertPublisher())
611610
register(newEphemeralVolumeControllerDescriptor())
612611

613612
// 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
@@ -78,6 +78,7 @@ const (
7878
PersistentVolumeProtectionController = "persistentvolume-protection-controller"
7979
TTLAfterFinishedController = "ttl-after-finished-controller"
8080
RootCACertificatePublisherController = "root-ca-certificate-publisher-controller"
81+
ServiceCACertificatePublisherController = "service-ca-certificate-publisher-controller"
8182
KubeAPIServerClusterTrustBundlePublisherController = "kube-apiserver-serving-clustertrustbundle-publisher-controller"
8283
EphemeralVolumeController = "ephemeral-volume-controller"
8384
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)