What is the confused deputy problem and how to address it in your AWS environment? 🧵
Confused deputy is a privilege escalation attack wherein a threat actor tricks a privileged entity into performing actions the actor doesn't have permission to perform.
In AWS, the privileged entity could be an AWS service or a third-party service served from an AWS account.
Example:
Let's say you'd like build a Lambda-backed API exposed to the internet through API Gateway.
For that to work, you'll need to give API Gateway permissions to invoke your Lambda.
Here's a seemingly reasonable resource policy you could attach to your Lambda:
{
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Principal": {
"Service": "https://t.co/2AHRaNK4Xu"
},
"Resource": "arn:aws:lambda:region:account:function:example-lambda"
}
This is however an insecure way to give API Gateway permission to invoke your Lambda.
You're essentially giving any API Gateway API in any AWS account permission to invoke your Lambda.
If an attacker happened to know your Lambda ARN, which is typically not treated as a secret, they can simply create an API Gateway API in their account and hook it to your Lambda, effectively allowing them to invoke your Lambda.
In this case, the attacker tricked the API Gateway service into calling your Lambda.
To prevent this, you need to limit your Lambda invocation permissions to a specific API Gateway API (or all API Gateway APIs in a specific account).
To limit you Lambda invocation permissions to a specific API Gateway API, add the following condition to your Lambda resource policy:
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:execute-api:region:account:api-id/*/*/myapi"
}
}
To limit you Lambda invocation permissions to API Gateway APIs in a specific AWS account, add the following condition to your Lambda resource policy:
"Condition": {
"StringEquals": {
"aws:SourceAccount": "account-id"
}
}
Now, let's talk about confused deputy in the context of third-party vendor services offered from an AWS account.
Let's say you use an AWS Marketplace vendor solution requiring you to create an IAM role with a trust relationship allowing a vendor-owned AWS account to assume it.
Here's a seemingly reasonable, but actually insecure, trust relationship:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {
"AWS": "vendor-account-id"
},
"Action": "sts:AssumeRole"
}
}
This allows a malicious actor that happens to know your role's ARN, which is typically not treated as a secret, to trick the vendor solution into assuming that role in your account.
To prevent this, the vendor has to provide you with a customer-specific secret identifier.
To protect yourself from third-party confused deputy issues, add the following condition to the role's trust relationship:
"Condition": {
"StringEquals": {
"sts:ExternalId": "identifier"
}
}
where "identifier" is the vendor-supplied customer-specific identifier.
Every time the vendor needs to assume your role, they'll have to pass your customer-specific identifier as part of the AssumeRole call. This prevents a malicious actor (with a different customer-specific identifier) from tricking the vendor solution into assuming your role.
To summarize:
1) Use "aws:SourceArn" or "aws:SourceAccount" global condition context keys to protect yourself from AWS service confused deputy attacks.
2) Use "sts:ExternalId" condition context key to protect yourself from confused deputy attacks on 3rd-party vendor solutions.
If you wanna learn more about securing your AWS environments, share the first tweet in this thread and give me a follow @hgad.
https://t.co/8xh1mtFzhx