Error creating IAM Role: MalformedPolicyDocument: Has prohibited field Resource - aws-lambda

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.

Related

is there any possibility in terraform to enable Encryption in transit

I'm trying to enable Encryption in transit for my environment variable in lambda.
However I couldn't find any possible documentation in terraform to fix this?
I was able to create and attach customer master key in lambda. kms_key_arn
I have created this :
data "aws_kms_ciphertext" "secret_encryption" {
key_id = aws_kms_key.kms_key.key_id
plaintext = <<EOF
{
"token": "${var.token}"
}
EOF
}
now in my lambda's environment variable :
environment {
variables = {
ENV_TOKEN = data.aws_kms_ciphertext.secret_encryption.ciphertext_blob
}
also I attached the kms:decryt to lambda execution role
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:XXXX:XXXX:key/1234-567-...."
}
}
In my lambda:
encrypted_token = os.environ["ENV_TOKEN"]
decrypt_github_token = boto3.client('kms').decrypt( CiphertextBlob=base64.b64decode(encrypted_token)
)['Plaintext'].decode('utf-8')
But i'm getting "An error occurred (AccessDeniedException) when calling the Decrypt operation:when calling the Decrypt operation: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access."
does anyone knows where i'm doing wrong.
Should the encryption be only value format not the key value format?
Maybe the error is happening prior to decryption. I wonder if you can't even read the key itself. You can test this by appending "kms:DescribeKey".
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "arn:aws:kms:XXXX:XXXX:key/1234-567-...."
}
}

terraform aws iam_policy: Creating...failed with Policy document should not specify a principal

What I am trying to archive is getting an IAM role with an attached policy in AWS. The terraform script for policy creation is:
iam_policy.tf
resource "aws_iam_policy" "js_csm_iam_policy" {
name = "js_csm_iam_policy_02-2021"
path = "/"
description = "My CSM policy created 02 2021"
policy = file("cmsiampolicy.json")
}
and another script to create the role as well as attach the plolicy created above with
iam_role.tf
resource "aws_iam_role" "js_csm_iam_role" {
name = "js_csm_iam_role_02_2021"
assume_role_policy = file("csmiamrole.json")
}
##
### IAM role poliy attachment
##
resource "aws_iam_role_policy_attachment" "assign-policy1" {
role = aws_iam_role.js_csm_iam_role.name
policy_arn = aws_iam_policy.js_csm_iam_policy.arn
}
##
### instance_profile
##
resource "aws_iam_instance_profile" "js_csm_profile1" {
name = "js_csm_instance_profile"
role = aws_iam_role.js_csm_iam_role.name
}
csmiamrole.json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
terraform apply -auto-approve
aws_iam_role.js_csm_iam_role: Refreshing state... [id=js_csm_iam_role_02_2021]
aws_iam_instance_profile.js_csm_profile1: Refreshing state... [id=js_csm_instance_profile]
aws_iam_policy.js_csm_iam_policy: Creating...
Error: Error creating IAM policy js_csm_iam_policy_02-2021: MalformedPolicyDocument: Policy document should not specify a principal.
status code: 400, request id: 53da615d-0541-4b94-ac28-f2e4fdfc23be

Why add-event-source attach a new inline policy

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)

Correct terraform syntax for adding permissions to AWS Lambda

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.

Using AWS lambda function to call lex chat bot

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.

Resources