Go as the ultimate PCI Compliant Language

When I first began working with Docker I had one thought in mind: How do I get my PCI auditor to certify this?

On the surface it seems like a simple issue: A Docker Container is a box with the application inside of it, so the container does not need to be audited, only the underlying host. But what if you get an auditor who sees the docker container as another layer of virtualization that must be audited as well as the underlying host?

So my perspective was to ensure that the Docker containers would all be little PCI complaint boxes that when surveyed on their own, would pass muster. This of course lead me down a very strange course where I installed ClamAV on all my docker images because PCI requires antivirus be installed. If an OS change was required by PCI, then my Docker images got the change as well.

Which leads me to statically-linked Go. The problem with something like Java is that you need to install the JVM. Which is huge and difficult to keep up to date. However, Go apps are distributed as a single binary. The single binary model makes the Go app very easy to deploy on any platform. If the Go app is compiled statically, meaning that all the required libraries have been included in to the application, then you can literally install the binary on any server without concern for install dependencies.

Aside from being able to do tricks like use ImageMagick libs without ImageMagick being installed, it means that in the case of a PCI audit of a Docker container: there could be nothing inside the image other than our Go application.

Docker provides a base Image called scratch which can be used to create other images. scratch contains nothing. The image is completely empty. A blank canvas for you to add your packages to. If we take scratch and combine it with our Go application, then we are able to create an Image that only contains the Go app. Yes you need to perform a code security audit, but the container no longer has any OS redundancies that would neccesitate a PCI-mandated item like a virus scanner.

Creating a container with just the application inside of it also creates one mighty small image. In a world of 500mb - 1gb images, it’s nice to know that an image under 10mb is possible.

Create a statically compiled GO application that does not depend on any system libs

## Do not look for C libs on the system.
## Disable cgo to create a static binary.
export CGO_ENABLED="0"

## Compile for 64-bit Linux
export GOOS="linux"
export GOARCH="amd64"

## -a : Rebuild all packages
##      All imported libs will be rebuilt with CGO disabled.
go build -a -installsuffix bin -o application application.go

Build the Docker Image

  • Use the empty scratch image as the base.
  • Scratch is a completely empty image, which will work well with the staticly compiled go app.
  • In Docker, FROM scratch is a no-op in the Dockerfile, and will not create an extra layer in your image, so the image will be as small as possible.

Create the Dockerfile

FROM   scratch
ADD    application /
CMD    ["/application"]

Build a tagged image

docker build .
categories: golang | devops | pci |