Skip to content

Commit d701e9a

Browse files
Merge pull request #1878 from anik120/auth-catsrc
Add authentication for private index images
2 parents bf9eeb1 + f2ad0ee commit d701e9a

File tree

7 files changed

+140
-24
lines changed

7 files changed

+140
-24
lines changed

pkg/controller/operators/catalog/operator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1424,7 +1424,7 @@ func toManifest(t *testing.T, obj runtime.Object) string {
14241424
}
14251425

14261426
func pod(s v1alpha1.CatalogSource) *corev1.Pod {
1427-
pod := reconciler.Pod(&s, "registry-server", s.Spec.Image, s.GetLabels(), 5, 10)
1427+
pod := reconciler.Pod(&s, "registry-server", s.Spec.Image, s.GetName(), s.GetLabels(), 5, 10)
14281428
ownerutil.AddOwner(pod, &s, false, false)
14291429
return pod
14301430
}

pkg/controller/registry/reconciler/configmap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func (s *configMapCatalogSourceDecorator) Service() *v1.Service {
9595
}
9696

9797
func (s *configMapCatalogSourceDecorator) Pod(image string) *v1.Pod {
98-
pod := Pod(s.CatalogSource, "configmap-registry-server", image, s.Labels(), 5, 2)
98+
pod := Pod(s.CatalogSource, "configmap-registry-server", image, "", s.Labels(), 5, 2)
9999
pod.Spec.ServiceAccountName = s.GetName() + ConfigMapServerPostfix
100100
pod.Spec.Containers[0].Command = []string{"configmap-server", "-c", s.Spec.ConfigMap, "-n", s.GetNamespace()}
101101
ownerutil.AddOwner(pod, s.CatalogSource, false, false)

pkg/controller/registry/reconciler/configmap_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func objectsForCatalogSource(catsrc *v1alpha1.CatalogSource) []runtime.Object {
204204
if catsrc.Spec.Image != "" {
205205
decorated := grpcCatalogSourceDecorator{catsrc}
206206
objs = clientfake.AddSimpleGeneratedNames(
207-
decorated.Pod(),
207+
decorated.Pod(""),
208208
decorated.Service(),
209209
)
210210
}

pkg/controller/registry/reconciler/grpc.go

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/pkg/errors"
1010
"github.com/sirupsen/logrus"
1111
corev1 "k8s.io/api/core/v1"
12+
v1 "k8s.io/api/core/v1"
13+
k8serror "k8s.io/apimachinery/pkg/api/errors"
1214
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1315
"k8s.io/apimachinery/pkg/labels"
1416
"k8s.io/apimachinery/pkg/util/intstr"
@@ -86,8 +88,34 @@ func (s *grpcCatalogSourceDecorator) Service() *corev1.Service {
8688
return svc
8789
}
8890

89-
func (s *grpcCatalogSourceDecorator) Pod() *corev1.Pod {
90-
pod := Pod(s.CatalogSource, "registry-server", s.Spec.Image, s.Labels(), 5, 10)
91+
func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount {
92+
var secrets []corev1.LocalObjectReference
93+
blockOwnerDeletion := true
94+
isController := true
95+
for _, secretName := range s.CatalogSource.Spec.Secrets {
96+
secrets = append(secrets, corev1.LocalObjectReference{Name: secretName})
97+
}
98+
return &corev1.ServiceAccount{
99+
ObjectMeta: metav1.ObjectMeta{
100+
Name: s.GetName(),
101+
Namespace: s.GetNamespace(),
102+
OwnerReferences: []metav1.OwnerReference{
103+
{
104+
Name: s.GetName(),
105+
Kind: v1alpha1.CatalogSourceKind,
106+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
107+
UID: s.GetUID(),
108+
Controller: &isController,
109+
BlockOwnerDeletion: &blockOwnerDeletion,
110+
},
111+
},
112+
},
113+
ImagePullSecrets: secrets,
114+
}
115+
}
116+
117+
func (s *grpcCatalogSourceDecorator) Pod(saName string) *corev1.Pod {
118+
pod := Pod(s.CatalogSource, "registry-server", s.Spec.Image, saName, s.Labels(), 5, 10)
91119
ownerutil.AddOwner(pod, s.CatalogSource, false, false)
92120
return pod
93121
}
@@ -160,14 +188,18 @@ func (c *GrpcRegistryReconciler) EnsureRegistryServer(catalogSource *v1alpha1.Ca
160188
overwritePod := overwrite || len(c.currentPodsWithCorrectImage(source)) == 0
161189

162190
//TODO: if any of these error out, we should write a status back (possibly set RegistryServiceStatus to nil so they get recreated)
163-
if err := c.ensurePod(source, overwritePod); err != nil {
164-
return errors.Wrapf(err, "error ensuring pod: %s", source.Pod().GetName())
191+
sa, err := c.ensureSA(source)
192+
if err != nil && !k8serror.IsAlreadyExists(err) {
193+
return errors.Wrapf(err, "error ensuring service account: %s", source.GetName())
194+
}
195+
if err := c.ensurePod(source, sa.GetName(), overwritePod); err != nil {
196+
return errors.Wrapf(err, "error ensuring pod: %s", source.Pod(sa.Name).GetName())
165197
}
166-
if err := c.ensureUpdatePod(source); err != nil {
198+
if err := c.ensureUpdatePod(source, sa.Name); err != nil {
167199
if _, ok := err.(UpdateNotReadyErr); ok {
168200
return err
169201
}
170-
return errors.Wrapf(err, "error ensuring updated catalog source pod: %s", source.Pod().GetName())
202+
return errors.Wrapf(err, "error ensuring updated catalog source pod: %s", source.Pod(sa.Name).GetName())
171203
}
172204
if err := c.ensureService(source, overwrite); err != nil {
173205
return errors.Wrapf(err, "error ensuring service: %s", source.Service().GetName())
@@ -186,7 +218,7 @@ func (c *GrpcRegistryReconciler) EnsureRegistryServer(catalogSource *v1alpha1.Ca
186218
return nil
187219
}
188220

189-
func (c *GrpcRegistryReconciler) ensurePod(source grpcCatalogSourceDecorator, overwrite bool) error {
221+
func (c *GrpcRegistryReconciler) ensurePod(source grpcCatalogSourceDecorator, saName string, overwrite bool) error {
190222
// currentLivePods refers to the currently live instances of the catalog source
191223
currentLivePods := c.currentPods(source)
192224
if len(currentLivePods) > 0 {
@@ -199,16 +231,16 @@ func (c *GrpcRegistryReconciler) ensurePod(source grpcCatalogSourceDecorator, ov
199231
}
200232
}
201233
}
202-
_, err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Create(context.TODO(), source.Pod(), metav1.CreateOptions{})
234+
_, err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Create(context.TODO(), source.Pod(saName), metav1.CreateOptions{})
203235
if err != nil {
204-
return errors.Wrapf(err, "error creating new pod: %s", source.Pod().GetGenerateName())
236+
return errors.Wrapf(err, "error creating new pod: %s", source.Pod(saName).GetGenerateName())
205237
}
206238

207239
return nil
208240
}
209241

210242
// ensureUpdatePod checks that for the same catalog source version the same container imageID is running
211-
func (c *GrpcRegistryReconciler) ensureUpdatePod(source grpcCatalogSourceDecorator) error {
243+
func (c *GrpcRegistryReconciler) ensureUpdatePod(source grpcCatalogSourceDecorator, saName string) error {
212244
if !source.Poll() {
213245
return nil
214246
}
@@ -218,7 +250,7 @@ func (c *GrpcRegistryReconciler) ensureUpdatePod(source grpcCatalogSourceDecorat
218250

219251
if source.Update() && len(currentUpdatePods) == 0 {
220252
logrus.WithField("CatalogSource", source.GetName()).Infof("catalog update required at %s", time.Now().String())
221-
pod, err := c.createUpdatePod(source)
253+
pod, err := c.createUpdatePod(source, saName)
222254
if err != nil {
223255
return errors.Wrapf(err, "creating update catalog source pod")
224256
}
@@ -283,6 +315,14 @@ func (c *GrpcRegistryReconciler) ensureService(source grpcCatalogSourceDecorator
283315
return err
284316
}
285317

318+
func (c *GrpcRegistryReconciler) ensureSA(source grpcCatalogSourceDecorator) (*v1.ServiceAccount, error) {
319+
sa := source.ServiceAccount()
320+
if _, err := c.OpClient.CreateServiceAccount(sa); err != nil {
321+
return sa, err
322+
}
323+
return sa, nil
324+
}
325+
286326
// ServiceHashMatch will check the hash info in existing Service to ensure its
287327
// hash info matches the desired Service's hash.
288328
func ServiceHashMatch(existing, new *corev1.Service) bool {
@@ -317,14 +357,14 @@ func HashServiceSpec(spec corev1.ServiceSpec) string {
317357
}
318358

319359
// createUpdatePod is an internal method that creates a pod using the latest catalog source.
320-
func (c *GrpcRegistryReconciler) createUpdatePod(source grpcCatalogSourceDecorator) (*corev1.Pod, error) {
360+
func (c *GrpcRegistryReconciler) createUpdatePod(source grpcCatalogSourceDecorator, saName string) (*corev1.Pod, error) {
321361
// remove label from pod to ensure service does not accidentally route traffic to the pod
322-
p := source.Pod()
362+
p := source.Pod(saName)
323363
p = swapLabels(p, "", source.Name)
324364

325365
pod, err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Create(context.TODO(), p, metav1.CreateOptions{})
326366
if err != nil {
327-
logrus.WithField("pod", source.Pod().GetName()).Warn("couldn't create new catalogsource pod")
367+
logrus.WithField("pod", source.Pod(saName).GetName()).Warn("couldn't create new catalogsource pod")
328368
return nil, err
329369
}
330370

pkg/controller/registry/reconciler/grpc_test.go

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,27 @@ func validGrpcCatalogSource(image, address string) *v1alpha1.CatalogSource {
3333
}
3434
}
3535

36+
func grpcCatalogSourceWithSecret(secretName string) *v1alpha1.CatalogSource {
37+
return &v1alpha1.CatalogSource{
38+
ObjectMeta: metav1.ObjectMeta{
39+
Name: "private-catalog",
40+
Namespace: testNamespace,
41+
UID: types.UID("catalog-uid"),
42+
Labels: map[string]string{"olm.catalogSource": "img-catalog"},
43+
},
44+
Spec: v1alpha1.CatalogSourceSpec{
45+
Image: "private-image",
46+
Address: "",
47+
SourceType: v1alpha1.SourceTypeGrpc,
48+
Secrets: []string{secretName},
49+
},
50+
}
51+
}
52+
3653
func TestGrpcRegistryReconciler(t *testing.T) {
3754
now := func() metav1.Time { return metav1.Date(2018, time.January, 26, 20, 40, 0, 0, time.UTC) }
55+
blockOwnerDeletion := true
56+
isController := true
3857

3958
type cluster struct {
4059
k8sObjs []runtime.Object
@@ -44,8 +63,9 @@ func TestGrpcRegistryReconciler(t *testing.T) {
4463
catsrc *v1alpha1.CatalogSource
4564
}
4665
type out struct {
47-
status *v1alpha1.RegistryServiceStatus
48-
err error
66+
status *v1alpha1.RegistryServiceStatus
67+
cluster cluster
68+
err error
4969
}
5070
tests := []struct {
5171
testName string
@@ -186,6 +206,56 @@ func TestGrpcRegistryReconciler(t *testing.T) {
186206
},
187207
},
188208
},
209+
{
210+
testName: "Grpc/PrivateRegistry/SAHasSecrets",
211+
in: in{
212+
cluster: cluster{
213+
k8sObjs: []runtime.Object{
214+
&corev1.Secret{
215+
ObjectMeta: metav1.ObjectMeta{
216+
Name: "test-secret",
217+
Namespace: testNamespace,
218+
},
219+
},
220+
},
221+
},
222+
catsrc: grpcCatalogSourceWithSecret("test-secret"),
223+
},
224+
out: out{
225+
status: &v1alpha1.RegistryServiceStatus{
226+
CreatedAt: now(),
227+
Protocol: "grpc",
228+
ServiceName: "private-catalog",
229+
ServiceNamespace: testNamespace,
230+
Port: "50051",
231+
},
232+
cluster: cluster{
233+
k8sObjs: []runtime.Object{
234+
&corev1.ServiceAccount{
235+
ObjectMeta: metav1.ObjectMeta{
236+
Name: "private-catalog",
237+
Namespace: testNamespace,
238+
OwnerReferences: []metav1.OwnerReference{
239+
{
240+
Name: "private-catalog",
241+
UID: types.UID("catalog-uid"),
242+
Kind: v1alpha1.CatalogSourceKind,
243+
APIVersion: v1alpha1.CatalogSourceCRDAPIVersion,
244+
BlockOwnerDeletion: &blockOwnerDeletion,
245+
Controller: &isController,
246+
},
247+
},
248+
},
249+
ImagePullSecrets: []corev1.LocalObjectReference{
250+
{
251+
Name: "test-secret",
252+
},
253+
},
254+
},
255+
},
256+
},
257+
},
258+
},
189259
}
190260
for _, tt := range tests {
191261
t.Run(tt.testName, func(t *testing.T) {
@@ -206,12 +276,13 @@ func TestGrpcRegistryReconciler(t *testing.T) {
206276

207277
// Check for resource existence
208278
decorated := grpcCatalogSourceDecorator{tt.in.catsrc}
209-
pod := decorated.Pod()
279+
pod := decorated.Pod(tt.in.catsrc.GetName())
210280
service := decorated.Service()
281+
sa := decorated.ServiceAccount()
211282
listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()}
212283
outPods, podErr := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions)
213284
outService, serviceErr := client.KubernetesInterface().CoreV1().Services(service.GetNamespace()).Get(context.TODO(), service.GetName(), metav1.GetOptions{})
214-
285+
outsa, saerr := client.KubernetesInterface().CoreV1().ServiceAccounts(sa.GetNamespace()).Get(context.TODO(), sa.GetName(), metav1.GetOptions{})
215286
switch rec.(type) {
216287
case *GrpcRegistryReconciler:
217288
// Should be created by a GrpcRegistryReconciler
@@ -223,6 +294,10 @@ func TestGrpcRegistryReconciler(t *testing.T) {
223294
require.Equal(t, pod.Spec, outPod.Spec)
224295
require.NoError(t, serviceErr)
225296
require.Equal(t, service, outService)
297+
require.NoError(t, saerr)
298+
if len(tt.in.catsrc.Spec.Secrets) > 0 {
299+
require.Equal(t, tt.out.cluster.k8sObjs[0], outsa)
300+
}
226301
case *GrpcAddressRegistryReconciler:
227302
// Should not be created by a GrpcAddressRegistryReconciler
228303
require.NoError(t, podErr)

pkg/controller/registry/reconciler/reconciler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient
9191
}
9292
}
9393

94-
func Pod(source *v1alpha1.CatalogSource, name string, image string, labels map[string]string, readinessDelay int32, livenessDelay int32) *v1.Pod {
94+
func Pod(source *v1alpha1.CatalogSource, name string, image string, saName string, labels map[string]string, readinessDelay int32, livenessDelay int32) *v1.Pod {
9595
// Ensure the catalog image is always pulled if the image is not based on a digest, measured by whether an "@" is included.
9696
// See https://github.com/docker/distribution/blob/master/reference/reference.go for more info.
9797
// This means recreating non-digest based catalog pods will result in the latest version of the catalog content being delivered on-cluster.
@@ -148,6 +148,7 @@ func Pod(source *v1alpha1.CatalogSource, name string, image string, labels map[s
148148
NodeSelector: map[string]string{
149149
"kubernetes.io/os": "linux",
150150
},
151+
ServiceAccountName: saName,
151152
},
152153
}
153154
return pod

pkg/controller/registry/reconciler/reconciler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestPodNodeSelector(t *testing.T) {
1919
key := "kubernetes.io/os"
2020
value := "linux"
2121

22-
gotCatSrcPod := Pod(catsrc, "hello", "busybox", map[string]string{}, int32(0), int32(0))
22+
gotCatSrcPod := Pod(catsrc, "hello", "busybox", "", map[string]string{}, int32(0), int32(0))
2323
gotCatSrcPodSelector := gotCatSrcPod.Spec.NodeSelector
2424

2525
if gotCatSrcPodSelector[key] != value {
@@ -67,7 +67,7 @@ func TestPullPolicy(t *testing.T) {
6767
}
6868

6969
for _, tt := range table {
70-
p := Pod(source, "catalog", tt.image, nil, int32(0), int32(0))
70+
p := Pod(source, "catalog", tt.image, "", nil, int32(0), int32(0))
7171
policy := p.Spec.Containers[0].ImagePullPolicy
7272
if policy != tt.policy {
7373
t.Fatalf("expected pull policy %s for image %s", tt.policy, tt.image)

0 commit comments

Comments
 (0)