Skip to content

Conversation

eugercek
Copy link

@eugercek eugercek commented Jul 24, 2025

Proposed Changes

This PR migrates the manifests in manifests/ from go‑bindata to Go’s built‑in embed package.

Unlike other externally downloaded assets, the files under manifests/ are already stored as plain‑text in the repository, which makes go:embed the straightforward and more secure choice. go‑bindata is useful when content is dynamically generated or when files are so large that they shouldn’t live in the repo, but the manifests fit neither case. Keeping them as a gzip‑compressed blob, complicates audits, and resembles the hidden‑payload pattern exploited in the XZ Utils backdoor.

Types of Changes

Added manifests/embed.go, which contains the //go:embed directive and two small helper functions that abstract access to the embedded files. If go:embed gains new options in the future or any other reason to add functionality, only the helper functions need to be updated and callers remain unchanged. Abstraction provides a small and simple interface.

Verification

I built from source then run dist/artifacts/k3s serverand checked manifests directory:

Example output
[root] tree /var/lib/rancher/k3s/server/manifests/
/var/lib/rancher/k3s/server/manifests/
├── ccm.yaml
├── coredns.yaml
├── local-storage.yaml
├── metrics-server
│   ├── aggregated-metrics-reader.yaml
│   ├── auth-delegator.yaml
│   ├── auth-reader.yaml
│   ├── metrics-apiservice.yaml
│   ├── metrics-server-deployment.yaml
│   ├── metrics-server-service.yaml
│   └── resource-reader.yaml
├── rolebindings.yaml
├── runtimes.yaml
└── traefik.yaml

1 directory, 13 files

Testing

Not covered.

Linked Issues

Per the contribution guide: "If you’re fixing a small issue, you can simply submit a PR and we will pick it up", I've opened this PR without a separate GitHub issue.

User-Facing Change

NONE

Further Comments

Design decisions:

  • Didn't touch structure of manifests it may complicate things for other projects etc, just ignored embed.go in List method.
  • Used fs.Walkdir, another approach may be fs.Glob code will be simpler but this is more future proof, adding new hierarchies etc are easier.
  • Returned sorted list in List to make api more precise. This package should be very simple and straightforward IMO.

Listed trade-offs of this PR below:

Cons:

  • Introduction of go:embed, k3s uses go-bindata in multiple places.

Pros:

  • Simplifies the codebase: +43 lines of new code, -527 lines of generated code and eliminating a code‑generation step.
  • Easier audit.
  • Fewer components to maintain.
  • Simpler git diff, for example see this recent commit
  • Faster local builds an CI
  • Easier patching for k3s wrappers, tooling around k3s.
  • No big size change, (even reduction ?): built both from master (02c898d) and my branch.
Example sizes
# my branch
[root]# ls -la dist/artifacts/
total 1060880
drwxr-xr-x. 2 root root       151 Jul 24 23:24 .
drwxr-xr-x. 3 root root        23 Jul 22 17:59 ..
-rwxr-xr-x. 1 root root  74539192 Jul 24 23:23 k3s
-rw-------. 1 root root 655377408 Jul 24 23:24 k3s-airgap-images-amd64.tar
-rw-r--r--. 1 root root 197209222 Jul 24 23:27 k3s-airgap-images-amd64.tar.gz
-rw-------. 1 root root 159200014 Jul 24 23:24 k3s-airgap-images-amd64.tar.zst
-rw-r--r--. 1 root root       373 Jul 24 23:27 k3s-images.txt

# master
[root]# ls -la dist/artifacts/
total 1060916
drwxr-xr-x. 2 root root       151 Jul 24 23:35 .
drwxr-xr-x. 3 root root        23 Jul 22 17:59 ..
-rwxr-xr-x. 1 root root  74576056 Jul 24 23:35 k3s
-rw-------. 1 root root 655377408 Jul 24 23:35 k3s-airgap-images-amd64.tar
-rw-r--r--. 1 root root 197209220 Jul 24 23:38 k3s-airgap-images-amd64.tar.gz
-rw-------. 1 root root 159199929 Jul 24 23:35 k3s-airgap-images-amd64.tar.zst
-rw-r--r--. 1 root root       373 Jul 24 23:38 k3s-images.txt

Other changes comes from make format.

Thanks for your time.

Signed-off-by: Emin Umut Gercek <[email protected]>
@eugercek eugercek requested a review from a team as a code owner July 24, 2025 23:48
@eugercek eugercek changed the title Implement embed.go Use embed package for manifests directory Jul 24, 2025
@eugercek eugercek changed the title Use embed package for manifests directory Use embed package for manifests directory to reduce attack surface Jul 24, 2025
@brandond
Copy link
Member

brandond commented Jul 25, 2025

In what way does this modify the "attack surface" of this project? How does the current method of embedding comprise a vulnerability or avenue of attack?

We could be open to switching embedding libraries, but I'd like to see a specific reason to do so. And we would not be open to anything that drops compression, as we are highly sensitive to anything that will increase the size of our release artifact.

Also note that there are two k3s binaries - the self-extracting wrapper, and the actual cli that is extracted out, or used standalone in the docker image. Have you confirmed that the size of both is not impacted?

@eugercek
Copy link
Author

eugercek commented Jul 26, 2025

In what way does this modify the "attack surface" of this project? How does the current method of embedding comprise a vulnerability or avenue of attack?

After using go:embed these "obfuscated" lines will be removed, I believe that this reduces attack surface because it's far more easier to detect any suspicious manifest.

We could be open to switching embedding libraries, but I'd like to see a specific reason to do so. And we would not be open to anything that drops compression, as we are highly sensitive to anything that will increase the size of our release artifact.

I also believe this simplifies maintenance, since there's no additional step to build these manifests, which is easier to develop and debug.

Also note that there are two k3s binaries - the self-extracting wrapper, and the actual cli that is extracted out, or used standalone in the docker image. Have you confirmed that the size of both is not impacted?

Sorry for my lack of k3s building, I did below steps to find binary size changes:

# Finding master size
git clone https://github.com/k3s-io/k3s.git
cd k3s
mkdir -p build/data && make download && make generate
make
ls -la dist/artifacts/ > /tmp/master-size

# Find this PR's branch size
git remote add mine https://github.com/eugercek/k3s.git
git fetch mine
git switch -c embed-manifests mine/embed-manifests
make
ls -la dist/artifacts/  > /tmp/pr-size

echo "Printing size differences"
echo "Master:"
cat /tmp/master-size
echo "PR:"
cat /tmp/pr-size

And it looks like binary size is smaller in this version, below is the size differences. Let me know if this is not proper test. (Re-run the build steps for proper data, and double checking).

  • k3s binary : 74576056-74539192 this pr makes k3s binary 36.864 bytes smaller
  • airgapped images: 655377408-655377408 same size
  • airgapped gzip: 197209260-197209224 36 bytes smaller :D
  • airgapped zstd: 159187880-159186806 1074 bytes smaller

master:

total 1060904
drwxr-xr-x. 2 root root       151 Jul 26 14:49 .
drwxr-xr-x. 3 root root        23 Jul 26 14:44 ..
-rwxr-xr-x. 1 root root  74576056 Jul 26 14:45 k3s
-rw-------. 1 root root 655377408 Jul 26 14:46 k3s-airgap-images-amd64.tar
-rw-r--r--. 1 root root 197209260 Jul 26 14:49 k3s-airgap-images-amd64.tar.gz
-rw-------. 1 root root 159187880 Jul 26 14:46 k3s-airgap-images-amd64.tar.zst
-rw-r--r--. 1 root root       373 Jul 26 14:49 k3s-images.txt

this pr:

total 1060864
drwxr-xr-x. 2 root root       151 Jul 26 14:59 .
drwxr-xr-x. 3 root root        23 Jul 26 14:54 ..
-rwxr-xr-x. 1 root root  74539192 Jul 26 14:58 k3s
-rw-------. 1 root root 655377408 Jul 26 14:59 k3s-airgap-images-amd64.tar
-rw-r--r--. 1 root root 197209224 Jul 26 15:01 k3s-airgap-images-amd64.tar.gz
-rw-------. 1 root root 159186806 Jul 26 14:59 k3s-airgap-images-amd64.tar.zst
-rw-r--r--. 1 root root       373 Jul 26 15:01 k3s-images.txt

@brandond
Copy link
Member

brandond commented Jul 28, 2025

I appreciate that you took the time to address some tech debt. Embed was not available at the time we started using go-bindata, and our CI and build pipeline ensures that the content does not drift so I don't believe that there is any vulnerability present here.

That said, referring to the current state of things as being "obfuscated" (which implies malicious intent) or comprising an "attack surface" is not correct, and sets an unnecessarily contentious tone.

If you'd like to update the title and PR template to describe this in terms of addressing tech debt, instead of playing up the current state as somehow insecure, I think it's something we could approve. We have had issues in the past when accepting PRs that advertise things as security fixes - having to clean up externally-issued CVEs with incorrect information, for example.

@muicoder
Copy link
Contributor

muicoder commented Jul 29, 2025

A simple way of refactoring is realized: 06689013

@brandond
Copy link
Member

@muicoder that does appear to be a much more minimal change than what's proposed here. Has the same easily-addressed issues with missing build tags, but lgtm other than that.

@eugercek
Copy link
Author

eugercek commented Jul 29, 2025

Hi @brandond — My intent wasn’t to be contentious; any sharpness was likely a language issue on my side. My goal was to reduce maintenance overhead, I use k3s daily and wanted to contribute back. With the new PR, embedding all static assets is good idea, will simplify even more. Should I close this PR?

@eugercek eugercek changed the title Use embed package for manifests directory to reduce attack surface refactor: Use embed package for manifests directory Jul 29, 2025
@brandond
Copy link
Member

brandond commented Jul 31, 2025

Thanks for pointing this out as a potential improvement @eugercek - as per the other PR, go-bindata has now been completely removed from k3s.

@eugercek eugercek closed this Jul 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants