Pages

Showing posts with label ci. Show all posts
Showing posts with label ci. Show all posts

Monday, 13 December 2021

Docker best practices

 General guidelines and recommendations

Run as a non-root user

Running containers as a non-root user substantially decreases the risk that container -> host privilege escalation could occur. 

Recommends to run our components as a normal user preferably with UID, GID >10000 

Use a static UID, GID

Eventually some point in time there would require volume sharing between containers, which will lead to manipulating file permissions. For eg: read herethis, and this.

It is best that you use a single static UID/GID for all of your containers that never change. We suggest 10000:10000 such that "$ chown 10000:10000 files" always works for containers following these best practices. 


Use the binary as the ENTRYPOINT

Try to use the main binary as your ENTRYPOINT, and use CMD to pass only arguments. It allows people to ergonomically pass arguments to your binary without having to guess its name.

And also this way helps to write k8s YAMLs without having to know about its name and args.


Create ephemeral containers

The image defined by your Dockerfile should generate containers that are as ephemeral as possible. By “ephemeral”, we mean that the container can be stopped and destroyed, then rebuilt and replaced with an absolute minimum set up and configuration. Also adding unwanted dependencies or packages will increase the image size. For eg: if we have an image with a binary as the ENTRYPOINT, try to avoid other dependencies that are not needed to run binary. Also, we should use a distro less base image or use "FROM scratch". The same we could achieve also by making use of multi-stage builds.

Metadata labels

It is a Dockerfile best practice to include metadata labels when building your image. 

Labels will help in image management, like including the application version, a link to the website, how to contact the maintainer, and more.

You can take a look at the predefined annotations from the OCI image spec .


Locally scan images during development

Image scanning is another way of detecting potential problems before running your containers. 

It is a security best practice to apply the “shift left security” paradigm by directly scanning your images, as soon as they are built, in your CI pipelines before pushing them to the registry.

This also includes the developer's computer. 


Sign images and verify signatures

It is one of the Dockerfile best practices to use docker content trust, Docker notary, Harbor notary, or similar tools to digitally sign your images and then verify them on runtime.

Tag mutability

In the container world, tags are a volatile reference to a concrete image version at a specific point in time.

Tags can change unexpectedly, and at any moment. See this “Attack of the mutant tags”.

Suggested to use format like this: docker pull kindest/node:v1.19.1@sha256:98cf5288864662e37115e362b23e4369c8c4a408f99cbc06e58ac30ddc721600

Misconfigurations

  • Exposing insecure ports, like the ssh port 22 that shouldn’t be open on containers.
  • Including private files accidentally via a bad “COPY” or “ADD” command.
  • Including (leaking) secrets or credentials instead of injecting them via environment variables or mounts.
  • Envs or mounts may be encrypted in K8s YAMLs, but decrypting them and exporting them as plain texts at runtime, exposes the secrets. Decryption shall be done within the code, and decrypted values shall not be exposed as ENVs or mounts.

Exclude with .dockerignore


Tools and utilities

Below lists some of the tools and utilities available that can be used in the lifecycle of a container. Also, lists below are some findings after trying out some of the available open-source tools.

docker-bench-security

(https://github.com/docker/docker-bench-security)

The Docker Bench for Security is a script that checks for dozens of common best-practices around deploying Docker containers in production. The tests are all automated and are based on the CIS Docker Benchmark v1.3.1.

Quick run: 

$git clone https://github.com/docker/docker-bench-security.git

$cd docker-bench-security/

$./docker-bench-security.sh 

This script will scan all the images available in the docker host.


Pros:

It's easy to set up and use.

Cons:

Hope it had a nice report and some structured output like in JSON format.






docker-scan

The docker CLI has an option,"scan" (which uses "snyk" tool as the provider) to scan for vulnerabilities in the image.

Linux installation steps here.

Pros:

Detailed reports

Easy to set up and use


Cons:

Require docker hub/snyk login


hadolint Dockerfile Linter

https://github.com/hadolint/hadolint

This is a Dockerfile linter, validate inline bash, written in Haskell.

quick run: $ docker run --rm -i ghcr.io/hadolint/hadolint < Dockerfile


Pros:

Easy to use.

Docker image available.

Scans for inline bash scripts.


Cons:

--





docker-lock

https://github.com/safe-waters/docker-lock


clair

Clair is an application for parsing image contents and reporting vulnerabilities affecting the contents. This is done via static analysis and not at runtime.

https://quay.github.io/clair/howto/getting_started.html

https://github.com/quay/clair


Pros:

Open-source, widely adopted, and active project

Well documented


Cons:

Not yet fully adopted CIS benchmark

Yet-to-try


dockle

https://github.com/goodwithtech/dockle

Container Image Linter for Security, Helping build the Best-Practice Docker Image.


quick run eg: 

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock  goodwithtech/dockle:v0.4.2 <your-image-url>


Pros:

Single binary, easy to set up and use

docker image available

Open source, active


Cons:

--





openscap by RedHat

https://www.open-scap.org/resources/documentation/security-compliance-of-rhel7-docker-containers/

https://www.open-scap.org/


notary

https://github.com/notaryproject/notary

Notary is a project that allows anyone to have trust over arbitrary collections of data.


syft

https://github.com/anchore/syft

SBOM generator from docker images.


threatmapper

https://github.com/deepfence/ThreatMapper

Identify vulnerabilities in running containers, images, hosts, and repositories

FAQs

Refs


https://techbeacon.com/enterprise-it/container-security-what-you-need-know-about-nist-standards
https://www.nist.gov/publications/application-container-security-guide

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

https://github.com/hexops/dockerfile

https://docs.docker.com/get-started/09_image_best/

https://sysdig.com/blog/dockerfile-best-practices/

https://github.com/docker/docker-bench-security

https://12factor.net/processes

https://geekflare.com/container-security-scanners/


Saturday, 4 December 2021

Declarative Jenkinsfile

Some snippets:

steps:

------

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'echo "Hello World"'
                sh '''
                    echo "Multiline shell steps"
                    ls –lah
                '''
            }
        }
    }
}

timeouts:

----------

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                timeout(time: 3, unit: 'MINUTES') {
                    retry(5) {
                        powershell '.\flakey-deploy.ps1'
                    }
                }
            }
        }
    }
}

stages:

-------
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building'
            }
        }
        stage('Test') {
            steps {
                echo 'Testing'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying'
            }
        }
    }
}

when

-----
pipeline {
    agent any
        stages {
            stage('Build') {
                when {
                    expression {
                        "foo" == "bar"
                    }
                }
                steps {
                    echo 'Building'
                }
            }
        stage('Test') {
            when {
                environment name: 'JOB_NAME', value: 'foo'
            }
            steps {
                echo 'Testing'
            }
        }
        stage('Deploy') {
            when {
                branch 'master'
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

when allOf:

----------
pipeline {
    agent any
    stages {
        stage('Build') {
            when {
                allOf {
                    not { branch 'master' }
                    environment name: 'JOB_NAME', value: 'Foo'
                }
            }
            steps {
                echo 'Building'
            }
        }
    }
}


parallel stages:

------------------
pipeline {
    agent any
    stages {
        stage('Browser Tests') {
            parallel {
                stage('Chrome') {
                    steps {
                        echo "Chrome Tests"
                    }
                }
                stage('Firefox') {
                    steps {
                        echo "Firefox Tests"
                    }
                }
            }
        }
    }
}

Docker

--------
pipeline {
    agent {
        docker {
            label 'docker'
            image 'maven:3.5.0-jdk-8'
        }
    }
}

One of the advantages of using containers is creating an immutable environment that defines only the tools required in a consistent manner.
Rather than creating one large image with every tool needed by the Pipeline, it is possible to use different containers in each stage and
reuse the workspace, keeping all of your files in one place.

pipeline {
    agent {
        node { label 'my-docker' }
    }
    stages {
        stage("Build") {
            agent {
                docker {
                reuseNode true
                image 'maven:3.5.0-jdk-8'
                }
            }
            steps {
                sh 'mvn install'
            }
        }
    }
}


Envs:

-----
pipeline {
    agent any
    environment {
        DISABLE_AUTH = 'true'
        DB_ENGINE        = 'sqlite'
    }
    stages {
        stage('Build') {
            steps {
                sh 'printenv’
            }
        }
    }
}

Credentials envs:

------------------
environment {
    AWS_ACCESS = credentials('AWS_ KEY')
    AWS_SECRET = credentials('AWS_SECRET')
}

post-actions:

------------
pipeline {
    agent any
    stages {
        stage('No-op') {
            steps {
                sh 'ls'
            }
        }
    }
    post {
        always {
            echo 'I have finished'
            deleteDir() // clean up workspace
        }
        success {
            echo 'I succeeded!'
        }
        unstable {
            echo 'I am unstable :/'
        }
        failure {
            echo 'I failed :('
        }
        changed {
            echo 'Things are different...'
        }
    }
}

Notify post actions:

-----------------
post {
    failure {
        mail to: 'team@example.com',
            subject: 'Failed Pipeline',
            body: "Something is wrong"
    }
}

slack:

------
post {
    success {
        slackSend channel:'#ops-room',
            color: 'good',
            message: 'Completed successfully.'
    }
}