Skip to main content

iam-floyd-usage

Expert guidance for using the iam-floyd and cdk-iam-floyd libraries to generate AWS IAM policy statements with a fluent, type-safe interface in TypeScript, JavaScript, Python, Java, C#/.NET and Go projects. Use this skill whenever a user asks how to write IAM policies with iam-floyd, wants to allow or deny AWS actions, needs to scope policies to specific resources, wants to add conditions to IAM statements, is working on least-privilege IAM in AWS CDK, or is trying to understand the library's API (toXxx, onXxx, ifXxx, allow/deny, allActions, etc.). Also trigger for questions about semantic policy classes, subclassing Statement providers, using Collections, policy documents with size limits and splitting, or converting JSON policies to iam-floyd code.

Source facts

Repository
udondan/iam-floyd
Last source activity
October 6, 2026 at 17:35
Detected SKILL.md language
English
Stars
571
Forks
20

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
iam-floyd-usage
description
Expert guidance for using the iam-floyd and cdk-iam-floyd libraries to generate AWS IAM policy statements with a fluent, type-safe interface in TypeScript, JavaScript, Python, Java, C#/.NET and Go projects. Use this skill whenever a user asks how to write IAM policies with iam-floyd, wants to allow or deny AWS actions, needs to scope policies to specific resources, wants to add conditions to IAM statements, is working on least-privilege IAM in AWS CDK, or is trying to understand the library's API (toXxx, onXxx, ifXxx, allow/deny, allActions, etc.). Also trigger for questions about semantic policy classes, subclassing Statement providers, using Collections, policy documents with size limits and splitting, or converting JSON policies to iam-floyd code.
# Using iam-floyd / cdk-iam-floyd IAM Floyd is a **fluent, type-safe AWS IAM policy statement generator**. Instead of writing error-prone JSON, you call strongly-typed methods and let the library build the correct policy structure. It comes in two variants with the same API, released together with the same version number in every language: - **`iam-floyd`** (standalone) creates statements as JSON, for the AWS SDKs, CloudFormation, Terraform or anything else that takes an IAM policy. The packages for Python, Java, .NET and Go are native: no Node.js, no dependencies. - **`cdk-iam-floyd`** creates AWS CDK v2 statements: every statement is an `iam.PolicyStatement`. The packages for Python, Java, .NET and Go are built with jsii, like the AWS CDK itself, and need Node.js. The examples in this skill are TypeScript. The API is the same in every language, with names adapted to the language, see [Other languages](#other-languages). ## Installation | Language | `iam-floyd` | `cdk-iam-floyd` | | ----------------------- | ------------------------------------------------ | --------------------------------------------------- | | TypeScript / JavaScript | `npm install iam-floyd` | `npm install cdk-iam-floyd` | | Python (3.9+) | `pip install iam-floyd` | `pip install cdk-iam-floyd` | | Java (11+) | Maven `com.udondan:iam-floyd` | Maven `com.udondan:cdk-iam-floyd` | | C# / .NET (8+) | `dotnet add package IAM.Floyd` | `dotnet add package CDK.IAM.Floyd` | | Go (1.21+) | `go get udondan.github.io/iam-floyd/go/iamfloyd` | `go get udondan.github.io/iam-floyd/go/cdkiamfloyd` | > **Pin the exact version** (e.g. `"iam-floyd": "0.850.0"` in `package.json`, > `iam-floyd==0.850.0` for pip) — the package is pre-1.0.0 and the API may change. > A new version is released every Monday. CDK v2 requires `cdk-iam-floyd >= 0.300.0`. > > The Go modules are not on GitHub, but on a module proxy under > `udondan.github.io/iam-floyd/go`, which keeps the newest 30 releases. `go get` > finds it without any configuration. ## Basic import ```typescript // TypeScript / ESM import { Statement } from 'iam-floyd'; import { Statement } from 'cdk-iam-floyd'; // CDK variant // CommonJS const { Statement } = require('iam-floyd'); ``` The statement providers (`Ec2`, `S3`, ...) live in a sub-package or namespace `statement`. The core classes (`Operator`, `Collection`, the policy documents, `AwsManagedPolicy`, `AwsServicePrincipal`) live in the package itself: | Language | `iam-floyd` | `cdk-iam-floyd` | | -------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------- | | Python | `from iam_floyd import Statement` | `from cdk_iam_floyd import Statement` | | Java | `com.udondan.iamFloyd.statement.Ec2`, core `com.udondan.iamFloyd.*` | `com.udondan.iamFloyd.cdk.statement.Ec2`, core `com.udondan.iamFloyd.cdk.*` | | C# | `using Statement = IAM.Floyd.Statement;`, core `using IAM.Floyd;` | `using Statement = CDK.IAM.Floyd.Statement;`, core `using CDK.IAM.Floyd;` | | Go | `.../go/iamfloyd/statement`, core `.../go/iamfloyd`, `.../collection` | `.../go/cdkiamfloyd/statement`, core and collection `.../go/cdkiamfloyd` | In Go, both imports are needed: `statement.NewEc2(nil)` and `iamfloyd.NewManagedPolicyDocument(...)`. --- ## Core vocabulary — the fluent chain Every statement follows this readable pattern: ```text new Statement.<Service>() // pick the AWS service .allow() | .deny() // effect (allow is the default) .toXxx() // actions ("to do something") .onXxx() // resources ("on a specific resource") .ifXxx() // conditions ("if a condition is met") ``` ### Effect — `allow()` / `deny()` The default effect is `Allow`, so `.allow()` is optional but improves readability. ```typescript new Statement.Ec2().allow().toStartInstances(); new Statement.Ec2().deny().toStopInstances(); ``` ### Actions — `to*()` Every documented IAM action has a typed `to*()` method: ```typescript new Statement.Ec2() .allow() .toStartInstances() .toStopInstances() .toDescribeInstances(); ``` **Bulk action helpers:** | Method | Effect | | -------------------------------------- | ----------------------------------------- | | `allActions()` | Adds `ec2:*` | | `allListActions()` | All actions with access level _List_ | | `allReadActions()` | All actions with access level _Read_ | | `allWriteActions()` | All actions with access level _Write_ | | `allPermissionManagementActions()` | All permission-management actions | | `allTaggingActions()` | All tagging actions | | `allMatchingActions('/pattern/flags')` | Regex match (JS literal style, as string) | > `allMatchingActions` and access-level methods expand to an **explicit list** at > call time — they won't auto-update if AWS adds new actions later. Use `.compact()` after access-level methods to collapse the list into wildcard patterns (reduces policy size, but future AWS actions may match unexpectedly): ```typescript new Statement.Ec2().allow().allReadActions().allListActions().compact(); // produces: ["ec2:Describe*", "ec2:Get*", ...] ``` **Missing action?** Use the generic `to()` escape hatch: ```typescript .to('missingAction') // becomes ec2:missingAction ``` ### Resources — `on*()` Every resource type has an `on*()` method that builds the correct ARN: ```typescript new Statement.S3() .allow() .allActions() .onBucket('example-bucket') .onObject('example-bucket', 'some/prefix/*'); new Statement.Lambda().allow().toInvokeFunction().onFunction('my-function'); // optional: account, region, partition params new Statement.Ec2() .allow() .toStartInstances() .toStopInstances() .onInstance('i-1234567890abcdef0'); ``` In **cdk-iam-floyd**, omitting account/region defaults to the CDK stack's values. In **iam-floyd** (standalone), they default to `*`. In **cdk-iam-floyd**, the `on*()` methods also take a CDK construct (L1 or L2) in place of the name, if aws-cdk-lib has a reference interface for it (`aws-cdk-lib/interfaces`, e.g. `IBucketRef`). The ARN of the construct is used; account, region and partition are ignored: ```typescript const bucket = new s3.Bucket(this, 'Bucket'); new Statement.S3().allow().toListBucket().onBucket(bucket); new Statement.Lambda().allow().toInvokeFunction().onFunction(myFunction); // lambda.IFunction ``` **Override defaults for multiple resources** using `in*()` / `in()`: ```typescript new Statement.Lambda() .allow() .toUpdateFunctionCode() .inAccount('098765432109') .inRegion('us-east-1') .inPartition('aws') .onFunction('my-function-1') .onFunction('my-function-2') // Shorthand: .in('098765432109', 'us-east-1', 'aws') .onFunction('my-function-1') // Switch context mid-statement: .in('111111111111', 'eu-west-1', 'aws') .onFunction('cross-account-function'); ``` > `in*()` methods set defaults **only for resources added after them** — call them > before the `on*()` calls they should affect. **Already have an ARN?** Use the generic `on()`: ```typescript .on('arn:aws:s3:::my-bucket', 'arn:aws:s3:::another-bucket') ``` ### Conditions — `if*()` Every documented condition key has an `if*()` method. Global AWS conditions start with `ifAws*`. ```typescript new Statement.Ec2() .allow() .toStartInstances() .ifEncrypted() // Bool condition .ifInstanceType(['t3.micro', 't3.nano']) // StringLike with multiple values .ifAssociatePublicIpAddress(false) // Bool: false .ifAwsRequestTag('Owner', 'alice'); // Tag condition ``` Multiple conditions on one statement are AND-ed together. For OR logic, use multiple statements. **Override the operator** (last argument): ```typescript .ifAwsRequestTag('Env', '*John*', 'StringEquals') // Or use the typed Operator class: import { Operator } from 'iam-floyd'; .ifAwsRequestTag('Env', '*John*', Operator.stringEquals) ``` > **Deny + condition operator trap**: When using `deny()` with a tag condition, the > operator direction matters a lot. The default operator on most `if*()` methods is > `StringLike`. So `.deny().toStopInstances().ifResourceTag('Owner', 'alice')` means > "deny stop _when_ the tag matches alice" — which denies the owner, not others. > To deny everyone _except_ the owner, flip it: > `.deny().toStopInstances().ifResourceTag('Owner', 'alice', Operator.stringNotEquals)` **Complex operators** (ForAllValues, ForAnyValue, IfExists): ```typescript import { Operator } from 'iam-floyd'; new Statement.Dynamodb() .allow() .toGetItem() .onTable('Thread') .ifAttributes( ['ID', 'Message'], new Operator().stringEquals().forAllValues(), ); new Statement.Ec2() .allow() .toStartInstances() .ifAwsRequestTag( 'Environment', ['Prod', 'Dev'], new Operator().stringEquals().ifExists(), ); ``` **Missing condition?** Use the generic `if()`: ```typescript
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub