Integrando Best Practices en CICD Tools usando Hadolint y Kubelinter

Integrando Best Practices en CICD Tools usando Hadolint y Kubelinter

GITLAB-CI | GITHUB-ACTIONS |AWS CODEPIPELINE | JENKINS

Debería considerar integrar Linter con su herramienta de CI para obtener informes instantáneos a medida que se confirman los cambios de Dockerfile. Esto acelera la revisión del código al brindarles a los desarrolladores una visibilidad inmediata de los problemas. También puede usar la herramienta localmente mientras trabaja a través de extensiones de editor compatibles con la comunidad, lo que proporciona un ciclo de comentarios aún más corto.

Pueden revisar mis post anteriores

KubeLinter: detecta errores de configuración y vulnerabilidades en los archivos YAML y Charts de Helm de Kubernetes. https://hashnode.com/post/clk0famta00020ajpgpyx5gd1

Una forma rápida de detectar malas prácticas en un Dockerfile con Hadolint https://hashnode.com/post/cli6q351t000109mjb5bd2goi

CI/CD Patterns and Practices - CD Foundation

Repositorio de template de integración CICD: https://github.com/roxsross/cicd-linter

Integración con Github-Actions

Pueden revisar la documentacion de Github Actions https://docs.github.com/es/actions

Primero deben agregar el pipeline en la siguiente ruta

.github/workflows/linter.yml

Lo ideal que se ejecute en todos los branches y features

name: LINTER
on:
  push:
    branches: [ * ]
  workflow_dispatch:

jobs:
  hadolint:
    name: Linter dockerfile ⚙️
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Install hadolint
      run: docker run --rm -i hadolint/hadolint < Dockerfile

  kubelinter:
    name: Linter kubernetes ⚙️
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      actions: read
      contents: read
    steps:
    - uses: actions/checkout@v3
    - name: Scan repo with kube-linter Actions
      uses: stackrox/kube-linter-action@v1.0.4
      with:
        directory: cicd-linter
        format: sarif
        output-file: kube-linter.sarif
    - name: Scan repo with kube-linter Docker
      run: |
       export REPO_NAME=${{ github.event.repository.name }}
       docker run -v $(pwd):/dir stackrox/kube-linter lint --format json /dir/$REPO_NAME > kube-linter.json
    - uses: actions/upload-artifact@v3
      name: upload kubelinter report
      with:
        name: kubelinter
        path: kube-linter.json

Si existe vulnerabilidades, corta el pipeline, en caso de querer avanzar en caso de saber que existe la vulnerabilidad pueden agregar

continue-on-error: true

Y si quieres guardar los resultados en formato sarif para revisarlo en el modulo de seguridad de Github puedes agregar *este ultimo el repo debe ser público.

    - name: Upload kubelinter scan results to GitHub tab
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: 'kube-linter.sarif'

Integración con Gitlab

Se debe crear un archivo .gitlab-ci.yml, pueden seguir la documentación de Gitlab https://docs.gitlab.com/

stages:
  - linter
variables:
  DOCKER_HOST: tcp://localhost:2375
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""

services:
  - docker:20.10.19-dind

docker-lint:
  stage: linter
  image: hadolint/hadolint:latest-debian
  script:
    - | 
      hadolint --ignore DL3018 --ignore DL3019 Dockerfile

kube-linter:
  stage: linter
  image: alpine:latest
  script:
    - | 
      apk add --no-cache curl unzip
      curl -LO --silent https://github.com/stackrox/kube-linter/releases/download/v0.6.4/kube-linter-linux.tar.gz
      tar -xzf kube-linter-linux.tar.gz ; chmod +x ./kube-linter
      ./kube-linter version 
      ./kube-linter lint $CI_PROJECT_NAME

Si no cuenta con las buenas practicas pero quieres que aparezca como warning en vez de cortar el pipeline puede agregar en los jobs

allow_failure: true

Integración con CodePipeline y CodeBuild

Primero armemos nuestro pipeline con CodePipeline

https://docs.aws.amazon.com/es_es/codepipeline/latest/userguide/concepts.html

la primera etapa es del source en este caso uso github, pero podrian usar codecommit, luego creamos una segunda etapa con nuestros linters

Documentación CodeBuild: https://docs.aws.amazon.com/codebuild/latest/userguide/welcome.html

Cree este archivo, asígnele un nombre buildspec.ymly luego guárdelo en el directorio raíz (nivel superior).

Para las dos herramientas uso: buildspec-hadolint.yml y buildspec-kubelinter.yml

Hadolint

version: 0.2

phases:
  install:
    commands:
      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 &
      - timeout 15 sh -c "until docker info; do echo .; sleep 1; done"
  build:
    commands:
      - echo "Build started on $(date)"
      - echo "Scanning with Hadolint..."        
      - result=`docker run --rm -i -v ${PWD}/hadolint.yml:/.hadolint.yaml hadolint/hadolint hadolint -f json - < ${PWD}/Dockerfile`

  post_build:
    commands:
      - echo "Lint Results:"
      - echo $result | jq . >result-hadolint.json
      - bash -c "if [ /"$CODEBUILD_BUILD_SUCCEEDING/" == /"0/" ]; then exit 1; fi"
      - echo Build completed on `date`
artifacts:
  files: result-hadolint.json

Kube-Linter

version: 0.2

phases:
  install:
    commands:
      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 &
      - timeout 15 sh -c "until docker info; do echo .; sleep 1; done"
  build:
    commands:
      - echo "Build started on $(date)"
      - echo "Scanning with Kubelinter..."   
      - export REPO_NAME=${git_url/\.git/''}
      - echo $REPO_NAME
      - docker run --rm -v $(pwd):/dir stackrox/kube-linter lint --format json /dir/$REPO_NAME > result-kube-linter.json || EXITCODE=$?

  post_build:
    commands:
      - bash -c "if [ /"$CODEBUILD_BUILD_SUCCEEDING/" == /"0/" ]; then exit 1; fi"
      - echo Build completed on `date`

artifacts:
  files: result-kube-linter.json

Integración con Jenkins

Documentación: https://www.jenkins.io/

Crean un Jenkinsfile en el Directorio del repositorio

pipeline {
    agent any
        environment {
        GITHUB_REPO_NAME = env.GIT_URL.replaceFirst(/^.*\/([^\/]+?).git$/, '$1')
    }
    stages {
        stage('Check Linters') {
            parallel {
                stage('Linter Hadolint') {
                    steps {
                        sh 'docker run --rm -i hadolint/hadolint < Dockerfile'      
                    }

                }
                stage('Linter Kube-linter') {
                    steps {
                        sh '''
                        echo $GITHUB_REPO_NAME
                        docker run --rm -v $(pwd):/dir stackrox/kube-linter lint --format json /dir/$GITHUB_REPO_NAME > kube-linter.json
                        stash includes: 'kube-linter.json', name: 'kube-linter.json'
                        '''
                    }
                }
            }
        }
    }
}

Pero si requieres Saltear el Error debes usar

catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
}

Elegir una plataforma de CI/CD que le brinde la flexibilidad necesaria para configurar su proceso según sus necesidades, sin dejar de ser fácil de gestionar, le ayudará a forjar un proceso de publicación fiable y mejorar la calidad de su software.

Como recomendación integrar notificaciónes para que el equipo revise y pueda solventar, son controles necesarios para lograr una aplicación productiva saludable.

Nos vemos!