home.social

Search

9 results for “ingo_don”

  1. A few weeks ago, I ran an audit on a backend microservice container running in our staging cluster.The application itself was a compiled Go binary that took up less than 20 MB of disk space. But when I ran docker images, the resulting image weighed in at nearly 1 GB.Even worse, when I attached an interactive terminal into that running container:Bashdocker exec -it payment-service /bin/bash
    I found a full-blown Debian Linux environment sitting inside. Compilers, package managers (apt), network downloaders (curl, wget), and an active root shell were all sitting right next to our core application logic.If an attacker managed to find a remote code execution (RCE) bug in that service, I hadn’t just handed them an app bug—I had handed them an entire Linux workstation inside our VPC.Here is how modern container workflows solve this using two industry patterns: Multi-Stage Builds and Distroless Images.1. Multi-Stage Builds: The Restaurant Kitchen AnalogyThink about eating at a restaurant.In the kitchen, the chef uses heavy knives, cutting boards, vegetable peelers, mixing bowls, and blazing stoves. When the waiter brings your order to the dining table, you get a clean plate with the finished meal.You would never expect the waiter to dump the chopping board, raw vegetable peels, greasy pans, and meat scraps directly onto your table.Yet that is exactly what a single-stage Dockerfile does.+-----------------------------------------------------------+
    | SINGLE STAGE (Messy Kitchen + Food Shipped Together) |
    | Compilers + SDKs + Git + Headers + Source Code + Binary |
    | Image Size: ~900 MB |
    +-----------------------------------------------------------+
    When building an application in Go, Rust, C++, Java, or even Node.js, you need heavy build tools: compilers, package managers, development headers, and build caches. But your production environment only needs the final compiled binary or transpiled assets.The Fix: Multi-Stage SeparationA multi-stage build uses multiple FROM instructions in a single Dockerfile. Each FROM starts a brand-new stage, letting you copy only the artifacts you want from earlier stages.Here is what that looks like in practice:Dockerfile# -------------------------------------------------------------

    STAGE 1: "The Kitchen" (Builder stage with compilers and SDKs)

    -------------------------------------------------------------


    FROM golang:1.23-alpine AS builder

    WORKDIR /build

    Cache dependency downloads


    COPY go.mod go.sum ./
    RUN go mod download

    Copy source and compile down to a standalone binary


    COPY . .
    RUN CGO_ENABLED=0 go build -o /build/payment-api .

    -------------------------------------------------------------

    STAGE 2: "The Dining Table" (Final production runtime)

    -------------------------------------------------------------


    FROM alpine:3.20

    WORKDIR /app

    Copy ONLY the compiled binary from Stage 1


    COPY --from=builder /build/payment-api /app/payment-api

    EXPOSE 8080
    CMD ["/app/payment-api"]
    The Difference:Single-Stage Image: ~900 MB (Go compiler, source code, build caches, git).Multi-Stage Image: ~15 MB (Tiny Alpine OS layer + compiled binary).Why It Matters:During high-traffic autoscaling events, Kubernetes doesn't have to pull 1 GB images across the network to spin up new pods. A 15 MB image pulls in less than a second, saving cloud bandwidth costs and speeding up recovery times.2. Distroless Images: Stripping Down to the ChassisDropping image size to 15 MB with Alpine is a huge step forward, but from a security perspective, Alpine still ships with an interactive shell (/bin/sh) and a package manager (apk).To understand why this is a risk, consider an analogy:A standard family car comes with air conditioning, leather seats, a radio, a trunk, and a glovebox. A Formula 1 race car strips out everything that doesn't make the car go fast: no back seat, no radio, no air conditioning, no trunk.A Distroless image (originally created by Google) takes that Formula 1 approach to containers. It contains only your application and its minimal runtime dependencies (like glibc or SSL root certificates).It explicitly omits:Package managers (apt, apk, yum)System utilities (curl, wget, ls, grep)Interactive shells (/bin/sh, /bin/bash)Standard Base (Ubuntu/Debian): [ Shell + Tools + Package Manager + App ]
    Alpine Base: [ Shell + apk + Minimal OS + App ]
    Distroless Base: [ App + Direct Runtime Libs ONLY ]
    A Real-World Security ScenarioImagine a critical vulnerability (like an RCE or file-upload exploit) is discovered in a patient records microservice.Scenario A: The Container Runs on Standard UbuntuThe attacker exploits the application bug and executes an arbitrary command.They run curl or apt-get install nmap directly inside the container.They download an external botnet or reconnaissance script.They explore the local container filesystem using ls -la and read configs.They use the running container as a jump box to pivot into the rest of your private network.Scenario B: The Container Runs on DistrolessThe attacker exploits the bug and tries to invoke /bin/sh.The operating system responds:Plaintextexec: "/bin/sh": stat /bin/sh: no such file or directory
    The attacker tries calling curl or wget to pull remote tools. Neither exists.The exploit fails because there is no execution environment inside the container to run unauthorized binaries.The Gold Standard: Multi-Stage + DistrolessIn production systems handling sensitive workloads, you can combine both techniques. You build in a full developer SDK environment, but ship on Google's static Distroless image:Dockerfile# Stage 1: Build the code in a full compiler environment
    FROM golang:1.23 AS builder

    WORKDIR /src
    COPY . .
    RUN CGO_ENABLED=0 go build -o /app/server .

    Stage 2: Deploy to Google's Distroless static runtime


    FROM gcr.io/distroless/static-debian12

    Copy the binary from the builder stage


    COPY --from=builder /app/server /server

    Distroless provides a built-in non-root user (UID 65532: nonroot)


    USER nonroot:nonroot

    EXPOSE 8080
    ENTRYPOINT ["/server"]
    What You Get:Tiny footprint: Image sizes drop to the bare minimum required for execution.Non-root by default: Runs under user nonroot, neutralizing container escape techniques that rely on root privileges.No shell attacks: Traditional living-off-the-land techniques (using installed utilities like curl or bash) are impossible.Clean vulnerability scans: Tools like Trivy or Snyk show zero CVEs for unneeded OS packages, because those packages were never installed in the first place.Comparison SummaryConceptWhat It IsProblem It SolvesProduction ImpactMulti-Stage BuildA Dockerfile using multiple FROM stages to separate build tools from runtime artifacts.Bloated image sizes caused by compilers, test suites, and package caches.Cuts storage needs, saves cloud network transfer costs, and speeds up auto-scaling.Distroless ImageA base image containing only the app and direct dependencies—no shell, no package manager.Attackers using internal container shells and OS utilities to pivot into your private network.Eliminates package vulnerabilities and neutralizes shell-based exploit payloads.Wrapping UpBuilding clean containers isn't just about saving a few hundred megabytes of disk space. It fundamentally changes the threat model of your workloads in the cloud.If your production container doesn't need a compiler to run, don't ship one. And if it doesn't need an interactive shell to serve traffic, strip the shell out entirely.Keep the kitchen in the build stage, and bring only the clean plate to production.#devops #docker #go #security #software #coding #development #engineering #inclusive #community
    The Clean Plate Problem: How Multi-Stage Builds and Distroless Images Cut Container Attack Surfaces to Zero

  2. @mechanical0815 Sicher, dass ein Verteilungsproblem ist? Ich hätte eher auf Social Media getippt – also diese Unterhaltungsapps des überwachungskapitalistischen Komplexes? (Freilich kann es auch die Kombination aus beidem und noch allerlei anderem sein.)

    #uberwachungskapitalismus

  3. In my experience a published PGP key for security reports rarely fails on the cryptography. Someone can't find the passphrase, or the key was generated on a laptop that has since left the company, or it's on a USB stick in a drawer in an office nobody goes to any more.

    So I wrote up the version where there's no private key anywhere to rot, or to steal.

    The secret material sits in AWS KMS, which offers no API that would export it, and your process only ever asks it for two operations on data anyone is allowed to see.

    The walkthrough takes about twenty minutes:

    • create two KMS keys (an agreement key can't sign its own binding signature)
    • assemble a publishable OpenPGP certificate in Go
    • play the researcher: gpg imports it and encrypts a report to it
    • read the report back with sigillum

    Three KMS calls do all the secret work: two kms:Sign to build the certificate, one kms:DeriveSharedSecret to open the message. Everything else happens locally.

    It also covers why the creation time is fixed rather than time.Now(), and how gpg falls back to AES-128 without mentioning it if you leave the preferences out.

    One caveat: the Go compiles clean against the pinned versions, but I haven't re-run the KMS round trip itself for this post. The steps are the docs' own, validated when they were written.

    phpboyscout.uk/read-the-report

  4. Excellent animations AND tech content by Phuong Le
    Escape analysis in Go: stack or heap?

    youtu.be/BanG_wLnSfE?si=I-K3M-

  5. Shout out to @gotosocial for being a great project and platform - written in Go!

    I'm selfhosting a instance myself, give me a follow there, I'm posting more non-tech stuff over there:

    @graves

  6. 🚨 EByte ransomware shared on a forum, written in Go

    An actor known as "procurator" has shared EByte, a ransomware tool written in Go that reportedly combines ChaCha20 and ECIES encryption to lock files.

    The ransomware uses selective encryption, encrypting one byte while leaving the next two unencrypted. The post also mentions a management panel and a decryptor for recovering encrypted files.

    The tool's functionality and encryption capabilities have not been independently verified.

    💥 No delays. No guessing. No redactions. Get the intel threat actors see, the moment they post it. darkwebinformer.com/pricing

  7. Stop paying cloud taxes for managed services. Build your own Kubernetes Operator in Go! ⚙️

    Our hands-on SRE guide covers:
    🏗️ Kubebuilder Scaffolding: Custom APIs & Controllers
    💥 TypeMeta SSA Fix: Stop HTTP 409 & missing kind crashes
    🧪 CircleCI envtest: Simulated control plane testing
    🚀 Bare Metal etcd IOPS: Zero latency reconciliation

    🔗 irexta.com/tutorials/kubernete

    #Kubernetes #Golang #CircleCI #DevOps #SRE #BareMetal #iRexta

  8. How big is a tool that does nothing?

    I asked go-tool-base that about a year later than I should have, and the answer was 81 MB.

    The framework blank-imported every chat and forge adapter it knew about, so a tool built on it carried OpenAI's SDK, Anthropic's, Google's auth stack, go-github and the GitLab client whether it talked to any of them or not. Empty the two provider files and the same build drops to 34 MB, so 58% of hello world was SDKs for services it would never call.

    The awkward part is that both files carried a comment, written by me, saying a downstream could opt out and import only what it needed. Not a word of it was true. You can add imports in Go, but you can't subtract one that a dependency has already made.

    The fix moved the registering into each tool's own main, split the gtb CLI into a nested module as the one kitchen-sink binary, and taught the generator to emit only the adapters a tool asks for. That split had a price, and I paid it two days later.

    phpboyscout.uk/eighty-one-mega

Share on Mastodon

Enter the server where you have an account.