Skip to content

add rvn-aws-iam-policy#72

Open
flybayer wants to merge 3 commits into
mainfrom
bb-iam-policy
Open

add rvn-aws-iam-policy#72
flybayer wants to merge 3 commits into
mainfrom
bb-iam-policy

Conversation

@flybayer

@flybayer flybayer commented Jul 23, 2026

Copy link
Copy Markdown
Member

Greptile Summary

This PR adds a new security/iam_policy Terraform/OpenTofu module that creates a single reusable customer-managed AWS IAM policy from either structured statements or a raw JSON document, along with its Ravion module definition (rvn-aws-iam-policy-definition.yml).

  • Module core: iam_policy.tf creates aws_iam_policy with a lifecycle precondition ensuring at least one policy source is supplied; locals.tf uses one() to collapse the count-based aws_iam_policy_document data source into a scalar; variables.tf enforces XOR between actions/not_actions and resources/not_resources per statement.
  • Ravion definition: rvn-aws-iam-policy-definition.yml correctly marks name, description, and path as immutable: true; UI-only action_match_mode/resource_match_mode selectors control which sub-fields are shown without leaking into Terraform variables.
  • Tests: Seven tftest.hcl runs cover defaults, JSON-override precedence, tag merging, and all major validation rejections using a mock AWS provider.

Confidence Score: 5/5

Safe to merge — the module is well-scoped, all three ForceNew policy identity fields (name, description, path) are marked immutable in the Ravion definition, and the precondition correctly guards against empty policy inputs.

The Terraform logic is clean and the resource lifecycle boundary is correctly enforced. The description field is now marked immutable (addressing the concern from a prior review), the lock file includes both platform and registry checksums as required, and the test suite covers defaults, precedence, tag merging, and all major validation rejections.

No files require special attention.

Important Files Changed

Filename Overview
security/iam_policy/iam_policy.tf Single aws_iam_policy resource with a precondition guarding the empty-input case; clean and correct.
security/iam_policy/variables.tf Well-typed variables with solid validations; XOR enforcement on actions/not_actions and resources/not_resources is correct.
security/iam_policy/locals.tf policy_document local correctly uses one() to collapse the count-based data source; tag merge follows repo conventions.
security/iam_policy/data.tf Count-guarded aws_iam_policy_document data source; dynamic statement block correctly maps all optional list fields to the provider.
security/iam_policy/rvn-aws-iam-policy-definition.yml name, description, and path all correctly carry immutable: true; UI-only selectors (action_match_mode, resource_match_mode) are properly kept out of Terraform variables.
security/iam_policy/tests/basic.tftest.hcl Good coverage of defaults, precedence, tag merging, and validation rejections; mock provider correctly overrides provider-computed fields only.
security/iam_policy/versions.tf Required version constraints and cloud {} block follow the Ravion platform conventions for managed state.
security/iam_policy/.terraform.lock.hcl Lock file includes both h1: platform hashes (linux_amd64 + darwin_arm64) and all required zh: registry checksums per AGENTS.md.
security/iam_policy/outputs.tf All outputs include descriptions and expose the expected policy attributes plus account ID and region.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A([Module inputs]) --> B{policy_json != null?}
    B -- Yes --> C[local.policy_document = var.policy_json]
    B -- No --> D{len policy_statements > 0?}
    D -- Yes --> E[data.aws_iam_policy_document.structured count=1]
    E --> F[local.policy_document = structured.json]
    D -- No --> G[precondition FAIL\ncount=0, one returns null]
    C --> H[aws_iam_policy.this]
    F --> H
    G -. blocked by precondition .-> H
    H --> I([Outputs: ARN, ID, name, path, attachment_count])
Loading

Reviews (2): Last reviewed commit: "code review" | Re-trigger Greptile

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Ravion Module Publish Plan

Dry run only. No Ravion API mutations were made.

Module Current Version New Version Description
rvn-aws-iam-policy n/a 0.1.0 Initial module definition with immutable policy identity fields and structured statement support.

Diffs

rvn-aws-iam-policy n/a -> 0.1.0

--- remote
+++ compiled
-
+description: Creates one reusable customer-managed AWS IAM policy from structured statements or a complete JSON policy document.
+name: AWS IAM Policy
+type: rvn-aws-iam-policy

rvn-aws-iam-policy n/a -> 0.1.0

--- remote
+++ compiled
+inputs:
+  - id: section_aws
+    label: AWS account & region
+    type: section
+  - id: aws_account_id
+    immutable: true
+    label: AWS account
+    required: true
+    type: string
+    values: $values:ravion/aws_accounts
+  - id: aws_region
+    immutable: true
+    label: Region
+    required: true
+    type: string
+    values: $values:aws/regions
+  - id: section_policy
+    label: IAM policy
+    type: section
+  - default: <<module.given_id>>
+    description: Name of the customer-managed IAM policy. Policy names must be unique within their path in the AWS account.
+    id: name
+    immutable: true
+    label: Policy name
+    patterns:
+      - message: 1-128 letters, numbers, plus, equals, comma, period, at, underscore, or hyphen characters.
+        pattern: ^[A-Za-z0-9+=,.@_-]{1,128}$
+    required: true
+    type: string
+  - description: Optional description stored on the IAM policy. AWS does not allow this value to be changed after creation.
+    id: description
+    immutable: true
+    label: Description
+    patterns:
+      - message: 1000 characters or fewer.
+        pattern: ^.{0,1000}$
+    type: string
+  - collapsible: true
+    default: /
+    description: IAM path for organizing the policy. Most policies should use the root path.
+    id: path
+    immutable: true
+    label: Path
+    patterns:
+      - message: Start and end with a slash, for example / or /application/.
+        pattern: ^/$|^/.*/$
+      - message: Asterisks are not allowed in IAM paths.
+        pattern: ^[^*]*$
+      - message: 512 characters or fewer.
+        pattern: ^.{1,512}$
+    required: true
+    type: string
+  - id: section_document
+    label: Policy document
+    type: section
+  - default: structured
+    description: Build the policy with structured statements or provide a complete JSON document.
+    id: policy_document_mode
+    label: Policy document format
+    required: true
+    type: string
+    values:
+      - label: Structured statements
+        value: structured
+      - label: JSON document
+        value: json
+  - default: []
+    description: Define permissions this policy grants or denies. Each statement matches Action or NotAction values against Resource or NotResource ARNs and can add conditions to narrow access. Prefer explicit actions and resource ARNs over wildcards.
+    id: policy_statements
+    item_inputs:
+      - description: Optional IAM statement ID.
+        id: sid
+        label: SID
+        required: false
+        type: string
+      - default: Allow
+        description: Whether this statement allows or denies the listed actions.
+        id: effect
+        label: Effect
+        required: true
+        type: string
+        values:
+          - label: Allow
+            value: Allow
+          - label: Deny
+            value: Deny
+      - default: Action
+        description: Match the listed actions or every applicable action except those listed.
+        id: action_match_mode
+        label: Action matching
+        required: true
+        type: string
+        values:
+          - label: Listed actions
+            value: Action
+          - label: All except listed actions
+            value: NotAction
+      - add_button_label: Add action
+        description: IAM actions granted or denied by this statement.
+        id: actions
+        label: Actions
+        placeholder: s3:GetObject
+        required: true
+        show_when:
+          action_match_mode: Action
+        type: string_array
+      - add_button_label: Add excluded action
+        description: IAM actions excluded from this statement's match. NotAction can create broad permissions and should be used carefully.
+        id: not_actions
+        label: Excluded actions (NotAction)
+        placeholder: iam:*
+        required: true
+        show_when:
+          action_match_mode: NotAction
+        type: string_array
+      - default: Resource
+        description: Match the listed resources or every applicable resource except those listed.
+        id: resource_match_mode
+        label: Resource matching
+        required: true
+        type: string
+        values:
+          - label: Listed resources
+            value: Resource
+          - label: All except listed resources
+            value: NotResource
+      - add_button_label: Add resource
+        description: Resource ARNs covered by this statement. Use wildcards only when the AWS service requires them.
+        id: resources
+        label: Resources
+        placeholder: arn:aws:s3:::my-bucket/*
+        required: true
+        show_when:
+          resource_match_mode: Resource
+        type: string_array
+      - add_button_label: Add excluded resource
+        description: Resource ARNs excluded from this statement's match. NotResource can create broad permissions and should be used carefully.
+        id: not_resources
+        label: Excluded resources (NotResource)
+        placeholder: arn:aws:s3:::my-bucket/protected/*
+        required: true
+        show_when:
+          resource_match_mode: NotResource
+        type: string_array
+      - default: []
+        description: Optional IAM conditions that further restrict this statement.
+        id: conditions
+        item_inputs:
+          - default: StringEquals
+            description: IAM condition operator used to compare the condition key and values. Common operators are listed, and custom IAM operators such as ForAnyValue:StringLike can be entered manually.
+            id: test
+            label: Condition operator
+            required: true
+            type: string
+            values:
+              - label: String equals
+                value: StringEquals
+              - label: String not equals
+                value: StringNotEquals
+              - label: String equals ignore case
+                value: StringEqualsIgnoreCase
+              - label: String not equals ignore case
+                value: StringNotEqualsIgnoreCase
+              - label: String like
+                value: StringLike
+              - label: String not like
+                value: StringNotLike
+              - label: Numeric equals
+                value: NumericEquals
+              - label: Numeric not equals
+                value: NumericNotEquals
+              - label: Numeric less than
+                value: NumericLessThan
+              - label: Numeric less than or equals
+                value: NumericLessThanEquals
+              - label: Numeric greater than
+                value: NumericGreaterThan
+              - label: Numeric greater than or equals
+                value: NumericGreaterThanEquals
+              - label: Date equals
+                value: DateEquals
+              - label: Date not equals
+                value: DateNotEquals
+              - label: Date less than
+                value: DateLessThan
+              - label: Date less than or equals
+                value: DateLessThanEquals
+              - label: Date greater than
+                value: DateGreaterThan
+              - label: Date greater than or equals
+                value: DateGreaterThanEquals
+              - label: Boolean
+                value: Bool
+              - label: Binary equals
+                value: BinaryEquals
+              - label: IP address
+                value: IpAddress
+              - label: Not IP address
+                value: NotIpAddress
+              - label: ARN equals
+                value: ArnEquals
+              - label: ARN not equals
+                value: ArnNotEquals
+              - label: ARN like
+                value: ArnLike
+              - label: ARN not like
+                value: ArnNotLike
+              - label: "Null"
+                value: "Null"
+          - description: IAM context key evaluated by the condition.
+            id: variable
+            label: Condition key
+            placeholder: aws:ResourceAccount
+            required: true
+            type: string
+          - add_button_label: Add condition value
+            description: Allowed or matched values for the condition key.
+            id: values
+            label: Condition values
+            placeholder: "123456789012"
+            required: true
+            type: string_array
+        item_label: Condition
+        label: Conditions
+        required: false
+        type: object_array
+    item_label: Policy statement
+    item_title:
+      fallback: Policy statement
+      template: "{effect}: {action_match_mode} on {resource_match_mode}"
+    label: Policy statements
+    required: true
+    show_when:
+      policy_document_mode: structured
+    type: object_array
+  - description: Complete IAM policy JSON document. This is used instead of structured statements.
+    id: policy_json
+    label: Policy JSON
+    patterns:
+      - message: Include a JSON object with Version and Statement properties.
+        pattern: ^\s*\{[\s\S]*"Version"[\s\S]*"Statement"[\s\S]*\}\s*$
+    placeholder: |-
+      {
+        "Version": "2012-10-17",
+        "Statement": [
+          {
+            "Effect": "Allow",
+            "Action": ["s3:GetObject"],
+            "Resource": ["arn:aws:s3:::my-bucket/*"]
+          }
+        ]
+      }
+    required: true
+    show_when:
+      policy_document_mode: json
+    type: text
+  - id: section_misc
+    label: Misc
+    type: section
+  - collapsible: true
+    description: A map of tags to assign to all resources. Default tags are `Owner`, `ProjectGivenId`, `EnvironmentGivenId`, `ModuleGivenId`, `ModuleId`
+    id: tags
+    label: Tags
+    required: false
+    type: keyvalue
+  - id: section_advanced
+    label: Terraform settings
+    type: section
+  - collapsible: true
+    description: Override the environment's default version for this module
+    id: opentofu_version
+    label: OpenTofu version override
+    required: false
+    type: string
+    values: $values:opentofu/versions
+  - collapsible: true
+    description: Override Terraform state backend workspace name. Defaults to project + environment + module given ids.
+    id: ravion_state_backend_workspace
+    immutable: true
+    label: Ravion Terraform workspace name
+    type: string
+  - collapsible: true
+    default: {}
+    description: Optional raw Terraform variable overrides for advanced module inputs or one-off overrides. Values here override the generated variables above.
+    id: advanced_terraform_variables
+    label: Advanced Terraform variables
+    required: false
+    type: object
+  - collapsible: true
+    description: Override the execution environment for Terraform runners. Must use the same AWS account as selected above.
+    id: execution_environment_id
+    label: Terraform execution environment
+    required: false
+    type: string
+    values: $values:ravion/execution_environments
+readme: |
+  Creates one reusable customer-managed AWS IAM policy from structured statements or a complete JSON policy document.
 
+  ## Overview
+
+  Use this module when permissions need to be managed independently from an IAM role. The policy ARN can be attached to one or more roles, reused across workloads, or supplied as a permissions boundary.
+
+  Customer-managed policies are versioned by AWS when their document changes. Keep statements narrowly scoped to the actions and resource ARNs each workload needs.
+
+  ## Use cases
+
+  | Scenario | Benefit |
+  | --- | --- |
+  | Shared workload permissions | Reuse one policy across several IAM roles without duplicating inline policy documents. |
+  | Permissions boundary | Set the maximum permissions that another IAM role can receive. |
+  | Independently managed access | Update permissions without combining policy ownership with trust relationships or instance profiles. |
+  | Complex policy document | Use complete JSON when a policy cannot be represented by the structured stateme
... diff truncated ...

Comment thread security/iam_policy/locals.tf Outdated
Comment thread security/iam_policy/tests/basic.tftest.hcl
@flybayer

Copy link
Copy Markdown
Member Author

@greptile

@flybayer
flybayer requested a review from mabadir July 23, 2026 21:21
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