<p>I want to reject all docker registries except my own one. I'm looking for a some kind of policies for docker registries and their images.</p>

<p>For example my registry name is <code>registry.my.com</code>. I want to make kubernetes pulling/running images only from <code>registry.my.com</code>, so:</p>

<pre><code>image: prometheus:2.6.1
</code></pre>

<p>or any another should be rejected, while:</p>

<pre><code>image: registry.my.com/prometheus:2.6.1
</code></pre>

<p>shouldn't.</p>

<p>Is there a way to do that?</p>

<p><a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/" rel="noreferrer">Admission Controllers</a> is what you are looking for.</p>

<p>Admission controllers intercept operations to validate what should happen before the operation is committed by the api-server.</p>

<p>An example is the <a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook" rel="noreferrer">ImagePolicyWebhook</a>, an admission controller that intercept Image operations to validate if it should be allowed or rejected.</p>

<p>It will make a call to an REST endpoint with a payload like:</p>

<pre><code>{  
  "apiVersion":"imagepolicy.k8s.io/v1alpha1",
  "kind":"ImageReview",
  "spec":{  
    "containers":[  
      {  
        "image":"myrepo/myimage:v1"
      },
      {  
        "image":"myrepo/myimage@sha256:beb6bd6a68f114c1dc2ea4b28db81bdf91de202a9014972bec5e4d9171d90ed"
      }
    ],
    "annotations":[  
      "mycluster.image-policy.k8s.io/ticket-1234": "break-glass"
    ],
    "namespace":"mynamespace"
  }
}
</code></pre>

<p>and the API answer with <strong>Allowed</strong>:</p>

<pre><code>{
  "apiVersion": "imagepolicy.k8s.io/v1alpha1",
  "kind": "ImageReview",
  "status": {
    "allowed": true
  }
}
</code></pre>

<p>or <strong>Rejected</strong>:</p>

<pre><code>{
  "apiVersion": "imagepolicy.k8s.io/v1alpha1",
  "kind": "ImageReview",
  "status": {
    "allowed": false,
    "reason": "image currently blacklisted"
  }
}
</code></pre>

<p>The endpoint could be a Lambda function or a container running in the cluster.</p>

<p>This github repo <a href="https://github.com/flavio/kube-image-bouncer" rel="noreferrer">github.com/flavio/kube-image-bouncer</a> implements a sample using <a href="https://github.com/flavio/kube-image-bouncer/blob/master/handlers/image_policy.go" rel="noreferrer"><strong>ImagePolicyWebhook</strong></a> to reject containers using the tag "Latest". </p>

<p>There is also the option to use the flag <em><code>registry-whitelist</code></em> on startup to a pass a comma separated list of allowed  registries, this will be used by the <a href="https://github.com/flavio/kube-image-bouncer/blob/master/handlers/validating_admission.go" rel="noreferrer"><strong>ValidatingAdmissionWebhook</strong></a> to validate if the registry is whitelisted.</p>

<p>.</p>

<p>The other alternative is the project <a href="https://github.com/open-policy-agent/kubernetes-policy-controller" rel="noreferrer">Open Policy Agent</a>[OPA].</p>

<p>OPA is a flexible engine used to create policies based on rules to match resources and take decisions according to the result of these expressions. It is a mutating and a validating webhook that gets called for matching Kubernetes API server requests by the admission controller mentioned above. In summary, the operation would work similarly as described above, the only difference is that the rules are written as configuration instead of code. The same example above rewritter to use OPA would be similar to this:</p>

<pre><code>package admission

import data.k8s.matches

deny[{
    "id": "container-image-whitelist",  # identifies type of violation
    "resource": {
        "kind": "pods",                 # identifies kind of resource
        "namespace": namespace,         # identifies namespace of resource
        "name": name                    # identifies name of resource
    },
    "resolution": {"message": msg},     # provides human-readable message to display
}] {
    matches[["pods", namespace, name, matched_pod]]
    container = matched_pod.spec.containers[_]
    not re_match("^registry.acmecorp.com/.+$", container.image) # The actual validation
    msg := sprintf("invalid container registry image %q", [container.image])
}
</code></pre>

<p>The above translates to: <em>deny any pod where the container image does not match the following registry <code>registry.acmecorp.com</code></em></p>
