feat(lambda): give function containers the AWS environment - #2562
Conversation
Real Lambda injects region and execution-role credentials, and function code relies on them: an SDK client built with no region or credentials fails before it reaches an endpoint. fakecloud injected none of the standard variables, only the function's own environment, so handler code that called AWS did nothing useful -- CDK's `BucketDeployment` reported success having copied no files. Inject `AWS_REGION`, `AWS_DEFAULT_REGION` and credentials, plus `AWS_ENDPOINT_URL` pointing at the backend's host alias and this server's port. The endpoint is the one deliberate deviation from AWS: there the variable is absent and the SDK's defaults are correct, whereas here the container has to be pointed back at fakecloud or the handler reaches out to the real internet. `localhost` would resolve to the container itself, so the existing host alias is reused. Defaults are emitted before the function's own environment, so a function that sets any of them wins. The E2E asserts the environment the container actually observes. It stops short of a full SDK round-trip from inside the container: that also needs container-to-host reachability on an arbitrary host port, which does not hold on every developer machine (WSL2 here), and would make the test flaky for reasons unrelated to this change.
- Give each function instance a real STS session for its execution role (assumed-role/<role>/<function>, minted like /_fakecloud/credentials and revoked on retire) instead of static keys that matched the root bypass. - Build one environment for the docker and k8s backends: region from the function ARN, reserved Lambda variables that always win, AWS_ENDPOINT_URL pointed back at fakecloud. Credentials travel as docker -e names with values on the CLI's environment, and as a per-pod Secret on k8s. - Reject reserved environment keys on CreateFunction, UpdateFunctionConfiguration and AWS::Lambda::Function as AWS does, and run the execution-role trust check on update and CloudFormation too; a cross-account role is refused under IAM enforcement. - Key the warm pool by qualified function ARN and fold the launch config into deploy_id so config changes start a fresh instance; never evict a busy instance; an IAM reset retires credentialed instances. - Unit tests for environment assembly, the k8s spec, the pool and issuer; e2e for the observed environment under --verify-sigv4, reserved keys, and the role checks in default and enforcement modes.
- Refuse a cross-account role only under --iam strict; soft logs it. - Run the trust check in the account the session is minted in. - Mark instances retiring synchronously on an IAM reset. - Revoke a launch's credentials if the launch fails or is cancelled. - Judge instance age from the credentials' expiration. - Retire busy instances of a deleted version when they are released. - Fold tags into the deploy fingerprint only for the k8s backend. - Share one ARN account parser (fakecloud_aws::arn::account_of). - Carry the InvalidParameterValueException code on the CloudFormation reserved-key failure.
|
Thanks a lot for this, @Sorttech. Giving function containers the region and credentials real Lambda injects is what makes handler code like CDK's BucketDeployment actually reach AWS APIs locally, and pointing AWS_ENDPOINT_URL back at fakecloud through the host alias was the right call. I pushed a few follow-ups before merging: the static test/test keys matched fakecloud's root bypass, so each instance now gets a real STS session for its execution role (assumed-role//, revoked when the instance retires, with any launch that fails or is cancelled cleaned up); the k8s backend gets the same environment, with credentials in a per-pod Secret rather than inline, and Docker passes them via the CLI environment rather than argv; reserved Lambda variables always win over the function's own and are rejected on CreateFunction, UpdateFunctionConfiguration and AWS::Lambda::Function as AWS does; the region comes from the function ARN; the execution-role trust check now also runs on update and CloudFormation, and a cross-account role is refused under --iam strict; and the warm pool is keyed by qualified function ARN with the launch config in the deploy fingerprint, so config changes start a fresh instance without ever killing a busy one. Unit tests for each plus e2e coverage under --verify-sigv4 (the handler calls STS and sees its assumed role). Merged. Really appreciate the contribution. |
Real Lambda injects region and execution-role credentials, and function
code relies on them: an SDK client built with no region or credentials
fails before it reaches an endpoint. fakecloud injected none of the
standard variables, only the function's own environment, so handler code
that called AWS did nothing useful -- CDK's
BucketDeploymentreportedsuccess having copied no files.
Inject
AWS_REGION,AWS_DEFAULT_REGIONand credentials, plusAWS_ENDPOINT_URLpointing at the backend's host alias and this server'sport. The endpoint is the one deliberate deviation from AWS: there the
variable is absent and the SDK's defaults are correct, whereas here the
container has to be pointed back at fakecloud or the handler reaches out
to the real internet.
localhostwould resolve to the container itself,so the existing host alias is reused. Defaults are emitted before the
function's own environment, so a function that sets any of them wins.
The E2E asserts the environment the container actually observes. It stops
short of a full SDK round-trip from inside the container: that also needs
container-to-host reachability on an arbitrary host port, which does not
hold on every developer machine (WSL2 here), and would make the test flaky
for reasons unrelated to this change.
Test plan
Regression test:
lambda_container_receives_the_aws_environmentincrates/fakecloud-e2e/tests/lambda_aws_env.rsVerification
On this exact head, rebased onto current
main:cargo fmt --all --check- clean.cargo clippy --workspace --all-targets -- -D warnings- clean.cargo test --workspaceexcludingfakecloud-e2e,fakecloud-conformance,fakecloud-tfaccandfakecloud-parity(the same set CI'stestjob runs),plus
cargo test -p fakecloud-conformance --lib- 9931 passed, 0 failed.cargo test -p fakecloud-e2e --test lambda_aws_env- the regression testabove passes in a real Lambda container under Docker against a freshly
built
target/debug/fakecloud.Found by deploying a CDK CloudFront + S3 SPA against fakecloud.
Summary by cubic
Injects the AWS environment real Lambda provides into function containers — region, reserved variables, and real execution-role session credentials — pointed back at fakecloud, so handler code that calls AWS works against the emulator instead of silently reaching the real internet.
CreateFunction,UpdateFunctionConfiguration, andAWS::Lambda::Function; cross-account roles are refused under--iam strictand soft-logged otherwise.create/patch/deleteon Secrets (RBAC docs updated).Written for commit 7a03a17. Summary will update on new commits.