top of page

Conftest: The path to more efficient and effective Kubernetes automated testing


This TeraTip is to take our DevSecOps pipelines to the next level! We are going to make use of Conftest. What is Conftest?

Conftest is a utility to help you write tests against structured configuration data. For instance, you could write tests for your Kubernetes configurations, Tekton pipeline definitions, Terraform code, Serverless configs or any other structured data.

Conftest relies on the Rego language from Open Policy Agent for writing policies. If you're unsure what exactly a policy is, or unfamiliar with the Rego policy language, the Policy Language documentation provided by the Open Policy Agent documentation site is a great resource to read.

We are going to make a brief demo to configure some rules on a Dockerfile. It's demo time!

1) Get familiar with the Rego language

2) Let's begin writing some rules for our Dockerfile. Execute the following

touch opa-docker-security.rego

Remember, don't forget the file extension, must be .rego

3) With your IDE of choice open the file and add the following rule

package main

# Do Not store secrets in ENV variables

secrets_env = [












deny[msg] {

input[i].Cmd == "env"

val := input[i].Value

contains(lower(val[_]), secrets_env[_])

msg = sprintf("Line %d: Potential secret in ENV key found: %s", [i, val]) }

With this rule, we are checking for potential keys and sensible data within the Dockerfile. The list is secrets_env.

4) If you don't have a Dockerfile ready, then its time to create one.

touch Dockerfile

And write some content into it.

FROM adoptopenjdk/openjdk8:alpine-slim



ARG ${JAR_FILE}=/app.jar

ENV tera-secret="secret"

RUN sudo apt-get upgrade

RUN curl

COPY ${JAR_FILE} /app.jar

ENTRYPOINT ["java","-jar","/app.jar"]

5) With our Dockerfile and our OPA rules defined we can proceed to the scan. Execute the following.

docker run --rm -v $(pwd):/project openpolicyagent/conftest test --policy opa docker-security.rego Dockerfile

If you don't have the image locally it will pull it automatically. Make sure you run this command in the same directory where your Dockerfile lives.

The output shows.


Since our Dockerfile is not using the best practices, let's add some more rules in the next step.

6) Add more OPA rules!

Copy and paste the following on our .rego file

# Do not use 'latest' tag for base imagedeny[msg]

deny[msg] {

input[i].Cmd == "from"

val := split(input[i].Value[0], ":")

contains(lower(val[1]), "latest")

msg = sprintf("Line %d: do not use 'latest' tag for base images", [i])


# Avoid curl bashing

deny[msg] {

input[i].Cmd == "run"

val := concat(" ", input[i].Value)

matches := regex.find_n("(curl|wget)[^|^>]*[|>]", lower(val), -1)

count(matches) > 0

msg = sprintf("Line %d: Avoid curl bashing", [i])


# Do not upgrade your system packages

upgrade_commands = [

"apk upgrade",

"apt-get upgrade",



deny[msg] {

input[i].Cmd == "run"

val := concat(" ", input[i].Value)

contains(val, upgrade_commands[_])

msg = sprintf("Line: %d: Do not upgrade your system packages", [i])


# Do not use ADD if possible

deny[msg] {

input[i].Cmd == "add"

msg = sprintf("Line %d: Use COPY instead of ADD", [i])


# Any user...

any_user {

input[i].Cmd == "user"


deny[msg] {

not any_user

msg = "Do not run as root, use USER instead"


# ... but do not root

forbidden_users = [





deny[msg] {

input[i].Cmd == "user"

val := input[i].Value

contains(lower(val[_]), forbidden_users[_])

msg = sprintf("Line %d: Do not run as root: %s", [i, val])


# Do not sudo

deny[msg] {

input[i].Cmd == "run"

val := concat(" ", input[i].Value)

contains(lower(val), "sudo")

msg = sprintf("Line %d: Do not use 'sudo' command", [i])


7) Alright! now run again the Conftest.

The output shows:


We got some failures! remediate them on the next step.

8) Make your Dockerfile compliant with your established rules! (Try it out without seeing the solution).

New Dockerfile.

FROM adoptopenjdk/openjdk8:alpine-slim



ARG JAR_FILE=target/*.jar

RUN addgroup -S pipeline && adduser -S sec-pipeline -G pipeline

COPY ${JAR_FILE} /home/sec-pipeline/app.jar

USER sec-pipeline

ENTRYPOINT ["java","-jar","/home/k8s-pipeline/app.jar"]

The output.


Awesome! We successfully added OPA rules for our Dockerfile!

Now, our Dockerfiles are going to be more secure and will follow the standards we established.




Tomás Torales

Cloud Engineer


If you want to know more about Kubernetes, we suggest going check Enhance your Kubernetes security by leveraging KubeSec


Entradas recientes
Buscar por tags
  • Twitter Basic Square
bottom of page