Skip to content

fix(cmd): write k6 config with owner-only permissions (0o600/0o700) - #6011

Merged
oleiade merged 3 commits into
masterfrom
fix-cloud-config-file-permissions
Jun 12, 2026
Merged

fix(cmd): write k6 config with owner-only permissions (0o600/0o700)#6011
oleiade merged 3 commits into
masterfrom
fix-cloud-config-file-permissions

Conversation

@oleiade

@oleiade oleiade commented May 26, 2026

Copy link
Copy Markdown
Contributor

What?

The on-disk k6 config file (default ~/.config/k6/config.json) can contain the Grafana Cloud API token under collectors.cloud.token, persisted by k6 cloud login and read back by k6 cloud run, k6 cloud test, and the launcher's build-service auth. It was previously written with mode 0o644 inside a directory created with mode 0o755, leaving the token readable by any other local user on shared hosts (CI runners, multi-user dev boxes, sidecar containers, container images that bake in $HOME) — an attacker could lift the token and impersonate the user against Grafana Cloud.

Tighten the modes to 0o600 for the file and 0o700 for the directory. afero's WriteFile and MkdirAll don't change permissions on pre-existing paths, so an explicit Chmod is performed after each, so existing installs are upgraded the next time writeDiskConfig runs (e.g. the next k6 cloud login). The modes are exposed as named constants (configFileMode, configDirMode) so the policy is documented in one place.

Add regression tests covering both the fresh-install case and the upgrade path (pre-existing 0o644 file / 0o755 directory get tightened on the next write).

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

The on-disk k6 config file (default `~/.config/k6/config.json`) can
contain the Grafana Cloud API token under `collectors.cloud.token`,
persisted by `k6 cloud login` and read back by `k6 cloud run`,
`k6 cloud test`, and the launcher's build-service auth. It was
previously written with mode 0o644 inside a directory created with
mode 0o755, leaving the token readable by any other local user on
shared hosts (CI runners, multi-user dev boxes, sidecar containers,
container images that bake in $HOME) — an attacker could lift the
token and impersonate the user against Grafana Cloud.

Tighten the modes to 0o600 for the file and 0o700 for the directory.
afero's WriteFile and MkdirAll don't change permissions on pre-existing
paths, so an explicit Chmod is performed after each, so existing
installs are upgraded the next time writeDiskConfig runs (e.g. the next
`k6 cloud login`). The modes are exposed as named constants
(configFileMode, configDirMode) so the policy is documented in one
place.

Add regression tests covering both the fresh-install case and the
upgrade path (pre-existing 0o644 file / 0o755 directory get tightened
on the next write).
@oleiade oleiade added this to the v2.1.0 milestone May 26, 2026
@oleiade oleiade self-assigned this May 26, 2026
@oleiade
oleiade requested a review from a team as a code owner May 26, 2026 09:39
@oleiade
oleiade requested review from mstoykov and szkiba and removed request for a team May 26, 2026 09:39
@oleiade
oleiade temporarily deployed to azure-trusted-signing May 26, 2026 09:44 — with GitHub Actions Inactive
@oleiade
oleiade temporarily deployed to azure-trusted-signing May 26, 2026 09:47 — with GitHub Actions Inactive
@oleiade
oleiade temporarily deployed to azure-trusted-signing May 26, 2026 10:33 — with GitHub Actions Inactive
@oleiade
oleiade temporarily deployed to azure-trusted-signing May 26, 2026 10:35 — with GitHub Actions Inactive
@szkiba
szkiba temporarily deployed to azure-trusted-signing June 1, 2026 09:42 — with GitHub Actions Inactive
@szkiba
szkiba temporarily deployed to azure-trusted-signing June 1, 2026 09:44 — with GitHub Actions Inactive

@mstoykov mstoykov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Not certain abotu erroring on chmod errors, but I guess it might be something strange, so lets see if people have problems I guess

@oleiade
oleiade merged commit 20124dd into master Jun 12, 2026
51 of 59 checks passed
@oleiade
oleiade deleted the fix-cloud-config-file-permissions branch June 12, 2026 08:08
@dmckernanacv

Copy link
Copy Markdown

LGTM. Not certain abotu erroring on chmod errors, but I guess it might be something strange, so lets see if people have problems I guess

@mstoykov @oleiade

I am having errors with this, I am trying to run k6 cloud login and k6 cloud run in separate docker containers, to do this I mount in the k6-config.json, this change broke my workflow, getting the error:

         /\      Grafana   /‾‾/  
    /\  /  \     |\  __   /  /   
   /  \/    \    | |/ /  /   ‾‾\ 
  /          \   |   (  |  (‾)  |
 / __________ \  |_|\_\  \_____/ 

time="2026-07-02T18:59:28Z" level=error msg="chmod /home/k6/.config/k6: operation not permitted"

when running k6 cloud login inside a container where the k6-config.json is mounted in / already exists.

You can reproduce with the following commands:

echo '{}'>k6-config.json 
chmod 600 k6-config.json
docker run --rm -v ./k6-config.json:/home/k6/.config/k6/config.json grafana/k6:2.1.0 cloud login --token ${K6_CLOUD_TOKEN} --stack ${K6_CLOUD_STACK}

@dmckernanacv

Copy link
Copy Markdown

fyi, I was able to workaround this by binding the config to /home/k6/k6-config.json and passing it in to all k6 commands with the -c flag.
Docker will create any bound subdirs of a volume to root, even when using the -u command to run as a user, so it has to be bound to a directory that already exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants