cfn2iam
Generate the IAM policy a CloudFormation stack needs, from its template, before you deploy it.
Deploy roles are usually far broader than the stack needs, often AdministratorAccess, because working out the minimum by hand means reading the docs for every resource type in the template. IAM Access Analyzer can generate a policy, but it works from CloudTrail, so you have to deploy with broad permissions first and narrow them afterwards. cfn2iam reads the template instead.
Install
pip install cfn2iam # or: uv tool install cfn2iam
pip install "cfn2iam[iam]" # adds boto3, for --create-role and registry lookups of private types
Requires Python 3.9+ and network access to the schema host (see How it works).
Usage
cfn2iam template.yaml
This writes policy-<random>.json to the current directory:
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["s3:CreateBucket", "s3:GetBucketTagging", "..."], "Resource": "*" },
{ "Effect": "Deny", "Action": ["s3:DeleteBucket", "..."], "Resource": "*" }
]
}
| Option | Effect |
|---|---|
-d, --allow-delete |
Allow the delete-only actions instead of denying them |
-c, --create-role |
Also create an IAM role CloudFormation can assume, with this policy inline (needs cfn2iam[iam] and AWS credentials) |
-r, --role-name NAME |
Role name for --create-role (default cfn2iam-<random>) |
-p, --permissions-boundary ARN |
Permissions boundary for the created role |
--ignore-unknown |
Skip resource types found in neither the public schemas nor the CloudFormation registry, instead of failing |
--registry |
Look up every resource type with CloudFormation DescribeType in your account instead of the published schemas (needs cfn2iam[iam] and AWS credentials) |
--region REGION |
Region for CloudFormation registry lookups (default: your AWS config) |
--version |
Print the version |
Examples:
cfn2iam template.yaml -d # allow deletes, e.g. for stacks you tear down
cfn2iam template.yaml -c -r MyDeployRole # create the role as well
cfn2iam template.yaml -c -p arn:aws:iam::123456789012:policy/boundary
How it works
- Reads the template (JSON or YAML, including short-form intrinsics like
!Ref) and collects the resource types. - Expands SAM resources (
AWS::Serverless::*) into the resources SAM creates, using rules that check the resource's properties (for example, a function with an SQS event also needs the event source mapping). - Fetches each type's CloudFormation resource schema from mrlikl.github.io/cfn2iam/backend/schemas. These are AWS's published schemas, refreshed weekly by a GitHub workflow. The SAM expansion rules live next to them, in
backend/sam_rules. - For a type with no public schema (a private type, or a third-party type activated in your account), it calls CloudFormation
DescribeTypein your account and region. This needscfn2iam[iam], AWS credentials andcloudformation:DescribeType. With--registry, every type is looked up this way; SAM rules still come from the published rules. - Takes the permissions each schema lists for its
create,read,updateandlisthandlers as Allow, and the permissions only itsdeletehandler needs as Deny (or Allow with-d).
If any resource type can't be resolved, cfn2iam lists them, writes no policy, and exits with status 1. A partial policy would fail mid-deploy at best. Network failures can't be skipped; types found nowhere can, with --ignore-unknown.
Limitations
- Actions, not resources. Every statement uses
"Resource": "*". Resource ARNs mostly don't exist until the stack does, so the policy is least-privilege on actions only. - The delete statement is an explicit Deny. An explicit Deny overrides an Allow from any other policy attached to the same role. Use
-dif the role also has to delete these resources. - Custom resources are skipped (
Custom::*,AWS::CloudFormation::CustomResource,AWS::CDK::Metadata). Anything they need, such as permission to invoke their Lambda function, isn't included. - The policy is only as complete as AWS's schemas. The handler permission lists are maintained by AWS and can be incomplete for some resource types or configurations. Test the policy on a non-production stack first.
License
MIT. See LICENSE.
Metadata
Release files for cfn2iam 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cfn2iam-0.2.1.tar.gz | 33.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cfn2iam-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 42.4 kB
Release files / cfn2iam-0.2.1.tar.gz
| Download URL | cfn2iam-0.2.1.tar.gz |
|---|---|
| Size | 33.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dfb02fc6f994971b3b23ee30da96c280b5a950dccb9ab2e1472a51bac73d09a0
|
|
BLAKE2b-256 checksum How to use checksums |
fc57d41ea28ebb9ee22967d7fb09727ea1c4f7b3586d74f3905efe77d4161e7f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / cfn2iam-0.2.1-py3-none-any.whl
| Download URL | cfn2iam-0.2.1-py3-none-any.whl |
|---|---|
| Size | 9.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
342ca147fcddbbaac3847bdc82ff98f7acc0ed8b331d126b45e6601b74ffa633
|
|
BLAKE2b-256 checksum How to use checksums |
b6e9d4066015c480665005e6d84a01ca98a7d674be7c0d3bb848e4e9157c92b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|