Skip to content

feat(iam): resolve AWS-managed policies from a built-in catalog#1880

Merged
vieiralucas merged 2 commits into
mainfrom
worktree-worktree-iam-managed-policies-b1
Jun 23, 2026
Merged

feat(iam): resolve AWS-managed policies from a built-in catalog#1880
vieiralucas merged 2 commits into
mainfrom
worktree-worktree-iam-managed-policies-b1

Conversation

@vieiralucas

@vieiralucas vieiralucas commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary

AWS-managed policy ARNs (arn:aws:iam::aws:policy/*) were accepted by the Attach* calls but never inserted into state, so GetPolicy / GetPolicyVersion / ListPolicyVersions / ListEntitiesForPolicy hard-failed with NoSuchEntity and ListPolicies(Scope=AWS) returned an empty list. That broke the extremely common Terraform/CDK/console flow of attaching an AWS-managed policy (e.g. AdministratorAccess, AWSLambdaBasicExecutionRole) to a role and then reading it back.

This batch seeds a built-in catalog of 28 of the most-attached AWS-managed policies and makes the read surface resolve them like real AWS.

What changed

  • New crates/fakecloud-iam/src/managed_policies module: catalog.json (the 28 policies, embedded via include_str!) plus lookup / all / default_document and ManagedPolicy::to_iam_policy.
  • The documents are the exact current AWS documents, fetched verbatim from the AWS managed-policy reference (docs.aws.amazon.com/aws-managed-policy/...): no stubs, no abbreviation.
  • get_policy / get_policy_version / list_policy_versions resolve an ARN from the catalog when it is not held in account state.
  • list_entities_for_policy accepts seeded managed ARNs.
  • list_policies returns the catalog for Scope=All and Scope=AWS; Scope=Local stays customer-only (matches real AWS).
  • AttachmentCount is derived on demand from the attachment maps; PolicyId is a deterministic ANPA... id (AWS does not publish the real per-policy id; clients key off the ARN).

Decisions

  • Curated, not exhaustive. The catalog covers the policies most commonly attached in IaC, not all ~1,400 AWS-managed policies. An ARN that is not seeded behaves exactly as before (attachable, but NoSuchEntity on read), so adding entries later is purely additive.
  • Scope=All now includes AWS-managed policies (it previously returned only customer policies). This matches real AWS; the existing list_policies_paginates_via_marker test was updated to use Scope=Local to isolate customer policies.
  • Enforcement deferred to a follow-up batch (the evaluator catalog fallback).

Test plan

  • cargo test -p fakecloud-iam: 489 unit/service tests pass, including new catalog tests and read-op resolution tests.
  • cargo test -p fakecloud-e2e --test iam managed: new E2E tests via the AWS SDK, iam_get_aws_managed_policy_from_catalog and iam_attach_aws_managed_policy_round_trips.
  • cargo clippy -p fakecloud-iam --all-targets clean; cargo fmt.

Surface

  • No new operations or introspection endpoints, so no SDK changes, no conformance-baseline count change, no ops-index/parity change.
  • Docs: website/content/docs/services/iam.md gains an AWS-managed-policies bullet.

Resolves AWS-managed IAM policies from a built-in catalog so attach-then-read flows work like real AWS and ListPolicies(Scope=AWS) returns managed policies instead of empty results.

AWS-managed policy ARNs (arn:aws:iam::aws:policy/*) were accepted by the
Attach* calls but never inserted into state, so GetPolicy /
GetPolicyVersion / ListPolicyVersions / ListEntitiesForPolicy hard-failed
with NoSuchEntity and ListPolicies(Scope=AWS) returned an empty list -
breaking the very common Terraform/CDK/console flow of attaching an
AWS-managed policy to a role.

Seed a curated catalog (crates/fakecloud-iam/src/managed_policies) of 28
of the most-attached AWS-managed policies, embedding the exact current
AWS policy documents fetched verbatim from the AWS managed-policy
reference. Read ops now resolve these ARNs from the catalog when not held
in account state, with on-demand AttachmentCount derived from the
attachment maps and a deterministic ANPA-prefixed PolicyId.

- new managed_policies module: catalog.json + lookup/all/default_document
  and ManagedPolicy::to_iam_policy
- get_policy/get_policy_version/list_policy_versions resolve via catalog
- list_entities_for_policy accepts seeded managed ARNs
- list_policies returns the catalog for Scope=All and Scope=AWS; Scope=Local
  stays customer-only (matches real AWS)
- unit + service-level + E2E tests; iam.md updated

Enforcement of managed-policy grants by the evaluator follows in a later
batch.
@vieiralucas vieiralucas merged commit 481aafd into main Jun 23, 2026
87 checks passed
@vieiralucas vieiralucas deleted the worktree-worktree-iam-managed-policies-b1 branch June 23, 2026 06:29
vieiralucas added a commit that referenced this pull request Jun 23, 2026
…facc

With AWS-managed policy resolution shipped (#1880, AWSGlueServiceRole now
resolves), the upstream TestAccGlueJob_basic and TestAccGlueTrigger_basic
acceptance tests get past role-attach but surfaced two Glue gaps:

- CreateJob did not default Timeout, so GetJob returned 0; AWS defaults it
  to 2880 minutes for batch jobs (no default for gluestreaming). The
  provider asserts 2880.
- StartTrigger unconditionally set State=ACTIVATED. For ON_DEMAND triggers
  AWS fires a single run but leaves State=CREATED; only scheduled/
  conditional triggers go ACTIVATED. The provider computes the trigger's
  "enabled" attribute from this (ON_DEMAND + CREATED => enabled=true), so
  the wrong state made "enabled" read false.

Fix both, then drop the glue Job/Trigger entries from the tfacc deny-list.
Adds glue unit tests (timeout default incl. streaming + explicit override;
ON_DEMAND stays CREATED on StartTrigger; SCHEDULED goes ACTIVATED) and
updates the existing trigger test to the AWS-correct state.

Validated locally: the full glue tfacc shard passes (TestAccGlueJob_basic
and TestAccGlueTrigger_basic included).
ericz7900 pushed a commit to ericz7900/fakecloud that referenced this pull request Jun 27, 2026
Follows faiscadev#1880 (AWS-managed policy catalog). The evaluator and the
SimulatePrincipalPolicy policy collector resolved managed policy
documents from account state only, so an attached AWS-managed policy
(arn:aws:iam::aws:policy/*) granted nothing under --iam soft|strict and
SimulatePrincipalPolicy returned implicitDeny for actions it should have
allowed.

Resolve the default-version document from the seeded catalog when the ARN
is not held in account state:
- evaluator::managed_policy_default_document falls back to the catalog
  (covers role/user/group identity-policy collection used for live
  enforcement)
- simulate_policy's collect_principal_policy_jsons does the same for
  principal + group attachments (covers SimulatePrincipalPolicy)

Adds evaluator unit tests (attached AmazonS3FullAccess grants s3:* but
not dynamodb; unseeded managed ARN grants nothing) and an E2E
SimulatePrincipalPolicy test resolving AmazonS3FullAccess from the
catalog. iam.md updated to note managed grants are enforced.
ericz7900 pushed a commit to ericz7900/fakecloud that referenced this pull request Jun 27, 2026
The IAM enforcement reference listed "managed" identity policies without
distinguishing customer-managed from AWS-managed. With the AWS-managed
policy catalog (faiscadev#1880) and its enforcement (faiscadev#1881), attaching an
AWS-managed policy (arn:aws:iam::aws:policy/*) now grants its permissions
under --iam soft|strict. Spell that out so the evaluated-policy scope
matches the implementation.
ericz7900 pushed a commit to ericz7900/fakecloud that referenced this pull request Jun 27, 2026
…er arms

Several CloudFormation provisioner arms accepted a resource and returned
CREATE_COMPLETE but dropped the properties that make it functional, so the
stack looked healthy while the resource silently misbehaved:

- AWS::IAM::Role dropped Policies / ManagedPolicyArns / PermissionsBoundary /
  Tags / MaxSessionDuration. With real AWS-managed-policy enforcement (faiscadev#1880),
  a role provisioned this way granted nothing — every workload assuming it was
  denied. Now mirrors the IAM user arm (inline + managed policies attached).
- AWS::Events::Rule dropped Targets. PutEvents only delivers to rules with
  non-empty targets, so a CFN/SAM rule matched events but fired into the void.
  Targets are now parsed via the shared eventbridge parse_target.
- AWS::DynamoDB::Table dropped GSIs/LSIs/SSE/Tags. A Query/Scan on the index
  name 400s at runtime. Now parsed via the same dynamodb parse_gsi/parse_lsi
  helpers CreateTable uses.
- AWS::SQS::Queue dropped the typed RedrivePolicy (DLQ routing never happened)
  and the AWS-default attributes (drift vs an API-created queue). Now seeds the
  real defaults, keeps object/bool-valued attributes, and parses the typed
  RedrivePolicy via the shared parse_redrive_policy.
- AWS::SNS::Topic dropped its inline Subscription list and config attributes
  (DisplayName/KmsMasterKeyId/FifoTopic/...), so fan-out was silently broken.
  Both are now carried.

Exports the relevant parsers/types from the eventbridge, dynamodb and sqs
crates so the provisioner reuses one source of truth instead of re-deriving
(the recurring root cause). Adds an E2E test provisioning all five resource
types and reading each property back via its service SDK.
ericz7900 pushed a commit to ericz7900/fakecloud that referenced this pull request Jun 27, 2026
…PI events into triggers

A SAM AWS::Serverless::Function's `Policies` and `Events` were dropped by the
transform, so a `sam deploy` produced a function with no execution role (every
IAM-enforced call denied under faiscadev#1880 enforcement) and no triggers (nothing ever
invoked it).

The transform now synthesizes the native resources the existing provisioner
arms already handle:
- `Policies` -> an implicit `AWS::IAM::Role` (`<Fn>Role`) whose trust policy
  allows lambda.amazonaws.com; managed-policy names/ARNs become
  ManagedPolicyArns, inline statement docs become inline policies. The
  function's Role is set to GetAtt the role. An explicit `Role` is kept as-is.
- `Schedule`/`ScheduleV2` -> `Events::Rule` (ScheduleExpression) targeting the
  function + `Lambda::Permission`.
- `SQS`/`DynamoDB`/`Kinesis`/`MSK`/`MQ` -> `Lambda::EventSourceMapping`.
- `SNS` -> `SNS::Subscription` (protocol lambda) + `Lambda::Permission`.
- `EventBridgeRule`/`CloudWatchEvent` -> `Events::Rule` (EventPattern) + permission.

Api/HttpApi events (implicit-API route synthesis) follow in a separate change.
SAM policy *templates* (DynamoDBCrudPolicy etc.) aren't expanded into statements
yet — the role is still created so the function is no longer role-less.

Adds unit tests for the expansion and an E2E test deploying a function with
Policies + Schedule + SQS events and asserting the role, Events::Rule target,
and EventSourceMapping are all created.
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.

1 participant