Skip to content

Commit

Permalink
Add authentication for private index images
Browse files Browse the repository at this point in the history
Fixes Issue #1536 #1505
This PR attaches the secrets in the `spec.Secrets` field of the
CatalogSource to the default service account in the CatalogSource's
namespace, to allow for pulling of index images that are backed
by authentication.
  • Loading branch information
anik120 committed Dec 1, 2020
1 parent cd0fdf6 commit 025eee2
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 2 deletions.
21 changes: 21 additions & 0 deletions pkg/controller/registry/reconciler/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ func (c *GrpcRegistryReconciler) EnsureRegistryServer(catalogSource *v1alpha1.Ca
overwritePod := overwrite || len(c.currentPodsWithCorrectImage(source)) == 0

//TODO: if any of these error out, we should write a status back (possibly set RegistryServiceStatus to nil so they get recreated)
if err := c.ensureSecret(source); err != nil {
return errors.Wrap(err, "error ensuring secrets for default service account")
}
if err := c.ensurePod(source, overwritePod); err != nil {
return errors.Wrapf(err, "error ensuring pod: %s", source.Pod().GetName())
}
Expand Down Expand Up @@ -283,6 +286,24 @@ func (c *GrpcRegistryReconciler) ensureService(source grpcCatalogSourceDecorator
return err
}

// ensureSecret attaches any secret passed with the CatalogSource to the default service account of the CatalogSource's namespace
func (c *GrpcRegistryReconciler) ensureSecret(source grpcCatalogSourceDecorator) error {
if len(source.Spec.Secrets) == 0 {
return nil
}
sa, err := c.OpClient.GetServiceAccount(source.GetNamespace(), "default")
if err != nil {
return err
}
for _, secretName := range source.Spec.Secrets {
sa.ImagePullSecrets = append(sa.ImagePullSecrets, corev1.LocalObjectReference{Name: secretName})
}
if _, err := c.OpClient.UpdateServiceAccount(sa); err != nil {
return err
}
return nil
}

// ServiceHashMatch will check the hash info in existing Service to ensure its
// hash info matches the desired Service's hash.
func ServiceHashMatch(existing, new *corev1.Service) bool {
Expand Down
73 changes: 71 additions & 2 deletions pkg/controller/registry/reconciler/grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ func validGrpcCatalogSource(image, address string) *v1alpha1.CatalogSource {
}
}

func grpcCatalogSourceWithSecret(secretName string) *v1alpha1.CatalogSource {
return &v1alpha1.CatalogSource{
ObjectMeta: metav1.ObjectMeta{
Name: "private-catalog",
Namespace: testNamespace,
UID: types.UID("catalog-uid"),
Labels: map[string]string{"olm.catalogSource": "img-catalog"},
},
Spec: v1alpha1.CatalogSourceSpec{
Image: "private-image",
Address: "",
SourceType: v1alpha1.SourceTypeGrpc,
Secrets: []string{secretName},
},
}
}

func TestGrpcRegistryReconciler(t *testing.T) {
now := func() metav1.Time { return metav1.Date(2018, time.January, 26, 20, 40, 0, 0, time.UTC) }

Expand All @@ -44,8 +61,9 @@ func TestGrpcRegistryReconciler(t *testing.T) {
catsrc *v1alpha1.CatalogSource
}
type out struct {
status *v1alpha1.RegistryServiceStatus
err error
status *v1alpha1.RegistryServiceStatus
cluster cluster
err error
}
tests := []struct {
testName string
Expand Down Expand Up @@ -186,6 +204,52 @@ func TestGrpcRegistryReconciler(t *testing.T) {
},
},
},
{
testName: "Grpc/PrivateRegistry/SecretGetsAttachedToDefaultSA",
in: in{
cluster: cluster{
k8sObjs: []runtime.Object{
&corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Namespace: testNamespace,
},
},
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: testNamespace,
},
},
},
},
catsrc: grpcCatalogSourceWithSecret("test-secret"),
},
out: out{
status: &v1alpha1.RegistryServiceStatus{
CreatedAt: now(),
Protocol: "grpc",
ServiceName: "private-catalog",
ServiceNamespace: testNamespace,
Port: "50051",
},
cluster: cluster{
k8sObjs: []runtime.Object{
&corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: "default",
Namespace: testNamespace,
},
ImagePullSecrets: []corev1.LocalObjectReference{
{
Name: "test-secret",
},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.testName, func(t *testing.T) {
Expand Down Expand Up @@ -223,6 +287,11 @@ func TestGrpcRegistryReconciler(t *testing.T) {
require.Equal(t, pod.Spec, outPod.Spec)
require.NoError(t, serviceErr)
require.Equal(t, service, outService)
if len(tt.in.catsrc.Spec.Secrets) > 0 {
sa, err := client.KubernetesInterface().CoreV1().ServiceAccounts(testNamespace).Get(context.TODO(), "default", metav1.GetOptions{})
require.NoError(t, err)
require.Equal(t, tt.out.cluster.k8sObjs[0], sa)
}
case *GrpcAddressRegistryReconciler:
// Should not be created by a GrpcAddressRegistryReconciler
require.NoError(t, podErr)
Expand Down

0 comments on commit 025eee2

Please sign in to comment.