Inappropriate value for attribute "security_groups": element 0: string required - amazon-web-services

I'm not sure why I'm getting this value.
I have this resource in bastion/main.tf
resource "aws_security_group" "bastion_sg" {
name = "${var.name}-bastion-security-group"
vpc_id = var.vpc_id
ingress {
protocol = "tcp"
from_port = 22
to_port = 22
cidr_blocks = ["0.0.0.0/0"]
}
egress {
protocol = -1
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.name}-bastion-sg"
}
}
here is my output for that bastion/outputs.tf
output "bastion_sg_id" {
value = aws_security_group.bastion_sg
}
My eks module in my root directory main.tf
module "eks" {
source = "./eks"
name = var.name
key_name = module.bastion.key_name
bastion_sg = module.bastion.bastion_sg_id
vpc_id = module.networking.vpc_id
private_subnets = module.networking.vpc_private_subnets
}
my variables in my eks/variables.tf
variable "bastion_sg" {
description = "bastion sg to add to ingress rule of node sg"
}
lastly, my eks/main.tf where the error is occuring
esource "aws_security_group" "node-sg" {
name = "${var.name}-node-security-group"
vpc_id = var.vpc_id
ingress {
protocol = "tcp"
from_port = 22
to_port = 22
security_groups = [var.bastion_sg]
}
egress {
protocol = -1
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}
I tried it with and without the [] for the security_groups argument and when I did it without I got the set of strings required error and when I added the [] I got this error
on eks\main.tf line 95, in resource "aws_security_group" "node-sg":
│ 95: security_groups = [var.bastion_sg]
│ ├────────────────
│ │ var.bastion_sg is object with 13 attributes
│
│ Inappropriate value for attribute "security_groups": element 0: string required.

It should be:
output "bastion_sg_id" {
value = aws_security_group.bastion_sg.id
}

Related

How to create module for security group in terraform

I have this resource to make security groups and have several entry rules.
These files are inside the "security-group" folder because I have to create a module for it.
Main.tf
resource "aws_security_group" "main" {
name = var.sg_name
dynamic "ingress" {
for_each = local.ingress_rules
content {
description = ingress.value.description
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
variable.tf
locals {
ingress_rules = [{
port = 443
description = "Port 443"
},
{
port = 80
description = "Port 80"
}]
}
Now outside of the modules/security-group/ folder I have the main .tf file where I want to call that module to create security groups.
module "security_group" {
source = "./modules/security-group"
dynamic "ingress" {
for_each = local.ingress_rules
content {
description = ingress.value.description
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
│ Error: Unsupported block type
│
│ on main.tf line 29, in module "security_group":
│ 29: dynamic "ingress" {
│
│ Blocks of type "dynamic" are not expected here.
╵
How else can I call this module to create the rules and other necessary things? Many thanks in advance
There are no dynamic blocks for modules. You have to pass your rules as regular variables to the module, not local values:
variable "ingress_rules" {
default = [{
from_port = 443
to_port = 443
description = "Port 443"
},
{
from_port = 80
to_port = 80
description = "Port 80"
}]
}
resource "aws_security_group" "main" {
name = var.sg_name
dynamic "ingress" {
for_each = var.ingress_rules
content {
description = ingress.value.description
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
then in parent folder:
module "security_group" {
source = "./modules/security-group"
ingress_rules = [
{
description = "description"
from_port = 20
to_port = 20
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
]
}
You have to fix all those names of your attributes. You can't just mix port and to_port.

Terraform ec2 instance don't creating

Hello i have tf file for create my ec2 instance
resource "aws_vpc" "magazin-vpc" {
cidr_block = 10.249.0.0/16
}
resource "aws_subnet" "magazin-subnet" {
vpc_id = aws_vpc.magazin-vpc.id
cidr_block = "10.249.2.0/28"
}
resource "aws_instance" "magazin-vm" {
ami = "ami-058c02d7640104f1e"
instance_type = "t2.micro"
private_ip = "10.249.2.5"
subnet_id = aws_subnet.magazin-subnet.id
vpc_security_group_ids = [aws_security_group.magazin-sg.id]
credit_specification {
cpu_credits = "unlimited"
}
}
resource "aws_ebs_volume" "magazin-ebs" {
availability_zone = "eu-north-1a"
size = 10
tags = {
Name = "magazin-ebs"
}
}
resource "aws_volume_attachment" "magazin-ebs-att" {
device_name = "/dev/sdh"
volume_id = aws_ebs_volume.magazin-ebs.id
instance_id = aws_instance.magazin-vm.id
}
resource "aws_security_group" "magazin-sg" {
name = "magazin-sg"
ingress {
description = "Allow port SSH from office"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["172.16.0.0/24"]
}
ingress {
description = "Allow port HTTPS"
from_port = 9200
to_port = 9200
protocol = "tcp"
cidr_blocks = ["172.16.0.0/24"]
}
ingress {
description = "Allow port HTTPS"
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["172.16.0.0/24"]
}
egress {
description = "Allow ALL ports"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
and when i launch terraform apply i got
│ Error: Error launching source instance: InvalidParameter: Security group sg-090289f530fb61f8d and subnet subnet-08d14b2d736d10286 belong to different networks.
│ status code: 400, request id: 953d0bb8-cf92-4d8c-9923-d911cec3b453
│
│ with aws_instance.magazin-vm,
│ on dev-aerospike.tf line 6, in resource "aws_instance" "magazin-vm":
│ 6: resource "aws_instance" "magazin-vm" {
│
why this error happens? because i declarate vpc and subnet in my terraform file
i'm using terraform 1.1.6
p.s the site says that the text should be longer but I don't know what else to write so I'll write that terraform is a cool thing, though I still don't know how to use it
You have to specify vpc_id in your aws_security_group. Without that your group will be created in a default VPC, not the one you are creating:
resource "aws_security_group" "magazin-sg" {
name = "magazin-sg"
vpc_id = aws_vpc.magazin-vpc.id
ingress {
description = "Allow port SSH from office"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["172.16.0.0/24"]
}
ingress {
description = "Allow port HTTPS"
from_port = 9200
to_port = 9200
protocol = "tcp"
cidr_blocks = ["172.16.0.0/24"]
}
ingress {
description = "Allow port HTTPS"
from_port = -1
to_port = -1
protocol = "icmp"
cidr_blocks = ["172.16.0.0/24"]
}
egress {
description = "Allow ALL ports"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

Creating multiple SecurityGroups / Rules in AWS using Terraform

I am trying to create multiple Security Groups and rules within this group at the same time in a module for AWS.
I have a variable type like this below
variable "security_rules" {
type = map(map(object({
type = string
description = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
})))
}
And i am passing the values like this
security_rules = {
internal_sg = {
"rule1" = { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], description = "For SSH" },
"rule2" = { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], description = "For SSH" }
external_sg = {
"rule1" = { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp"
}
}
Where internal_sg and external_sg would be security group name and there corresponding rules.
I am able to create the security groups but failing to add rules on top of that.
locals {
name = var.security_rules
}
resource "aws_security_group" "ec2_security_groups" {
for_each = local.name
name = each.key
vpc_id = data.aws_vpc.selected.id
}
But i am just unable to make the logic for the security group rules
resource "aws_security_group_rule" "rules" {
for_each = { for k, v in local.name : k => v }
type = each.value.type
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
description = each.value.description
security_group_id = aws_security_group.ec2_security_groups[each.key]
}
Error:
╷
│ Error: Missing map element
│
│ on ../../terraform-stacks/Stacks/security-group/main.tf line 19, in resource "aws_security_group_rule" "rules":
│ 19: type = each.value.type
│ ├────────────────
│ │ each.value is map of object with 3 elements
│
│ This map does not have an element with the key "type".
╵
You have to flatten your variable first:
locals {
flat_security_rules = merge([
for sg, rules in var.security_rules:
{
for rule, vals in rules:
"${sg}-${rule}" => merge(vals, {sg_name = sg})
}
]...) # please, do NOT remove the dots
}
then
resource "aws_security_group_rule" "rules" {
for_each = local.flat_security_rules
type = each.value.type
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
description = each.value.description
security_group_id = aws_security_group.ec2_security_groups[each.value.sg_name].id
}

How to specify list of string within for_each loop?

I'm trying to create a reusable security group and its rules using for_each. While passing the cidr_blocks = list(string), I'm getting the below error. If I remove the cidr_blocks the code works fine
╷
│ Error: Invalid index
│
│ on ../../modules/security/main.tf line 18, in resource "aws_security_group" "app_sg":
│ 18: cidr_blocks = ingress.value["cidr_blocks"]
│ ├────────────────
│ │ ingress.value is object with 3 attributes
│
│ The given key does not identify an element in this collection value.
╵
Root Module
###################################
# Create a security group & rules #
###################################
module "application_sg" {
source = "../../modules/security"
create_sg = var.create_sg
name_suffix = var.name_suffix
sg_name = var.sg_name
environment = local.common-tags.environment
vpc_id = one(module.mgt_vpc.vpc_id)
egress_rules = var.app_egress_rules
ingress_rules = var.app_ingress_rules
cidr_blocks = var.app_cidr_blocks
common-tags = local.common-tags
}
module "database_sg" {
source = "../../modules/security"
create_sg = var.create_sg
vpc_id = one(module.sre_vpc.vpc_id)
sg_name = var.db_sg_name
name_suffix = var.name_suffix
environment = local.common-tags.environment
egress_rules = var.db_egress_rules
ingress_rules = var.db_ingress_rules
ingress_self_sg = true
common-tags = local.common-tags
}
################################
# List of Security Group Rules #
################################
variable "app_ingress_rules" {
type = map(object({
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
default = {
SSH = {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
HTTP = {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
HTTPS = {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
variable "app_egress_rules" {
type = map(object({
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
default = {
ALLOW_ALL = {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
variable "db_ingress_rules" {
type = map(object({
from_port = number
to_port = number
protocol = string
}))
default = {
MYSQL = {
from_port = 3306
to_port = 3306
protocol = "tcp"
},
HTTPS = {
from_port = 443
to_port = 443
protocol = "tcp"
}
}
}
variable "db_egress_rules" {
type = map(object({
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
default = {
ALLOW_ALL = {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
Child Module
################################
# Create Securiy Group & Rules #
################################
resource "aws_security_group" "app_sg" {
for_each = var.create_sg ? toset(var.sg_name) : []
name = each.key
vpc_id = var.vpc_id
dynamic "ingress" {
for_each = var.ingress_rules != {} ? toset(values(var.ingress_rules)) : []
content {
from_port = ingress.value["from_port"]
to_port = ingress.value["to_port"]
protocol = ingress.value["protocol"]
cidr_blocks = ingress.value["cidr_blocks"]
security_groups = var.security_groups
self = var.ingress_self_sg
}
}
dynamic "egress" {
for_each = var.egress_rules != {} ? toset(values(var.egress_rules)) : []
content {
from_port = egress.value["from_port"]
to_port = egress.value["to_port"]
protocol = egress.value["protocol"]
cidr_blocks = egress.value["cidr_blocks"]
security_groups = var.security_groups
self = var.egress_self_sg
}
}
tags = merge(
var.common-tags,
{
"Name" = "${each.key}-${lower(var.environment)}"
}
)
}
// Variables
variable "create_sg" {
}
variable "vpc_id" {
}
variable "environment" {
}
variable "name_suffix" {
}
variable "sg_name" {
}
variable "common-tags" {
}
variable "ingress_rules" {
type = any
default = {}
}
variable "egress_rules" {
type = any
default = {}
}
variable "security_groups" {
type = list(string)
default = []
}
variable "ingress_self_sg" {
type = bool
default = false
}
variable "egress_self_sg" {
type = bool
default = false
}
Your var.db_ingress_rules does not have cidr_blocks. You have to add it there, e.g.:
variable "db_ingress_rules" {
type = map(object({
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
default = {
MYSQL = {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
HTTPS = {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}

AWS Terraform - using dynamic block on resource

I'm trying to write a Terraform module for AWS Security Groups with the dynamic block, but I'm having this error:
│
│ on main.tf line 17, in module "security_group":
│ 17: ingress = {
│
│ The argument "ingress" was already set at main.tf:8,5-12. Each argument may be set only once.
I've followed the documentation but I'm still having the error
I'm using Terraform 0.15.1 and AWS provider version 3.38.0
Here is my code
./modules/security_group/main.tf
resource "aws_security_group" "main" {
.......
dynamic "ingress" {
for_each = var.ingress
content {
description = ingress.value["description"]
from_port = ingress.value["from_port"]
to_port = ingress.value["to_port"]
protocol = ingress.value["protocol"]
cidr_blocks = ingress.value["cidr_blocks"]
ipv6_cidr_blocks = ingress.value["ipv6_cidr_blocks"]
}
}
.......
}
./modules/security_group/variables.tf
variable "ingress" {
description = ""
type = object({
description = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
ipv6_cidr_blocks = list(string)
})
default = {
description = ""
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = []
ipv6_cidr_blocks = []
}
}
./main.tf
module "security_group" {
source = "./modules/security_group"
name = "${var.project}-sg"
description = "security group testing"
vpc_id = "my-vpc"
ingress = {
description = ""
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = []
ipv6_cidr_blocks = []
}
ingress = {
description = ""
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = []
ipv6_cidr_blocks = []
}
}
You have ingress arguments. I think you want to have one as a list:
variable "ingress" {
description = ""
type = list(object({
description = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
ipv6_cidr_blocks = list(string)
}))
default = [{
description = ""
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = []
ipv6_cidr_blocks = []
}
}]
module "security_group" {
source = "./modules/security_group"
name = "${var.project}-sg"
description = "security group testing"
vpc_id = "my-vpc"
ingress = [{
description = ""
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = []
ipv6_cidr_blocks = []
}, {
description = ""
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = []
ipv6_cidr_blocks = []
}]
}