Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 1.0.2
name: k8sdisallowedtags
displayName: Disallow tags
createdAt: "2025-06-26T13:09:27Z"
description: |-
Requires container images to have an image tag different from the ones in the specified list.
https://kubernetes.io/docs/concepts/containers/images/#image-names
digest: 49570f47aaa2367dc7496f0cb73a7f19456ed5f130f0fab6ff73ff24987751a3
license: Apache-2.0
homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/disallowedtags
keywords:
- gatekeeper
- open-policy-agent
- policies
readme: |-
# Disallow tags
Requires container images to have an image tag different from the ones in the specified list.
https://kubernetes.io/docs/concepts/containers/images/#image-names
install: |-
### Usage
```shell
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/disallowedtags/1.0.2/template.yaml
```
provider:
name: Gatekeeper Library
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDisallowedTags
metadata:
name: container-image-must-not-have-latest-tag
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- "default"
parameters:
tags: ["latest"]
exemptImages: ["openpolicyagent/opa-exp:latest", "openpolicyagent/opa-exp2:latest"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-disallowed-ephemeral
spec:
containers:
- name: opa
image: openpolicyagent/opa:0.9.2
args:
- "run"
- "--server"
- "--addr=localhost:8080"
ephemeralContainers:
- name: opa
image: openpolicyagent/opa:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-allowed
spec:
containers:
- name: opa
image: openpolicyagent/opa:0.9.2
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-disallowed-2
spec:
containers:
- name: opa
image: openpolicyagent/opa:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-exempt-allowed
spec:
containers:
- name: opa-exp
image: openpolicyagent/opa-exp:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
- name: opa-init
image: openpolicyagent/init:v1
args:
- "run"
- "--server"
- "--addr=localhost:8080"
- name: opa-exp2
image: openpolicyagent/opa-exp2:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-disallowed
spec:
containers:
- name: opa
image: openpolicyagent/opa
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-disallowed-4
spec:
containers:
- name: opa
image: openpolicyagent:443/opa
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a new line

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-disallowed-3
spec:
containers:
- name: opa
image: openpolicyagent/opa-exp:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
- name: opa-init
image: openpolicyagent/init:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
- name: opa-exp2
image: openpolicyagent/opa-exp2:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
- name: opa-monitor
image: openpolicyagent/monitor:latest
args:
- "run"
- "--server"
- "--addr=localhost:8080"
37 changes: 37 additions & 0 deletions artifacthub/library/general/disallowedtags/1.0.2/suite.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
kind: Suite
apiVersion: test.gatekeeper.sh/v1alpha1
metadata:
name: disallowedtags
tests:
- name: disallowed-tags
template: template.yaml
constraint: samples/container-image-must-not-have-latest-tag/constraint.yaml
cases:
- name: allowed
object: samples/container-image-must-not-have-latest-tag/example_allowed.yaml
assertions:
- violations: no
- name: exempt-images-with-disallowed-tags
object: samples/container-image-must-not-have-latest-tag/example_exempt_image_w_disallowed_tag.yaml
assertions:
- violations: no
- name: no-tag
object: samples/container-image-must-not-have-latest-tag/example_no_tag.yaml
assertions:
- violations: yes
- name: no-tag-with-port
object: samples/container-image-must-not-have-latest-tag/example_no_tag_w_port.yaml
assertions:
- violations: yes
- name: single-disallowed-tag
object: samples/container-image-must-not-have-latest-tag/example_disallowed_tag.yaml
assertions:
- violations: yes
- name: single-disallowed-tag-ephemeral
object: samples/container-image-must-not-have-latest-tag/disallowed_tag_ephemeral.yaml
assertions:
- violations: yes
- name: some-disallow-tags
object: samples/container-image-must-not-have-latest-tag/example_some_disallowed_tags.yaml
assertions:
- violations: yes
90 changes: 90 additions & 0 deletions artifacthub/library/general/disallowedtags/1.0.2/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdisallowedtags
annotations:
metadata.gatekeeper.sh/title: "Disallow tags"
metadata.gatekeeper.sh/version: 1.0.2
description: >-
Requires container images to have an image tag different from the ones in
the specified list.

https://kubernetes.io/docs/concepts/containers/images/#image-names
spec:
crd:
spec:
names:
kind: K8sDisallowedTags
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
properties:
exemptImages:
description: >-
Any container that uses an image that matches an entry in this list will be excluded
from enforcement. Prefix-matching can be signified with `*`. For example: `my-image-*`.
It is recommended that users use the fully-qualified Docker image name (e.g. start with a domain name)
in order to avoid unexpectedly exempting images from an untrusted repository.
type: array
items:
type: string
tags:
type: array
description: Disallowed container image tags.
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdisallowedtags

import data.lib.exempt_container.is_exempt

violation[{"msg": msg}] {
container := input_containers[_]
not is_exempt(container)
tags := [tag_with_prefix | tag := input.parameters.tags[_]; tag_with_prefix := concat(":", ["", tag])]
strings.any_suffix_match(container.image, tags)
msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags])
}

violation[{"msg": msg}] {
container := input_containers[_]
not is_exempt(container)
parts := split(container.image, "/")
not contains(parts[count(parts) - 1], ":")
msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image])
}

input_containers[c] {
c := input.review.object.spec.containers[_]
}
input_containers[c] {
c := input.review.object.spec.initContainers[_]
}
input_containers[c] {
c := input.review.object.spec.ephemeralContainers[_]
}
libs:
- |
package lib.exempt_container

is_exempt(container) {
exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", [])
img := container.image
exemption := exempt_images[_]
_matches_exemption(img, exemption)
}

_matches_exemption(img, exemption) {
not endswith(exemption, "*")
exemption == img
}

_matches_exemption(img, exemption) {
endswith(exemption, "*")
prefix := trim_suffix(exemption, "*")
startswith(img, prefix)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: opa-disallowed-4
spec:
containers:
- name: opa
image: openpolicyagent:443/opa
args:
- "run"
- "--server"
- "--addr=localhost:8080"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a new line

4 changes: 4 additions & 0 deletions library/general/disallowedtags/suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ tests:
object: samples/container-image-must-not-have-latest-tag/example_no_tag.yaml
assertions:
- violations: yes
- name: no-tag-with-port
object: samples/container-image-must-not-have-latest-tag/example_no_tag_w_port.yaml
assertions:
- violations: yes
- name: single-disallowed-tag
object: samples/container-image-must-not-have-latest-tag/example_disallowed_tag.yaml
assertions:
Expand Down
5 changes: 3 additions & 2 deletions library/general/disallowedtags/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
name: k8sdisallowedtags
annotations:
metadata.gatekeeper.sh/title: "Disallow tags"
metadata.gatekeeper.sh/version: 1.0.1
metadata.gatekeeper.sh/version: 1.0.2
description: >-
Requires container images to have an image tag different from the ones in
the specified list.
Expand Down Expand Up @@ -52,7 +52,8 @@ spec:
violation[{"msg": msg}] {
container := input_containers[_]
not is_exempt(container)
not contains(container.image, ":")
parts := split(container.image, "/")
not contains(parts[count(parts) - 1], ":")
msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image])
}

Expand Down
2 changes: 1 addition & 1 deletion src/general/disallowedtags/constraint.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
name: k8sdisallowedtags
annotations:
metadata.gatekeeper.sh/title: "Disallow tags"
metadata.gatekeeper.sh/version: 1.0.1
metadata.gatekeeper.sh/version: 1.0.2
description: >-
Requires container images to have an image tag different from the ones in
the specified list.
Expand Down
3 changes: 2 additions & 1 deletion src/general/disallowedtags/src.rego
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ violation[{"msg": msg}] {
violation[{"msg": msg}] {
container := input_containers[_]
not is_exempt(container)
not contains(container.image, ":")
parts := split(container.image, "/")
not contains(parts[count(parts) - 1], ":")
msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image])
}

Expand Down
13 changes: 12 additions & 1 deletion src/general/disallowedtags/src_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ test_input_denied_container_emtpy {
results := violation with input as inp
count(results) == 1
}
test_input_denied_container_empty_with_port {
inp := { "review": input_review(input_container_denied_empty_with_port), "parameters": {"tags": ["latest", "testing"]}}
results := violation with input as inp
count(results) == 1
}
test_input_denied_container_latest {
inp := { "review": input_review(input_container_denied_latest), "parameters": {"tags": ["latest", "testing"]}}
results := violation with input as inp
Expand Down Expand Up @@ -146,6 +151,12 @@ input_container_denied_empty = [
"image": "nginx",
}]

input_container_denied_empty_with_port = [
{
"name": "nginx",
"image": "nginx:443/nginx",
}]

input_container_denied_latest = [
{
"name": "nginx",
Expand Down Expand Up @@ -175,4 +186,4 @@ input_container_exempt = [
}, {
"name": "exempt",
"image": "exempt:testing",
}]
}]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a new line

Loading