Detecting Public AWS Resources via Misconfigured Policy

What is Policy???

A policy is an object in AWS that, when associated with an entity or resource, defines its permissions. AWS evaluates these policies when a principal, such as a user, makes a request. Permissions in the policies determine whether the request is allowed or denied. Most policies are stored in AWS as JSON documents.

Let's deep dive into Policies.

Policy 1

{
    "Version": "2012-10-17",
    "Id": "arn:aws:sqs:region:myaccount:sqsname/SQSDefaultPolicy",
    "Statement": [
        {
            "Sid": "Sid157790325",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "SQS:*",
            "Resource": "arn:aws:sqs:region:myaccount:sqsname"
        }
    ]
}

Our main focus part is Statement which contains all the parameters of Policies.

The statement contains five parameters,

Sid: The Sid (statement ID) is an optional identifier that you provide for the policy statement.

Effect: The Effect specifies whether the statement results in an allow or an explicit deny.

Principal: Principal element in a policy to specify the principal that is allowed or denied access to a resource.

And in Principal we can define the below elements:

  1. AWS account and root user

  2. IAM users

  3. Federated users (using web identity or SAML federation)

  4. IAM roles

  5. Assumed-role sessions

  6. AWS services

  7. Anonymous users ("*")

Action: The action element describes the specific action or actions that will be allowed or denied.

Resource: The Resource element specifies the object or objects that the statement covers.

There is one more parameter that is not mentioned on the above policy JSON "Condition".

Condition: The Condition element lets you specify conditions for when a policy is in effect. Condition have multiple operators, variable and tags which we can use while making the policy for example:

"Condition": {"StringLike": {"s3:prefix": ["${aws:username}/*"]}}

What about the misconfiguration??

Let's look at Policy 1. in this policy we will only focus on the Statement,

"Principal": "*",

As we can the value of the principal is "*" which means we are allowing everyone to access our SQS to perform any action on it.

We can avoid this misconfiguration by simply putting a condition or instead of "*" we can specify the specific account number on principal value whom we want to give access to this resource.

Fixed Policy:

{
    "Version": "2012-10-17",
    "Id": "arn:aws:sqs:region:myaccount:sqsname/SQSDefaultPolicy",
    "Statement": [
        {
            "Sid": "Sid157790325",
            "Effect": "Allow",
            "Principal": "account_no",
            "Action": "SQS:*",
            "Resource": "arn:aws:sqs:region:myaccount:sqsname"
        }
    ]
}

Let's look at another vulnerable example of Policy:

{
    "Action": "lambda:InvokeFunction",
    "Effect": "Allow",
    "Principal": {
        "Service": "apigateway.amazonaws.com" 
    },
    "Resource": "arn:aws:lambda:...:function:myfunction"
}

The problem here is that this isn’t just allowing the API Gateway within this account to call this Lambda, but instead is allowing API Gateway, from any account, to call this Lambda! This means if you had some sort of restrictions on your API Gateway, they could be bypassed by an attacker setting up their own API Gateway to call this function.

Such an attack would require knowing about this Lambda ARN. If an attacker obtained access to terraform/CloudFormation scripts or other knowledge of an environment’s internals, they could abuse this issue.

Fixed Policy:

{
    "Action": "lambda:InvokeFunction",
    "Effect": "Allow",
    "Principal": {
        "Service": "apigateway.amazonaws.com" 
    },
    "Resource": "arn:aws:lambda:...:function:myfunction"


"Condition": {
  "ArnLike": {
    "AWS:SourceArn": 
    "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*/*/myapi"
  }
}
}

This ensures that only a specific API Gateway can invoke the Lambda.

The solution to detect such Misconfiguration

I wrote automation that will find such misconfigured policies in real-time, By reading cloudtrail events for particular services and extracting the policy parameter from them. Then that policy will be parsed to the lambda to identify policies which has the value asterisk in the Principal parameter and send alerts to slack at the same time.

Services this automation cover currently:

  • SQS
  • SNS
  • ECR
  • KMS
  • Secret Manager
  • Glacier
  • ES

Sometimes we have to forcefully put an asterisk in Principal but we secure it by adding a condition. This automation will alert at this case as well, but it is always good to have visibility of what condition we have put it in while having an asterisk in principal.