AWS IAM Managed Policy
AWS Managed Policies are standalone identity-based policies that you can attach to multiple users, groups, and roles. They provide reusable permission sets following the principle of least privilege.
Quick Start
#r "../src/bin/Release/net8.0/publish/Amazon.JSII.Runtime.dll"
#r "../src/bin/Release/net8.0/publish/Constructs.dll"
#r "../src/bin/Release/net8.0/publish/Amazon.CDK.Lib.dll"
#r "../src/bin/Release/net8.0/publish/FsCDK.dll"
open FsCDK
open Amazon.CDK
open Amazon.CDK.AWS.IAM
open Amazon.CDK.AWS.S3
Basic Managed Policy
Create a managed policy with explicit permissions.
stack "BasicManagedPolicy" {
managedPolicy "S3ReadPolicy" {
description "Read-only access to S3 bucket"
managedPolicyName "S3ReadOnlyPolicy"
policyStatement {
effect Effect.ALLOW
actions [ "s3:GetObject"; "s3:ListBucket" ]
resources [ "arn:aws:s3:::my-bucket"; "arn:aws:s3:::my-bucket/*" ]
}
}
}
Policy with Multiple Statements
Combine multiple permissions in a single policy.
stack "MultiStatementPolicy" {
let s3Statement =
PolicyStatement(
PolicyStatementProps(
Sid = "S3Access",
Effect = Effect.ALLOW,
Actions = [| "s3:GetObject"; "s3:PutObject" |],
Resources = [| "arn:aws:s3:::data-bucket/*" |]
)
)
let dynamoStatement =
PolicyStatement(
PolicyStatementProps(
Sid = "DynamoDBAccess",
Effect = Effect.ALLOW,
Actions = [| "dynamodb:GetItem"; "dynamodb:PutItem" |],
Resources = [| "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable" |]
)
)
managedPolicy "DataAccessPolicy" {
description "Access to S3 and DynamoDB"
statements [ s3Statement; dynamoStatement ]
}
}
Using Helper Methods
FsCDK provides convenient helpers for common permission patterns.
stack "HelperMethodsPolicy" {
managedPolicy "QuickAccessPolicy" {
description "Quick policy using helpers"
allow [ "s3:GetObject"; "s3:ListBucket" ] [ "arn:aws:s3:::my-bucket/*" ]
deny [ "s3:DeleteObject" ] [ "arn:aws:s3:::my-bucket/*" ]
}
}
Using Pre-Built Statements
Use the ManagedPolicyStatements module for common scenarios.
stack "PreBuiltStatements" {
let bucketArn = "arn:aws:s3:::my-bucket"
let tableArn = "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable"
managedPolicy "ApplicationPolicy" {
description "Standard application permissions"
statements
[ (ManagedPolicyStatements.s3ReadOnly bucketArn)
(ManagedPolicyStatements.dynamoDBFullAccess tableArn)
(ManagedPolicyStatements.cloudWatchLogsWrite "/aws/lambda/my-function") ]
}
}
Attaching to Roles
Attach policies to IAM roles for EC2, Lambda, or other services.
stack "PolicyWithRole" {
// Create a role for Lambda
let lambdaRole1 =
lambdaRole "my-function-role" {
basicExecution
vpcExecution
kmsDecrypt
xrayTracing
managedPolicy "AmazonS3ReadOnlyAccess"
inlinePolicy (IAM.allow [ "dynamodb:Query" ] [ "arn:aws:dynamodb:*:*:table/MyTable" ])
}
// Create and attach policy
managedPolicy "LambdaS3Policy" {
description "Lambda S3 access"
statement (ManagedPolicyStatements.s3FullAccess "arn:aws:s3:::lambda-bucket")
attachToRole lambdaRole1
}
}
Cross-Account Access Policy
Grant permissions for cross-account access.
stack "CrossAccountPolicy" {
managedPolicy "CrossAccountPolicy" {
description "Allow access from partner account"
policyStatement {
sid "CrossAccountS3Access"
effect Effect.ALLOW
actions [ "s3:GetObject"; "s3:ListBucket" ]
resources [ "arn:aws:s3:::shared-bucket"; "arn:aws:s3:::shared-bucket/*" ]
}
}
}
Conditional Permissions
Use conditions to restrict permissions based on context.
stack "ConditionalPolicy" {
let conds = System.Collections.Generic.Dictionary<string, obj>()
conds.Add("aws:SourceIp", [| "203.0.113.0/24" |] :> obj)
managedPolicy "IPRestrictedPolicy" {
description "S3 access only from specific IP range"
policyStatement {
sid "IPRestrictedAccess"
effect Effect.ALLOW
actions [ "s3:*" ]
resources [ "arn:aws:s3:::secure-bucket/*" ]
conditions [ "IpAddress", conds ]
}
}
}
Secrets Manager Access
Grant access to AWS Secrets Manager secrets.
stack "SecretsPolicy" {
let secretArn =
"arn:aws:secretsmanager:us-east-1:123456789012:secret:MySecret-AbCdEf"
managedPolicy "SecretsAccessPolicy" {
description "Access to application secrets"
ManagedPolicyStatements.secretsManagerRead secretArn
}
}
KMS Encryption Policy
Grant permissions to use KMS keys for encryption/decryption.
stack "KMSPolicy" {
let kmsKeyArn =
"arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
managedPolicy "KMSAccessPolicy" {
description "KMS key usage for encryption"
ManagedPolicyStatements.kmsDecrypt kmsKeyArn
}
}
Lambda Execution Policy
Complete policy for Lambda function execution.
stack "LambdaExecutionPolicy" {
let functionName = "my-function"
let logGroupArn = $"/aws/lambda/{functionName}"
let bucketArn = "arn:aws:s3:::lambda-data"
let tableArn = "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable"
managedPolicy "LambdaFullAccessPolicy" {
description "Complete Lambda execution permissions"
statements
[ ManagedPolicyStatements.cloudWatchLogsWrite logGroupArn
ManagedPolicyStatements.s3FullAccess bucketArn
ManagedPolicyStatements.dynamoDBFullAccess tableArn ]
}
}
Read-Only Policy
Create a read-only policy for auditors or monitoring.
stack "ReadOnlyPolicy" {
managedPolicy "AuditorPolicy" {
description "Read-only access for auditing"
ManagedPolicyStatements.ec2Describe ()
ManagedPolicyStatements.s3ReadOnly "arn:aws:s3:::audit-logs"
ManagedPolicyStatements.dynamoDBReadOnly "arn:aws:dynamodb:us-east-1:123456789012:table/*"
}
}
Deny Override Policy
Use deny statements to prevent specific actions (overrides allows).
stack "DenyOverridePolicy" {
let allowStatement =
PolicyStatement(
PolicyStatementProps(
Sid = "AllowS3Access",
Effect = Effect.ALLOW,
Actions = [| "s3:*" |],
Resources = [| "arn:aws:s3:::my-bucket/*" |]
)
)
let denyStatement =
PolicyStatement(
PolicyStatementProps(
Sid = "DenyDeleteActions",
Effect = Effect.DENY,
Actions = [| "s3:DeleteObject"; "s3:DeleteBucket" |],
Resources = [| "arn:aws:s3:::my-bucket"; "arn:aws:s3:::my-bucket/*" |]
)
)
managedPolicy "SafeS3Policy" {
description "S3 access without delete permissions"
statements [ allowStatement; denyStatement ]
}
}
Best Practices
Security
- Follow principle of least privilege
- Use specific resources instead of wildcards when possible
- Add explicit deny statements for sensitive actions
- Use conditions to limit scope (IP, time, MFA)
- Regularly audit and review policies
Operational Excellence
- Use descriptive Sid values for each statement
- Add meaningful descriptions to policies
- Group related permissions together
- Version policies using Git
- Test policies in non-production first
Organization
- Create reusable policies for common patterns
- Use consistent naming conventions
- Organize policies by service or team
- Use paths to organize policies hierarchically
- Attach policies to roles, not users directly
Compliance
- Document why each permission is needed
- Set up AWS Config rules to monitor policies
- Enable CloudTrail to audit policy usage
- Review policies during security audits
- Implement policy change approval workflows
Maintenance
- Remove unused policies regularly
- Consolidate duplicate policies
- Update policies when AWS introduces new services
- Monitor for policy changes in CloudTrail
- Use IAM Access Analyzer to validate policies
<summary>Creates an AWS CDK Stack construct.</summary>
<param name="name">The name of the stack.</param>
<code lang="fsharp"> stack "MyStack" { lambda myFunction bucket myBucket } </code>
<summary>Creates a Managed Policy with AWS IAM best practices.</summary>
<param name="name">The policy name.</param>
<code lang="fsharp"> managedPolicy "S3ReadPolicy" { description "Read-only access to S3 buckets" statements [ policyStatement { effect Effect.ALLOW actions [ "s3:GetObject" ] resources [ "*" ] } ] attachToRole myRole } </code>
<summary>Sets the policy description.</summary>
<param name="config">The current managed policy configuration.</param>
<param name="description">The policy description.</param>
<code lang="fsharp"> managedPolicy "MyPolicy" { description "This is my custom managed policy" ... } </code>
<summary>Sets the managed policy name.</summary>
<param name="config">The current managed policy configuration.</param>
<param name="name">The policy name as it appears in IAM.</param>
<code lang="fsharp"> managedPolicy "MyPolicy" { managedPolicyName "CustomPolicyName" ... } </code>
type PolicyStatement = inherit DeputyBase new: ?props: IPolicyStatementProps -> unit member AddAccountCondition: accountId: string -> unit member AddAccountRootPrincipal: unit -> unit member AddActions: [<ParamArray>] actions: string array -> unit member AddAllResources: unit -> unit member AddAnyPrincipal: unit -> unit member AddArnPrincipal: arn: string -> unit member AddAwsAccountPrincipal: accountId: string -> unit member AddCanonicalUserPrincipal: canonicalUserId: string -> unit ...
--------------------
PolicyStatement(?props: IPolicyStatementProps) : PolicyStatement
type PolicyStatementProps = interface IPolicyStatementProps new: unit -> unit member Actions: string array member Conditions: IDictionary<string,obj> member Effect: Nullable<Effect> member NotActions: string array member NotPrincipals: IPrincipal array member NotResources: string array member Principals: IPrincipal array member Resources: string array ...
--------------------
PolicyStatementProps() : PolicyStatementProps
<summary>Adds a policy statement.</summary>
<param name="config">The current managed policy configuration.</param>
<param name="statement">The policy statement to add.</param>
<code lang="fsharp"> managedPolicy "MyPolicy" { statements [ policyStatement { effect Effect.ALLOW actions [ "s3:GetObject" ] resources [ "*" ] } ] } </code>
<summary>Adds a statement allowing specific actions on specific resources.</summary>
<summary>Adds a statement denying specific actions on specific resources.</summary>
<summary> Creates a statement for S3 read-only access </summary>
<summary> Creates a statement for DynamoDB full access </summary>
<summary> Creates a statement for CloudWatch Logs write access </summary>
type Dictionary<'TKey,'TValue> = interface ICollection<KeyValuePair<'TKey,'TValue>> interface IEnumerable<KeyValuePair<'TKey,'TValue>> interface IEnumerable interface IDictionary<'TKey,'TValue> interface IReadOnlyCollection<KeyValuePair<'TKey,'TValue>> interface IReadOnlyDictionary<'TKey,'TValue> interface ICollection interface IDictionary interface IDeserializationCallback interface ISerializable ...
<summary>Represents a collection of keys and values.</summary>
<typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
<typeparam name="TValue">The type of the values in the dictionary.</typeparam>
--------------------
System.Collections.Generic.Dictionary() : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(dictionary: System.Collections.Generic.IDictionary<'TKey,'TValue>) : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(collection: System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<'TKey,'TValue>>) : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(comparer: System.Collections.Generic.IEqualityComparer<'TKey>) : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(capacity: int) : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(dictionary: System.Collections.Generic.IDictionary<'TKey,'TValue>, comparer: System.Collections.Generic.IEqualityComparer<'TKey>) : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(collection: System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<'TKey,'TValue>>, comparer: System.Collections.Generic.IEqualityComparer<'TKey>) : System.Collections.Generic.Dictionary<'TKey,'TValue>
System.Collections.Generic.Dictionary(capacity: int, comparer: System.Collections.Generic.IEqualityComparer<'TKey>) : System.Collections.Generic.Dictionary<'TKey,'TValue>
val string: value: 'T -> string
--------------------
type string = System.String
<summary> Creates a statement for Secrets Manager read access </summary>
<summary> Creates a statement for KMS decrypt permissions </summary>
<summary> Creates a statement for S3 full access </summary>
<summary> Creates a statement for EC2 describe permissions (read-only) </summary>
<summary> Creates a statement for DynamoDB read-only access </summary>
FsCDK