pipelines to sync, build and scan containers that are vendored or built for GeoNet
- sync to vendor images
- build container images
- run security scans again each destination image in configuration
- separate implementation from the data
- implementation can be swapped out underneath, if need be and maintain the function
The repo is mostly concerned with base images or images used in build processes.
list of vendored base images
Image | Description |
---|---|
ghcr.io/geonet/base-images/alpine | standard Alpine base image |
ghcr.io/geonet/base-images/datadog/agent | datadog agent |
ghcr.io/geonet/base-images/debian | standard Debian slim image |
ghcr.io/geonet/base-images/git | Alpine with git installed |
ghcr.io/geonet/base-images/git-ssh | Alpine with git and ssh installed |
ghcr.io/geonet/base-images/go | a minimal image for building Go applications |
ghcr.io/geonet/base-images/govc | golang client for vsphere |
ghcr.io/geonet/base-images/hadolint/hadolint | a Dockerfile linter |
ghcr.io/geonet/base-images/hashicorp/terraform | Terraform image |
ghcr.io/geonet/base-images/hashicorp/tfc-agent | Terraform cloud agent image |
ghcr.io/geonet/base-images/mkdocs_plus | a custom build image for docs |
ghcr.io/geonet/base-images/mkdocs | a build of mkdocs material for docs |
ghcr.io/geonet/base-images/nginx | minimal nginx image |
ghcr.io/geonet/base-images/nginx-rtmp | alpine base image with nginx and rtmp |
ghcr.io/geonet/base-images/node | Alpine based node image |
ghcr.io/geonet/base-images/python | Alpine and Debian base Python images |
ghcr.io/geonet/base-images/python-arcgis | Alpine Python image with arcgis installed (includes Rust as a dependency) |
ghcr.io/geonet/base-images/siderolabs-conform | conform policy for pull request commits |
ghcr.io/geonet/base-images/static | scratch with timezone and ca-certificate data pre-installed. Great for Go apps |
ghcr.io/geonet/base-images/texlive | a latex image |
ghcr.io/geonet/base-images/ubi8 | Red Hat Universal Base Image 8 |
ghcr.io/geonet/base-images/ubi8-minimal | Red Hat Universal Base Image 8 minimal |
ghcr.io/geonet/base-images/almalinux | Almalinux 8 for testing RHEL apps |
ghcr.io/geonet/base-images/centos | Centos 7 and stream variants available as tags eg :centos7 :stream8 |
ghcr.io/geonet/base-images/chart-centos7 | Centos 7 base image updated to add extract packages needed for the chart app |
ghcr.io/geonet/base-images/curl | A minimal image only containing curl |
ghcr.io/geonet/base-images/zaproxy/zaproxy | An image to run OWASP's Zed Attack Proxy security web scanner |
ghcr.io/geonet/base-images/alpine-xslt | Alpine with libxslt for XML parsing |
ghcr.io/geonet/base-images/alpine-ffmpeg | Alpine with ffmpeg for video streaming and processing |
ghcr.io/geonet/base-images/alpine-gdal | Alpine with gdal for raster and vector geospatial data formats |
ghcr.io/geonet/base-images/fedora | fedora for build tasks |
ghcr.io/geonet/base-images/fedora-coreos | fedora coreos for edge devices |
ghcr.io/geonet/base-images/alpine-iputils | includes tools like ping |
ghcr.io/geonet/base-images/shellcheck | shellcheck bash scripts |
ghcr.io/geonet/base-images/rpmbuild-almalinux8 | image for building RPMs with, based on AlmaLinux |
ghcr.io/geonet/base-images/rpmbuild-centos7 | image for building RPMs with, based on CentOS 7 |
ghcr.io/geonet/base-images/rpmbuild-centos-stream8 | image for building RPMs with, based on CentOS Stream 8 |
ghcr.io/geonet/base-images/rpmbuild-centos-stream9 | image for building RPMs with, based on CentOS Stream 9 |
ghcr.io/geonet/base-images/rpmbuild-fedora | image for building RPMs with, based on fedora38 |
ghcr.io/geonet/base-images/yq | yq for GitHub actions |
ghcr.io/geonet/base-images/binfmt | Cross-platform emulator collection distributed with Docker images |
862640294325.dkr.ecr.ap-southeast-2.amazonaws.com/datadog-agent | datadog agent for use in ECS |
ghcr.io/geonet/base-images/prometheus | Prometheus time series database |
ghcr.io/geonet/base-images/snmp-exporter | Prometheus snmp exporter |
ghcr.io/geonet/base-images/blackbox-exporter | Prometheus blackbox exporter |
ghcr.io/geonet/base-images/grafana/grafana-oss | Grafana image for building and displaying dashboards |
for tags, check config.yaml.
- declarative image sync management, given source and destination
- declarative apko build management
- with Melange (Alpine APK building) integration
- generated SBOMs
- container image signing
- automatic security scanning for each image synced and built
- multiple build modes
- apko
- apko + melange
- docker (fallback)
- automatic trigger of builds, sync and scan every week
the structure of the repo is as follows:
config.yaml
: define configuration about runtimeimages/NAME/{images.yaml|Dockerfile,*}
: images to build configurations.github/workflows/{sync,scan,build}.yml
: lifecycle actions
Images are synced by specifying source repositories in sync-ghcr.yml for github and sync-ecr.yml for ecs/ecr
check skopeo documentation for more details https://github.com/containers/skopeo/blob/main/docs/skopeo-sync.1.md
quay.io:
tls-verify: true
images:
fedora/fedora-coreos:
- stable
on pull requests skopeo sync
runs with --dry-run
full sync runs when merged to main
Images for building are specified with the source being an apko formatted YAML file and an image destination
build:
- source: ./images/acoolthing/image.yaml
destination: ghcr.io/somecoolorg/images/acoolthing:latest
with ./images/acoolthing/image.yaml
being something like this
contents:
repositories:
- https://dl-cdn.alpinelinux.org/alpine/v3.17/main
- https://dl-cdn.alpinelinux.org/alpine/v3.17/community
packages:
- alpine-base
- busybox
- ca-certificates-bundle
entrypoint:
command: /bin/sh -c
archs:
- x86_64
- aarch64
Specify a source, destination and as many melangeConfigs
build:
- source: ./images/coolthing/image.yaml
destination: ghcr.io/somecoolorg/images/coolthing:latest
melangeConfigs:
- ./images/coolthing/pkg-hello.yaml
with each melange config being a path to the package to build.
An entry in the apko YAML must be set contents.repositories[last index]
to @local /github/workspace/packages
, then packages can be installed with NAME@local
; like this apko configuration
contents:
repositories:
- https://dl-cdn.alpinelinux.org/alpine/v3.17/main
- https://dl-cdn.alpinelinux.org/alpine/v3.17/community
- '@local /github/workspace/packages'
packages:
- alpine-base
- busybox
- ca-certificates-bundle
- hello@local
entrypoint:
command: /bin/sh -c
archs:
- x86_64
Only use this if you have to. It is better to build with apko.
Images can be built with Docker like this
build:
- source: ./images/oldschool/Dockerfile
destination: ghcr.io/somecoolorg/images/oldschool:latest
note that the context of the build runs in the folder which the source is in.
IMAGE_REF refers to an image reference in the format of either
- ghcr.io/somecoolorg/images/hello:latest (just a tag)
- ghcr.io/somecoolorg/images/hello@sha256:a61743b19423a01827ba68a1ec81a09d04f84bc69848303905ecbc73824fb88b (just a digest)
- ghcr.io/somecoolorg/images/hello:latest@sha256:a61743b19423a01827ba68a1ec81a09d04f84bc69848303905ecbc73824fb88b (a tag and a digest)
the digest can be obtained through
crane digest IMAGE_REF
to use it, it can be included when an image ref is formatted like the examples above in What is an image ref?.
determine the digest of the image, for example given the image is ghcr.io/somecoolorg/images/hello:latest
crane digest ghcr.io/somecoolorg/images/hello:latest
the digest might be sha256:a61743b19423a01827ba68a1ec81a09d04f84bc69848303905ecbc73824fb88b
.
add a new sync image to the sync key like
- source: ghcr.io/somecoolorg/images/hello@sha256:a61743b19423a01827ba68a1ec81a09d04f84bc69848303905ecbc73824fb88b
destination: ghcr.io/somecoolorg/images/hello:some-cool-tag
Images are signed using cosign
with keyless, this means that
- signatures depend on the build or key infrastructure
- there's no worry of key rotation
Images are able to be verified through
cosign verify \
--certificate-identity-regexp 'https://github.com/GeoNet/base-images/.github/workflows/(sync|build).yml@refs/heads/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
IMAGE_REF
please note: the certificate identity field will vary between
- https://github.com/GeoNet/base-images/.github/workflows/sync.yml@refs/heads/main
- https://github.com/GeoNet/base-images/.github/workflows/build.yml@refs/heads/main
produces a nice and readible tree of signatures, attestations and SBOMs related to the IMAGE_REF
cosign tree IMAGE_REF
verify the attestation (raw base64 encoded JSON)
cosign verify-attestation \
--certificate-identity-regexp 'https://github.com/GeoNet/base-images/.github/workflows/(sync|build).yml@refs/heads/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
IMAGE_REF
since SBOMs are the predicate of a signed attestation instead of just uploaded, it requires an extra layer to retrieve their content
cosign verify-attestation IMAGE_REF --certificate-identity-regexp 'https://github.com/GeoNet/base-images/.github/workflows/(sync|build).yml@refs/heads/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com | jq -r .payload | base64 -d | jq -r .predicate.Data
using sigs.k8s.io/bom, the SBOM attestation can be visualised
π cosign verify-attestation IMAGE_REF --certificate-identity-regexp 'https://github.com/GeoNet/base-images/.github/workflows/(sync|build).yml@refs/heads/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com | jq -r .payload | base64 -d | jq -r .predicate.Data | bom document outline -
Verification for ghcr.io/GeoNet/base-images/hello:latest --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The signatures were verified against the specified public key
&{Version:SPDX-2.3 DataLicense:CC0-1.0 ID:SPDXRef-DOCUMENT Name:sbom-sha256:e1097a462313187e2a61ba229179efafa8e62bd6166dc94698c9dcffdff05c9c Namespace:https://spdx.org/spdxdocs/apko/ Creator:{Person: Organization:Chainguard, Inc Tool:[apko (v0.7.3-45-g39b16b5)]} Created:1970-01-01 00:00:00 +0000 UTC LicenseListVersion:3.16 Packages:map[SPDXRef-Package-sha256-63bd196f274790f29c3956c9df4a8525aacec14c1c2ecb684cf7462c53f0471f:0xc000314000] Files:map[] ExternalDocRefs:[]}
PACKAGE: <nil>
_
___ _ __ __| |_ __
/ __| '_ \ / _` \ \/ /
\__ \ |_) | (_| |> <
|___/ .__/ \__,_/_/\_\
|_|
π SPDX Document sbom-sha256:e1097a462313187e2a61ba229179efafa8e62bd6166dc94698c9dcffdff05c9c
β
β π¦ DESCRIBES 1 Packages
β
β sha256:63bd196f274790f29c3956c9df4a8525aacec14c1c2ecb684cf7462c53f0471f
β β π 2 Relationships
β β CONTAINS PACKAGE sha256:e1097a462313187e2a61ba229179efafa8e62bd6166dc94698c9dcffdff05c9c@unknown
β β β π 4 Relationships
β β β CONTAINS PACKAGE [email protected]
β β β CONTAINS PACKAGE ca-certificates-bundle@20220614-r4
β β β CONTAINS PACKAGE [email protected]
β β β CONTAINS PACKAGE [email protected]
β β β β π 3 Relationships
β β β β CONTAINS FILE /usr/bin/hello (/usr/bin/hello)
β β β β CONTAINS FILE /usr/share/info/hello.info (/usr/share/info/hello.info)
β β β β CONTAINS FILE /usr/share/man/man1/hello.1 (/usr/share/man/man1/hello.1)
β β β
β β
β β GENERATED_FROM PACKAGE github.com/GeoNet/base-images@6d8476f50ccdd7864eb0d46b2036f44516a55336
β
β π DESCRIBES 0 Files
Name | Description | Links | Related/Alternatives |
---|---|---|---|
crane | an officially supported cli container registry tool from Google | https://github.com/google/go-containerregistry/tree/main/cmd/crane | skopeo |
yq | a cli YAML parser | https://github.com/mikefarah/yq | jq |
cosign | a cli container image artifact signing utility by Sigstore (Linux Foundation) | https://github.com/sigstore/cosign | ... |
melange | a cli Alpine APK package declarative builder supported by Chainguard | https://github.com/chainguard-dev/melange | ... |
apko | a cli tool for declaratively building Alpine based container images | https://github.com/chainguard-dev/apko | ko (https://ko.build - Linux Foundation) |
docker | a container ecosystem, primarily for development | https://docker.io | podman |
trivy | a container image scanner | https://github.com/aquasecurity/trivy | clair |
syft | a cli tool to generate sboms based on container images and filesystems | https://github.com/anchore/syft |
semi-related topics
- require signed container images for use in production
- use distroless container images as base images
- don't ship package managers into production
- https://github.com/chainguard-images
- run containers as non-root users
- limit workload privilege
- https://github.com/chainguard-dev/apko/blob/main/docs/apko_file.md#accounts-top-level-element
- set
pod.spec.containers.securityContext.runAsUser
; https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod docker run --user 10000 ...
https://docs.docker.com/engine/reference/commandline/run- https://docs.aws.amazon.com/config/latest/developerguide/ecs-task-definition-nonroot-user.html
- use a static tag with digest instead of latest
- ensure that you are using the version of the image that you expect
- don't use e.g:
alpine:latest
, instead use an immutable image reference likealpine:3.17.3@sha256:b6ca290b6b4cdcca5b3db3ffa338ee0285c11744b4a6abaa9627746ee3291d8d
to ensure an expected version is always used - version full digests can be manually resolved for consumption using
crane digest alpine:3.17.3
(for example) - when using systems like Knative, these digests are automatically resolved
- deploy containers with a read-only root filesystem
- https://docs.aws.amazon.com/config/latest/developerguide/ecs-containers-readonly-access.html
docker run --read-only ...
; https://docs.docker.com/engine/reference/commandline/run- set
pod.spec.containers.securityContext.readOnlyRootFilesystem
totrue
; https://kubernetes.io/docs/tasks/configure-pod-container/security-context
- build Go apps with ko