feat: opt-in EBS encryption for runner root volume (Phase 6.b)#27
Merged
Conversation
Rounds out Phase 6 (IMDSv2 landed in #24, EBS encryption deferred until a per-AMI root-device lookup could be done safely). ## Change New 'encrypt-ebs' input on action.yml, default 'false' (opt-in). When 'true', the action: 1. Fetches the AMI's DescribeImages result (already needed to resolve image IDs when 'ec2-image-filters' is set). 2. Finds the BlockDeviceMapping matching the AMI's RootDeviceName. 3. Clones that mapping, drops SnapshotId (AWS uses the AMI's snapshot automatically), sets 'Encrypted: true'. 4. Passes the cloned mapping as RunInstances.BlockDeviceMappings. Result: root volume launches with SSE-EBS, key 'alias/aws/ebs' in the launch account. VolumeSize / VolumeType / IOPS / DeleteOnTermination preserved from the AMI — only the encryption bit is new. ## Why opt-in The launch account (not necessarily the AMI owner account) must have either default EBS encryption enabled, or at minimum permission to use the default AWS-managed KMS key. If the AMI's snapshot is encrypted with a customer-managed key that doesn't have a cross- account grant, RunInstances fails. Defaulting to 'true' would regress every consumer whose IAM / KMS policy isn't set up for this. Default 'false' lets each consumer opt in after verifying their account can handle it. ## Why not account-level default encryption AWS supports 'aws ec2 enable-ebs-encryption-by-default' at the account level — and that's the preferred belt-and-suspenders. But not every consumer runs in an AWS account they control (e.g., Namecheap's CI runs in a shared org account). Action-side opt-in is the only portable control. ## Refactor alongside resolveImageId -> resolveImage: now returns both the ID and the full Image metadata. Callers that only need the ID use .id; the EBS-encryption code path uses .image.BlockDeviceMappings to build the encrypted clone. ## Tests tests/ebs.test.js — 6 new cases for buildEncryptedRootMapping: happy path with full EBS config + non-EBS sibling mapping, volume type / size / iops preservation, and five null-return paths for exotic AMI shapes (no RootDeviceName, no mappings, non-EBS root, orphan RootDeviceName). tests/config.test.js — 2 new cases for the encrypt-ebs input (default fallback + override). Total: 44 -> 52 tests. ## Consumer dogfood Separate PR on terraform-provider-namecheap rotates the pin and enables 'encrypt-ebs: true' on the CI job. If the dogfood fails with a KMS / IAM permissions error, we know the account needs policy work before enabling; action-side code is fine either way. Signed-off-by: yuriyryabikov <22548029+kurok@users.noreply.github.com>
kurok
added a commit
to namecheap/terraform-provider-namecheap
that referenced
this pull request
Apr 21, 2026
#192) namecheap/ec2-github-runner#27 merged. Rotates both pins from 0fdd401 (Phase 4 retry) to 7c6a9a7 (Phase 6.b) and flips the new encrypt-ebs input to 'true' so the acceptance-test runner's root volume launches with SSE-EBS. Risk: if the CI AWS account can't use the default aws/ebs KMS key or the shared AMI's snapshot is encrypted with a customer-managed key lacking a cross-account grant, start-runner will fail with a KMS / IAM error. The action-side code handles that gracefully (throws early rather than timing out on registration), so diagnostics are easy via aws ec2 get-console-output. If dogfood fails, revert just the encrypt-ebs line; SHA rotation is orthogonal and can stay green. Signed-off-by: yuriyryabikov <22548029+kurok@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes Phase 6 (IMDSv2 landed in #24; EBS encryption was deferred until we could do per-AMI root-device lookup safely).
Change
New
encrypt-ebsinput, default'false'. When set to'true':DescribeImagesreturns the AMI metadata (same call already used to resolve AMI IDs whenec2-image-filtersis used; widened to includeBlockDeviceMappings).RootDeviceName, clones its EBS sub-object, dropsSnapshotId, and setsEncrypted: true.RunInstances.BlockDeviceMappings.Volume size, type, IOPS, DeleteOnTermination — all preserved from the AMI. The only new bit is encryption.
Why opt-in default
Enabling EBS encryption requires the launch account to have either default EBS encryption on, or permission to use the
alias/aws/ebsKMS key. If the AMI is shared from another account and encrypted with a customer-managed key, the launch account needs a cross-account grant. Defaulting to'true'would regress every consumer whose policy isn't set up for that. Defaulting to'false'makes the switch visible — maintainers see a new input + opt in after verifying.Refactor
resolveImageId→resolveImage. Returns{ id, image }instead of just the ID. The EBS-encryption path uses.image.BlockDeviceMappings; existing callers just use.id.Tests
tests/ebs.test.js— 6 new cases for the purebuildEncryptedRootMappingfunction:SnapshotId, setsEncrypted: true.nullfor: noRootDeviceName, noBlockDeviceMappings, non-EBS root mapping, orphanRootDeviceName.tests/config.test.js— 2 new cases for theencrypt-ebsinput (default + override).Total: 44 → 52 tests.
Dogfood plan
Separate PR on
terraform-provider-namecheaprotates the pin AND addsencrypt-ebs: 'true'to theStart EC2 runnerstep. If the dogfood launch fails with a KMS / IAM error, the action-side code is still fine — just means the launch account needs policy work before opting in. I'll diagnose via theaws ec2 get-console-outputrecipe (from the Phase 4.b work in my local notes).Out of scope for this PR
kms-key-idinput). AWS's default AWS-managed key is almost always the right choice; supporting customer-managed keys is a future feature if anyone asks.BlockDeviceMappingsvia... nowhere right now. Today the action only lets you encrypt the root via this toggle; everything else falls back to AMI defaults.