Skip to content

Conversation

@maennchen
Copy link
Member

What changed

  • Introduced environment: release to the publish-to-hex job so that only workflows explicitly targeting the release environment can read sensitive values.
  • Added a safeguardif: ${{ vars.HEX_AWS_REGION }} – to skip the job in forks that don’t define release variables.
  • Converted non-secret AWS settings to environment variables
    • ${{ vars.HEX_AWS_REGION }}
    • ${{ vars.HEX_AWS_S3_BUCKET }}
      These are configuration values, not credentials, so variables are a better fit and remain visible only to jobs using the release environment.
  • Scoped Fastly secrets to the purge step instead of the whole job, keeping tokens out of steps that don’t need them.

Why it matters

Placing secrets in an environment and scoping them to the minimum surface area:

  • prevents forks and unrelated jobs from accessing production credentials;
  • limits accidental leakage in logs;
  • follows the principle of least privilege, reducing the blast radius if any single step is compromised.

TODO for Maintainers

Item New home
HEX_AWS_REGION, HEX_AWS_S3_BUCKET Environment → release → Variables
HEX_AWS_ACCESS_KEY_ID
HEX_AWS_SECRET_ACCESS_KEY
HEX_FASTLY_REPO_SERVICE_ID
HEX_FASTLY_BUILDS_SERVICE_ID
HEX_FASTLY_KEY
Environment → release → Secrets

Once the moves are complete, new release builds will run with the tighter permissions automatically.

* Add `environment: release` to the "publish-to-hex" job so that only
  workflows explicitly targeting the release environment can read
  sensitive values.
* Gate the job behind `if: ${{ vars.HEX_AWS_REGION }}` to avoid noisy
  failures in forks where the variable is not configured.
* Replace `${{ secrets.HEX_AWS_REGION }}` / `${{ secrets.HEX_AWS_S3_BUCKET }}`
  references with `${{ vars.* }}`.  These are not credentials, so
  environment-level *variables* are a better fit and keep them readable
  only by jobs that declare the environment.
* Remove Fastly secrets from the job-wide `env:` block and inject them
  only into the Fastly purge step, following the principle of least
  privilege.  Other steps no longer see these tokens.

Restricting secret visibility to an environment and to the exact step
that needs them reduces the blast radius of a compromised workflow run,
blocks accidental exposure in logs of unrelated steps, and stops forks
from obtaining privileged data.
@ericmj ericmj self-assigned this Aug 29, 2025
@ericmj
Copy link
Member

ericmj commented Aug 29, 2025

I have added the environment variables and secrets. Is it ready to merge?

@maennchen
Copy link
Member Author

@ericmj Yes, if the TODOs were done, this is ready.

Please make sure to either backport the change to all still maintained versions or leave the old variables until they are no longer needed.

@ericmj ericmj merged commit 56333d4 into elixir-lang:main Sep 3, 2025
13 checks passed
ericmj pushed a commit that referenced this pull request Sep 3, 2025
* Add `environment: release` to the "publish-to-hex" job so that only
  workflows explicitly targeting the release environment can read
  sensitive values.
* Gate the job behind `if: ${{ vars.HEX_AWS_REGION }}` to avoid noisy
  failures in forks where the variable is not configured.
* Replace `${{ secrets.HEX_AWS_REGION }}` / `${{ secrets.HEX_AWS_S3_BUCKET }}`
  references with `${{ vars.* }}`.  These are not credentials, so
  environment-level *variables* are a better fit and keep them readable
  only by jobs that declare the environment.
* Remove Fastly secrets from the job-wide `env:` block and inject them
  only into the Fastly purge step, following the principle of least
  privilege.  Other steps no longer see these tokens.

Restricting secret visibility to an environment and to the exact step
that needs them reduces the blast radius of a compromised workflow run,
blocks accidental exposure in logs of unrelated steps, and stops forks
from obtaining privileged data.
ericmj pushed a commit that referenced this pull request Sep 3, 2025
* Add `environment: release` to the "publish-to-hex" job so that only
  workflows explicitly targeting the release environment can read
  sensitive values.
* Gate the job behind `if: ${{ vars.HEX_AWS_REGION }}` to avoid noisy
  failures in forks where the variable is not configured.
* Replace `${{ secrets.HEX_AWS_REGION }}` / `${{ secrets.HEX_AWS_S3_BUCKET }}`
  references with `${{ vars.* }}`.  These are not credentials, so
  environment-level *variables* are a better fit and keep them readable
  only by jobs that declare the environment.
* Remove Fastly secrets from the job-wide `env:` block and inject them
  only into the Fastly purge step, following the principle of least
  privilege.  Other steps no longer see these tokens.

Restricting secret visibility to an environment and to the exact step
that needs them reduces the blast radius of a compromised workflow run,
blocks accidental exposure in logs of unrelated steps, and stops forks
from obtaining privileged data.
@maennchen maennchen deleted the jm/secure_aws_fastly_variables branch September 3, 2025 20:18
@ericmj
Copy link
Member

ericmj commented Sep 3, 2025

I backported to v1.18 and v1.19.

I also removed the repository secrets, if we need them back to ship new versions of <v1.18 hex maintainers can revert this commit: https://github.com/hexpm/hexpm-ops/commit/8188ddeeccd26b391070f7cf479fad50add115bb.

@maennchen
Copy link
Member Author

@ericmj https://github.com/elixir-lang/elixir/actions/runs/17445029605/job/49537507599 fails. That is because #14604 is not backported to 1.18.

@ericmj
Copy link
Member

ericmj commented Sep 3, 2025

Okay, backporting that PR to v1.18 also.

@maennchen
Copy link
Member Author

@ericmj Hm, there's another issue. I'll open a PR with a fix for 1.18

maennchen added a commit to maennchen/elixir that referenced this pull request Sep 3, 2025
Backported PRs:
* elixir-lang#14604
* elixir-lang#14627

The commits are based on the SBoM PR (elixir-lang#14241) which changed the
actions.
@maennchen
Copy link
Member Author

@ericmj See #14745

josevalim pushed a commit that referenced this pull request Sep 5, 2025
Backported PRs:
* #14604
* #14627

The commits are based on the SBoM PR (#14241) which changed the
actions.
@ericmj
Copy link
Member

ericmj commented Sep 15, 2025

@maennchen

It looks like the upload-builds-hex-pm is being skipped now: https://github.com/elixir-lang/elixir/actions/runs/17493062408/job/49687676489.

We have this conditional https://github.com/elixir-lang/elixir/blob/main/.github/workflows/release.yml#L308 but it should be true:

image

@maennchen
Copy link
Member Author

@ericmj What is currently listed in Deployment branches and tags in Settings / Environments / release?

@ericmj
Copy link
Member

ericmj commented Sep 15, 2025

What is currently listed in Deployment branches and tags in Settings / Environments / release?

"No restriction"

@maennchen
Copy link
Member Author

Ok, that's not the reason then. I'll debug in my fork and open a PR.

You might want to change the "no restriction", that defeats the purpose a bit. In my fork I listed main, v* branches and v* tags.

@josevalim
Copy link
Member

@maennchen don't we also need it in main, since we are always pushing main builds to Hex as well?

@maennchen
Copy link
Member Author

@josevalim Yes, I listed main, v prefixed tags and v prefixed branches.

@maennchen
Copy link
Member Author

@ericmj Interesting, if: "${{ vars.HEX_AWS_REGION }}" evaluates to false on the job level but true on the step level.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants