1

I have a terraform script that provides a lambda function on aws to send emails. I pieced this terraform script from tutorials and templates on the web to use AWS SES, Api Gateway, Lambda and Cloudwatch services.

To get permissions to work though, I had to run the script and then, separately, build a policy in the AWS console and apply it to the lambda function so that it could fully access the SES and Cloudwatch services. But it's not at all not clear to me how to take that working policy and adapt it to my terraform script. Could anyone please provide or point to guidance on this matter?

The limited/inadequate but otherwise working role in my terraform script looks like this:

resource "aws_iam_role" "iam_for_lambda" {
    name = "${var.role_name}"
    assume_role_policy = <<EOF 
    { 
        "Version": "2012-10-17", 
        "Statement": [ 
            { 
                "Action": "sts:AssumeRole", 
                "Principal": { 
                    "Service": [ 
                        "lambda.amazonaws.com" 
                    ] 
                }, 
                "Effect": "Allow", 
                "Sid": "" 
            } 
        ] 
    } EOF 
}

... and the working policy generated in the console (by combining two roles together for all-Cloudwatch and all-SES access):

{
  "permissionsBoundary": {},
  "roleName": "las_role_new",
  "policies": [
    {
      "document": {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Action": [
              "autoscaling:Describe*",
              "cloudwatch:*",
              "logs:*",
              "sns:*",
              "iam:GetPolicy",
              "iam:GetPolicyVersion",
              "iam:GetRole"
            ],
            "Effect": "Allow",
            "Resource": "*"
          },
          {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "arn:aws:iam::*:role/aws-service-role/events.amazonaws.com/AWSServiceRoleForCloudWatchEvents*",
            "Condition": {
              "StringLike": {
                "iam:AWSServiceName": "events.amazonaws.com"
              }
            }
          }
        ]
      },
      "name": "CloudWatchFullAccess",
      "id": "ANPAIKEABORKUXN6DEAZU",
      "type": "managed",
      "arn": "arn:aws:iam::aws:policy/CloudWatchFullAccess"
    },
    {
      "document": {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "ses:*"
            ],
            "Resource": "*"
          }
        ]
      },
      "name": "AmazonSESFullAccess",
      "id": "ANPAJ2P4NXCHAT7NDPNR4",
      "type": "managed",
      "arn": "arn:aws:iam::aws:policy/AmazonSESFullAccess"
    }
  ],
  "trustedEntities": [
    "lambda.amazonaws.com"
  ]
}

There are fields So my question in summary, and put most generally, is this:

given a "policy" built in the aws console (by selecting a bunch of roles, etc. as in ), how do you convert that to a "role" as required for the terraform script?

Magnus
  • 3,086
  • 2
  • 29
  • 51
  • Are you perhaps confusing `policy` of `aws_iam_role_policy` with the `assume_role_policy` of `aws_iam_role`? You've listed a IAM policy but your resource takes an assume role policy. The assume role policy dictates _who_ or what can assume that role. The policy sets what the role is allowed to do. I found an answer at https://stackoverflow.com/a/44643708/684908 which has some explanation. – Andy Shinn Jan 18 '20 at 20:21
  • Thanks -- yes, I was very confused about the situation. I think things are slightly clearer now. – Magnus Jan 20 '20 at 17:19

1 Answers1

1

To anyone else who might struggle to understand terraform-aws-policy matters, here's my understanding after some grappling. The game here is to carefully distinguish the various similar-sounding terraform structures (aws_iam_role, aws_iam_role_policy, aws_iam_role, assume_role_policy, etc.) and to work out how these black-box structures fit together.

First, the point of an aws role is to collect together policies (i.e. permissions to do stuff). By assigning such a role to a service (e.g. lambda), you thereby give that service the permissions described by those policies. A role must have at least one policy sort of built-in to it: the 'assume-role' policy that specifies which service(s) can use ('assume') that role. This assume-role policy is relatively simple and so 'might as well' be included in the terraform script explicitly (using the <<EOF ... EOF syntax above).

Secondly, if you want to now let that service with the (basic) role do anything to other services, then you need to somehow associate additional policies with that role. I've learned that there are several ways to do this but, in order to answer my question most succinctly, I'll now describe the most elegant way I have found to incorporate multiple template policies offered in the AWS console into one's terraform script.

The code is:

# Define variable for name of lambda function
variable "role_name" {
  description = "Name for the Lambda role."
  default     = "las-role"
}

# Create role with basic policy enabling lambda service to use it
resource "aws_iam_role" "iam_for_lambda" {
  name = "${var.role_name}"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": [ "lambda.amazonaws.com" ]
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}


# Define a list of policy arn's given in the AWS console
variable "iam_policy_arn_list" {
  type        = list(string)
  description = "IAM Policies to be attached to role"
  default     = ["arn:aws:iam::aws:policy/CloudWatchFullAccess", "arn:aws:iam::aws:policy/AmazonSESFullAccess"]
}

# Create attachment of the policies for the above arn's to our named role
# The count syntax has the effect of looping over the items in the list
resource "aws_iam_role_policy_attachment" "role-policy-attachment" {
  role       = var.role_name
  count      = length(var.iam_policy_arn_list)
  policy_arn = var.iam_policy_arn_list[count.index]
  depends_on = [aws_iam_role.iam_for_lambda]
}

As you can see, the template policies are included here using the arns which can be found in the AWS console. For example, here's the view for finding the arn for full access to Amazon SES via the AWS Management Console:

enter image description here

When you succesfully deploy your lambda to AWS using terraform, it will pull down these policies from the arns and generate a permission json for your lambda function (which you can view in the lambda-service section of the aws console) that looks a lot like the json I posted in the question.

Magnus
  • 3,086
  • 2
  • 29
  • 51