Broken Authorization in AWS
In Amazon Web Services (AWS), policies and permissions are essential components of the security framework governing access to AWS account resources. AWS Identity and Access Management (IAM) is the service that enables you to manage access to your AWS resources securely. IAM policies define the permissions granted to users, groups, and roles in your AWS account.
Access Policy Types
-
Identity-based policies: Identity-based policies in AWS are IAM policies that you can attach to individual IAM users, groups, or roles. These policies define the permissions granted to these identities to access AWS resources within your account.
-
Resource-based policies: In AWS, IAM policies are attached to a resource, such as an S3 bucket or a Lambda function, rather than an identity like a user or group. These policies define the permissions granted to other AWS accounts or IAM users, groups, or roles needing to access the resource.
-
Access control lists (ACLs): Access Control Lists in AWS are rules used to specify which principals in other AWS accounts are granted or denied access to resources.
-
Permissions boundaries: Permissions boundaries are IAM policies that define the maximum permissions an IAM entity (user or role) can have, regardless of its identity-based policies.
-
Organization SCPs: Organizations Service Control Policies allow setting policies across multiple accounts to restrict or allow access to AWS services and actions.
-
Session policies: Session policies in AWS are policies that can be passed as a parameter when a temporary session is programmatically created for a role or federated user. These policies can limit the identity-based policies of the IAM entity (user or role).
Identity-based policies
Identity-based policies in AWS can be attached to IAM users, groups, and roles, enabling fine-grained access control on various resources such as S3, SQS, SNS, Lambda, RDS, DynamoDB, KMS keys, and many others.
You can create an identity-based policy in Terraform by defining an aws_iam_policy
resource and its policy
attribute. The policy document is a JSON-formatted document that describes the permissions granted or denied to the user, group, or role.
The following is an example IAM user and policy defined with Terraform’s AWS aws_iam_user
and attached with an aws_iam_user_policy
resource.
resource "aws_iam_user_policy" "bucket_user_policy" {
user = aws_iam_user.bucket_user.name
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
]
Effect = "Allow"
Resource = "arn:aws:s3:::example-s3/*"
},
]
})
}
resource "aws_iam_user" "bucket_user" {
name = "bucket_user"
}
Policies have three main components: Actions, Effect, and Resources.
-
Actions: Actions are specific operations that can be performed on an AWS resource, such as reading, writing, or deleting a resource. Action values depend on the resource. Wildcards grant permissions for multiple actions, e.g.,
s3:*
, to grant permission for all S3. You can browse actions for S3, SQS, SNS, Lambda, and so on. -
Effect: Effect is the outcome of the policy statement when the conditions are met. The two possible values are
Allow
andDeny.
-
Resources: Resources are the AWS resources to which the policy statement applies. Resources can be specified using an Amazon Resource Name (ARN), a wildcard (
*
) to apply to all resources or a combination of both.
Resource-based Policies
Resource-based policies in AWS are attached to a resource rather than an identity like a user or group.
In Terraform, you can attach different policies variating the resource name, for example, by using aws_s3_bucket_policy
resources with S3 buckets, aws_sqs_queue_policy
for SQS queues, and so on.
The following is an example bucket policy defined with Terraform’s AWS aws_iam_policy_document
and attached with aws_s3_bucket_policy
resources.
resource "aws_s3_bucket" "example_bucket" {
bucket = "example-s3"
}
resource "aws_s3_bucket_policy" "bucket_policy" {
bucket = aws_s3_bucket.example_bucket.id
policy = data.aws_iam_policy_document.bucket_policy_document.json
}
data "aws_iam_policy_document" "bucket_policy_document" {
statement {
principals {
type = "AWS"
identifiers = ["123456789012"]
}
actions = [
"s3:GetObject",
"s3:GetObjectAcl",
"s3:ListBucket",
]
resources = [
aws_s3_bucket.example_bucket.arn,
"${aws_s3_bucket.bucket_policy.arn}/*",
]
}
}
Lambda Permissions
Lambda functions support resource-based permissions to grant usage permission to other AWS accounts or organizations per resource.
In Terraform, Lambda permissions can be defined using the “aws_lambda_permission” resource to grant permissions to AWS resources, such as Amazon S3 buckets or other Lambda functions, to invoke your Lambda function.
The following is an AWS Lambda permission that allows an S3 bucket to invoke the Lambda function.
resource "aws_lambda_permission" "allow_s3_bucket" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.example_function.function_name
principal = "s3.amazonaws.com"
source_arn = aws_s3_bucket.example_bucket.arn
}
resource "aws_lambda_function" "example_function" {
# ... Lambda configuration ...
}
resource "aws_s3_bucket" "example_bucket" {
# ... S3 configuration ...
}
ACLs
Although ACLs are similar to resource-based policies, they do not use the JSON policy document format. S3, WAF, and VPC are some of the services that support ACLs, while other services, such as SQS and SNS, do not support them.
Access control lists (ACLs) in S3
Most modern use cases in Amazon S3 no longer require ACL use, and it’s recommended to disable ACLs except where you need to control access for each object individually.
In Terraform, you can use the aws_s3_bucket_acl
resource to define an ACL for a bucket.
resource "aws_s3_bucket_acl" "acls" {
bucket = "example-s3"
access_control_policy {
grant {
grantee {
id = "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be"
type = "CanonicalUser"
}
permission = "WRITE"
}
grant {
grantee {
type = "Group"
uri = "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
}
permission = "READ"
}
owner {
id = data.aws_canonical_user_id.current.id
}
}
}
The access_control_policy
block identifies some grant
blocks with the grantee
and the permission granted: a specific AWS account assigned with write permission, the global AuthenticatedUsers
group who has read permission, and the bucket owner as having complete control of the bucket.
Canned Access control lists (ACLs) in S3
S3 also supports a set of predefined grants known as canned ACLs. Each canned ACL has a predefined set of grantees and permissions.
The following is an example S3 Canned ACL defined with Terraform’s AWS aws_s3_bucket_acl
resource.
resource "aws_s3_bucket" "example_bucket" {
bucket = "example-s3"
}
resource "aws_s3_bucket_acl" "example_bucket_canned_acl" {
bucket = aws_s3_bucket.example_bucket.id
acl = "private"
}
You can read more about S3 ACLs here.
S3 Block Public Access
By default, new buckets, access points, and objects don’t allow public access. However, users can modify bucket policies, access point policies, or object permissions to allow public access. S3 Block Public Access settings override these policies and permissions to limit public access to these resources.
The following is an example bucket public access policy defined with Terraform’s AWS aws_s3_bucket_public_access_block
resource.
resource "aws_s3_bucket" "example_bucket" {
bucket = "example-s3"
}
resource "aws_s3_bucket_public_access_block" "public_access_bucket_policy" {
bucket = aws_s3_bucket.example_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
This configuration ensures that the specified S3 bucket is private and not accessible to the public.
AMI Permissions
Amazon Machine Images (AMIs) are the source for EC2 instances. You can use AMIs to launch EC2 instances. AMIs are private by default; you can share them with other AWS accounts or make them public for anyone to launch an EC2 instance from them. This can be a way to expose sensitive data accidentally.
In Terraform, you can use the aws_ami_launch_permission
resource to define an AMI permission; the example below shows how to share an AMI with another AWS account.
resource "aws_ami_launch_permission" "example_ami" {
image_id = "ami-1234567890"
account_id = "123456789012"
}
They also allow sharing between organizations and the much more scary option of publicizing the AMI.
References
Policies and permissions
AWS - Policies and permissions in IAM
S3
AWS - S3 Security Best Practices
AWS - S3 Managing Access Control
AWS - S3 Access Control using Policies
AWS - S3 Access Control using ACLs
SQS
AWS SQS Security Best Practices
AWS SQS Authentication and Access Control
SNS
AWS - Example cases for Amazon SNS access control
AWS - Using identity-based policies with Amazon SNS