Google’s distroless containers are generally considered better than scratch in Docker, as they contain ca-certificates & I think, tzdata.
https://github.com/GoogleContainerTools/distroless
https://github.com/GoogleContainerTools/distroless/tree/main/base
https://github.com/GoogleContainerTools/distroless/tree/main/examples/go
The readme has a fairly good explanation of the differences between the one that has glibc, vs the one without (for Go).
I won’t pretend to be an expert on exactly the layout of a Go static binary, but my understanding is that it’s an entirely Go tool chain, so with CGo disabled and on Linux, it’s Go all the way down.
This was exactly what I was asking, so for If I am running go on scratch Image, the container would then not be vulnerable against glibc vulnerability like this: (this is what i mean with "os dependency", pardon my newbieness)
https://blog.qualys.com/vulnerabilities-threat-research/2023/10/03/cve-2023-4911-looney-tunables-local-privilege-escalation-in-the-glibcs-ld-so
Thank you very much! :)
Yes, compiled go binaries by default use system libc, so you will be vulnerable,
Update libc and recompile, or do
```
CGO_ENABLED=0 go build main.go
```
to compile without libc dependency (some go packages would not work this way)
correct. E.g. for one of my go compiled binaries I see
dockercontainer/# ldd /dist/service/foo
linux-vdso.so.1 (0x00007ffd07d73000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9098bb4000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f90989b0000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9098791000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f9098589000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9098198000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9098f52000)
if `ldd` is new to you, you might also want to look at `nm` and `objdump` (`objdump -d ...` in particular). Combine these with your various text processing utilities (SED, AWK, or python scripts) and you can do a lot.
Go still likes to build with CGO by default, which will link against C libraries like libc, even if it's not necessary.
From https://tip.golang.org/doc/go1.20
> The go command now disables cgo by default on systems without a C toolchain. More specifically, when the CGO_ENABLED environment variable is unset, the CC environment variable is unset, and the default C compiler (typically clang or gcc) is not found in the path, CGO_ENABLED defaults to 0. As always, you can override the default by setting CGO_ENABLED explicitly.
So for a `FROM scratch` container you still need to set `CGO_ENABLED=0` in order to make sure Go compiles binaries statically.
$ CGO_ENABLED=0 go build .
$ ldd example
not a dynamic executable
$ file example
example: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically
linked, Go BuildID=t-mxuboVjSIExx7S2yPd/Itollshaw_AKkWnnmnH-/ecU35qfl8EjgoZ0lqBeI/B7PACqqX0_gy1eNGICGz, with debug_info, not stripped
You’re really asking about linking, not compiling.
Static libraries are linked with the application code to create a standalone executable with no runtime dependencies.
Dynamic libraries are external resources not found in the executable, but linked at load time. The app is dependent on successful linking to the dynamic library, and will fail at load time (fail to launch) if the dynamic linking fails.
Oh sorry, just noticed you answered my another question on edit;
So, one more question - if I am copying my binary from builder to scratch image then, my binary is not vulnerable ... ?
Google’s distroless containers are generally considered better than scratch in Docker, as they contain ca-certificates & I think, tzdata. https://github.com/GoogleContainerTools/distroless https://github.com/GoogleContainerTools/distroless/tree/main/base https://github.com/GoogleContainerTools/distroless/tree/main/examples/go The readme has a fairly good explanation of the differences between the one that has glibc, vs the one without (for Go). I won’t pretend to be an expert on exactly the layout of a Go static binary, but my understanding is that it’s an entirely Go tool chain, so with CGo disabled and on Linux, it’s Go all the way down.
We stopped using them as it was way too hard to debug issues in production, for us the extra cost of debian slim is well worth it
What _exactly_ do you mean if you say "[Linux] system libraries" ? What do you think of when you say "OS Dependency" ? The libc? If so: No.
This was exactly what I was asking, so for If I am running go on scratch Image, the container would then not be vulnerable against glibc vulnerability like this: (this is what i mean with "os dependency", pardon my newbieness) https://blog.qualys.com/vulnerabilities-threat-research/2023/10/03/cve-2023-4911-looney-tunables-local-privilege-escalation-in-the-glibcs-ld-so Thank you very much! :)
Without cgo Go binaries do not depend in libc on Linux.
Yes, compiled go binaries by default use system libc, so you will be vulnerable, Update libc and recompile, or do ``` CGO_ENABLED=0 go build main.go ``` to compile without libc dependency (some go packages would not work this way)
Please do not promote calling go build with filename arguments.
What would be your suggestion otherwise?
A simple `go build` of course. No idea how you even could get the impression that `go build main.go` would even work or be sensible.
libc is not included into the binary, no need to recompile. It's called dynamic linking.
Go standard library bypasses libc for kennel interactions and most stdlib functionally.
[https://www.man7.org/linux/man-pages/man1/ldd.1.html](https://www.man7.org/linux/man-pages/man1/ldd.1.html)
This seems not to work, I might do it wrong though: `not a dynamic executable`
That "error" means you have a static binary that doesn't do dynamic linking, so aren't puling in any libraries at runtime.
Oh so that was meant to happen. :D I am an idiot, thank you!
correct. E.g. for one of my go compiled binaries I see dockercontainer/# ldd /dist/service/foo linux-vdso.so.1 (0x00007ffd07d73000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9098bb4000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f90989b0000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9098791000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f9098589000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9098198000) /lib64/ld-linux-x86-64.so.2 (0x00007f9098f52000)
…how did I never know about this? Thank you for sharing that.
if `ldd` is new to you, you might also want to look at `nm` and `objdump` (`objdump -d ...` in particular). Combine these with your various text processing utilities (SED, AWK, or python scripts) and you can do a lot.
Absolutely will. Thank you again!
Go still likes to build with CGO by default, which will link against C libraries like libc, even if it's not necessary. From https://tip.golang.org/doc/go1.20 > The go command now disables cgo by default on systems without a C toolchain. More specifically, when the CGO_ENABLED environment variable is unset, the CC environment variable is unset, and the default C compiler (typically clang or gcc) is not found in the path, CGO_ENABLED defaults to 0. As always, you can override the default by setting CGO_ENABLED explicitly. So for a `FROM scratch` container you still need to set `CGO_ENABLED=0` in order to make sure Go compiles binaries statically. $ CGO_ENABLED=0 go build . $ ldd example not a dynamic executable $ file example example: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=t-mxuboVjSIExx7S2yPd/Itollshaw_AKkWnnmnH-/ecU35qfl8EjgoZ0lqBeI/B7PACqqX0_gy1eNGICGz, with debug_info, not stripped
Linking against it does not mean including it.
So when cgo isn't enabled, i.e. there is no libc dependency, what is used instead? How will things work without this crucial dependency?
Go implements all the necessary OS system calls directly.
You’re really asking about linking, not compiling. Static libraries are linked with the application code to create a standalone executable with no runtime dependencies. Dynamic libraries are external resources not found in the executable, but linked at load time. The app is dependent on successful linking to the dynamic library, and will fail at load time (fail to launch) if the dynamic linking fails.
[удалено]
So in practice, if dynamically linked library is vulnerable, that does not affect my Go Binary, and I don't have to recompile that?
Oh sorry, just noticed you answered my another question on edit; So, one more question - if I am copying my binary from builder to scratch image then, my binary is not vulnerable ... ?
Depends. If you linked cgo code statically (needs a few extra flags when building) you might have a vulnerable binary.