diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml index d2370ad..b01270f 100644 --- a/.github/workflows/docker-publish.yaml +++ b/.github/workflows/docker-publish.yaml @@ -6,35 +6,61 @@ on: - '**' tags: - 'v*' - -permissions: - contents: read + pull_request: + branches: + - '**' + types: + - opened + - reopened + - synchronize jobs: build-and-push: runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + outputs: + version_tag: ${{ steps.vars.outputs.version_tag }} steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + # Static binary so the runtime image can be distroless static-debian12. + # -trimpath strips host paths from the binary; -s -w drops debug info. + - name: Build Go binary (static) + env: + CGO_ENABLED: '0' + GOOS: linux + GOARCH: amd64 + run: go build -trimpath -ldflags="-s -w" -o cantcost ./bin/main.go + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - # 1) Configure AWS creds (needed for ECR auth) + # IAM role gh-oidc-build-cantcost is provisioned in AWS account + # 903295530547 and trusts this repo's GitHub OIDC subject. Do not + # rename without updating the role's trust policy. - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: - aws-access-key-id: ${{ secrets.TF_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.TF_AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws:iam::903295530547:role/gh-oidc-build-${{ github.event.repository.name }} aws-region: us-east-1 + role-session-name: gha-${{ github.run_id }} - # 2) Login to Public ECR - name: Login to Amazon ECR Public id: login-ecr-public uses: aws-actions/amazon-ecr-login@v2 with: registry-type: public + mask-password: true - name: Compute image tags id: vars @@ -46,9 +72,11 @@ jobs: if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then TAG_NAME="${GITHUB_REF_NAME}" # e.g. v1.2.3 + echo "version_tag=${TAG_NAME}" >> $GITHUB_OUTPUT echo "tags=${IMAGE}:${TAG_NAME},${IMAGE}:latest" >> $GITHUB_OUTPUT else SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7) + echo "version_tag=sha-${SHORT_SHA}" >> $GITHUB_OUTPUT echo "tags=${IMAGE}:sha-${SHORT_SHA}" >> $GITHUB_OUTPUT fi diff --git a/Dockerfile b/Dockerfile index ff6edbd..4bcb27f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,22 @@ -# Stage 1: Build -FROM golang:1.25-alpine AS builder +# syntax=docker/dockerfile:1.7 + +# Distroless static-debian12: ca-certificates + tzdata only. No glibc, no +# shell, no package manager — minimum possible attack surface. Suitable +# because the binary is built with CGO_ENABLED=0 (fully static). +# +# The :nonroot tag bakes in USER 65532:65532, so we can't be run as root. +# +# Pin by multi-arch index digest. Refresh with: +# docker buildx imagetools inspect gcr.io/distroless/static-debian12:nonroot +FROM gcr.io/distroless/static-debian12:nonroot@sha256:a9329520abc449e3b14d5bc3a6ffae065bdde0f02667fa10880c49b35c109fd1 WORKDIR /app -COPY go.mod go.sum ./ -RUN go mod download +# Binary is built on the host (CGO_ENABLED=0 go build) and copied in. +# nonroot is UID/GID 65532, predefined in the distroless image. +COPY --chown=nonroot:nonroot --chmod=0555 \ + ./cantcost /usr/local/bin/cantcost -COPY . . +USER nonroot:nonroot -RUN go build -o /log-catcher ./bin/main.go - -# Stage 2: Run -FROM alpine:latest - -# You can add ca-certificates if your app needs TLS -RUN apk --no-cache add ca-certificates - -WORKDIR /root/ - -COPY --from=builder /log-catcher . - -EXPOSE 8080 - -CMD ["./log-catcher"] \ No newline at end of file +ENTRYPOINT ["/usr/local/bin/cantcost"]