Skip to content

Commit c8e5071

Browse files
jacobseebertinatto
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 c165757 commit c8e5071

File tree

13 files changed

+602
-3
lines changed

13 files changed

+602
-3
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"k8s.io/controller-manager/controller"
3636
"k8s.io/klog/v2"
3737
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
38+
"k8s.io/kubernetes/openshift-kube-controller-manager/servicecacertpublisher"
3839
"k8s.io/kubernetes/pkg/controller/certificates/approver"
3940
"k8s.io/kubernetes/pkg/controller/certificates/cleaner"
4041
ctbpublisher "k8s.io/kubernetes/pkg/controller/certificates/clustertrustbundlepublisher"
@@ -344,3 +345,24 @@ func getKubeAPIServerCAFileContents(controllerContext ControllerContext) ([]byte
344345
return rootCA, nil
345346

346347
}
348+
349+
func newServiceCACertPublisher() *ControllerDescriptor {
350+
return &ControllerDescriptor{
351+
name: names.ServiceCACertificatePublisherController,
352+
aliases: []string{"service-ca-cert-publisher"},
353+
initFunc: startServiceCACertPublisher,
354+
}
355+
}
356+
357+
func startServiceCACertPublisher(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
358+
sac, err := servicecacertpublisher.NewPublisher(
359+
controllerContext.InformerFactory.Core().V1().ConfigMaps(),
360+
controllerContext.InformerFactory.Core().V1().Namespaces(),
361+
controllerContext.ClientBuilder.ClientOrDie("service-ca-cert-publisher"),
362+
)
363+
if err != nil {
364+
return nil, true, fmt.Errorf("error creating service CA certificate publisher: %v", err)
365+
}
366+
go sac.Run(1, ctx.Done())
367+
return nil, true, nil
368+
}

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

Lines changed: 2 additions & 3 deletions
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)
@@ -523,9 +523,7 @@ func ControllersDisabledByDefault() []string {
523523
controllersDisabledByDefault = append(controllersDisabledByDefault, name)
524524
}
525525
}
526-
527526
sort.Strings(controllersDisabledByDefault)
528-
529527
return controllersDisabledByDefault
530528
}
531529

@@ -611,6 +609,7 @@ func NewControllerDescriptors() map[string]*ControllerDescriptor {
611609
register(newTTLAfterFinishedControllerDescriptor())
612610
register(newRootCACertificatePublisherControllerDescriptor())
613611
register(newKubeAPIServerSignerClusterTrustBundledPublisherDescriptor())
612+
register(newServiceCACertPublisher())
614613
register(newEphemeralVolumeControllerDescriptor())
615614

616615
// feature gated

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ func TestControllerNamesDeclaration(t *testing.T) {
9292
names.TTLAfterFinishedController,
9393
names.RootCACertificatePublisherController,
9494
names.KubeAPIServerClusterTrustBundlePublisherController,
95+
names.ServiceCACertificatePublisherController,
9596
names.EphemeralVolumeController,
9697
names.StorageVersionGarbageCollectorController,
9798
names.ResourceClaimController,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const (
7979
PersistentVolumeProtectionController = "persistentvolume-protection-controller"
8080
TTLAfterFinishedController = "ttl-after-finished-controller"
8181
RootCACertificatePublisherController = "root-ca-certificate-publisher-controller"
82+
ServiceCACertificatePublisherController = "service-ca-certificate-publisher-controller"
8283
KubeAPIServerClusterTrustBundlePublisherController = "kube-apiserver-serving-clustertrustbundle-publisher-controller"
8384
EphemeralVolumeController = "ephemeral-volume-controller"
8485
StorageVersionGarbageCollectorController = "storageversion-garbage-collector-controller"
Lines changed: 56 additions & 0 deletions
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+
}
Lines changed: 81 additions & 0 deletions
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)