Correct terraform syntax for adding permissions to AWS Lambda - 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.

Related

User is not authorized to perform: iam:CreatePolicy on resource: policy AWSLambdaBasicExecutionRole?

Logged in as IAM user and trying to create lambda function but seeing below error, what is missing her?
User: arn:aws:iam::123334324324234:user/abx.dsd#rr.com is not authorized to perform: iam:CreatePolicy on resource: policy AWSLambdaBasicExecutionRole-e3e28520-4b65-439e-a006-24de73479562
When you create a AWS Lambda in the AWS Console a few things are done in the background by AWS. One such thing is creating a role/policy for your Lambda automatically.
To do so, your user (arn:aws:iam::123334324324234:user/abx.dsd#rr.com) needs the iam:CreatePolicy permission.
This is something a account administrator can fix for you.
adding iam:CreateRole is not enough, you need to add also several other permissions to the user, something like this
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:AttachRolePolicy",
"iam:CreateRole",
"iam:CreatePolicy",
"iam:PutRolePolicy"
],
"Resource": "*"
}
]
}
Note. I am not sure that all these policies are required.

Error creating IAM Role: MalformedPolicyDocument: Has prohibited field Resource

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.

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.

Ansible EC2 Dynamic inventory minimum IAM policies

Has someone figured out the minimum IAM policies required to run the EC2 dynamic inventory script (ec2.py) on ansible via an IAM role?
So far, I haven't seen a concrete reference in this matter other than specifying credentials for boto library in the official documentation of ansible, however, on production environments, I rarely use key pairs for access to AWS services from EC2 instances, instead I have embraced the use of IAM roles for that case scenario.
I have tried policies allowing ec2:Describe* actions but it doesn't seem to be enough for the script as it always exits with Unauthorized operation.
Could you help me out?
The script also looks at RDS and elasticache. They can be disabled in ec2.ini, but if you don't, the following policy seems to be enough to run the dynamic inventory.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Demo201505282045",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"route53:ListHostedZones",
"route53:ListResourceRecordSets",
"rds:Describe*",
"elasticache:Describe*"
],
"Resource": "*"
}
]
}
I just created a demo policy, created a new role and used that new policy, and then created a new instance that used that new role.
Demo Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Demo201505282045",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": "*"
}
]
}
I had to add route53 as I use the route53 option (route53 = true in the ec2.ini) but other than that it worked fine.
If you are still having problems, try running ec2.py from the commandline (./ec2.py) as that does usually give reasonable error messages when run directly.
The script checks also for Route53, RDS and ElastiCache configurations, so it will require access to ec2:Describe*, route53:ListHostedZones, route53:ListResourceRecordSets, rds:Describe* and elasticache:Describe*.
Still, if you don't use all these services you can selectively disable their check in the ec2.ini file by setting to False the values of the associated group_by_* variables: this will skip the fetching of those configurations, both allowing you to minimize the actions allowed for the role (eg: ec2:Describe* only) and reducing the overall query time of the script.
These are the permissions that I identified as required by ec2.py after checking CloudTrail:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"elasticache:DescribeReplicationGroups",
"ec2:DescribeInstances",
"ec2:DescribeTags",
"rds:DescribeDBInstances",
"elasticache:DescribeCacheClusters"
],
"Resource": "*"
}
]
}

AWS IAM Permissions for EC2 – Controlling Access on Specific Instances with particular region

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.

Resources