Image Repositories
The ImageRepository
API specifies how to scan OCI image repositories. A repository is a
collection of images – e.g., alpine
, as opposed to a specific image, e.g.,
alpine:3.1
. ImagePolicy
objects can then refer to an ImageRepository
in order to select a
specific image from those scanned.
Specification
The ImageRepository type holds details for scanning a particular image repository.
// ImageRepositorySpec defines the parameters for scanning an image
// repository, e.g., `fluxcd/flux`.
type ImageRepositorySpec struct {
// Image is the name of the image repository
// +required
Image string `json:"image,omitempty"`
// Interval is the length of time to wait between
// scans of the image repository.
// +required
Interval metav1.Duration `json:"interval,omitempty"`
// Timeout for image scanning.
// Defaults to 'Interval' duration.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// SecretRef can be given the name of a secret containing
// credentials to use for the image registry. The secret should be
// created with `kubectl create secret docker-registry`, or the
// equivalent.
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
// CertSecretRef can be given the name of a secret containing
// either or both of
//
// - a PEM-encoded client certificate (`certFile`) and private
// key (`keyFile`);
// - a PEM-encoded CA certificate (`caFile`)
//
// and whichever are supplied, will be used for connecting to the
// registry. The client cert and key are useful if you are
// authenticating with a certificate; the CA cert is useful if
// you are using a self-signed server certificate.
// +optional
CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"`
// ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
// the image pull if the service account has attached pull secrets.
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
// This flag tells the controller to suspend subsequent image scans.
// It does not apply to already started scans. Defaults to false.
// +optional
Suspend bool `json:"suspend,omitempty"`
// AccessFrom defines an ACL for allowing cross-namespace references
// to the ImageRepository object based on the caller's namespace labels.
// +optional
AccessFrom *AccessFrom `json:"accessFrom,omitempty"`
// ExclusionList is a list of regex strings used to exclude certain tags
// from being stored in the database.
// +optional
ExclusionList []string `json:"exclusionList,omitempty"`
}
The Suspend
field can be set to true
to stop the controller scanning the image repository
specified; remove the field value or set to false
to resume scanning.
Authentication
The spec.secretRef
names a secret in the same namespace that holds credentials for accessing the image
repository. This secret is expected to be in the same format as for
imagePullSecrets
. The usual way to create such a secret is with
kubectl create secret docker-registry ...
For using image pull secrets attached to a service account, you can specify the account name
with spec.serviceAccountName
.
For a publicly accessible image repository, you will not need to provide a secretRef
.
Automatic Authentication
When running on any of the three major cloud providers and using their container registry to store images, you should be able to rely on the controller retrieving credentials automatically. The controllers must be run with the corresponding flag for each provider.
For
EKS and
ECR,
the flag is --aws-autologin-for-ecr
.
For
GKE and
GCR,
the flag is --gcp-autologin-for-gcr
.
For
AKS and
ACR,
the flag is --azure-autologin-for-acr
.
These flags can be added by including a patch in the kustomization.yaml
overlay file in your flux-system
,
as described in
cloud providers authentication guide. If there is no need for a security boundary on your
cluster around container registries and you are not using Flux with so-called “soft multi-tenancy”, then
you will likely prefer to use the Auto-Login feature for the convenience and improved ease of use.
Alternatively, the advice to use a cron job to refresh a secret token under Other platforms below will also work with ECR, GCR, and ACR environments that require security boundaries and soft multi-tenancy.
Other platforms
If you are running on another platform that links service permissions to service accounts, you will
need to create the secret using tooling for that platform, rather than directly with kubectl create secret
. There is advice specific to some platforms
in the image automation
guide.
TLS Certificates
The certSecretRef
field names a secret with TLS certificate data. This is for two separate
purposes:
- to provide a client certificate and private key, if you use a certificate to authenticate with the image registry; and,
- to provide a CA certificate, if the registry uses a self-signed certificate.
These will often go together, if you are hosting an image registry yourself. All the files in the
secret are expected to be
PEM-encoded. This is an ASCII format for certificates and
keys; openssl
and such tools will typically give you an option of PEM output.
Assuming you have obtained a certificate file and private key and put them in the files client.crt
and client.key
respectively, you can create a secret with kubectl
like this:
SECRET_NAME=tls-certs
kubectl create secret generic $SECRET_NAME \
--from-file=certFile=client.crt \
--from-file=keyFile=client.key
You could also
prepare a secret and encrypt it; the important bit is that the data
keys in the secret are certFile
and keyFile
.
If you have a CA certificate for the client to use, the data key for that is caFile
. Adapting the
previous example, if you have the certificate in the file ca.crt
, and the client certificate and
key as before, the whole command would be:
SECRET_NAME=tls-certs
kubectl create secret generic $SECRET_NAME \
--from-file=certFile=client.crt \
--from-file=keyFile=client.key \
--from-file=caFile=ca.crt
Allow cross-namespace references
To grant access to an ImageRepository
for policies in other namespaces, the owner of the ImageRepository
has to specify a list of label selectors that match the namespaces of the ImagePolicy
objects.
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
name: app1
namespace: apps
spec:
interval: 5m
image: docker.io/org/image
secretRef:
name: regcred
accessFrom:
namespaceSelectors:
- matchLabels:
kubernetes.io/metadata.name: flux-system
Note that the kubernetes.io/metadata.name
is a readonly label added by Kubernetes >= 1.21
automatically on namespaces. If you’re using an older version of Kubernetes, please set labels
on the namespaces where the ImagePolicy
are.
The above definition, allows for ImagePolicy
in the flux-system
namespace
to reference the app1 ImageRepository
e.g.:
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
name: app1
namespace: flux-system
spec:
imageRepositoryRef:
name: app1
namespace: apps
policy:
semver:
range: 1.0.x
To grant access to all namespaces, an empty matchLabels
must be provided:
accessFrom:
namespaceSelectors:
- matchLabels: {}
Exclude Tags
To exclude certain tags, the spec.exclusionList
field can be used to specify a list of regex expressions.
Any tags that match any of the regex expressions, will be excluded from the final tag list.
If spec.exclusionList
is empty, by default the regex "^.*\\.sig$"
is used to exclude all tags ending with
.sig
, since these are
Cosign generated objects and not container images
which can be deployed on a Kubernetes cluster.
Status
// ImageRepositoryStatus defines the observed state of ImageRepository
type ImageRepositoryStatus struct {
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
// ObservedGeneration is the last reconciled generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// CanonicalImageName is the name of the image repository with all the
// implied bits made explicit; e.g., `docker.io/library/alpine`
// rather than `alpine`.
// +optional
CanonicalImageName string `json:"canonicalImageName,omitempty"`
// LastScanResult contains the number of fetched tags.
// +optional
LastScanResult *ScanResult `json:"lastScanResult,omitempty"`
meta.ReconcileRequestStatus `json:",inline"`
}
The CanonicalImageName
field gives the fully expanded image name, filling in any parts left implicit in
the spec. For instance, alpine
expands to docker.io/library/alpine
.
The LastScanResult
field gives a summary of the most recent scan:
type ScanResult struct {
TagCount int `json:"tagCount"`
ScanTime metav1.Time `json:"scanTime,omitempty"`
}
Conditions
There is one condition used: the GitOps toolkit-standard ReadyCondition
. This will be marked as
true when a scan succeeds, and false when a scan fails.
Examples
Fetch metadata for a public image every ten minutes:
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 10m
image: ghcr.io/stefanprodan/podinfo
Fetch metadata for a private image every minute:
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
name: podinfo
namespace: flux-system
spec:
interval: 1m0s
image: docker.io/org/image
secretRef:
name: regcred
For private images, you can create a Kubernetes secret in the same namespace
as the ImageRepository
with kubectl create secret docker-registry
,
and reference it under secretRef
.