I'm using the AWS CDK to build the infrastructure in Python.
Step1 ~ Step4 are in the same stack.
Step 1: Create the role lambda_role with AWS managed policy AmazonDynamoDBFullAccess for lambda.
lambda_role = aws_iam.Role(self, "lambda_role",
assumed_by=aws_iam.ServicePrincipal("lambda.amazonaws.com"),
role_name="lambda_role")
policy = "AmazonDynamoDBFullAccess"
lambda_role.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name(policy))
Step 2: Create a table my_table and enable streams
stream_view_type = aws_dynamodb.StreamViewType.NEW_AND_OLD_IMAGES
my_table = aws_dynamodb.Table(self, id=tableName,
table_name=tableName,
partition_key=partition_key,
stream=stream_view_type,
)
Step 3: Create lambda my_lambda with lambda_role
my_lambda = aws_lambda.Function(self, "my_lambda"
role=lambda_role)
Step 4: Set the table(my_table) as the trigger for lambda(my_lambda).
my_lambda.add_event_sources(
aws_lambda_event_sources.DynamoEventSource(
starting_position=aws_lambda.StartingPosition.LATEST,
table=my_table,
batch_size=table_setting["batch_size"],
retry_attempts=table_setting["retry_attempts"],
)
)
My Question:
Why Step 4 automatically create and attach the inline-policy to lambda_role? The scope of AmazonDynamoDBFullAccess which is created in step 1 overlaps the new created policy.
How to share the policy AmazonDynamoDBFullAccess instead of creating a new policy for each event_sources?
inline policy attached to lambda_role:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "dynamodb:ListStreams",
"Resource": "arn:aws:dynamodb:?:?:table/my_table/stream/*",
"Effect": "Allow"
},
{
"Action": [
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator"
],
"Resource": "arn:aws:dynamodb:?:?:table/my_table/stream/2020-07-22T03:35:56.757",
"Effect": "Allow"
}
]
}
Snippet of AmazonDynamoDBFullAccess attached to lambda_role:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:*", ...
],
"Effect": "Allow",
"Resource": "*"
}, ...
]
}
You can stop the redundant policy additions from add_event_source by preventing additional policy updates on your custom lambda execution role after it is created using the Role method: without_policy_updates.
To do it this way, you will also have to manually add whatever policies would have been automatically added during the lambda function initialization, since the lambda initialization won't be able to auto-update the role either. For a simple Lambda function, this would probably only be AWSLambdaBasicExecutionRole and AWSLambdaVPCAccessExecutionRole.
lambda_role = aws_iam.Role(self, "lambda_role",
assumed_by=aws_iam.ServicePrincipal("lambda.amazonaws.com"),
role_name="lambda_role",
managed_policies=[
aws_iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaBasicExecutionRole"
),
aws_iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaVPCAccessExecutionRole"
),
aws_iam.ManagedPolicy.
from_aws_managed_policy_name("AmazonDynamoDBFullAccess")
]
)
lambda_role = lambda_role.without_policy_updates()
my_lambda = aws_lambda.Function(self, "my_lambda"
role=lambda_role)
Related
I am trying to create a Lambda role and attach it a policy to Allow all ElasticSearch cluster operations.
Below is the code -
resource "aws_iam_role" "lambda_iam" {
name = "lambda_iam"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Action": [
"es:*"
],
"Effect": "Allow",
"Resource": "*"
}]
}
EOF
}
resource "aws_lambda_function" "developmentlambda" {
filename = "lambda_function.zip"
function_name = "name"
role = "${aws_iam_role.lambda_iam.arn}"
handler = "exports.handler"
source_code_hash = "${filebase64sha256("lambda_function.zip")}"
runtime = "nodejs10.x"
}
I get the following error
Error creating IAM Role lambda_iam: MalformedPolicyDocument: Has prohibited field Resource
The Terraform document regarding Resource says you can specify a "*" for ALL users. The Principal field is not mandatory either so thats not the problem.
I still changed it to be
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "es.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
But that said -
Error creating Lambda function: InvalidParameterValueException: The role defined for the function cannot be assumed by Lambda.
My lambda function definition is simple
resource "aws_lambda_function" "development_lambda" {
filename = "dev_lambda_function.zip"
function_name = "dev_lambda_function_name"
role = "${aws_iam_role.lambda_iam.arn}"
handler = "exports.test"
source_code_hash = "${filebase64sha256("dev_lambda_function.zip")}"
runtime = "nodejs10.x"
}
The lambda file itself has nothing in it but I do not know if that explains the error.
Is there something I am missing here ?
The assume role policy is the role's trust policy (allowing the role to be assumed), not the role's permissions policy (what permissions the role grants to the assuming entity).
A Lambda execution role needs both types of policies.
The immediate error, that the "role defined for the function cannot be assumed by Lambda" is occurring because it needs "Principal": {"Service": "lambda.amazonaws.com"}, not es.amazonaws.com -- that goes in the permissions policy. I don't use terraform, but it looks like that might be resource "aws_iam_policy" based on https://www.terraform.io/docs/providers/aws/r/lambda_function.html, which I assume is the reference you are working from.
I'm learning Terraform and I'm trying to get the correct syntax to specify the IAM role permissions for it. I want these capabailities:
Lambda can be invoked from an API Gateway that I also create in Terraform
Lambda can write to Cloudwatch logs
I have the following which allows the API gateway to invoke the Lambda:
resource "aws_iam_role" "my_lambda_execution_role" {
name = "my_lambda_execution_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"apigateway.amazonaws.com"
]
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
I have seen the snippet below allows the Lambda to write to CloudWatch. I'm trying to combine these snippets to get all of the permissions but I can't get it right. What is the correct syntax to give all of these permissions to the role?
{
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "arn:aws:logs:*:*:*"
}
]
}
https://www.terraform.io/docs/providers/aws/r/iam_role_policy_attachment.html
You need to create the policy and then attach it to your role. The link above includes a more complete example than on the iam role page.
IAM policy along with role.
# iam
data "aws_iam_policy_document" "policy" {
statement {
sid = ""
effect = "Allow"
principals {
identifiers = ["lambda.amazonaws.com"]
type = "Service"
}
actions = ["sts:AssumeRole"]
}
}
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = "${data.aws_iam_policy_document.policy.json}"
}
resource "aws_iam_role_policy" "frontend_lambda_role_policy" {
name = "frontend-lambda-role-policy"
role = "${aws_iam_role.iam_for_lambda.id}"
policy = "${data.aws_iam_policy_document.lambda_log_and_invoke_policy.json}"
}
data "aws_iam_policy_document" "lambda_log_and_invoke_policy" {
statement {
effect = "Allow"
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
]
resources = ["*"]
}
statement {
effect = "Allow"
actions = ["lambda:InvokeFunction"]
resources = ["arn:aws:lambda:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:function:*"]
}
}
Please find the complete terraform code at my github
In a previous answer I wrote up some background information on how IAM roles work and what an "assume role policy" is. I'm going to assume that background information in this answer.
The policy you've given in your assume_role_policy argument in the resource "aws_iam_role" "my_lambda_execution_role" block is the policy governing which users and services are allowed to "assume" this role. In this case, you are allowing AWS Lambda and Amazon API Gateway to make requests using the privileges granted by this role.
However, by default the role doesn't grant any privileges at all. To address that, we need to attach one or more access policies to the role. The other policy JSON you shared here is an access policy, and to associate it with the role we need to use the aws_iam_role_policy resource type:
resource "aws_iam_role_policy" "logs" {
name = "lambda-logs"
role = aws_iam_role.my_lambda_execution_role.name
policy = jsonencode({
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
],
"Effect": "Allow",
"Resource": "arn:aws:logs:*:*:*",
}
]
})
}
Usually Terraform automatically infers dependencies between resource blocks by noticing references like the aws_iam_role.my_lambda_execution_role expression in the above, and indeed in this case Terraform will determine automatically that it needs to complete the creation of the role before attempting to attach the policy to it.
However, Terraform cannot see automatically here that the policy attachment must complete before the policy itself is operable, and so when you refer to the role from your API Gateway and Lambda resources you must use depends_on to tell Terraform that the policy attachment must complete before the policy will become usable:
resource "aws_lambda_function" "example" {
filename = "${path.module}/example.zip"
function_name = "example"
role = aws_iam_role.my_lambda_execution_role.arn
handler = "example"
# (and any other configuration you need)
# Make sure the role policy is attached before trying to use the role
depends_on = [aws_iam_role_policy.logs]
}
If you don't use depends_on like this, there is a risk that the function will be created and executed before the role attachment is complete, and thus initial executions of your function could fail to write their logs. If your function is not executed immediately after it's created then this probably won't occur in practice, but it's good to include the depends_on to be thorough and to let a future human maintainer know that the role's access policy is also important for the functionality of the Lambda function.
I am trying to use boto3 from within AWS lambda function in order to do post_text to a Lex chat bot.
Python code:
client = boto3.client('lex-runtime')
data = "string input"
response = client.post_text(
botName='xxx',
botAlias='yyy',
userId='id',
inputText= data)
but i get:
An error occurred (AccessDeniedException) when calling the PostText
operation: User: arn:aws:sts::111111111:assumed-
role/functionName/functionName is not authorized to perform: lex:PostText on
resource: arn:aws:lex:us-east-1:111111111:bot:xxx:yyyy"
So i set up IAM rule an and policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lex:PostText"
],
"Resource": [
"arn:aws:lex:us-east-1:111111111:bot:xxx:yyyy"
]
}
]
}
Trust relationship:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
But it still doesn't work and i get the same error.
I experienced the same issue recently.
It is most certainly related to the permissions assigned to the IAM role that you're using when running the Lambda function.
The easiest way to resolve this is below:-
Open the Lambda function on the AWS Console.
Scroll down to the "Execution role" section.
Click the link under the role to view the role in a new window. It
should look something like this: "View the role".
In the new window under the permissions tab click on "Attach
policies".
This takes you to a new screen. On this screen filter the listed
policies by typing in "lex" in the input field.
The filtered list will contain a policy call "AmazonLexRunBotsOnly".
Attach this policy to your role.
Save the changes and make your way back to your lambda function.
Save the lambda function and retest.
This will resolve your issue.
I created a new IAM role through Cognito during the setup process. Here is that policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sns:publish"
],
"Resource": [
"*"
]
}
]
}
In the trust relationship tab, it shows "The identity provider(s) cognito-idp.amazonaws.com" and it has a condition for sts:Externalid.
I tried adding a policy for FullEC2Access but so far I have not been able to get this IAM role to show up in the drodown when creating a new EC2 instance.
I will be using this instance for a new web app which will utilize Cognito. Any feedback appreciated.
I am trying to set a group policy with IAM to provide access to the users at the particular region with specific vpc. As referring the AWS documents,trying to use vpc ID to filter the instances, since the resource-tag is not working with ec2 ( ResourceTag would be better option if its working with EC2).
Created a following rule for the same, but it did not help,
{ "Version": "2012-10-17",
"Statement": [ {
"Action": [
"ec2:RunInstances",
"ec2:StartInstances",
"ec2:Describe*" ],
"Resource": "*",
"Effect": "Allow",
"Condition": {
"StringEquals": {
"ec2:Vpc": "arn:aws:ec2:us-west-2:*:vpc/vpc-123456"
}
}
} ] }
the result shows "An error occurred fetching Instance data" on EC2 page.
May I have any suggestions to fix this ?
Thank you
Thank you for you reply Rico :-)
Unfortunately,The given policy is did not work for me as per my requirement.
Need to give access to a user for particular region and user should have access to the instance which based on particular Resource tag or VPC or subnet or security group.
The user should not have privileges to launch or edit anything and user should able to list out the instances based on the filter as mentioned above to view the instance details (Read-only).
By considering above aspects, I have defined similar policy with dual condition ,since ARN is not working well with Resources for me.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "*",
"Condition": {
"StringEquals": {
[
"ec2:Region": "us-west-2",
"ec2:ResourceTag/Name": "Test"
]
}
}
}
]
}
When I use ARN for resource, it's not working for me on below format,
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "arn:aws:ec2:us-west-2:1234567890:*/*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Name": "Test"
}
}
}
]
}
I have tried with filtering Instances by using Resource tag, Instance ID, Security group and subnet.
Now I understand from your reply that VPC filter is not possible as of now.
Please refer the image for the Resource Tag of my instance.
Your prompt response will be highly appreciated.
Thanks in advance!
I have discussed with AWS Solution architect and the given following update,
The Describe* APIs for EC2 cannot be restricted to certain resources yet.
In the initial releases of resource-level permissions for EC2 we focused on those actions that create new or modify existing resources.
See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-policies-for-amazon-ec2.html#ec2-supported-iam-actions-resources for the full list of actions in EC2 that support resource-level permissions.
We are working to extend the support for resource-level access control to more actions but we cannot provide with a date when this would be available for Describe* APIs.
Whether Resource-level permissions are supported or not depends on the action, see the link above.
In particular, restricting EC2 Describe* Actions to resources is not possible as of now, but the above ARN can be used to restrict Actions that modify resources.
Resource Tag,subnet , security-group and vpc are supported in the "Condition" section of an IAM policy statement, but only for certain Actions – see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-policies-for-amazon-ec2.html#amazon-ec2-keys for the available keys. However, Resource Tag,subnet , security-group and vpc are not supported in Conditions for the Describe* APIs.
Finally, I just ending with workaround by restricting a user with only region.
So this is not possible using IAM at the moment, the only way is to use a ResourceTag. Curious as to why they are not working for you? I've have been interacting with AWS Support and this is their response:
Unfortunately, there is not a way to do this at this time. While we do
now offer resource level permissions for EC2 resources, (more info
here...
http://aws.typepad.com/aws/2013/07/resource-permissions-for-ec2-and-rds-resources.html)
conditionally controlling access based on a specif VPC is not
supported.
This is because this link: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-policies-for-amazon-ec2.html#ec2-supported-iam-actions-resources shows that there are a limited number of EC2 API actions supported and none of them support VPC as a ARN.
There's also a limitation on "ec2:Describe*", which cannot be specified by a resource ARN at all, and cannot be conditionally controlled.
The workaround is to use the conditional statement "ResourceTag/tag-key" which is usable by most API calls. So you can potentially tag your instances with "Control":"Allow" and don't include the create or remove tag privileges in the policy to be attached to the user in question. Your policy would look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:RebootInstances",
"ec2:TerminateInstances"
],
"Resource": "arn:aws:ec2:REGION:ACCOUNTNUMBER:instance/*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Control": "Allow"
}
}
}
]
}
Then you can restrict the user to launch instance just in a particular VPC using its subnet-id:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": [
"arn:aws:ec2:region:account:instance/*",
"arn:aws:ec2:region:account:subnet/SUBNET-ID-HERE",
"arn:aws:ec2:region:account:volume/*",
"arn:aws:ec2:region:account:network-interface/*",
"arn:aws:ec2:region:account:key-pair/*",
"arn:aws:ec2:region:account:security-group/*",
"arn:aws:ec2:region::image/ami-*"
]
}
]
}
To answer your question for a specific region, IAM policies are already region restricted, so this policy would only work on the specific region where you user that you are trying to restrict is on.
Hope this helps.