Deploying a self managed EKS cluster via Terraform - terraform

It's my first time doing this, and this is mostly a copy pasted beginner example. Not sure what I'm missing.
self_managed_node_group_defaults = {
disk_size = 50
}
self_managed_node_groups = {
bottlerocket = {
name = "bottlerocket-self-mng"
platform = "bottlerocket"
ami_id = "xxx"
instance_type = "t2.small"
desired_size = 2
iam_role_additional_policies = ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
pre_bootstrap_user_data = <<-EOT
echo "foo"
export FOO=bar
EOT
bootstrap_extra_args = "--kubelet-extra-args '--node-labels=node.kubernetes.io/lifecycle=spot'"
post_bootstrap_user_data = <<-EOT
cd /tmp
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent
EOT
}
}
And the error it throws:
Error: Your query returned no results. Please change your search criteria and try again.
with module.eks.module.self_managed_node_group["bottlerocket"].data.aws_ami.eks_default[0]
on .terraform/modules/eks/modules/self-managed-node-group/main.tf line 5, in data "aws_ami" "eks_default":
data "aws_ami" "eks_default" {

Related

Unable to provision with file multiple time

While trying to provision with file multiple times, second occurance is not being considered. Not sure if I'm doing it correctly.
Please throw some light !
The below block works perfectly -
source = "/home/ubuntu/Desktop/aws_migration_using_terraform/tcs-btag-account_us-east-2/aws_infra_automation"
destination = "/home/ubuntu"
}
However, this one didn't work and there is no error thrown by terraform itself !
source = "/home/ubuntu/Desktop/aws_migration_using_terraform/tcs-btag-account_us-east-2/livedevops"
destination = "/home/ubuntu"
}
The entire code is given below --
resource "tls_private_key" "bastion-key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "generated_key" {
key_name = var.bastion_key
public_key = tls_private_key.bastion-key.public_key_openssh
}
resource "aws_instance" "bastion_host_us-east-2a" {
ami = var.bastion_ami_id
instance_type = var.bastion_ec2_instance_type
disable_api_termination = false
subnet_id = aws_subnet.devops_mig_pub_sub_01.id
vpc_security_group_ids = [aws_security_group.sg-btag-allow.id, aws_security_group.sg-ssh-allow.id]
associate_public_ip_address = true
availability_zone = aws_subnet.devops_mig_pub_sub_01.availability_zone
key_name = aws_key_pair.generated_key.id
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
port = 22
private_key = tls_private_key.bastion-key.private_key_pem
timeout = "60s"
}
#Copying files from local to remote
provisioner "file" {
source = "/home/ubuntu/Desktop/aws_migration_using_terraform/tcs-btag-account_us-east-2/aws_infra_automation"
destination = "/home/ubuntu"
}
provisioner "file" {
source = "/home/ubuntu/Desktop/aws_migration_using_terraform/tcs-btag-account_us-east-2/livedevops"
destination = "/home/ubuntu"
}
user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt update -y
sudo apt install -y ansible
/usr/bin/ansible --version > ansible-v.txt
echo "Installing the cloudwatch agent for Ubuntu Linux."
curl -O https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
dpkg -i -E ./amazon-cloudwatch-agent.deb
EOF
tags = {
"Name" = "bastion_host"
}
}
output "private_key" {
value = tls_private_key.bastion-key.private_key_pem
sensitive = true
}
output "bastion_public_ip" {
value = aws_instance.bastion_host_us-east-2a.public_ip
}
output "bastion_private_ip" {
value = aws_instance.bastion_host_us-east-2a.private_ip
}
resource "aws_ebs_volume" "bastion_storage" {
availability_zone = var.bastion-ebs-availability-zone
size = 50
type = "gp2"
tags = {
"Name" = "bastion_ebs_volume"
}
}
resource "local_file" "bastion_private_key" {
content = tls_private_key.bastion-key.private_key_pem
filename = "bastion-key.pem"
file_permission = "0400"
}
I see ubuntu being the user used to SSH to target machine. It's a bad idea to copy files directly to HOME directory of the user & in this case the file provisioner is just replacing everything available on /home/ubuntu directory.
The above directory also contains your SSH public keys used for authentication in ~/.ssh/authorized_keys. That's the reason it's failing at the second file provisioner.
You create a tmp directory under /home/ubuntu or use /tmp or /var/tmp directories if they allow ubuntu user to write something to write.

terraform provisioning locally cloudflared tunnel

I tried to use terraform without any Cloud instance - only for local install cloudflared tunnel using construction:
resource "null_resource" "tunell_install" {
triggers = {
always_run = timestamp()
}
provisioner "local-exec" {
command = "/home/uzer/script/tunnel.sh"
}
}
instead something like:
provider "google" {
project = var.gcp_project_id
}
but after running
$ terraform apply -auto-approve
successfully created /etc/cloudflared/cert.json with content:
{
"AccountTag" : "${account}",
"TunnelID" : "${tunnel_id}",
"TunnelName" : "${tunnel_name}",
"TunnelSecret" : "${secret}"
}
but as I undestood here must be values instead variables? It's seems that metadata_startup_script from instance.tf only applied to Google instance. How it's possible to change it for using terraform with install CF tunnel locally and running tunnel? Maybe also need to use templatefile but in other .tf file? The curent code block metadata_startup_script:
// This is where we configure the server (aka instance). Variables like web_zone take a terraform variable and provide it to the server so that it can use them as a local variable
metadata_startup_script = templatefile("./server.tpl",
{
web_zone = var.cloudflare_zone,
account = var.cloudflare_account_id,
tunnel_id = cloudflare_argo_tunnel.auto_tunnel.id,
tunnel_name = cloudflare_argo_tunnel.auto_tunnel.name,
secret = random_id.tunnel_secret.b64_std
})
Content of server.tpl file:
# Script to install Cloudflare Tunnel
# cloudflared configuration
cd
# The package for this OS is retrieved
wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb
sudo dpkg -i cloudflared-stable-linux-amd64.deb
# A local user directory is first created before we can install the tunnel as a system service
mkdir ~/.cloudflared
touch ~/.cloudflared/cert.json
touch ~/.cloudflared/config.yml
# Another herefile is used to dynamically populate the JSON credentials file
cat > ~/.cloudflared/cert.json << "EOF"
{
"AccountTag" : "${account}",
"TunnelID" : "${tunnel_id}",
"TunnelName" : "${tunnel_name}",
"TunnelSecret" : "${secret}"
}
EOF
# Same concept with the Ingress Rules the tunnel will use
cat > ~/.cloudflared/config.yml << "EOF"
tunnel: ${tunnel_id}
credentials-file: /etc/cloudflared/cert.json
logfile: /var/log/cloudflared.log
loglevel: info
ingress:
- hostname: ssh.${web_zone}
service: ssh://localhost:22
- hostname: "*"
service: hello-world
EOF
# Now we install the tunnel as a systemd service
sudo cloudflared service install
# The credentials file does not get copied over so we'll do that manually
sudo cp -via ~/.cloudflared/cert.json /etc/cloudflared/
# Now we can start the tunnel
sudo service cloudflared start
In argo.tf exist this code:
data "template_file" "init" {
template = file("server.tpl")
vars = {
web_zone = var.cloudflare_zone,
account = var.cloudflare_account_id,
tunnel_id = cloudflare_argo_tunnel.auto_tunnel.id,
tunnel_name = cloudflare_argo_tunnel.auto_tunnel.name,
secret = random_id.tunnel_secret.b64_std
}
}
If you are asking about how to create the file locally and populate the values, here is an example:
resource "local_file" "cloudflare_tunnel_script" {
content = templatefile("${path.module}/server.tpl",
{
web_zone = "webzone"
account = "account"
tunnel_id = "id"
tunnel_name = "name"
secret = "secret"
}
)
filename = "${path.module}/server.sh"
}
For this to work, you would have to assign the real values for all the template variables listed above. From what I see, there are already examples of how to use variables for those values. In other words, instead of hardcoding the values for template variables you could use standard variables:
resource "local_file" "cloudflare_tunnel_script" {
content = templatefile("${path.module}/server.tpl",
{
web_zone = var.cloudflare_zone
account = var.cloudflare_account_id
tunnel_id = cloudflare_argo_tunnel.auto_tunnel.id
tunnel_name = cloudflare_argo_tunnel.auto_tunnel.name
secret = random_id.tunnel_secret.b64_std
}
)
filename = "${path.module}/server.sh"
}
This code will populate all the values and create a server.sh script in the same directory you are running the Terraform code from.
You could complement this code with the null_resource you wanted:
resource "null_resource" "tunnel_install" {
depends_on = [
local_file.cloudflare_tunnel_script,
]
triggers = {
always_run = timestamp()
}
provisioner "local-exec" {
command = "${path.module}/server.sh"
}
}

FluentBit setup

I'm trying to set up FluentBit for my EKS cluster in Terraform, via this module, and I have couple of questions:
cluster_identity_oidc_issuer - what is this? Frankly, I was just told to set this up, so I have very little knowledge about FluentBit, but I assume this "issuer" provides an identity with needed permissions. For example, Okta? We use Okta, so what would I use as a value in here?
cluster_identity_oidc_issuer_arn - no idea what this value is supposed to be.
worker_iam_role_name - as in the role with autoscaling capabilities (oidc)?
This is what eks.tf looks like:
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_name = "DevOpsLabs"
cluster_version = "1.19"
cluster_endpoint_private_access = true
cluster_endpoint_public_access = true
cluster_addons = {
coredns = {
resolve_conflicts = "OVERWRITE"
}
kube-proxy = {}
vpc-cni = {
resolve_conflicts = "OVERWRITE"
}
}
vpc_id = "xxx"
subnet_ids = ["xxx","xxx", "xxx", "xxx" ]
self_managed_node_groups = {
bottlerocket = {
name = "bottlerocket-self-mng"
platform = "bottlerocket"
ami_id = "xxx"
instance_type = "t2.small"
desired_size = 2
iam_role_additional_policies = ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
pre_bootstrap_user_data = <<-EOT
echo "foo"
export FOO=bar
EOT
bootstrap_extra_args = "--kubelet-extra-args '--node-labels=node.kubernetes.io/lifecycle=spot'"
post_bootstrap_user_data = <<-EOT
cd /tmp
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent
EOT
}
}
}
And for the role.tf:
data "aws_iam_policy_document" "cluster_autoscaler" {
statement {
effect = "Allow"
actions = [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeTags",
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup",
"ec2:DescribeLaunchTemplateVersions",
]
resources = ["*"]
}
}
module "config" {
source = "github.com/ahmad-hamade/terraform-eks-config/modules/eks-iam-role-with-oidc"
cluster_name = module.eks.cluster_id
role_name = "cluster-autoscaler"
service_accounts = ["kube-system/cluster-autoscaler"]
policies = [data.aws_iam_policy_document.cluster_autoscaler.json]
tags = {
Terraform = "true"
Environment = "dev-test"
}
}
Since you are using a Terraform EKS module, you can access attributes of the created resources by looking at the Outputs tab [1]. There you can find the following outputs:
cluster_id
cluster_oidc_issuer_url
oidc_provider_arn
They are accessible by using the following syntax:
module.<module_name>.<output_id>
In your case, you would get the values you need using the following syntax:
cluster_id -> module.eks.cluster_id
cluster_oidc_issuer_url -> module.eks.cluster_oidc_issuer_url
oidc_provider_arn -> module.eks.oidc_provider_arn
and assign them to the inputs from the FluentBit module:
cluster_name = module.eks.cluster_id
cluster_identity_oidc_issuer = module.eks.cluster_oidc_issuer_url
cluster_identity_oidc_issuer_arn = module.eks.oidc_provider_arn
For the worker role I didn't see an output from the eks module, so I think that could be an output of the config module [2]:
worker_iam_role_name = module.config.iam_role_name
The OIDC parts of configuration are coming from the EKS cluster [3]. Another blog post going in details can be found here [4].
[1] https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest?tab=outputs
[2] https://github.com/ahmad-hamade/terraform-eks-config/blob/master/modules/eks-iam-role-with-oidc/outputs.tf
[3] https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
[4] https://aws.amazon.com/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks/

SSH isnt working in Windows with Terraform provisioner connection type

I tried Creating Instance in AWS using Terraform and try to copy a set of files into the newly created AWS Instance. I used "provisioner" for the same but for the connection, it always says connection timed out.
In the example below I showed like its AWS Pem file but I tried with both ppk and pem files. nothing works.
provider "aws" {
region = "ap-southeast-1"
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
}
resource "aws_instance" "firsttest" {
ami = "ami-061eb2b23f9f8839c"
instance_type = "t2.micro"
key_name = "deepak"
provisioner "file" {
source = "index.html"
destination = "/home/ubuntu/index.html"
connection {
type = "ssh"
user = "ubuntu"
private_key = file("D:/awskeyterraform/deepak.pem")
host = "${aws_instance.firsttest.public_ip}"
}
}
user_data = <<-EOF
#!/bin/bash
apt-get update -y
apt-get install -y nginx
systemctl enable nginx
service nginx restart
touch index.html
EOF
tags = {
name = "terraform-firsttest"
}
}
Expected should copy the index.html but actual the connection timed out to connect to the newly created instance
In Windows, SSH module Connection doesn't accept "*.pem". Instead, it accepts the PEM file after renaming it to "id_rsa".
provider "aws" {
region = "ap-southeast-1"
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
}
resource "aws_instance" "firsttest" {
ami = "ami-061eb2b23f9f8839c"
instance_type = "t2.micro"
key_name = "deepak"
provisioner "file" {
source = "index.html"
destination = "/home/ubuntu/index.html"
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("D:/awskeyterraform/id_rsa")}"
host = "${aws_instance.firsttest.public_ip}"
}
}
user_data = <<-EOF
#!/bin/bash
apt-get update -y
apt-get install -y nginx
systemctl enable nginx
service nginx restart
touch index.html
EOF
tags = {
name = "terraform-firsttest"
}
}
Hope this should solve the issue.

terraform not working with remote exec for tpl script

I have a simple aws ec2 instance as below
resource "aws_instance" "App01" {
##ami = "ami-846144f8"
ami = "${data.aws_ami.aws_linux.id}"
instance_type = "t1.micro"
subnet_id = "${aws_subnet.public_1a.id}"
associate_public_ip_address = true
vpc_security_group_ids = ["${aws_security_group.web_server.id}","${aws_security_group.allow_ssh.id}"]
key_name = "key"
provisioner "remote-exec"{
inline = ["${template_file.bootstrap.rendered}"]
}
tags {
Name = "App01"
}
}
data "aws_ami" "aws_linux" {
most_recent = true
filter {
name = "name"
values = ["amzn2-ami-*-x86_64-gp2"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
filter {
name = "owner-alias"
values = ["amazon"]
}
}
resource "template_file" "bootstrap" {
template = "${file("bootstrap.tpl")}"
vars {
app01ip = "${aws_instance.App01.private_ip}"
app02ip = "${aws_instance.App02.private_ip}"
DBandMQip = "${aws_instance.DBandMQ.private_ip}"
}
}
This is my tbl script
#!/bin/bash -xe
# install necessary items like ansible and
sudo yum-config-manager --enable epel
sudo amazon-linux-extras install ansible2
echo "${app01ip} App01" > /etc/hosts
echo "${app02ip} App02" > /etc/hosts
echo "${DBandMQip} DBandMQ" > /etc/hosts
I keep getting a
Error: Error asking for user input: 1 error(s) occurred:
* Cycle: aws_instance.App01, template_file.bootstrap
I believe its coming from the resource portion for remote-exec but I am unsure whats wrong because it looks fine to me. Anyone has any idea what I am doing wrong?

Resources