In this article, I’ll walk you through a complete real-time DevOps automation workflow:
✔ Build a Docker image from a Python application
✔ Scan the image using Trivy (HIGH+CRITICAL severity)
✔ Save scan report to /home/ubuntu/trivy-report.txt
✔ If scan passes → tag & push image to Docker Hub
✔ If scan fails → block push
✔ Entire workflow automated using OpenTofu (null_resource + local-exec)
This is a real-time DevOps automation task, similar to what you would implement in CI pipelines — but fully executed using OpenTofu on a server.
🗂 Project Structure
pythonapp/
└── tofu
├── Dockerfile
├── app
│ ├── app.py
│ └── requirements.txt
├── main.tf
├── outputs.tf
├── scripts
│ └── build_scan_push.sh
├── terraform.tfstate
├── terraform.tfstate.backup
└── variables.tf
Pre-req:
Install the Docker
# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <
Install Trivy
sudo apt-get install wget gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
🐍 Step 1 — Minimal Python Application
app/app.py
from flask import Flask
app = Flask(__name__)
@app.route("https://dev.to/")
def home():
return "Hello from Secure Python App!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
app/requirements.txt
Flask==2.2.5
🐳 Step 2 — Dockerfile for Python Application
Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ .
EXPOSE 5000
CMD ["python", "app.py"]
🔍 Step 3 — Trivy + Build + Scan + Push Script
scripts/build_scan_push.sh
#!/bin/bash
IMAGE_NAME=$1
IMAGE_TAG=$2
DOCKER_USER=$3
DOCKER_PASS=$4
REPORT_PATH="/home/ubuntu/trivy-report.txt"
echo "=== Building Docker image ==="
docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" .
echo "=== Running Trivy scan ==="
trivy image --exit-code 1 --severity HIGH,CRITICAL "${IMAGE_NAME}:${IMAGE_TAG}" > "$REPORT_PATH" 2>&1
SCAN_STATUS=$?
echo "=== Scan report stored at $REPORT_PATH ==="
if [ $SCAN_STATUS -ne 0 ]; then
echo "❌ Trivy scan failed — image NOT pushed!"
exit 1
fi
echo "=== Logging in to Docker Hub ==="
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
echo "=== Tagging image ==="
docker tag "${IMAGE_NAME}:${IMAGE_TAG}" "${DOCKER_USER}/${IMAGE_NAME}:${IMAGE_TAG}"
echo "=== Pushing image ==="
docker push "${DOCKER_USER}/${IMAGE_NAME}:${IMAGE_TAG}"
echo "✔ Scan passed — image pushed successfully!"
Make script executable:
chmod +x scripts/build_scan_push.sh
🌱 Step 4 — OpenTofu Variables
variables.tf
variable "image_name" {
type = string
}
variable "image_tag" {
type = string
}
variable "docker_username" {
type = string
}
variable "docker_password" {
type = string
sensitive = true
}
🔧 Step 5 — Main OpenTofu Configuration
main.tf
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0"
}
}
}
resource "null_resource" "build_scan_push" {
provisioner "local-exec" {
command = <
📤 Step 6 — Outputs
outputs.tf
output "docker_image" {
value = "${var.image_name}:${var.image_tag}"
}
🧪 Step 7 — Run OpenTofu
cd pythonapp/tofu/
tofu init
tofu fmt
tofu validate
tofu plan
tofu apply
Uploaded to Docker Hub:
latchudevops/python-secure-app:v1
🛡 Why This Workflow Is Production-Ready
| Step | Purpose |
| ------------------- | ----------------------------------- |
| Docker Build | Standard packaging of application |
| Trivy Scan | Security scanning (HIGH + CRITICAL) |
| Fail-Fast Push | Prevent vulnerable images |
| OpenTofu Automation | IaC-driven repeatable workflow |
| Sensitive Variables | Credentials kept securely |
🌟 Thanks for reading! If this post added value, a like ❤️, follow, or share would encourage me to keep creating more content.
— Latchu | Senior DevOps & Cloud Engineer
☁️ AWS | GCP | ☸️ Kubernetes | 🔐 Security | ⚡ Automation
📌 Sharing hands-on guides, best practices & real-world cloud solutions



