Why Secure CI/CD Matters

A CI/CD pipeline should do more than build and deploy code. For production systems, it should catch broken tests, poor code quality, vulnerable dependencies, insecure container images, and accidental configuration mistakes before they reach users.

The goal is simple: every change should pass through repeatable quality and security gates before it is trusted.

Pipeline Flow

Checkout Test Analyze Build Scan Push Clean

Recommended Repository Secrets

Store credentials in GitHub repository secrets instead of hard-coding them in workflow files. At minimum, configure these values:

  • SONAR_TOKEN for SonarQube authentication.
  • SONAR_HOST_URL for the SonarQube server endpoint.
  • REGISTRY_USERNAME for container registry login.
  • REGISTRY_PASSWORD for container registry authentication.

Example GitHub Actions Workflow

name: secure-microservice-pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  IMAGE_NAME: ghcr.io/your-org/your-service

jobs:
  build-test-scan:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v4

      - name: Set up Java
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "17"

      - name: Run tests
        run: ./mvnw test

      - name: SonarQube analysis
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        run: |
          ./mvnw sonar:sonar \
            -Dsonar.host.url=$SONAR_HOST_URL \
            -Dsonar.token=$SONAR_TOKEN

      - name: Log in to registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ secrets.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Build image
        run: docker build -t $IMAGE_NAME:${{ github.sha }} .

      - name: Scan image with Trivy
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ env.IMAGE_NAME }}:${{ github.sha }}
          severity: CRITICAL,HIGH
          exit-code: "1"

      - name: Push image
        if: github.ref == 'refs/heads/main'
        run: docker push $IMAGE_NAME:${{ github.sha }}

Security Gates to Add

The pipeline above gives you a strong baseline, but production teams should continue improving it. Common additions include:

  • Secret scanning before builds start.
  • Dependency review for pull requests.
  • SBOM generation for release artifacts.
  • Container image signing with provenance metadata.
  • Policy checks for Kubernetes manifests and Terraform code.
  • Promotion workflows between dev, staging, and production.

Practical Release Tagging

Use immutable tags for traceability. A Git commit SHA is useful because it maps a container image directly back to the exact source revision that produced it.

docker build -t ghcr.io/your-org/your-service:${GITHUB_SHA} .
docker push ghcr.io/your-org/your-service:${GITHUB_SHA}

Registry Cleanup

Container registries can become expensive and noisy if old tags are never removed. A mature setup should define retention rules, keep recent production releases, and remove stale development images.

Final Thought

Secure CI/CD is not a single tool. It is a delivery habit. Tests, scans, code review, secrets management, and release traceability work together to reduce risk while keeping engineering teams fast.