I am new to terraform and still learing.
I know there is way you can import your existing infrastructure to terraform and have the state file created. But As if now I have multiple AWS accounts and multiple regions in those accounts which have multiple VPCs.
My task is to create vpc flow log through terraform.
Is it possible?
If it is, could you please help me or direct me how to get this thing done.
It is possible, albeit a little messy. You will need to create a provider block (with a unique alias) for each account/region combination you have (you can use profiles but I think roles is best), and select those providers in your resources appropriately.
provider "aws" {
alias = "acct1uswest2"
region = "us-west-2"
assume_role {
role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
}
}
provider "aws" {
alias = "acct2useast1"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
}
}
resource "aws_flow_log" "flow1" {
provider = aws.acct1uswest2
vpc_id = "vpc id in account 1" # you mentioned the vpc already exists, so you can either import the vpc and reference it's .id attribute here, or just put the id here as a string
...
}
resource "aws_flow_log" "flow2" {
provider = aws.acct2useast1
vpc_id = "vpc id in account 2"
...
}
Suggest you read up on importing resources (and the implications) here
More on multiple providers here
Related
Looking at this example:
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_global_replication_group
The secondary region is referencing the aws.other_region variable, however the aws provider spec does not have an 'other_region' field
When I try to set that manually to 'us-west-1' for example it fails with failed to install provider
other_region provider can be defined like.
provider "aws" {
region = "us-west-2"
}
provider "aws" {
alias = "other_region"
region = "us-west-1"
}
Then you can use it on resources like.
resource "aws_elasticache_replication_group" "secondary" {
provider = aws.other_region
replication_group_id = "example-secondary"
}
I have created a policy X with ec2 and vpc full access and attached to userA. userA has console access. So, using switch role userA can create instance from console.
Now, userB has programatic access with policy Y with ec2 and vpc full access. But when I tried to create instance using Terraform got error.
Error: creating Security Group (allow-80-22): UnauthorizedOperation: You are not authorized to perform this operation. Encoded authorization failure message:
Even - aws ec2 describe-instances
gives error -
An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.
Anyone can help me on this.
Thanks in advance.
To be honest there are a couple of mistakes in the question itself but I have ignored them and provided a solution to
Create Resources using IAM user with only programmatic access having direct policies attached to it
In general, if you have an AWS IAM user who has programmatic access and already has the required policies attached to it then it's pretty straightforward to create any resources within the permissions. Like any normal use case.
Create Resources using IAM user with only programmatic access with assuming a role that has required policies attached to it(role only)
providers.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
## If you hardcoded the role_arn then it is not required to have two provider configs(one with hardcoded value is enough without any alias).
provider "aws" {
region = "eu-central-1"
}
provider "aws" {
alias = "ec2_and_vpc_full_access"
region = "eu-central-1"
assume_role {
role_arn = data.aws_iam_role.stackoverflow.arn
}
}
resources.tf
/*
!! Important !!
* Currently the AWS secrets(AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY) used for authentication to terraform is
* from the user which has direct AWS managed policy [IAMFullAccess] attached to it to read role arn.
*/
# If you have hardcoded role_arn in the provider config this can be ignored and no usage of alias provider config is required
## using default provider to read the role.
data "aws_iam_role" "stackoverflow" {
name = "stackoverflow-ec2-vpc-full-access-role"
}
# Using provider with the role having aws managed policies [ec2 and vpc full access] attached
data "aws_vpc" "default" {
provider = aws.ec2_and_vpc_full_access
default = true
}
# Using provider with the role having AWS managed policies [ec2 and vpc full access] attached
resource "aws_key_pair" "eks_jump_host" {
provider = aws.ec2_and_vpc_full_access
key_name = "ec2keypair"
public_key = file("${path.module}/../../ec2keypair.pub")
}
# Example from https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance
# Using provider with the role having aws managed policies [ec2 and vpc full access] attached
data "aws_ami" "ubuntu" {
provider = aws.ec2_and_vpc_full_access
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
# Using provider with the role having aws managed policies [ec2 and vpc full access] attached
resource "aws_instance" "terraform-ec2" {
provider = aws.ec2_and_vpc_full_access
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
key_name = "ec2keypair"
security_groups = [aws_security_group.t-allow_tls.name]
}
# Using provider with the role having aws managed policies [ec2 and vpc full access] attached
resource "aws_security_group" "t-allow_tls" {
provider = aws.ec2_and_vpc_full_access
name = "allow-80-22"
description = "Allow TLS inbound traffic"
vpc_id = data.aws_vpc.default.id
ingress {
description = "http"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
For a full solution refer to Github Repo, I hope this is something you were looking and helps.
Let me give some context to the issue.
I'm trying to create a terraform script that deploys an AWS Organization with some accounts and also some resources in those accounts.
So, the issue is that I cant seem to be able to figure out how to create resources on multiple accounts at runetime. Meaning that I'd like to create resources on accounts I created on the same script.
The "workflow" would be something like this
Script creates AWS Organization
Same script creates AWS Organizations account
Same script creates an S3 bucket on the account created
Is this a thing that is possible doing? I know one can "impersonate" users by doing something like the following.
provider "aws" {
alias = "dns"
assume_role {
role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
session_name = "SESSION_NAME"
external_id = "EXTERNAL_ID"
}
}
But is this information something I can get after creating the account as some sort of output from the AWS-organization-account terraform module?
Maybe there is another way of doing this and I just need some reading material.
You can do this but you may want to separate some of these things out to minimise blast radius so it's not all in a single terraform apply or terraform destroy.
As a quick example you could do something like the following:
resource "aws_organizations_organization" "org" {
aws_service_access_principals = [
"cloudtrail.amazonaws.com",
"config.amazonaws.com",
]
feature_set = "ALL"
}
resource "aws_organizations_account" "new_account" {
name = "my_new_account"
email = "john#doe.org"
depends_on = [
aws_organizations_organization.org,
]
}
provider "aws" {
alias = "new_account"
assume_role {
role_arn = "arn:aws:iam::${aws_organizations_account.new_account.id}:role/OrganizationAccountAccessRole"
session_name = "new_account_creation"
}
}
resource "aws_s3_bucket" "bucket" {
provider = aws.new_account
bucket = "new-account-bucket-${aws_organizations_account.new_account.id}"
acl = "private"
}
The above uses the default OrganizationAccountAccessRole IAM role that is created in the child account to then create the S3 bucket in that account.
I'm trying to provision an EC2 instance in an existing and specific VPC by providing an AWS region to Terraform.
I want to be able to automatically choose a specific vpc using regex or some other method, this is my tf file.
can anybody help me?
the VPC I want to be chosen automatically has a prefix "digital".
so instead of providing its name in here -> name = "tag:${local.env_profile}-vpc"
I want to provide only the region and then to get this specific VPC using regex.
provider "aws" {
region = "eu-west-3"
shared_credentials_file = "${var.shared_credentials_file}"
profile = "${var.profile}"
}
data "aws_vpc" "selected" {
filter {
name = "tag:${local.env_profile}-vpc"
values = ["${local.env_profile}-vpc"]
}
}
resource "aws_instance" "general" {
ami = "ami-00035f41c82244dab"
instance_type = "${var.type}"
vpc = "${data.aws_vpc.selected.id}"
key_name = "${var.key_name}"
tags {
Name = "empty"
}
}
I don't think there is a way to select a random VPC via regex in terraform. You can check the data source for VPC here https://www.terraform.io/docs/providers/aws/d/vpc.html
You can refer to a VPC . by using the ID and the name.
Terraform doesn't seem to be able to create AWS private hosted Route53 zones, and dies with the following error when I try to create a new hosted private zone associated with an existing VPC:
Error applying plan:
1 error(s) occurred:
aws_route53_zone.analytics: InvalidVPCId: The VPC: vpc-xxxxxxx you provided is not authorized to make the association.
status code: 400, request id: b411af23-0187-11e7-82e3-df8a3528194f
Here's my .tf file:
provider "aws" {
region = "${var.region}"
profile = "${var.environment}"
}
variable "vpcid" {
default = "vpc-xxxxxx"
}
variable "region" {
default = "eu-west-1"
}
variable "environment" {
default = "dev"
}
resource "aws_route53_zone" "analytics" {
vpc_id = "${var.vpcid}"
name = "data.int.example.com"
}
I'm not sure if the error is referring to either one of these:
VPC somehow needs to be authorised to associate with the Zone in advance.
The aws account running the terraform needs correct IAM permissions to associate the zone with the vpc
Would anyone have a clue how I could troubleshoot this further?
some times you also face such issue when the aws region which is configured in provider config is different then the region in which you have VPC deployed. for such cases we can use alias for aws provider. like below:
provider "aws" {
region = "us-east-1"
}
provider "aws" {
region = "ap-southeast-1"
alias = "singapore"
}
then we can use it as below in terraform resources:
resource "aws_route53_zone_association" "vpc_two" {
provider = "aws.singapore"
zone_id = "${aws_route53_zone.dlos_vpc.zone_id}"
vpc_id = "${aws_vpc.vpc_two.id}"
}
above snippet is helpful when you need your terraform script to do deployment in multiple regions.
check the terraform version if run with latest or not.
Second, your codes are wrong if compare with the sample
data "aws_route53_zone" "selected" {
name = "test.com."
private_zone = true
}
resource "aws_route53_record" "www" {
zone_id = "${data.aws_route53_zone.selected.zone_id}"
name = "www.${data.aws_route53_zone.selected.name}"
type = "A"
ttl = "300"
records = ["10.0.0.1"]
}
The error code you're getting is because either your user/role doesn't have the necessary VPC related permissions or you are using the wrong VPC id.
I'd suggest you double check the VPC id you are using, potentially using the VPC data source to fetch it:
# Assuming you use the "Name" tag on the VPC resource to identify your VPCs
variable "vpc_name" {}
data "aws_vpc" "selected" {
tags {
Name = "${var.vpc_name}"
}
}
resource "aws_route53_zone" "analytics" {
vpc_id = "${data.aws_vpc.selected.id}"
name = "data.int.example.com"
}
You also want to check that your user/role has the necessary VPC related permissions. For this you'll probably want all of the permissions listed in the docs: