I am creating a Terraform script which creates a IAM role to be assumbed by EC2 instance via Launch Template. I have a simple lambda function (boto3/python) that creates/launches the EC2 instance using the Launch Template. However, I am getting this error when I run the lambda function:
"errorMessage": "An error occurred (InvalidParameterValue) when calling the RunInstances operation:
Value (arn:aws:iam::xxx:instance-profile/RigstopgapInstanceProfile) for parameter iamInstanceProfile.name is invalid. Invalid IAM Instance Profile name",
"errorType": "ClientError",
My terraform code is this one:
resource "aws_launch_template" "rig_stopgap" {
name = "rig_stopgap"
image_id = var.ami_image
instance_type = var.instance_type
iam_instance_profile {
name = aws_iam_instance_profile.rig_stopgap.arn
}
...
}
resource "aws_iam_instance_profile" "rig_stopgap" {
name = "RigstopgapInstanceProfile"
role = aws_iam_role.rigs_stopgap_ec2.name
}
# EC2 "Trust relationships" policy (necessary to allow the instance to assume a role)
data "aws_iam_policy_document" "trust_relationships_ec2_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
# EC2 main policy
resource "aws_iam_policy" "rigs_stopgap_ec2_policy" {
name = "RigsStopgapPolicy"
description = "Rigs Stopgap Policy allowing access to all of the necessary resources"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:UpdateItem"
],
"Effect": "Allow",
"Resource": "${aws_dynamodb_table.rigs_stopgap.arn}"
}
]
}
EOF
}
# Attach the ec2 policy
resource "aws_iam_role_policy_attachment" "attach_ec2_instance_policy" {
role = aws_iam_role.rigs_stopgap_ec2.name
policy_arn = aws_iam_policy.rigs_stopgap_ec2_policy.arn
}
resource "aws_iam_role" "rigs_stopgap_ec2" {
name = "RigsStopgapRole"
assume_role_policy = data.aws_iam_policy_document.trust_relationships_ec2_policy.json
tags = var.common_tags
}
My Lambda code:
import boto3
ec2 = boto3.resource('ec2')
lt = {
'LaunchTemplateName': 'rig_stopgap',
'Version': '$Latest'
}
def handler(event, context):
instances = ec2.create_instances(
LaunchTemplate=lt,
MinCount=1,
MaxCount=1
)
What am I missing?
Update:
When I open the Launch Template in the AWS Console and navigate to the Instance Profile section it apparantly cannot find it:
I'm not familiar with Terraform, but it looks like you are providing an ARN when it is simply wanting a name:
iam_instance_profile {
name = aws_iam_instance_profile.rig_stopgap.arn
}
Instead of providing the ARN, try just providing the name of the role.
In your aws_launch_template there should be arn, not name, for iam_instance_profile:
iam_instance_profile {
arn = aws_iam_instance_profile.rig_stopgap.arn
}
Related
I am trying to allow my Lambda function permissions so that it can publish an SNS message.
I am creating my Lambda in Terraform:
resource "aws_lambda_function" "DynamoDB_SNS_Lambda" {
s3_bucket = var.bucket_id
s3_key = "s3key.zip"
handler = "index.handler"
runtime = "nodejs16.x"
role = aws_iam_role.lambda_iam_role.arn
function_name = "lambda_name"
}
I am then creating a new IAM role:
resource "aws_iam_role" "lambda_iam_role" {
name = "sns_lambda_iam_role"
assume_role_policy = data.aws_iam_policy_document.sns_lambda_policy.json
}
data "aws_iam_policy_document" "sns_lambda_policy" {
statement {
sid = ""
effect = "Allow"
actions = [
"sns:Publish",
]
resources = [
var.order_update_sns_topic_arn
]
}
}
I am then trying to attach a policy to that IAM role to allow SNS permissions.
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
role = aws_iam_role.lambda_iam_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonSNSRole"
}
When I run terraform apply, I get the following error:
module.Lambda.aws_iam_role.lambda_iam_role: Modifying... [id=sns_lambda_iam_role]
╷
│ Error: error updating IAM Role (sns_lambda_iam_role) assume role policy: MalformedPolicyDocument: Has prohibited field Resource
│ status code: 400, request id: 98a57a4c-1839-4a04-b903-e7deb409c71e
│
│ with module.Lambda.aws_iam_role.lambda_iam_role,
│ on modules/lambda/main.tf line 17, in resource "aws_iam_role" "lambda_iam_role":
│ 17: resource "aws_iam_role" "lambda_iam_role" {
Am I creating my aws_iam_policy_document correctly?
Am I correct in thinking I need to attach the policy to the role with aws_iam_role_policy_attachment?
This is incorrect assume policy. Assume policy tells only who/what can assume the role, not what permissions the role has. In your case, only lambda can assume the role. And the actual permissions can be set using inline_policy. For example:
resource "aws_iam_role" "lambda_iam_role" {
name = "sns_lambda_iam_role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "lambda.amazonaws.com"
}
},
]
})
inline_policy {
name = "policy-8675309"
policy = data.aws_iam_policy_document.sns_lambda_policy.json
}
}
I'm trying to create an IAM Role and IAM Policy using Terraform.
I'm getting this error:
│ Error: error creating IAM Role (asg-domain-join-policy): MalformedPolicyDocument: Has prohibited field Resource
status code: 400, request id: 53fa1ae0-f22f-4f2e-8aa6-1947421eae9b
with aws_iam_role.ad_join_role,
on iam.tf line 30, in resource "aws_iam_role" "ad_join_role":
30: resource "aws_iam_role" "ad_join_role" {
My current code for the IAM Role is the following:
resource "aws_iam_role" "ad_join_role" {
name = "asg-domain-join-policy"
assume_role_policy = data.aws_iam_policy_document.asg_domain_join_policy.json
permissions_boundary = "arn:aws:iam::${var.account_id}:policy/****"
}
The code for IAM Policy is the following:
data "aws_iam_policy_document" "asg_domain_join_policy" {
statement {
actions = [
"ssm:DescribeAssociation",
"ssm:GetDocument",
"ssm:ListAssociations",
"ssm:UpdateAssociationStatus",
"ssm:UpdateInstanceInformation",
"ssm:CreateAssociation",
]
effect = "Allow"
resources = ["ec2"]
}
}
I'm unsure why I'm getting that error.
The assume_role_policy can have a document which specifies only the AssumeRole action. What you have to do is split your policy to create separate ones for being able to assume a role, and being able to attach other permissions to the role.
For example:
# Allow EC2 instances to assume the role
data "aws_iam_policy_document" "asg_assume_role_policy" {
statement {
actions = [
"sts:AssumeRole"
]
effect = "Allow"
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
# Create the policy which allows other actions for the EC2 instance
data "aws_iam_policy_document" "asg_domain_join_policy" {
statement {
actions = [
"ssm:DescribeAssociation",
"ssm:GetDocument",
"ssm:ListAssociations",
"ssm:UpdateAssociationStatus",
"ssm:UpdateInstanceInformation",
"ssm:CreateAssociation"
]
effect = "Allow"
resources = ["*"]
}
}
resource "aws_iam_role" "ad_join_role" {
name = "asg-domain-join-policy"
assume_role_policy = data.aws_iam_policy_document.asg_assume_role_policy.json
# Attach the policy
inline_policy {
policy = data.aws_iam_policy_document.asg_domain_join_policy.json
}
}
Some things to note in this example:
The second policy is attached as an inline policy. This is fine, if the policy is shorter, otherwise you may want to use aws_iam_policy_attachment
The resource type for the actions in the second policy is a wildcard ["*"]. If you want more granularity for your actions on the policy, you may want to check out this page to see which action allows what kind of resource type. Obviously, ["ec2"] is not a valid resource type.
Your resource block is using an incorrect reference. ec2 is not a resource. If you are referencing an instance you need to use aws_instance.my_ec2_instance, or if you want to allow all resources you can put "*".
I'm writing a Lambda function that should be triggered (after X amount of time) using a CloudWatch event. I have almost the configuration working, but I can't get the policy business from AWS right. This is what I have so far:
data "aws_iam_policy_document" "this" {
statement {
actions = ["sts:AssumeRole"]
effect = "Allow"
principals {
identifiers = ["lambda.amazonaws.com"]
type = "Service"
}
}
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents",
]
effect = "Allow"
resources = ["arn:aws:logs:*:*:*"]
}
}
resource "aws_iam_role_policy_attachment" "this" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
role = aws_iam_role.this.name
}
resource "aws_iam_role" "this" {
assume_role_policy = data.aws_iam_policy_document.this.json
name = "AWSLambdaSpringCloudFunctionBasicExecutionRole"
}
I just want the Lambda to be able to write to CloudWatch and be triggered by the CloudWatch Event source...that's all, no more permissions. I'm creating the Log Group via Terraform, so no need for logs:CreateLogGroup.
When I do terraform apply (version 0.12.24) this error pops out:
aws_iam_role.this: Creating...
Error: Error creating IAM Role AWSLambdaSpringCloudFunctionBasicExecutionRole: MalformedPolicyDocument: Has prohibited field Resource
status code: 400, request id: 12ad676e-b98e-4c60-bedd-bf17487bd51d
Is there a way to declare the AWS Lambda policy and assume role policy together? If not, what are the recommended Terraform resources/data sources for doing this?
UPDATE: Complete Solution
As Oleksii pointed out, I was using the wrong resource to create the IAM policy:
data "aws_iam_policy_document" "assume_role" {
statement {
actions = ["sts:AssumeRole"]
effect = "Allow"
principals {
identifiers = ["lambda.amazonaws.com"]
type = "Service"
}
}
}
resource "aws_iam_role_policy_attachment" "assume_role" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
role = aws_iam_role.lambda.name
}
resource "aws_iam_role" "lambda" {
assume_role_policy = data.aws_iam_policy_document.assume_role.json
name = "Use Any Identifier/Name You Want Here For IAM Role"
}
data "aws_iam_policy_document" "logs" {
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents",
]
effect = "Allow"
resources = ["arn:aws:logs:*:*:*"]
}
}
resource "aws_iam_policy_attachment" "logs" {
name = "Use Any Identifier/Name You Want Here For IAM Policy Logs"
policy_arn = aws_iam_policy.logs.arn
roles = [aws_iam_role.lambda.name]
}
resource "aws_iam_policy" "logs" {
name = "Use Any Identifier/Name You Want Here For IAM Policy Logs"
policy = data.aws_iam_policy_document.logs.json
}
You're trying to define multiple statements in assume_role_policy, which is not a regular policy, but a "trust relation" type of policy. It only describes who can assume role and under which conditions.
From my understanding (limited Terraform knowledge) you need to move second statement to its own policy and then attach it via aws_iam_role_policy_attachment
I have a problem with AWS assume role using terraform.
In AWS I have three accounts: root, staging and production (let's focus only on root & staging account) in single organization. The root account has one IAM user terraform (with AdministratorAccess policy) which is used by terraform to provisioning all stuff.
The image of organization structure
Root account ID: 111111111111
Staging account ID: 333333333333
A terraform script looks like that:
############## backend.tf
terraform {
required_version = "0.12.19"
}
############## providers.tf
provider "aws" {
region = "eu-west-1"
profile = "default"
}
provider "aws" {
version = ">= 2.44"
region = "eu-west-1"
profile = "default"
assume_role {
role_arn = "arn:aws:iam::333333333333:role/staging-admin"
}
allowed_account_ids = ["333333333333"]
alias = "staging"
}
############## organization.tf
resource "aws_organizations_account" "staging" {
email = "staging#domain.com"
name = "Staging"
parent_id = "ZZZZZ"
}
############## data.tf
data "aws_iam_policy_document" "assume_staging_role" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
resources = [
aws_iam_role.staging.arn
]
}
}
data "aws_iam_policy" "administrator_access" {
arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
data "template_file" "cross_admin_trust_policy" {
template = file("templates/cross_admin_trust_policy.json")
vars = {
staging_account_number = aws_organizations_account.staging.id
}
}
############## iam.tf
resource "aws_iam_role" "staging" {
name = "staging-admin"
description = "Assumable role granting administrator permissions to the staging account"
assume_role_policy = data.template_file.cross_admin_trust_policy.rendered
max_session_duration = 20000
provider = aws.staging
}
resource "aws_iam_role_policy_attachment" "staging_admin_access" {
role = aws_iam_role.staging.name
policy_arn = data.aws_iam_policy.administrator_access.arn
provider = aws.staging_ireland
}
resource "aws_iam_role_policy_attachment" "staging_attach_assume_any_admin" {
role = aws_iam_role.staging.name
policy_arn = data.aws_iam_policy.administrator_access.arn
provider = aws.staging_ireland
}
and my policy.json file:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${staging_account_number}:role/staging-admin"
},
"Action": "sts:AssumeRole"
}
]
}
when I execute terraform plan I'm getting this error:
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.aws_iam_policy.administrator_access: Refreshing state...
aws_organizations_account.staging: Refreshing state... [id=333333333333]
data.template_file.cross_admin_trust_policy: Refreshing state...
Error: The role "arn:aws:iam::333333333333:role/staging-admin" cannot be assumed.
There are a number of possible causes of this - the most common are:
* The credentials used in order to assume the role are invalid
* The credentials do not have appropriate permission to assume the role
* The role ARN is not valid
on providers.tf line 25, in provider "aws"
Someone has an idea how to fix?
According to https://aws.amazon.com/premiumsupport/knowledge-center/iam-assume-role-cli/
Run the aws sts get-caller-identity command to check your identity.
Run the aws sts assume-role --role-arn arn:aws:iam::333333333333:role/staging-admin command to see if this role can be assumed by your identity.
Check your IAM role's trust relationship. You should restrict it so that the IAM role should be only assumed by specific IAM users.
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam:: 333333333333:root" },
"Action": "sts:AssumeRole"
}
}
According to the data you provided you don't have a role, and you trying to add roles with first apply. Correct me if I'm wrong.
You need to manually create an "account aws role" in IAM with "AdministratorAccess" policy attached.
With Terraform, following the doc here and there, I am trying to create a template for ec2 instance with elastic inference gpu specification and graphics.
This my code for aws launch template resource:
resource "aws_launch_template" "elastic_ec2" {
name_prefix = "DeepLearning"
description = "Deep Learning"
disable_api_termination = true
ebs_optimized = true
image_id = "ami-0d9d11b8557309342"
instance_initiated_shutdown_behavior = "terminate"
instance_type = "t3.medium"
key_name = "${local.pem_key_name}"
block_device_mappings {
device_name = "/dev/sda1"
}
capacity_reservation_specification {
capacity_reservation_preference = "open"
}
credit_specification {
cpu_credits = "standard"
}
elastic_gpu_specifications {
type = "eg1.medium"
}
elastic_inference_accelerator {
type = "eia1.medium"
}
iam_instance_profile {
name = "my-right-profile"
}
instance_market_options {
market_type = "spot"
}
monitoring {
enabled = true
}
network_interfaces {
associate_public_ip_address = true
}
placement {
availability_zone = "${var.main_location}"
}
tag_specifications {
resource_type = "instance"
tags = {
Environment = "${local.environment}"
}
}
}
resource "aws_instance" "web" {
ami = "${aws_launch_template.elastic_ec2.image_id}"
instance_type = "${aws_launch_template.elastic_ec2.instance_type}"
key_name = "${local.pem_key_name}"
iam_instance_profile = "${aws_iam_instance_profile.ec2_profile.name}"
tags = {
Environment = "${local.environment}"
App = "${local.app_name}"
}
}
Of course this the policies used for the deployment of the instance following the doc specifications here:
resource "aws_iam_role" "ec2_exec_role" {
name = "ec2_exec"
path = "/"
description = "Allows Lambda Function to call AWS services on your behalf."
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": [
"ec2.amazonaws.com",
"ecs-tasks.amazonaws.com"
]
},
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}
resource "aws_iam_instance_profile" "ec2_profile" {
name = "${local.environment}_ec2_profile"
role = "${aws_iam_role.ec2_exec_role.name}"
}
resource "aws_iam_policy" "ec2_policy" {
name = "${local.environment}_ec2_policy"
description = "Ec2 main polify for ${local.environment} environment"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elastic-inference:Connect",
"iam:List*",
"iam:Get*",
"ec2:Describe*",
"ec2:Get*",
"ecs:RegisterTaskDefinition",
"ecs:RunTask"
],
"Resource": [
"arn:aws:ec2:${var.main_location}::*",
"arn:aws:elastic-inference:${var.main_location}:${data.aws_caller_identity.current.account_id}:*",
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecs-ei-task-role",
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/ecsTaskExecutionRole"
]
}
]
}
EOF
}
resource "aws_iam_policy_attachment" "ec2_attachment" {
name = "${local.environment}_ec2__attachment"
roles = ["${aws_iam_role.ec2_exec_role.name}"]
policy_arn = "${aws_iam_policy.ec2_policy.arn}"
}
I have no error when I am deploying the terraform code with the command terraform plan and terraform apply. I have my instance template and my ec2 instance deployed, but I can see that in my instance I have no Elastic Inference Accelerator ID attached on it. What is the right configuration I need using terraform to attach correctly all elastic inference specifications
Thanks for making this question, it led me to answer how to launch an EC2 instance with an elastic inference accelerator. There's currently an issue open in the AWS terraform provider repo about adding an option to attach an EI directly to an EC2 instance.
The issue with this config is that the launch template isn't associated with your instance. I was able to launch my EC2 instance with an EI by specifying your launch template in a launch configuration for an Autoscaling Group.
But keep in mind that there are many other steps that you need to take to attach an EI to an EC2 instance. Specifying security groups, creating a VPC endpoint... Docs
Hope this helps.