Added existing IAM role to EC2 instance using Terraform - amazon-web-services

I have an existing IAM role setup (not created suing Terraform), i need to add this to a an EC2 instance I have built using Terraform.
I have tried various options of using the aws_iam_role, iam_instance_profile commands but cannot get this to work.

Import your existing role into Terraform.
terraform import aws_iam_role.my_role_identifier my_existing_role_name
Create an instance profile from this role.
resource "aws_iam_instance_profile" "my_instance_profile" {
name = "my_instance_profile"
role = "${aws_iam_role.my_role_identifier}"
}
Pass this instance profile to your instance.
resource "aws_instance" "my_instance" {
...
iam_instance_profile = "${aws_iam_instance_profile.my_instance_profile.name}"
}

Thanks all. In the end I cloned my role using terraform, assigned it to the instance and removed the original.

Related

Attach IAM role to existing EC2 instance using terraform

I am trying to attach an IAM role to EC2 instance using terraform. But after looking out on some web pages.. I found that the attaching can be done at the time of creating ec2 instance.
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
iam_instance_profile = "${aws_iam_instance_profile.ec2_profile.name}"
tags = {
Name = "HelloWorld"
}
}
As in the above part , it can be clearly seen that, AMI is being passed which will create a new instance.
Is it somehow possible that instead of using AMI id, we can provide instance it, so that it can attach role to that instance?
I found out one link from terraform community pointing out that this feature is not yet released.
https://github.com/hashicorp/terraform/issues/11852
Please provide inputs on how to accomplish this task.
Thanks in advance
As you pointed out this is not supported. But if you really want to use terraform for that you could consider two options:
Use local-exec which would use AWS CLI associate-iam-instance-profile to attach the role to an existing instance.
Use aws_lambda_invocation. This way you could invoke a custom lambda function from your terraform which would use AWS SDK to associate profile with the instance. For example, for boto3 the method is associate_iam_instance_profile.

Attach custom iam policy to iam role

I'm trying to deal with some terraform scripts that are held across different git repo's.
One of the repo's is used for provisioning eks infrastructure and the other is to hold generic tf scripts.
In the generic repo, I've created a custom iam policy. I want this to be attached to the iam role when the eks infrastructure repo is created. Is there a way to do this?
resource "aws_iam_role_policy_attachment" "eks-worker-node-data-access" {
policy_arn = "arn:aws:iam::aws:policy/base-data-capture"
role = "${module.eks-control-plane.worker_node_role_name}"
}
The policy arn field is set to the name of the policy that would be created, however this fails as it hasn't been imported...
What I'd like to do is something like
resource "aws_iam_role_policy_attachment" "eks-worker-node-data-access" {
source = "my-git-repo.policy"
policy_arn = "arn:aws:iam::aws:policy/base-data-capture"
role = "${module.eks-control-plane.worker_node_role_name}"
}
I suppose the obvious answer would be to just have the policy created in the same tf folder, but all other policies have been created in the generic repo.

How to block Terraform from deleting an imported resource?

I'm brand new to Terraform so I'm sure i'm missing something, but the answers i'm finding don't seem to be asking the same question I have.
I have an AWS VPC/Security Group that we need our EC2 instances to be created under and this VPC/SG is already created. To create an EC2 instance, Terraform requires that if I don't have a default VPC, I must import my own. But once I import and apply my plan, when I wish to destroy it, its trying to destroy my VPC as well. How do I encapsulate my resources so when I run "terraform apply", I can create an EC2 instance with my imported VPC, but when I run "terraform destroy" I only destroy my EC2 instance?
In case anyone wants to mention, I understand that:
lifecycle = {
prevent_destroy = true
}
is not what I'm looking for.
Here is my current practice code.
resource "aws_vpc" "my_vpc" {
cidr_block = "xx.xx.xx.xx/24"
}
provider "aws" {
region = "us-west-2"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t3.nano"
vpc_security_group_ids = ["sg-0e27d851dxxxxxxxxxx"]
subnet_id = "subnet-0755c2exxxxxxxx"
tags = {
Name = "HelloWorld"
}
}
Terraform should not require you to deploy or import a VPC in order to deploy an EC2 instance into it. You should be able to reference the VPC, subnets and security groups by id so TF is aware of your existing network infrastructure just like you've already done for SGs and subnets. All you should need to deploy the EC2 instance "aws_instance" is give it an existing subnet id in the existing VPC like you already did. Why do you say deploying or importing a VPC is required by Terraform? What error or issue do you have deploying without the VPC and just using the existing one?
You can protect the VPC through AWS if you really wanted to, but I don't think you really want to import the VPC into your Terraform state and let Terraform manage it here. Sounds like you want the VPC to service other resources, maybe applications manually deployed or through other TF stacks, and the VPC to live independent of anyone application deployment.
To answer the original question, you can use a data source and match your VPC by id or tag name :
data "aws_vpc" "main" {
tags = {
Name = "main_vpc"
}
}
Or
data "aws_vpc" "main" {
id = "vpc-nnnnnnnn"
}
Then refer to it with : data.aws_vpc.main
Also, if you already included your VPC but would like not to destroy it while remove it from your state, you can manage to do it with the terraform state command : https://www.terraform.io/docs/commands/state/index.html

Terraform set AMI permissions to public

I'm currently using Terraform to copy an AMI from one region to multiple regions using:
resource "aws_ami_copy" "my_ami" {
name = "my_ami-${var.region}"
source_ami_id = "${var.source_ami_id}"
source_ami_region = "${var.source_ami_region}"
}
I need to make this AMI public, I've looked online and I can't find a way to do this using Terraform.
Terraform doesn't have a native way to do this currently. You can normally use Terraform to share an AMI with another account using the aws_ami_launch_permission resource but this only supports adding specific accounts and not the all group required for making it public.
You could always use a local-exec provisioner to shell out to the AWS CLI to make the AMI public with something like:
resource "null_resource" "share_ami_publicly" {
provisioner "local-exec" {
command = "aws ec2 modify-image-attribute --image-id ami-12345678 --launch-permission '{\"Add\":[{\"Group\":\"all\"}]}'"
}
}
Where the provisioner could be attached to any relevant resource (such as the aws_ami resource if you are using that to create AMIs).

Use IAM role instead of credentials to create aws resource from an EC2 instance using terraform

We are working on a requirement where we want terraform apply which runs on AWS EC2 instance to use IAM role instead of using credentials(accesskey/secretkey) as part of aws provider to create route53 in AWS.
NOTE: IAM Role added to instance has been provided with policy which gives the role the route53fullaccess.
When we use below syntax in terraform.tf, it works fine. We are able to create route.
SYNTAX:
*provider "aws" {
access_key = "${var.aws_accesskey}
secret_key = "${var.aws_secretkey}
region = "us-east-1"
}
resource "aws_route53_record {}*
But, we want the terraform script to run with IAM Role and not with credentials. (Do not want to maintain credentials file)
STEPS TRIED:
1. Removed provider block from terraform.tf file and run the build.
SYNTAX:
resource "aws_route53_record {}
2.Getting the below error.
Provider.aws :InvalidClientTokenid.
3. Went through the terraform official documentation to use IAM Role. it says to use metadata api. but there is no working sample. (https://www.terraform.io/docs/providers/aws/index.html)
Am new to Terraforms so pardon me if its a basic question. Can someone help with the code/working sample to achieve this ?
You need to supply the profile arn in the "provider" block, not the role, like so :
provider "aws" {
profile = "arn:aws:iam::<your account>:instance-profile/<your role name>"
}
The 'role_arn' key mentioned in the answer above is actually invalid in the 'provider' context.
Insert the following line for IAM role in your terraform script, in provider:
role_arn = "arn:aws:iam::<your account>:role/SQS-Role-demo"