Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module provides data types and combinators that allow you to declare,
encode, and decode the
IAM JSON policy
language. The available Action
and Condition
keys can be found under the
AWS Service Actions and Condition Context Keys for Use in IAM policies
documentation.
Lenses and prisms for those wanting to traverse and manipulate policy documents and their constituent elements can be found in the Amazonka.IAM.Policy.Lens module.
Synopsis
- type Document = Policy Statement
- data Policy a = Policy {}
- document :: NonEmpty a -> Policy a
- singleton :: a -> Policy a
- encode :: Policy Statement -> ByteString
- data Block a
- data Match a
- some :: a -> Block a
- not :: a -> Block a
- any :: Block a
- none :: Block a
- data Version
- newtype Id = Id {}
- data Statement = Statement {}
- allow :: Statement
- deny :: Statement
- newtype Sid = Sid {}
- data Principal
- data Effect
- newtype Action = Action {
- fromAction :: Text
- newtype Resource = Resource {
- fromResource :: Text
- newtype Key = Key {}
- data Condition
- = StringEquals !Key !Text
- | StringNotEquals !Key !Text
- | StringEqualsIgnoreCase !Key !Text
- | StringNotEqualsIgnoreCase !Key !Text
- | StringLike !Key ![Text]
- | StringNotLike !Key ![Text]
- | NumericEquals !Key !Scientific
- | NumericNotEquals !Key !Scientific
- | NumericLessThan !Key !Scientific
- | NumericLessThanEquals !Key !Scientific
- | NumericGreaterThan !Key !Scientific
- | NumericGreaterThanEquals !Key !Scientific
- | DateEquals !Key !UTCTime
- | DateNotEquals !Key !UTCTime
- | DateLessThan !Key !UTCTime
- | DateLessThanEquals !Key !UTCTime
- | DateGreaterThan !Key !UTCTime
- | DateGreaterThanEquals !Key !UTCTime
- | Bool !Key !Bool
- | BinaryEquals !Key !ByteString
- | IpAddress !Key !ByteString
- | NotIpAddress !Key !ByteString
- | ArnEquals !Key !Text
- | ArnLike !Key !Text
- | ArnNotEquals !Key !Text
- | ArnNotLike !Key !Text
Usage
It's recommended that you import and use this module qualified to avoid any ambiguity with prelude functions.
The following is an example of using the Semigroup
instance of Policy
to
construct a document from multiple statements. This example creates a policy
that would allow an IAM user sufficient privilege to rotate their credentials:
{-# LANGUAGE OverloadedStrings #-} import qualified Amazonka.IAM.Policy as Policy ( Policy.singleton (Policy.allow { Policy.action = Policy.some [ "iam:ListUsers" , "iam:GetAccountPasswordPolicy" ] , Policy.resource = Policy.any }) <> Policy.singleton (Policy.allow { Policy.action = Policy.some [ "iam:*AccessKey*" , "iam:ChangePassword" , "iam:GetUser" , "iam:*ServiceSpecificCredential*" , "iam:*SigningCertificate*" ] , Policy.resource = Policy.some [ "arn:aws:iam::*:user/${aws:username}" ] }) )
Which results in the following encoded IAM JSON policy document:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:ListUsers", "iam:GetAccountPasswordPolicy" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "iam:*AccessKey*", "iam:ChangePassword", "iam:GetUser", "iam:*ServiceSpecificCredential*", "iam:*SigningCertificate*" ], "Resource": "arn:aws:iam::*:user/${aws:username}" } ] }
You can also use the OverloadedLists
extension with the document
smart constructor
to create a Policy
using the IsList
instance for NonEmpty
. The following example
sets up S3 bucket management:
{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} import qualified Amazonka.IAM.Policy as Policy Policy.document [ Policy.allow { Policy.action = Policy.some ["s3:*"] , Policy.resource = Policy.some [ "arn:aws:s3:::BUCKET-NAME" , "arn:aws:s3:::BUCKET-NAME/*" ] } , Policy.deny { Policy.action = Policy.not ["s3:*"] , Policy.resource = Policy.not [ , "arn:aws:s3:::BUCKET-NAME" , "arn:aws:s3:::BUCKET-NAME/*" ] } ]
Resulting in the following encoded IAM JSON policy document:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": [ "arn:aws:s3:::<BUCKET-NAME>", "arn:aws:s3:::<BUCKET-NAME>/*" ] }, { "Effect": "Deny", "NotAction": "s3:*", "NotResource": [ "arn:aws:s3:::<BUCKET-NAME>", "arn:aws:s3:::<BUCKET-NAME>/*" ] } ] }
Please be aware that the use of OverloadedLists
and NonEmpty
will error if
document
is passed an empty list.
Policy Documents
type Document = Policy Statement Source #
A policy document is a non-empty list of IAM statements with a supported version.
The statements of a policy document can be traversed and manipulated via the
Functor
, Foldable
, and Traverseable
instances. You can use the
Semigroup
instance to concatenate multiple Policy
documents together,
preserving the highest supported version and first encountered Id
.
Grammar
policy = { <version_block?> <id_block?> <statement_block> }
Instances
Constructing Policies
singleton :: a -> Policy a Source #
Construct a policy from a single Statement
using the default
2012-10-17
version and no identifier.
Example
>>>
encode' $ singleton (allow { resource = any })
{ "Statement": [ { "Effect": "Allow", "Action": [], "Resource": "*" } ], "Version": "2012-10-17" }
Encoding
encode :: Policy Statement -> ByteString Source #
Encode the IAM policy document as JSON.
Example
>>>
encode $ singleton allow
"{\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[]}],\"Version\":\"2012-10-17\"}"
Language Elements
IAM JSON policy documents are made up of elements. The elements are listed here roughly in the general order you use them in a policy.
The details of what goes into a policy vary for each service, depending on what actions the service makes available, what types of resources it contains, and so on. When you're writing policies for a specific service, it's helpful to see examples of policies for that service. View the AWS Services That Work with IAM documentation for more information.
This library attempts to stick as closely as possible to the IAM policy language grammar
and its specific terminology while providing a modicum of safety without going
overboard with type-level features. To support this, the concept of Element
vs
NotElement
and "*"
wildcards are generalised by the introduction of two
additional types not specified directly in the language grammar.
Firstly there is the Block
type which allows us to negate Principal
,
Action
, and Resource
elements via the related NotPrincipal
, NotAction
,
and NotResource
elements. Secondly the Match
type provides a way to
generally specific Some
values for an element, or the Wildcard
match
equivalent to "*"
. Combinators are then provided for the common cases.
Example
>>>
encode' $ singleton (allow { action = some ["foo", "bar"] })
... "Effect": "Allow", "Action": [ "foo", "bar" ] ...
>>>
encode' $ singleton (allow { action = not ["baz"] })
... "Effect": "Allow", "NotAction": "baz" ...
>>>
encode' $ singleton (allow { action = any })
... "Effect": "Allow", "Action": "*" ...
>>>
encode' $ singleton (allow { action = none })
... "Effect": "Allow", "NotAction": "*" ...
The above examples work identically for the action
, resource
, and
principal
statement elements.
A Block
is a shared type denoting blocks of the policy language grammar.
This is used by the Principal
, Action
, Resource
elements of the policy
language.
Grammar
<name_block> = ("Name" | "NotName") : <match_block>
Instances
A Match
is a shared type used to denote wildcards in the policy
language grammar.
This is used by the Principal
, Action
, Resource
elements of the policy
language.
Grammar
<match_block> = ("*" | <item>)
Instances
Specifying and Negating Elements
Version
The Version
elements specifies the language syntax rules that are to be
used to process this policy. If you include features that are not available in
the specified version, then your policy will generate errors or not work the
way you intend. As a general rule, you should specify the most recent version
available, unless you depend on a feature that was deprecated in later
versions.
Grammar
<version_block> = "Version" : ("2008-10-17" | "2012-10-17")
Example
>>>
JSON.encode Version_2012_10_17
"\"2012-10-17\""
Instances
Eq Version Source # | |
Ord Version Source # | |
Show Version Source # | |
Generic Version Source # | |
Semigroup Version Source # | '(<>)' always chooses the newest version. |
Hashable Version Source # | |
Defined in Amazonka.IAM.Policy | |
ToJSON Version Source # | |
Defined in Amazonka.IAM.Policy | |
FromJSON Version Source # | |
type Rep Version Source # | |
Id
The Id
element specifies an optional identifier for the policy. The ID
is used differently in different services.
For services that let you set an ID element, we recommend you use a UUID (GUID) for the value, or incorporate a UUID as part of the ID to ensure uniqueness.
Note: Some AWS services (for example, Amazon SQS or Amazon SNS) might require this element and have uniqueness requirements for it. For service-specific information about writing policies, refer to the documentation for the service you're working with.
Use the id
record field to set the Id
of a Policy
document.
Grammar
<id_block> = "Id" : <policy_id_string>
Example
>>>
encode' $ (singleton allow) { id = Just "123" }
{ ... "Id": "123" }
Statement
The Statement
element is the main element for a policy. This element is
required. It can include multiple elements (see the subsequent sections in this
page). The Statement element contains an array of individual statements.
Grammar
<statement_block> = "Statement" : [ <statement>, <statement>, ... ] <statement> = { <sid_block?>, <principal_block?>, <effect_block>, <action_block>, <resource_block>, <condition_block?> }
Instances
Constructing Statements
Sid
The Sid
(statement ID) is an optional identifier that you provide for the
policy statement. You can assign a Sid value to each statement in a statement
array. In services that let you specify an ID element, such as SQS and SNS, the
Sid value is just a sub-ID of the policy document's ID. In IAM, the Sid value
must be unique within a JSON policy.
In IAM, the Sid is not exposed in the IAM API. You can't retrieve a particular statement based on this ID.
Note: Some AWS services (for example, Amazon SQS or Amazon SNS) might require this element and have uniqueness requirements for it. For service-specific information about writing policies, refer to the documentation for the service you're working with.
Use the sid
record field to set the Sid
of a Statement
.
Grammar
<sid_block> = "Sid" : <sid_string>
Example
>>>
encode' $ singleton (allow { sid = Just "cd3ad3d9-2776-4ef1-a904-4c229d1642ee" })
{ "Statement": [ { "Effect": "Allow", "Action": [], "Sid": "cd3ad3d9-2776-4ef1-a904-4c229d1642ee" } ], "Version": "2012-10-17" }
Principal
Use the Principal
element to specify the user (IAM user, federated user, or
assumed-role user), AWS account, AWS service, or other principal entity that
is allowed or denied access to a resource. You use the Principal element in
the trust policies for IAM roles and in resource-based policies—that is, in
policies that you embed directly in a resource. For example, you can embed
such policies in an Amazon S3 bucket, an Amazon Glacier vault, an Amazon SNS
topic, an Amazon SQS queue, or an AWS KMS customer master key (CMK).
Use the Principal element in these ways:
In IAM roles, use the Principal element in the role's trust policy to specify who can assume the role. For cross-account access, you must specify the 12-digit identifier of the trusted account.
Note: After you create the role, you can change the account to "*" to allow everyone to assume the role. If you do this, we strongly recommend that you limit who can access the role through other means, such as a Condition element that limits access to only certain IP addresses. Do not leave your role accessible to everyone!
In resource-based policies, use the Principal
element to specify the
accounts or users who are allowed to access the resource.
You can use Not
to negate the meaning of a Principal
element.
Grammar
<principal_block> = ("Principal" | "NotPrincipal") : ("*" | <principal_map>) <principal_map> = { <principal_map_entry>, <principal_map_entry>, ... } <principal_map_entry> = ("AWS" | "Federated" | "Service") : [<principal_id_string>, <principal_id_string>, ...]
Example
>>>
encode' $ singleton (allow { principal = Just $ not Everyone })
{ "Statement": [ { "Effect": "Allow", "NotPrincipal": "*", "Action": [] } ], "Version": "2012-10-17" }
>>>
encode' $ singleton (allow { principal = Just $ some (AWS (pure "arn:foo:::bar")) })
{ "Statement": [ { "Effect": "Allow", "Action": [], "Principal": { "AWS": [ "arn:foo:::bar" ] } } ], "Version": "2012-10-17" }
Instances
Effect
The Effect
element is required and specifies whether the statement
results in an allow or an explicit deny.
By default, access to resources is denied. To allow access to a resource,
you must set the Effect element to Allow
. To override an allow (for example,
to override an allow that is otherwise in force), you set the Effect element
to Deny
.
See the allow
and deny
smart constructors to create a Statement
with the
desired Effect
set.
Grammar
<effect_block> = "Effect" : ("Allow" | "Deny")
Instances
Enum Effect Source # | |
Defined in Amazonka.IAM.Policy | |
Eq Effect Source # | |
Ord Effect Source # | |
Show Effect Source # | |
Generic Effect Source # | |
Hashable Effect Source # | |
Defined in Amazonka.IAM.Policy | |
ToJSON Effect Source # | |
Defined in Amazonka.IAM.Policy | |
FromJSON Effect Source # | |
type Rep Effect Source # | |
Action
The Action
element describes the specific action or actions that will be
allowed or denied. Statements must include either an Action or NotAction
element. Each AWS service has its own set of actions that describe tasks that
you can perform with that service.
You can use Not
to negate the meaning of a list of Action
elements.
Grammar
<action_block> = ("Action" | "NotAction") : ("*" | [<action_string>, <action_string>, ...])
Action | |
|
Resource
The Resource
element specifies the object or objects that the statement
covers. Statements must include either a Resource or a NotResource element.
Each service has its own set of resources. Although you always use an ARN to specify a resource, the details of the ARN for a resource depend on the service and the resource. For information about how to specify a resource, refer to the documentation for the service whose resources you're writing a statement for.
Note: Some services do not let you specify actions for individual
resources; instead, any actions that you list in the Action or NotAction
element apply to all resources in that service. In these cases, you use the
wildcard "*"
in the Resource element.
You can use Not
to negate the meaning of a list of Resource
elements.
Grammar
<resource_block> = ("Resource" | "NotResource") : ("*" | [<resource_string>, <resource_string>, ...])
Instances
Eq Resource Source # | |
Ord Resource Source # | |
Defined in Amazonka.IAM.Policy | |
Show Resource Source # | |
IsString Resource Source # | |
Defined in Amazonka.IAM.Policy fromString :: String -> Resource # | |
Hashable Resource Source # | |
Defined in Amazonka.IAM.Policy | |
ToJSON Resource Source # | |
Defined in Amazonka.IAM.Policy | |
FromJSON Resource Source # | |
Condition
A key that will be tested as the target of a Condition
.
The Condition
element (or Condition block) lets you specify conditions
for when a policy is in effect. The Condition element is optional. In the
Condition element, you build expressions in which you use condition operators
(equal, less than, etc.) to match the condition in the policy against values in
the request. Condition values can include date, time, the IP address of the
requester, the ARN of the request source, the user name, user ID, and the user
agent of the requester. Some services let you specify additional values in
conditions; for example, Amazon S3 lets you write a condition using the
s3:VersionId
key, which is unique to that service.
- String:
String condition operators let you construct
Condition
elements that restrict access based on comparing a key to a string value. - Numeric: Numeric condition operators let you construct Condition elements that restrict access based on comparing a key to an integer or decimal value.
- Date: Date condition operators let you construct Condition elements that restrict access based on comparing a key to a date/time value. You use these condition operators with the aws:CurrentTime key or aws:EpochTime keys. You must specify date/time values with one of the W3C implementations of the ISO 8601 date formats or in epoch (UNIX) time. Wildcards are not permitted for date condition operators.
- Boolean: Boolean conditions let you construct Condition elements that restrict access based on comparing a key to "true" or "false."
- Binary: The BinaryEquals condition operator let you construct Condition elements that test key values that are in binary format. It compares the value of the specified key byte for byte against a base-64 encoded representation of the binary value in the policy.
- IP Address: IP address condition operators let you construct Condition elements that restrict access based on comparing a key to an IPv4 or IPv6 address or range of IP addresses. You use these with the aws:SourceIp key. The value must be in the standard CIDR format (for example, 203.0.113.0/24 or 2001:DB8:1234:5678::/64). If you specify an IP address without the associated routing prefix, IAM uses the default prefix value of /32. Some AWS services support IPv6, using :: to represent a range of 0s. To learn whether a service supports IPv6, see the documentation for that service.
- Amazon Resource Name (ARN): Amazon Resource Name (ARN) condition operators let you construct Condition elements that restrict access based on comparing a key to an ARN. The ARN is considered a string. This value is available for only some services; not all services support request values that can be compared as ARNs.
- Key Existence: You can add IfExists to the end of any condition operator name except the Null condition—for example, StringLikeIfExists. You do this to say "If the policy key is present in the context of the request, process the key as specified in the policy. If the key is not present, the condition evaluate the condition element as true." Other condition elements in the statement can still result in a nonmatch, but not a missing key when checked with ...IfExists.
- Null: Use a Null condition operator to check if a condition key is present at the time of authorization. In the policy statement, use either true (the key doesn't exist — it is null) or false (the key exists and its value is not null). For example, you can use this condition operator to determine whether a user is using their own credentials for the operation or temporary credentials. If the user is using temporary credentials, then the key aws:TokenIssueTime exists and has a value. The following example shows a condition that states that the user must not be using temporary credentials (the key must not exist) for the user to use the Amazon EC2 API.
Grammar
<condition_block> = "Condition" : { <condition_map> } <condition_map> { <condition_type_string> : { <condition_key_string> : <condition_value_list> }, <condition_type_string> : { <condition_key_string> : <condition_value_list> }, ... } <condition_value_list> = [<condition_value>, <condition_value>, ...] <condition_value> = ("string" | "number" | "Boolean")
Example
>>>
encode' $ singleton (allow { condition = Just (Bool "aws:MultiFactorAuthPresent" True) })
{ "Statement": [ { "Effect": "Allow", "Action": [], "Condition": { "Bool": { "aws:MultiFactorAuthPresent": true } } } ], "Version": "2012-10-17" }
StringEquals !Key !Text | Exact matching, case sensitive. |
StringNotEquals !Key !Text | Negated matching. |
StringEqualsIgnoreCase !Key !Text | Exact matching, ignoring case. |
StringNotEqualsIgnoreCase !Key !Text | Negated matching, ignoring case |
StringLike !Key ![Text] | Case-sensitive matching. The values can include a multi-character match wildcard (*) or a single-character match wildcard (?) anywhere in the string. If a key contains multiple values, StringLike can be qualified with set operators—ForAllValues:StringLike and ForAnyValue:StringLike. For more information, see Creating a Condition That Tests Multiple Key Values (Set Operations). |
StringNotLike !Key ![Text] | Negated case-sensitive matching. The values can include a multi-character match wildcard (*) or a single-character match wildcard (?) anywhere in the string. |
NumericEquals !Key !Scientific | Matching. |
NumericNotEquals !Key !Scientific | Negated matching. |
NumericLessThan !Key !Scientific | "Less than" matching. |
NumericLessThanEquals !Key !Scientific | "Less than or equals" matching. |
NumericGreaterThan !Key !Scientific | "Greater than" matching. |
NumericGreaterThanEquals !Key !Scientific | "Greater than or equals" matching. |
DateEquals !Key !UTCTime | Matching a specific date. |
DateNotEquals !Key !UTCTime | Negated matching. |
DateLessThan !Key !UTCTime | Matching before a specific date and time. |
DateLessThanEquals !Key !UTCTime | Matching at or before a specific date and time. |
DateGreaterThan !Key !UTCTime | Matching after a specific a date and time. |
DateGreaterThanEquals !Key !UTCTime | Matching at or after a specific date and time. |
Bool !Key !Bool | Boolean matching. |
BinaryEquals !Key !ByteString | The BinaryEquals condition operator let you construct Condition elements that test key values that are in binary format. It compares the value of the specified key byte for byte against a base-64 encoded representation of the binary value in the policy. |
IpAddress !Key !ByteString | The specified IP address or range. |
NotIpAddress !Key !ByteString | All IP addresses except the specified IP address or range. |
ArnEquals !Key !Text | Case-sensitive matching of the ARN. Each of the six colon-delimited components of the ARN is checked separately and each can include a multi-character match wildcard (*) or a single-character match wildcard (?). These behave identically. |
ArnLike !Key !Text | Case-sensitive matching of the ARN. Each of the six colon-delimited components of the ARN is checked separately and each can include a multi-character match wildcard (*) or a single-character match wildcard (?). These behave identically. |
ArnNotEquals !Key !Text | Negated matching for ARN. These behave identically. |
ArnNotLike !Key !Text | Negated matching for ARN. These behave identically. |