Skip to content

test: add AWS XKS CI test against remote server - #1114

Open
p0wline wants to merge 3 commits into
fix/xks_permissionsfrom
feat/ci-xks-remote
Open

test: add AWS XKS CI test against remote server#1114
p0wline wants to merge 3 commits into
fix/xks_permissionsfrom
feat/ci-xks-remote

Conversation

@p0wline

@p0wline p0wline commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Context

Before this PR, XKS tests only ran locally against a mock server. There was no way to catch regressions in the full AWS integration path.

What this PR does

1. scratchstack 0.10 → 0.11 migration

The SigV4 verification library rejected secret keys longer than 43 characters. Version 0.11 removes that restriction, which was blocking the real AWS infrastructure (key was 52 chars).

2. CI workflow .github/workflows/test_xks_remote.yml

On every PR and push:

  • Builds a non-fips release binary
  • Deploys it to the persistent EC2 test server (aws-xks-kms.cosmian.dev) via SSH
  • Step 1 — Proxy-direct tests: provisions three test keys (aws_xks_kek, encrypt_only_key, decrypt_only_key), enforces usage restrictions (encrypt-only / decrypt-only), then runs the vendored AWS XKS curl test suite directly against the server using SigV4 — no AWS KMS involved
  • Step 2 — End-to-end test: calls aws kms encrypt / aws kms decrypt via the real AWS KMS API, which routes through the configured external key store to our proxy — verifies the full chain from AWS to Cosmian KMS and back

3. Cherry-pick of a14031598 (fix: create a dedicated AWS-XKS user)

Pulled in from your fix/xks_permissions branch. The server now uses the reserved identity [aws-xks-service] for all XKS operations instead of awsPrincipalArn from the request body. This is required for the end-to-end test to work: when AWS KMS calls the proxy, the injected ARN varies per caller, but [aws-xks-service] gets a single permanent grant at startup on every XKS key.

4. test_data submodule update

Points to fix/xks-config-env-override which fixes config.sh to respect env vars (see test_data PR #13). Without this, the vendored test suite ignored the SigV4 credentials injected by the CI workflow.

5. lychee.toml

Added kms\.example\.com and kms\.different\.com to the link-checker exclusions — these are fictional hostnames used in unit tests inside start_kms_server.rs and were causing lychee to fail on every commit.

Required GitHub secrets (repo Cosmian/kms)

Secret Purpose
AWS_XKS_ACCESS_KEY_ID IAM key ID for aws kms encrypt/decrypt (xks-test user)
AWS_XKS_SECRET_ACCESS_KEY Matching IAM secret
AWS_XKS_KEY_ARN ARN of the KMS key backed by the external key store
KMS_XKS_SIGV4_ACCESS_KEY_ID SigV4 access key configured on the proxy server
KMS_XKS_SIGV4_SECRET_ACCESS_KEY Matching SigV4 secret key
KMS_XKS_SSH_PRIVATE_KEY SSH private key to deploy the binary to the EC2 instance
KMS_XKS_SSH_KNOWN_HOSTS SSH known hosts entry for aws-xks-kms.cosmian.dev
KMS_XKS_SSH_USER SSH user on the EC2 instance

Note

Add remote AWS XKS CI test and harden Sigv4Middleware with scratchstack 0.11

  • Adds a GitHub Actions workflow (test_xks_remote.yml) that builds the release KMS binary, deploys it to a remote XKS server via deploy_xks_remote.sh, and runs the vendored XKS test suite plus an AWS KMS encrypt/decrypt end-to-end test
  • Migrates aws_xks.Sigv4Middleware.call from the synchronous scratchstack 0.10 API to the 0.11 validator with a local SigningKeyService; request verification now runs in Tokio's blocking pool with a CPU-sized semaphore
  • Adds enforce_sigv4_request_freshness to reject requests outside a five-minute replay window, with timestamp extraction from X-Amz-Date header, Date header, or X-Amz-Date query parameter
  • Adds remote test runner (test_xks_remote.sh) that provisions test keys, grants permissions to both AWS identities, enforces encrypt-only and decrypt-only cases, and runs the vendored curl suite over HTTPS
  • Risk: XKS requests that previously passed without timestamp validation will now be rejected if the SigV4 timestamp is missing, invalid, or outside the five-minute window; the deployment script replaces the remote binary and rolls back on health-check failure, but a failed rollback could leave the service down

Macroscope summarized 65b72e5.

@p0wline
p0wline force-pushed the feat/ci-xks-remote branch from 32abf5e to 043c5da Compare August 14, 2026 14:06
@Manuthor
Manuthor changed the base branch from develop to fix/xks_permissions August 17, 2026 04:47
@Manuthor
Manuthor changed the base branch from fix/xks_permissions to develop August 17, 2026 04:47
@Manuthor
Manuthor changed the base branch from develop to fix/xks_permissions August 17, 2026 04:49
@Manuthor
Manuthor changed the base branch from fix/xks_permissions to develop August 17, 2026 04:50
@p0wline
p0wline force-pushed the feat/ci-xks-remote branch 2 times, most recently from 00a4b94 to 757474b Compare September 2, 2026 08:57
@Manuthor
Manuthor changed the base branch from develop to fix/xks_permissions September 3, 2026 09:33
@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown

Macroscope has since reviewed this pull request. An earlier review was skipped by a cost limit; a review has now completed, so that notice no longer applies.

Comment thread .mise/scripts/sbom/generate_sbom.sh Outdated
Comment thread .mise/scripts/sbom/generate_sbom.sh Outdated
Comment thread .mise/scripts/sbom/generate_sbom.sh Outdated
Comment thread documentation/docs/integrations/spire_spiffe.md Outdated
Comment thread documentation/docs/integrations/spire_spiffe.md Outdated
Comment thread documentation/docs/integrations/spire_spiffe.md Outdated
Comment thread .github/workflows/test_xks_remote.yml
Comment thread .github/workflows/test_xks_remote.yml
Comment thread crate/server/src/start_kms_server.rs Outdated
Comment thread crate/server/src/routes/aws_xks/sigv4_middleware.rs Outdated
Comment thread documentation/docs/integrations/spire_spiffe.md Outdated
@Manuthor
Manuthor force-pushed the feat/ci-xks-remote branch 2 times, most recently from eefdf45 to fa66ce8 Compare September 3, 2026 12:57
Comment thread crate/server/src/routes/aws_xks/sigv4_middleware.rs Outdated
Manuthor added a commit that referenced this pull request Sep 3, 2026
Pin dtolnay/rust-toolchain to a reviewed commit SHA instead of the mutable
@master ref (CWE-829), and gate the secrets-bearing xks-remote job behind a
GitHub Environment requiring manual reviewer approval before any
same-repository PR can access KMS_XKS_SSH_PRIVATE_KEY / AWS credentials
(CWE-284). Maintainers must configure required reviewers on the
xks-remote-approval environment in repo Settings > Environments.

Addresses PR #1114 review comments 3923422441 and 3924659091.
Manuthor added a commit that referenced this pull request Sep 3, 2026
…gration

migrate_aws_xks_key_access wrapped kms_server.params.default_username in
UserId::from(...) before comparing it to AWS_XKS_SERVICE_USER. UserId's
From<&str> impl carries a debug_assert!(!s.is_empty()), which is reachable
(CWE-617) because ServerParams derives Default and default_username defaults
to an empty string — a valid configuration in debug/test builds. Compare the
raw &str directly instead of constructing a UserId on this path. Also drops
a duplicate AWS_XKS_SERVICE_USER import on the same use line.

Adds a regression test asserting the migration succeeds for an empty
default_username, which required fixing a pre-existing compile error in
aws_xks/tests.rs (UserId::from(owner) where owner is already &UserId) that
was otherwise blocking the whole crate's --tests target.

Addresses PR #1114 review comment 3924659097.
Manuthor added a commit that referenced this pull request Sep 3, 2026
This PR's switch from scratchstack_aws_signature::sigv4_verify (previously
hardcoded to Duration::minutes(5)) to sigv4_validate_request silently
widened the accepted request-timestamp skew to that crate's internal
15-minute default, tripling the window during which a captured XKS SigV4
request remains replayable (CWE-294, OWASP A07:2021).

The pinned scratchstack-aws-signature 0.11.4 exposes no public API to
configure this: SignatureOptions has no allowed_mismatch field and
sigv4_validate_request hard-codes ALLOWED_MISMATCH_MINUTES = 15 internally.
Add an explicit 5-minute freshness check that parses the signed request
timestamp (X-Amz-Date header, X-Amz-Date query parameter, or Date header)
and rejects requests outside that window with AuthenticationFailedException
before delegating to sigv4_validate_request for signature verification.

Adds unit tests for timestamp extraction and freshness boundary/rejection.

Addresses PR #1114 review comment 3924659101.
Comment thread crate/server/src/routes/aws_xks/sigv4_middleware.rs Outdated
Comment thread crate/server/src/routes/aws_xks/sigv4_middleware.rs
Comment thread .github/workflows/test_xks_remote.yml
Manuthor added a commit that referenced this pull request Sep 3, 2026
Pin dtolnay/rust-toolchain to a reviewed commit SHA instead of the mutable
@master ref (CWE-829), and gate the secrets-bearing xks-remote job behind a
GitHub Environment requiring manual reviewer approval before any
same-repository PR can access KMS_XKS_SSH_PRIVATE_KEY / AWS credentials
(CWE-284). Maintainers must configure required reviewers on the
xks-remote-approval environment in repo Settings > Environments.

Addresses PR #1114 review comments 3923422441 and 3924659091.
Manuthor added a commit that referenced this pull request Sep 3, 2026
…gration

migrate_aws_xks_key_access wrapped kms_server.params.default_username in
UserId::from(...) before comparing it to AWS_XKS_SERVICE_USER. UserId's
From<&str> impl carries a debug_assert!(!s.is_empty()), which is reachable
(CWE-617) because ServerParams derives Default and default_username defaults
to an empty string — a valid configuration in debug/test builds. Compare the
raw &str directly instead of constructing a UserId on this path. Also drops
a duplicate AWS_XKS_SERVICE_USER import on the same use line.

Adds a regression test asserting the migration succeeds for an empty
default_username, which required fixing a pre-existing compile error in
aws_xks/tests.rs (UserId::from(owner) where owner is already &UserId) that
was otherwise blocking the whole crate's --tests target.

Addresses PR #1114 review comment 3924659097.
Manuthor added a commit that referenced this pull request Sep 3, 2026
This PR's switch from scratchstack_aws_signature::sigv4_verify (previously
hardcoded to Duration::minutes(5)) to sigv4_validate_request silently
widened the accepted request-timestamp skew to that crate's internal
15-minute default, tripling the window during which a captured XKS SigV4
request remains replayable (CWE-294, OWASP A07:2021).

The pinned scratchstack-aws-signature 0.11.4 exposes no public API to
configure this: SignatureOptions has no allowed_mismatch field and
sigv4_validate_request hard-codes ALLOWED_MISMATCH_MINUTES = 15 internally.
Add an explicit 5-minute freshness check that parses the signed request
timestamp (X-Amz-Date header, X-Amz-Date query parameter, or Date header)
and rejects requests outside that window with AuthenticationFailedException
before delegating to sigv4_validate_request for signature verification.

Adds unit tests for timestamp extraction and freshness boundary/rejection.

Addresses PR #1114 review comment 3924659101.
Comment thread crate/server/src/routes/aws_xks/sigv4_middleware.rs
Comment thread .github/workflows/test_xks_remote.yml
Comment thread .github/workflows/test_xks_remote.yml
Comment thread documentation/docs/SUMMARY.md Outdated
@Manuthor
Manuthor deployed to xks-remote-approval September 3, 2026 17:13 — with GitHub Actions Active
Comment thread .github/workflows/test_xks_remote.yml
@Manuthor
Manuthor deployed to xks-remote-approval September 3, 2026 20:35 — with GitHub Actions Active
@Manuthor
Manuthor deployed to xks-remote-approval September 3, 2026 20:47 — with GitHub Actions Active
@Manuthor
Manuthor deployed to xks-remote-approval September 4, 2026 04:59 — with GitHub Actions Active
@Manuthor
Manuthor deployed to xks-remote-approval September 4, 2026 14:14 — with GitHub Actions Active
.checked_add_signed(allowed_mismatch)
.unwrap_or(server_timestamp);

if request_timestamp < min_timestamp || request_timestamp > max_timestamp {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 High aws_xks/sigv4_middleware.rs:282

A request queued on SIGV4_VERIFICATION_PERMITS can pass the five-minute freshness check after that window has expired, weakening the anti-replay control. server_timestamp is captured before permit acquisition and reused by both enforce_sigv4_request_freshness and sigv4_validate_request; capture the current time after acquiring the permit or immediately before validation.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @crate/server/src/routes/aws_xks/sigv4_middleware.rs around line 282:

A request queued on `SIGV4_VERIFICATION_PERMITS` can pass the five-minute freshness check after that window has expired, weakening the anti-replay control. `server_timestamp` is captured before permit acquisition and reused by both `enforce_sigv4_request_freshness` and `sigv4_validate_request`; capture the current time after acquiring the permit or immediately before validation.

@Manuthor
Manuthor deployed to xks-remote-approval September 4, 2026 14:22 — with GitHub Actions Active
@Manuthor
Manuthor deployed to xks-remote-approval September 5, 2026 07:25 — with GitHub Actions Active
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.

2 participants