Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circumvent insecure secrets listing #138

4 changes: 4 additions & 0 deletions helm/charts/k8s-image-availability-exporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

This chart bootstraps a [k8s-image-availability-exporter](https://github.com/flant/k8s-image-availability-exporter) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.

> [!WARNING]
> By default, k8s-iae has unconstrained access to **all** secrets in the cluster!

## Prerequisites
- Kubernetes 1.12+
- Helm 2+
Expand Down Expand Up @@ -39,6 +42,7 @@ The following tables list the configurable parameters of the k8s-image-availabil
### General
| Parameter | Description | Default |
| ----- | ----------- | ------ |
| `k8sImageAvailabilityExporter.useSecretsForPrivateRepositories` | Give k8s-iae unconstrained access to all secrets in the cluster. This is necessary if there are images that are referenced from private registries, which are deployed in pods, where the pull secret is not defined in `spec.imagePullSecrets` in plaintext but rather in an external secret. This setting only modifies the RBAC rules. | `true` |
| `k8sImageAvailabilityExporter.image.pullPolicy` | Image pull policy to use for the k8s-image-availability-exporter deployment | `IfNotPresent` |
| `k8sImageAvailabilityExporter.image.repository` | Repository to use for the k8s-image-availability-exporter deployment | `flant/k8s-image-availability-exporter` |
| `k8sImageAvailabilityExporter.image.tag` | Tag to use for the k8s-image-availability-exporter deployment | `v0.1.13` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ kind: ClusterRole
metadata:
name: {{ template "k8s-image-availability-exporter.fullname" . }}
rules:
{{- if .Values.k8sImageAvailabilityExporter.useSecretsForPrivateRepositories }}
- apiGroups:
- ""
resources:
Expand All @@ -12,6 +13,7 @@ rules:
- list
- watch
- get
{{- end }}
- apiGroups:
- ""
resources:
Expand Down
1 change: 1 addition & 0 deletions helm/charts/k8s-image-availability-exporter/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ k8sImageAvailabilityExporter:
pullPolicy: IfNotPresent
replicas: 1
resources: {}
useSecretsForPrivateRepositories: true # Setting this to false will prevent k8s-iae having unconstrained cluster-wide secret access
args:
- --bind-address=:8080

Expand Down
19 changes: 18 additions & 1 deletion pkg/registry_checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/sirupsen/logrus"

k8sapierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
appsv1informers "k8s.io/client-go/informers/apps/v1"
batchv1informers "k8s.io/client-go/informers/batch/v1"
corev1informers "k8s.io/client-go/informers/core/v1"
Expand Down Expand Up @@ -193,7 +195,22 @@ func NewRegistryChecker(
}
rc.controllerIndexers.cronJobIndexer = rc.cronJobsInformer.Informer().GetIndexer()

rc.controllerIndexers.secretIndexer = rc.secretsInformer.Informer().GetIndexer()
namespace := "default"
// Create a context
ctx := context.TODO()
// Attempt to list secrets in the default namespace
_, enumerr := kubeClient.CoreV1().Secrets(namespace).List(ctx, metav1.ListOptions{ResourceVersion: "0"})
if statusError, isStatus := enumerr.(*k8sapierrors.StatusError); isStatus {
if statusError.ErrStatus.Code == 401 {
logrus.Warn("The provided ServiceAccount is not able to list secrets. The check for images in private registries requires 'spec.imagePullSecrets' to be configured correctly.")
} else {
logrus.Error("Error trying to list secrets %v\n", statusError.ErrStatus.Message)
}
} else if err != nil {
panic(err.Error())
} else {
rc.controllerIndexers.secretIndexer = rc.secretsInformer.Informer().GetIndexer()
}

go informerFactory.Start(stopCh)
logrus.Info("Waiting for cache sync")
Expand Down