Skip to content

Commit b99e4f0

Browse files
marunatiratree
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 8c15efd commit b99e4f0

File tree

13 files changed

+604
-3
lines changed

13 files changed

+604
-3
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"k8s.io/controller-manager/controller"
2727
"k8s.io/klog/v2"
2828
"k8s.io/kubernetes/cmd/kube-controller-manager/names"
29+
"k8s.io/kubernetes/openshift-kube-controller-manager/servicecacertpublisher"
2930
"k8s.io/kubernetes/pkg/controller/certificates/approver"
3031
"k8s.io/kubernetes/pkg/controller/certificates/cleaner"
3132
"k8s.io/kubernetes/pkg/controller/certificates/rootcacertpublisher"
@@ -224,3 +225,24 @@ func startRootCACertificatePublisherController(ctx context.Context, controllerCo
224225
go sac.Run(ctx, 1)
225226
return nil, true, nil
226227
}
228+
229+
func newServiceCACertPublisher() *ControllerDescriptor {
230+
return &ControllerDescriptor{
231+
name: names.ServiceCACertificatePublisherController,
232+
aliases: []string{"service-ca-cert-publisher"},
233+
initFunc: startServiceCACertPublisher,
234+
}
235+
}
236+
237+
func startServiceCACertPublisher(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
238+
sac, err := servicecacertpublisher.NewPublisher(
239+
controllerContext.InformerFactory.Core().V1().ConfigMaps(),
240+
controllerContext.InformerFactory.Core().V1().Namespaces(),
241+
controllerContext.ClientBuilder.ClientOrDie("service-ca-cert-publisher"),
242+
)
243+
if err != nil {
244+
return nil, true, fmt.Errorf("error creating service CA certificate publisher: %v", err)
245+
}
246+
go sac.Run(1, ctx.Done())
247+
return nil, true, nil
248+
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ controller, and serviceaccounts controller.`,
145145
return err
146146
}
147147
cliflag.PrintFlags(cmd.Flags())
148-
148+
149149
if err := SetUpPreferredHostForOpenShift(s); err != nil {
150150
fmt.Fprintf(os.Stderr, "%v\n", err)
151151
os.Exit(1)
@@ -529,9 +529,7 @@ func ControllersDisabledByDefault() []string {
529529
controllersDisabledByDefault = append(controllersDisabledByDefault, name)
530530
}
531531
}
532-
533532
sort.Strings(controllersDisabledByDefault)
534-
535533
return controllersDisabledByDefault
536534
}
537535

@@ -615,6 +613,7 @@ func NewControllerDescriptors() map[string]*ControllerDescriptor {
615613
register(newPersistentVolumeProtectionControllerDescriptor())
616614
register(newTTLAfterFinishedControllerDescriptor())
617615
register(newRootCACertificatePublisherControllerDescriptor())
616+
register(newServiceCACertPublisher())
618617
register(newEphemeralVolumeControllerDescriptor())
619618

620619
// feature gated

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func TestControllerNamesDeclaration(t *testing.T) {
8888
names.PersistentVolumeProtectionController,
8989
names.TTLAfterFinishedController,
9090
names.RootCACertificatePublisherController,
91+
names.ServiceCACertificatePublisherController,
9192
names.EphemeralVolumeController,
9293
names.StorageVersionGarbageCollectorController,
9394
names.ResourceClaimController,

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

Lines changed: 1 addition & 0 deletions
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
EphemeralVolumeController = "ephemeral-volume-controller"
8182
StorageVersionGarbageCollectorController = "storageversion-garbage-collector-controller"
8283
ResourceClaimController = "resourceclaim-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)