diff --git a/.github/workflows/publish-fips.yaml b/.github/workflows/publish-fips.yaml new file mode 100644 index 00000000..f927cfe3 --- /dev/null +++ b/.github/workflows/publish-fips.yaml @@ -0,0 +1,65 @@ +name: Publish agent FIPS + +on: + push: + tags: + - 'v*.*.*' + +env: + GOPATH: /home/runner/go/ + GOPROXY: "https://proxy.golang.org" + +jobs: + publish-agent-fips: + name: Build and push agent FIPS container + runs-on: ubuntu-20.04 + permissions: + contents: 'read' + id-token: 'write' + packages: 'write' + outputs: + version: ${{ steps.meta.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/pluralsh/deployment-operator + docker.io/pluralsh/deployment-operator + tags: | + type=semver,pattern={{version}},suffix=-fips,priority=1000 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker + uses: docker/login-action@v3 + with: + username: mjgpluralsh + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: "." + file: "./dockerfiles/agent/fips.Dockerfile" + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + GO_FIPS_IMAGE_REPO=ghcr.io/pluralsh/go-fips + GO_FIPS_IMAGE_TAG=1.23.2 + diff --git a/.github/workflows/publish-harness-fips.yaml b/.github/workflows/publish-harness-fips.yaml new file mode 100644 index 00000000..2e8f3629 --- /dev/null +++ b/.github/workflows/publish-harness-fips.yaml @@ -0,0 +1,143 @@ +name: Publish Harness FIPS +on: + pull_request: + branches: + - "main" + push: + tags: + - 'v*.*.*' +env: + GOPATH: /home/runner/go/ + GOPROXY: "https://proxy.golang.org" +jobs: + + publish-harness-base: + name: Build and push harness base FIPS container + runs-on: ubuntu-20.04 + permissions: + contents: 'read' + id-token: 'write' + packages: 'write' + outputs: + version: ${{ steps.meta.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + # list of Docker images to use as base name for tags + images: | + ghcr.io/pluralsh/stackrun-harness-base + docker.io/pluralsh/stackrun-harness-base + tags: | + type=semver,pattern={{version}},suffix=-fips,priority=1000 + type=sha,suffix=-fips,priority=800 + type=ref,event=pr,suffix=-fips,priority=600 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker + uses: docker/login-action@v3 + with: + username: mjgpluralsh + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: "." + file: "./dockerfiles/harness/base.fips.Dockerfile" + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + VERSION=${{ steps.meta.outputs.version }} + GO_FIPS_IMAGE_REPO=ghcr.io/pluralsh/go-fips + GO_FIPS_IMAGE_TAG=1.23.2 + + publish-harness-ansible: + name: Build and push harness ansible FIPS container + runs-on: ubuntu-20.04 + needs: [publish-harness-base] + strategy: + matrix: + versions: + - ansible: '7.7.0' + python: '3.11' + tag: '7.7' + - ansible: '8.7.0' + python: '3.11' + tag: '8.7' + - ansible: '9.0.0' + python: '3.12' + tag: '9.0' + - ansible: '10.0.0' + python: '3.12' + tag: '10.0' + permissions: + contents: write + discussions: write + pull-requests: write + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/pluralsh/harness + docker.io/pluralsh/harness + tags: | + type=semver,pattern={{version}},suffix=-ansible-${{ matrix.versions.tag }}-fips,priority=1000 + type=sha,suffix=-ansible-${{ matrix.versions.tag }}-fips,priority=800 + type=ref,event=pr,suffix=-ansible-${{ matrix.versions.tag }}-fips,priority=600 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker + uses: docker/login-action@v3 + with: + username: mjgpluralsh + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: "." + file: "./dockerfiles/harness/ansible.fips.Dockerfile" + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + ANSIBLE_VERSION=${{ matrix.versions.ansible }} + PYTHON_VERSION=${{ matrix.versions.python }} + HARNESS_BASE_IMAGE_REPO=ghcr.io/pluralsh/stackrun-harness-base + HARNESS_BASE_IMAGE_TAG=${{ needs.publish-harness-base.outputs.version }} + GO_FIPS_IMAGE_REPO=ghcr.io/pluralsh/go-fips + GO_FIPS_IMAGE_TAG=1.23.2 diff --git a/Makefile b/Makefile index 83725b69..0121b4cf 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,24 @@ docker-build: ## build image docker-push: ## push image docker push ${IMG} +.PHONY: docker-build-harness-base-fips +docker-build-harness-base-fips: ## build fips base docker harness image + docker build \ + --no-cache \ + --build-arg=VERSION="0.0.0-dev" \ + -t harness-base-fips \ + -f dockerfiles/harness/base.fips.Dockerfile \ + . + +.PHONY: docker-build-harness-ansible-fips +docker-build-harness-ansible-fips: docker-build-harness-base-fips ## build fips ansible docker harness image + docker build \ + --no-cache \ + --build-arg=HARNESS_IMAGE_TAG="latest" \ + -t harness-fips \ + -f dockerfiles/harness/ansible.fips.Dockerfile \ + . + .PHONY: docker-build-harness-base docker-build-harness-base: ## build base docker harness image docker build \ @@ -124,6 +142,13 @@ docker-run-harness: docker-build-harness-terraform docker-build-harness-ansible --console-token=${PLURAL_DEPLOY_TOKEN} \ --stack-run-id=${PLURAL_STACK_RUN_ID} +.PHONY: docker-build-agent-fips +docker-build-agent-fips: ## build docker fips agent image + docker build \ + -t deployment-agent-fips \ + -f dockerfiles/agent/fips.Dockerfile \ + . + velero-crds: @curl -L $(VELERO_CHART_URL) --output velero.tgz @tar zxvf velero.tgz velero/crds diff --git a/dockerfiles/agent/fips.Dockerfile b/dockerfiles/agent/fips.Dockerfile new file mode 100644 index 00000000..81c244c4 --- /dev/null +++ b/dockerfiles/agent/fips.Dockerfile @@ -0,0 +1,45 @@ +ARG UBI_MINIMAL_VERSION="latest" +ARG GO_FIPS_IMAGE_TAG=1.23.2 +ARG GO_FIPS_IMAGE_REPO=ghcr.io/pluralsh/go-fips +ARG GO_FIPS_BASE_IMAGE=$GO_FIPS_IMAGE_REPO:$GO_FIPS_IMAGE_TAG + +FROM ${GO_FIPS_BASE_IMAGE} AS builder + +# Set environment variables for FIPS compliance +ENV OPENSSL_FIPS=1 +ENV FIPS_MODE=true +# Set up Go environment +ENV CGO_ENABLED=1 +ENV CC=gcc + +ARG TARGETARCH + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY /cmd/agent cmd/agent +COPY /pkg pkg/ +COPY /api api/ +COPY /internal internal/ +# Build +RUN GOOS=linux GOARCH=${TARGETARCH} GO111MODULE=on go build -a -o deployment-agent cmd/agent/*.go + +# This the minimal UBI FIPS compliance image +FROM registry.access.redhat.com/ubi8/ubi-minimal:$UBI_MINIMAL_VERSION +WORKDIR /workspace + +RUN microdnf install -y openssl && \ + microdnf clean all + +RUN mkdir /.kube && chown 65532:65532 /.kube + +COPY --from=builder /workspace/deployment-agent . +USER 65532:65532 + +ENTRYPOINT ["/workspace/deployment-agent"] \ No newline at end of file diff --git a/dockerfiles/harness/ansible.fips.Dockerfile b/dockerfiles/harness/ansible.fips.Dockerfile new file mode 100644 index 00000000..77a525a9 --- /dev/null +++ b/dockerfiles/harness/ansible.fips.Dockerfile @@ -0,0 +1,47 @@ +ARG HARNESS_BASE_IMAGE_TAG=latest +ARG HARNESS_BASE_IMAGE_REPO=harness-base-fips +ARG HARNESS_BASE_IMAGE=$HARNESS_BASE_IMAGE_REPO:$HARNESS_BASE_IMAGE_TAG +ARG PYTHON_VERSION=3.12 + + +# Use harness base image +FROM ${HARNESS_BASE_IMAGE} as harness + +# Build Ansible from Python Image +FROM registry.access.redhat.com/ubi8/ubi:latest as final + +# Set environment variables for FIPS compliance +ENV OPENSSL_FIPS=1 +ENV FIPS_MODE=true + +# Copy Harness bin from the Harness Image +COPY --from=harness /harness /usr/local/bin/harness +# Change ownership of the harness binary to UID/GID 65532 +RUN chown -R 65532:65532 /usr/local/bin/harness + +# Install build dependencies, Ansible, and openssh-client +ARG ANSIBLE_VERSION=9.0.0 +ARG PYTHON_VERSION=3.12 + +# Install dependencies for building Python +RUN INSTALL_PKGS="python${PYTHON_VERSION} python${PYTHON_VERSION}-devel python${PYTHON_VERSION}-setuptools python${PYTHON_VERSION}-pip nss_wrapper \ + httpd httpd-devel mod_ssl mod_auth_gssapi mod_ldap \ + mod_session atlas-devel gcc-gfortran libffi-devel libtool-ltdl \ + enchant krb5-devel gcc openssl make" && \ + yum -y module enable httpd:2.4 && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + # Remove redhat-logos-httpd (httpd dependency) to keep image size smaller. + rpm -e --nodeps redhat-logos-httpd && \ + yum -y clean all --enablerepo='*' + +# Install Ansible via Pip. +RUN pip3 install --upgrade pip \ + && pip3 install setuptools-rust +RUN pip3 install --no-cache-dir ansible==${ANSIBLE_VERSION} + +# Switch to the non-root user +USER 65532:65532 +WORKDIR /plural + +ENTRYPOINT ["harness", "--working-dir=/plural"] diff --git a/dockerfiles/harness/base.fips.Dockerfile b/dockerfiles/harness/base.fips.Dockerfile new file mode 100644 index 00000000..28e9b3c5 --- /dev/null +++ b/dockerfiles/harness/base.fips.Dockerfile @@ -0,0 +1,55 @@ +ARG GO_FIPS_IMAGE_TAG=1.23.2 +ARG GO_FIPS_IMAGE_REPO=ghcr.io/pluralsh/go-fips +ARG GO_FIPS_BASE_IMAGE=$GO_FIPS_IMAGE_REPO:$GO_FIPS_IMAGE_TAG + +FROM $GO_FIPS_BASE_IMAGE AS builder + +# Set environment variables for FIPS compliance +ENV OPENSSL_FIPS=1 +ENV FIPS_MODE=true +# Set up Go environment +ENV CGO_ENABLED=1 +ENV CC=gcc + +ARG TARGETARCH +ARG TARGETOS +ARG VERSION + + + +WORKDIR /workspace + +# Retrieve application dependencies. +# This allows the container build to reuse cached dependencies. +# Expecting to copy go.mod and if present go.sum. +COPY go.mod go.mod +COPY go.sum go.sum +RUN go mod download + +COPY cmd/harness ./cmd/harness +COPY pkg ./pkg +COPY internal ./internal +COPY api ./api + + +RUN CGO_ENABLED=1 CC=gcc GOOS=linux GOARCH=${TARGETARCH} GO111MODULE=on go build -a \ + -ldflags="-s -w -X github.com/pluralsh/deployment-operator/pkg/harness/environment.Version=${VERSION}" \ + -o harness \ + cmd/harness/*.go + +FROM registry.access.redhat.com/ubi8/ubi-minimal:latest AS final + +RUN microdnf install -y git openssl && \ + microdnf clean all + +# Switch to the nonroot user +USER 65532:65532 + +# Set up the environment +# 3. copy the harness binary +# 4. copy the terraform binary +COPY --from=builder /workspace/harness /harness + +WORKDIR /plural + +ENTRYPOINT ["/harness", "--working-dir=/plural"]