Secret Injector

The SecretInjector custom resource sets rules for injecting image pull secrets into service accounts. The SecretInjector is a cluster scoped resource.

The raw custom resource definition for the SecretInjector custom resource can be viewed by running:

kubectl get crd/secretinjectors.secrets.educates.dev -o yaml

Specifying the source secret

To inject the named secrets in any namespace, into all service accounts in the same namespace as the secret, set sourceSecrets.nameSelector.

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials

Note that nothing is done to validate the secret is of the correct type before it is added as an image pull secret in the service account.

Service account names to match

If you only want the secret injected into the default service account set serviceAccounts.nameSelector.

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    serviceAccounts:
      nameSelector:
        matchNames:
        - default

More than one service account name can be specified if required.

Filtering based on resource labels

Labels can instead be used on both the source secret and service accounts using sourceSecrets.labelSelector and serviceAccounts.labelSelector.

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      labelSelector:
        matchLabels:
          image-pull-secret: ""
    serviceAccounts:
      labelSelector:
        matchLabels:
          inject-image-pull-secrets: ""

Limiting set of target namespaces

You can be selective about what namespaces injection is performed. This can be done by specifying the names of the namespaces using targetNamespaces.nameSelector:

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    targetNamespaces:
      nameSelector:
        matchNames:
        - developer-1
        - developer-2

The list of names can be the exact value, or you can also use a shell style glob expression to match a set of names.

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    targetNamespaces:
      nameSelector:
        matchNames:
        - developer-*

Rather than matching namespaces by their name, you can match any labels on a namespace by setting targetNamespaces.labelSelector.matchLabels:

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    targetNamespaces:
      labelSelector:
        matchLabels:
          developer-namespace: ""

Or if more flexible matching of labels is required, you can supply a list of expressions by setting targetNamespaces.labelSelector.matchExpressions.

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    targetNamespaces:
      labelSelector:
        matchExpressions:
        - key: developer-namespace
          operator: In
          values:
          - ""

For an expression the list of operators is In, NotIn, Exists and DoesNotExist. For In and NotIn a non empty list of values must be supplied. The Exists and DoesNotExist only pertain to the existance of the label key.

When targeting a specific namespace and the namespace is deleted, then recreated, the rule will still match the new instance of the namespace if selectors match the new instance of the namespace, even though it may notionally be used for a different purpose and the secret shouldn’t be copied there.

If you need to ensure that secrets should only be injected into service accounts in context of that specific instance of the namespace, and not a future version of the namespace created subsequent to its deletion, you can require the namespace have a specific uid by setting targetNamespaces.uidSelector.

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    targetNamespaces:
      uidSelector:
        matchUIDs:
        - 9b030c48-b773-4ffb-9d8f-7eacf7dbcfbe

The uid should be that set by Kubernetes in the metadata section of the namespace resource.

Kubernetes reserved namespaces

Although it was originally said that where no selectors are specified which target specific namespaces, that all namespaces are targeted, this isn’t actually the case. Instead if no nameSelector is specified, it defaults to the equivalent of:

apiVersion: secrets.educates.dev/v1beta1
kind: SecretInjector
metadata:
  name: registry-credentials
spec:
  rules:
  - sourceSecrets:
      nameSelector:
        matchNames:
        - registry-credentials
    targetNamespaces:
      nameSelector:
        matchNames:
        - !kube-*

That is, neither kube-public, kube-system or other namespaces starting with kube- will be targeted, they being generally reserved by Kubernetes itself. The ! before the names indicates the namespace will be excluded.

If you need to target these namespaces, you will need to list them explicitly using matchNames, which will negate the default. When using labelSelector and you need to exclude certain namespaces even though it may have matching labels, you can list those namespaces in matchNames with the leading ! to have them excluded. When overriding matchNames to list excluded namespaces, you will need to manually include the exclusion for kube-public and kube-system if necessary.

Multiple selectors for reosurces

More than one type of selector can be listed under sourceSecrets, serviceAccounts and targetNamespaces, in which case all selectors must match else nothing will be done in respect of the secret, service account or namespace.

Multiple rules for injecting secrets

The rules property is a list, so rules for more than one secret can be specified in the one custom resource.

Deletion of the target secret

The name of a secret is not removed from the list of image pull secrets in a service account if the secret is removed or rules change meaning it would no longer have been added.