IAM Policy Generator for Go

Paste Go code that uses the AWS SDK for Go v2 and get a draft IAM policy covering the actions it calls, ready to scope and attach to your service's role.

Your codeGo (AWS SDK for Go)
Drop the file to load it
Tab indents · Esc, Tab exits
ResultIAM policy JSON
Your IAM policy JSON will appear hereClick Generate IAM policy or press Ctrl Enter
policy.json
Don't paste secrets

How to generate an IAM policy from Go code

To generate an IAM policy from Go code, paste the file that creates AWS clients with NewFromConfig into the editor above and press Generate IAM policy. Each client method, such as ReceiveMessage, becomes the matching IAM action, grouped by resource. Then fill in any wildcard ARNs and validate the policy before attaching it.

  1. Paste the Go codeAdd the file or package that builds your clients and calls them, using Paste, Open file (.go or .txt, up to 500 KB) or drag and drop. Sample loads a worker that archives SQS messages to S3.
  2. Let the secret check runYour code is scanned in the browser for AWS access keys, secret keys, private keys and API tokens before it's sent anywhere.
  3. Generate the policyClick Generate IAM policy or press Ctrl + Enter. The JSON streams in, and you can stop the run at any time.
  4. Check the hidden permissionsLook for calls that need more than one permission: SSE-KMS writes, waiters, the S3 transfer manager and anything that passes a role. The diagram below lists the common ones.
  5. Scope, validate and attachReplace wildcards with real ARNs, validate with IAM Access Analyzer, download policy.json and attach it to the ECS task role, EC2 instance role or Lambda execution role.
Pipeline from a Go file to an IAM policy: main.go imports the S3 and SQS services, clients are created with NewFromConfig, the methods ReceiveMessage, DeleteMessage and PutObject are called, and policy.json lists the matching sqs and s3 actions
Clients, then methods, then actions: how the sample's calls become a policy.

Why generate an IAM policy from Go code

Go services tend to be long-running: queue workers, API backends on ECS or EKS, and CLIs that platform teams hand to everyone. Their roles often start broad during development and never get trimmed. Generating a policy from the methods the code actually calls gives you a precise list to replace that broad policy with.

It's useful before the first deployment, when there's no CloudTrail history to learn from, and during code review, when a change adds a new client or method and the role needs to follow. Because the AWS SDK for Go v2 names every method after its API operation, the mapping from code to IAM action is unusually direct.

What the generator can't see is anything decided at runtime: bucket names from flags or config files, the account and region from the loaded config, and calls made in packages you didn't paste. Once the service has run in a test account, IAM Access Analyzer policy generation can build a policy from its CloudTrail activity. Comparing the two is the most reliable way to catch gaps.

Comparison of generating an IAM policy from Go source code, which works before deployment but cannot see runtime values, with IAM Access Analyzer policy generation from up to 90 days of CloudTrail activity, which sees real resources but only paths that ran
Code-based and activity-based generation catch different things. Using both is the safest route.

How Go SDK calls become IAM actions

In the AWS SDK for Go v2, each client method is named after the API operation it calls, so the IAM mapping is usually direct: ReceiveMessage needs sqs:ReceiveMessage, DeleteMessage needs sqs:DeleteMessage, and PutObject needs s3:PutObject. The generator finds the clients created with NewFromConfig and the methods called on them, and groups the actions into statements by service.

The IAM prefix doesn't always match the Go package. The eventbridge package's PutEvents needs events:PutEvents, and the cloudwatchlogs package uses the logs: prefix. Some calls need extra permissions, too: writing to a bucket encrypted with a customer managed KMS key also needs kms:GenerateDataKey, and code that hands a role to Lambda or ECS needs iam:PassRole. The Service Authorization Reference documents the exact actions and resource types for every service.

Paginators and waiters call ordinary operations under the hood. dynamodb.NewScanPaginator repeatedly calls Scan, and s3.NewObjectExistsWaiter polls HeadObject, which is authorized by s3:GetObject.

Code written for the older AWS SDK for Go v1 (github.com/aws/aws-sdk-go) calls the same API operations, so it needs the same IAM actions. If you're porting Python automation to Go, the boto3 to Go converter can do the first draft, and you can generate the policy from its output.

Go SDK calls that need more than one IAM permission: PutObject to an SSE-KMS bucket needs s3:PutObject and kms:GenerateDataKey, CreateFunction with a role needs lambda:CreateFunction and iam:PassRole, and ListObjectsV2 needs s3:ListBucket on the bucket ARN
The method name tells you the main action. Encryption and roles add more.

AWS SDK for Go v2 calls and the IAM actions they need

A quick reference for common Go SDK calls, including the ones where the package, method and permission don't line up.

AWS SDK for Go v2 calls, IAM actions and resources
Go callIAM actionResource
sqs.ReceiveMessage, DeleteMessagesqs:ReceiveMessage, sqs:DeleteMessageThe queue ARN, not the queue URL
s3.ListObjectsV2s3:ListBucketarn:aws:s3:::bucket (the bucket itself)
manager.Uploader.Uploads3:PutObject, plus s3:AbortMultipartUploadarn:aws:s3:::bucket/key
s3.NewObjectExistsWaiters3:GetObject (the waiter calls HeadObject)arn:aws:s3:::bucket/key
dynamodb.NewScanPaginatordynamodb:Scanarn:aws:dynamodb:region:account:table/NAME
eventbridge.PutEventsevents:PutEventsarn:aws:events:region:account:event-bus/NAME
kinesis.PutRecordskinesis:PutRecordsarn:aws:kinesis:region:account:stream/NAME
ecr.GetAuthorizationTokenecr:GetAuthorizationToken* (no resource-level permissions)
sts.GetCallerIdentityNone neededWorks even when every other action is denied

Key features

  • Follows clients to their methodsFinds clients created with NewFromConfig and maps each method called on them to an IAM action.
  • Reads paginators and waitersPaginators like NewScanPaginator and waiters like NewObjectExistsWaiter are mapped to the operations they call.
  • Exact ARNs from constantsQueue URLs, bucket names and table names defined as constants become precise ARNs, as in the sample's 123456789012:orders queue.
  • Wildcards where values come from configNames from flags, environment variables and config files, plus unknown regions and accounts, show up as * so you know what to fill in.
  • Nothing inventedPolicy JSON has no comments, so actions the model can't infer from your code are left out instead of guessed. Check the draft against your calls.
  • Download as policy.jsonCopy the result or save it as policy.json for the console, CLI, CDK or Terraform.
  • Secret check before sendingKeys and tokens are flagged in your browser before any code leaves it.

Examples: Go code and the IAM policy it needs

Three patterns from real Go services, with a correct least-privilege policy for each. Choose Try this example to load the code into the generator and compare its draft with the policy shown here.

Clean up expired sessions with a scan paginator

The paginator calls Scan once per page. Deleting items is a separate action on the same table.

Go (AWS SDK for Go)
package sessions

import (
	"context"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)

func DeleteExpired(ctx context.Context, db *dynamodb.Client) error {
	now := strconv.FormatInt(time.Now().Unix(), 10)
	p := dynamodb.NewScanPaginator(db, &dynamodb.ScanInput{
		TableName:                 aws.String("sessions"),
		FilterExpression:          aws.String("expiresAt < :now"),
		ExpressionAttributeValues: map[string]types.AttributeValue{
			":now": &types.AttributeValueMemberN{Value: now},
		},
	})
	for p.HasMorePages() {
		page, err := p.NextPage(ctx)
		if err != nil {
			return err
		}
		for _, item := range page.Items {
			_, err := db.DeleteItem(ctx, &dynamodb.DeleteItemInput{
				TableName: aws.String("sessions"),
				Key:       map[string]types.AttributeValue{"id": item["id"]},
			})
			if err != nil {
				return err
			}
		}
	}
	return nil
}
IAM policy JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:Scan",
        "dynamodb:DeleteItem"
      ],
      "Resource": "arn:aws:dynamodb:*:*:table/sessions"
    }
  ]
}

Upload large files with the S3 transfer manager

Multipart uploads are authorized by s3:PutObject. When an upload fails, the uploader aborts it, which needs s3:AbortMultipartUpload. A code-only draft may leave that out.

Go (AWS SDK for Go)
package backup

import (
	"context"
	"os"
	"path/filepath"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

func UploadDump(ctx context.Context, client *s3.Client, path string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()

	uploader := manager.NewUploader(client)
	_, err = uploader.Upload(ctx, &s3.PutObjectInput{
		Bucket: aws.String("acme-db-backups"),
		Key:    aws.String("nightly/" + filepath.Base(path)),
		Body:   f,
	})
	return err
}
IAM policy JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:AbortMultipartUpload"
      ],
      "Resource": "arn:aws:s3:::acme-db-backups/nightly/*"
    }
  ]
}

Publish an event to a custom EventBridge bus

The Go package is eventbridge, but the IAM prefix is events. The resource is the event bus, not a rule.

Go (AWS SDK for Go)
package orders

import (
	"context"
	"encoding/json"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/eventbridge"
	"github.com/aws/aws-sdk-go-v2/service/eventbridge/types"
)

func PublishShipped(ctx context.Context, eb *eventbridge.Client, orderID string) error {
	detail, _ := json.Marshal(map[string]string{"orderId": orderID})
	_, err := eb.PutEvents(ctx, &eventbridge.PutEventsInput{
		Entries: []types.PutEventsRequestEntry{{
			EventBusName: aws.String("orders"),
			Source:       aws.String("acme.orders"),
			DetailType:   aws.String("OrderShipped"),
			Detail:       aws.String(string(detail)),
		}},
	})
	return err
}
IAM policy JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "events:PutEvents",
      "Resource": "arn:aws:events:*:*:event-bus/orders"
    }
  ]
}

Tips for better results

  • Paste the package, not just main.go. Methods on helper structs and interfaces that wrap SDK clients are only visible if their code is included.
  • Keep constants in view. When a queue URL or bucket name is a const, the generator can build the exact ARN. Values loaded from flags or config become wildcards.
  • Look for waiters and the transfer manager. They call operations you don't see by name, such as HeadObject or AbortMultipartUpload. Check the draft includes what they need.
  • Test the calls that matter. The IAM policy simulator shows whether a specific action on a specific ARN is allowed before you deploy.
  • Compare with real activity after a test run. IAM Access Analyzer policy generation can build a policy from up to 90 days of the role's CloudTrail activity. Anything in one policy but not the other is worth a closer look.

Common mistakes to avoid

  • Using the Go package name as the IAM prefix. eventbridge is events:, cloudwatchlogs is logs:, and sfn is states:.
  • Denying the waiter's HeadObject. Object waiters need s3:GetObject. Without s3:ListBucket on the bucket, a missing object also returns 403 instead of 404, which can confuse retry logic.
  • Leaving out s3:AbortMultipartUpload. Failed transfer manager uploads can't clean up after themselves, and the orphaned parts keep costing money until a lifecycle rule removes them.
  • Trying to scope ecr:GetAuthorizationToken. It only works with "Resource": "*". Scope the image pull actions to the repository instead.
  • Forgetting iam:PassRole. Any call that sets a role on a Lambda function, ECS task or Step Functions state machine needs permission to pass that role, restricted to its ARN.
  • Adding a permission for GetCallerIdentity. STS allows it for every principal, so there's nothing to grant.

Frequently asked questions

How do I generate an IAM policy from Go code?

Paste the Go code that uses the AWS SDK into the editor at the top of this page and press Generate IAM policy. The generator maps each client method to its IAM action and groups them into policy JSON by resource. Fill in any wildcard ARNs, validate the policy and attach it to your service's role.

Which Go SDK versions does it support?

The sample and examples use the AWS SDK for Go v2, where clients are created with NewFromConfig. Code using the older v1 SDK calls the same API operations, so it maps to the same IAM actions.

Is the generated policy least-privilege?

It's a least-privilege starting point: only the actions your code calls, on the resources it can identify. Replace wildcards with exact ARNs, add conditions where they help, and check it with IAM Access Analyzer policy validation. Before you attach it, follow the checklist to review a generated IAM policy for least privilege.

Why does it use wildcards in some ARNs?

The generator reads code, not your account. Resource names from flags, environment variables or config files, and the region and account from config.LoadDefaultConfig, aren't in the source, so they appear as *. Object paths after / are written as wildcards too.

Does it handle paginators, waiters and the transfer manager?

It maps them to the operations they call, such as Scan for a scan paginator and PutObject for the uploader. Some helpers call extra operations, like AbortMultipartUpload on failure, so check the draft against the table above.

Can it miss permissions?

Yes. It can't see code you didn't paste, calls whose target is built at runtime, or permissions triggered indirectly, such as KMS for encrypted resources or iam:PassRole. Run your tests with the policy attached and look for AccessDenied errors. If a call still fails, here is how to troubleshoot AWS IAM access denied errors step by step.

Where should I attach the policy?

To the role your Go service runs as: the ECS task role, the EKS service account role, the EC2 instance profile role or the Lambda execution role. Paste the JSON into the IAM console, or copy it into your CDK or Terraform code.

Is my code stored?

No. The code is sent to an AI model hosted on NVIDIA's API only to produce the policy, and ChatWithCloud doesn't store or log it. Your latest draft stays in your browser. Replace real keys and passwords with placeholders first; the page warns you if it spots one. For the full picture, see whether it's safe to paste AWS code into an AI converter.

Is it free, and how much code can I paste?

Yes, it's free. Each run accepts up to 60,000 characters, and files up to 500 KB. Without an account you can generate 6 policies a minute and 60 a day. A free account raises that to 12 a minute and 200 a day and lists your recent runs on your dashboard. The guide to ChatWithCloud free converter limits shows how far they stretch for a real migration.

Related tools and next steps