udondan/iam-floyd/iam-floyd-usage

Claude Code and agent skill by udondan/iam-floyd

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

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.

Install

npx vskill@latest install udondan/iam-floyd/iam-floyd-usage

SKILL.md

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.

Installation

Languageiam-floydcdk-iam-floyd
TypeScript / JavaScriptnpm install iam-floydnpm install cdk-iam-floyd
Python (3.10+)pip install iam-floydpip install cdk-iam-floyd
Java (11+)Maven com.udondan:iam-floydMaven com.udondan:cdk-iam-floyd
C# / .NET (8+)dotnet add package IAM.Floyddotnet add package CDK.IAM.Floyd
Go (1.21+)go get udondan.github.io/iam-floyd/go/iamfloydgo 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:

Languageiam-floydcdk-iam-floyd
Pythonfrom iam_floyd import Statementfrom cdk_iam_floyd import Statement
Javacom.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:

MethodEffect
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
.if('ec2:missingCondition', 'some-value') // defaults to StringLike
Principals — for*()
In cdk-iam-floyd, avoid building assume-role policies with iam-floyd — use
CDK's iam.PolicyDocument / iam.ManagedPolicy with a principal instead. iam-floyd's
for*() methods are mainly useful for resource-based policies (S3 bucket policies, etc.)
typescript
new Statement.Sts()
.allow()
.toAssumeRole()
.forAccount('123456789012') // Account root principal
.forUser('123456789012', 'Alice', 'Bob') // IAM users (same account)
.forRole('123456789012', 'my-role') // IAM role ARN
.forService('lambda.amazonaws.com') // AWS service
.forService(AwsServicePrincipal.ECS_TASKS) // AWS service, by constant
.forFederatedCognito() // Cognito identity pool
.forPublic() // Principal: *
.for('arn:foo:bar'); // Arbitrary ARN
// CDK only — accepts iam.IPrincipal objects:
new Statement.Sts()
.allow()
.toAssumeRole()
.forCdkPrincipal(
new iam.ServicePrincipal('sns.amazonaws.com'),
new iam.ServicePrincipal('lambda.amazonaws.com'),
);
NotAction / NotResource / NotPrincipal
Understand these well before using — they can be surprisingly permissive.
typescript
// Allow everything EXCEPT delete on this bucket:
new Statement.S3()
.allow()
.notAction()
.toDeleteBucket()
.onBucket('example-bucket');
// Deny all S3 actions NOT on this bucket:
new Statement.S3()
.allow()
.notResource()
.toDeleteBucket()
.onBucket('example-bucket');
// Deny all S3 actions for anyone who is NOT Bob:
new Statement.S3()
.deny()
.allActions()
.notPrincipal()
.forUser('1234567890', 'Bob')
.onObject('example-bucket', '*');
Statement SID
typescript
new Statement.Ec2('AllowEC2ReadOnly').allow().allReadActions();

Building a complete policy

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
573
Repository forks
21
7-day trend score
32

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/udondan/iam-floyd/iam-floyd-usage/badge)](https://verified-skill.com/skills/udondan/iam-floyd/iam-floyd-usage)

Something wrong with this skill or its page? Tell us.