{"id":18947652,"url":"https://github.com/yousafkhamza/aws-lambda-cost-optimization-with-terraform","last_synced_at":"2025-04-15T23:30:24.514Z","repository":{"id":195965526,"uuid":"402018592","full_name":"yousafkhamza/AWS-Lambda-Cost-Optimization-with-Terraform","owner":"yousafkhamza","description":"This is a terraform script for coast optimization using lambda. So, this script can set up a cron(schedule) to start and stop ec2 servers. So, if we need to work a server like an office time like 9:00 AM to 7:00 PM so we can save our time for the start and stop.","archived":false,"fork":false,"pushed_at":"2022-02-26T03:33:35.000Z","size":949,"stargazers_count":9,"open_issues_count":0,"forks_count":16,"subscribers_count":4,"default_branch":"main","last_synced_at":"2023-09-20T19:52:35.972Z","etag":null,"topics":["cloudwatch-events","lambda-functions","python-script","terraform","terraform-aws"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yousafkhamza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-09-01T10:21:26.000Z","updated_at":"2023-09-20T19:52:39.812Z","dependencies_parsed_at":"2023-09-20T20:13:31.256Z","dependency_job_id":null,"html_url":"https://github.com/yousafkhamza/AWS-Lambda-Cost-Optimization-with-Terraform","commit_stats":null,"previous_names":["yousafkhamza/aws-lambda-cost-optimization-with-terraform"],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FAWS-Lambda-Cost-Optimization-with-Terraform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FAWS-Lambda-Cost-Optimization-with-Terraform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FAWS-Lambda-Cost-Optimization-with-Terraform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yousafkhamza%2FAWS-Lambda-Cost-Optimization-with-Terraform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yousafkhamza","download_url":"https://codeload.github.com/yousafkhamza/AWS-Lambda-Cost-Optimization-with-Terraform/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223688710,"owners_count":17186298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudwatch-events","lambda-functions","python-script","terraform","terraform-aws"],"created_at":"2024-11-08T13:10:49.635Z","updated_at":"2024-11-08T13:10:52.842Z","avatar_url":"https://github.com/yousafkhamza.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AWS-Lambda-Cost-Optimization-with-Terraform\n\n[![Build](https://travis-ci.org/joemccann/dillinger.svg?branch=master)](https://travis-ci.org/joemccann/dillinger)\n\n---\n## Description\nThis is a terraform script for cost optimization using lambda. So, this script can set up a cron(schedule) to start and stop ec2 servers. So, if we need to work a server like an office time like 9:00 AM to 7:00 PM then we can save our time and effort to do this thing manually.\n\n----\n## Feature\n- We can save billing money  \n- Automated with CloudWatch\n- EC2 instance with root password (if you need key based please enable that after creation)\n\n----\n## Architecture\n![](lambda_code/screenshots/flow_architecture.jpg)\n\n----\n## Services Created\n\n- EC2\n- Security Group\n- IAM Role (Custom Inline Policies for lambda)\n- Lambda Functions\n- Cloudwatch Event Rule Trigger\n\n----\n## Pre-Requests\n- Terraform\n- Git\n\n#### Terraform Installation\n[Terraform Installation from official](https://www.terraform.io/downloads)\n\n_Terrafom Installation from my script:_\n```\ncurl -Ls https://raw.githubusercontent.com/yousafkhamza/Terraform_installation/main/terraform.sh | bash\n```\n\n#### Pre-Requests (for RedHat-based-Linux)\n```\nyum install -y git\n```\n\n#### Pre-Requests (for Debian-based-Linux)\n````\napt install -y git\n````\n\n#### Pre-Requests (for Termux-based-Linux)\n````\npkg upgrade\npkg install git\n````\n\n---\n## How to Get\n```\ngit clone https://github.com/yousafkhamza/AWS-Lambda-Cost-Optimization-with-Terraform.git\ncd AWS-Lambda-Cost-Optimization-with-Terraform.git\n```\n\n----\n## How to execute\n```\nterraform init\nterraform plan\nterraform apply\n```\n\n----\n## Output be like\n```\n terraform apply -auto-approve\n\nTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following\nsymbols:\n  + create\n\nTerraform will perform the following actions:\n\n  # aws_cloudwatch_event_rule.trigger_to_start_ec2_instance will be created\n  + resource \"aws_cloudwatch_event_rule\" \"trigger_to_start_ec2_instance\" {\n      + arn                 = (known after apply)\n      + description         = \"Trigger that moving data lambda\"\n      + event_bus_name      = \"default\"\n      + id                  = (known after apply)\n      + is_enabled          = true\n      + name                = \"Trigger-start-ec2-instance-lambda\"\n      + name_prefix         = (known after apply)\n      + schedule_expression = \"cron(0 8 * * ? *)\"\n      + tags                = {\n          + \"Name\" = \"ec2 start cloudwatch trigger\"\n        }\n      + tags_all            = {\n          + \"Name\" = \"ec2 start cloudwatch trigger\"\n        }\n    }\n\n  # aws_cloudwatch_event_rule.trigger_to_stop_ec2_instance will be created\n  + resource \"aws_cloudwatch_event_rule\" \"trigger_to_stop_ec2_instance\" {\n      + arn                 = (known after apply)\n      + description         = \"Trigger that moving data lambda\"\n      + event_bus_name      = \"default\"\n      + id                  = (known after apply)\n      + is_enabled          = true\n      + name                = \"Trigger-stop-ec2-instance-lambda\"\n      + name_prefix         = (known after apply)\n      + schedule_expression = \"cron(0 16 * * ? *)\"\n      + tags                = {\n          + \"Name\" = \"ec2 stop cloudwatch trigger\"\n        }\n      + tags_all            = {\n          + \"Name\" = \"ec2 stop cloudwatch trigger\"\n        }\n    }\n\n  # aws_cloudwatch_event_target.send_to_start_lambda_target will be created\n  + resource \"aws_cloudwatch_event_target\" \"send_to_start_lambda_target\" {\n      + arn            = (known after apply)\n      + event_bus_name = \"default\"\n      + id             = (known after apply)\n      + rule           = \"Trigger-start-ec2-instance-lambda\"\n      + target_id      = \"SendToLambda\"\n    }\n\n  # aws_cloudwatch_event_target.send_to_stop_lambda_target will be created\n  + resource \"aws_cloudwatch_event_target\" \"send_to_stop_lambda_target\" {\n      + arn            = (known after apply)\n      + event_bus_name = \"default\"\n      + id             = (known after apply)\n      + rule           = \"Trigger-stop-ec2-instance-lambda\"\n      + target_id      = \"SendToLambda\"\n    }\n\n  # aws_iam_role.lambda_iam_role_terraform will be created\n  + resource \"aws_iam_role\" \"lambda_iam_role_terraform\" {\n      + arn                   = (known after apply)\n      + assume_role_policy    = jsonencode(\n            {\n              + Statement = [\n                  + {\n                      + Action    = \"sts:AssumeRole\"\n                      + Effect    = \"Allow\"\n                      + Principal = {\n                          + Service = \"lambda.amazonaws.com\"\n                        }\n                      + Sid       = \"\"\n                    },\n                ]\n              + Version   = \"2012-10-17\"\n            }\n        )\n      + create_date           = (known after apply)\n      + description           = \"IAM role for lambda to stop start that instance which we created\"\n      + force_detach_policies = false\n      + id                    = (known after apply)\n      + managed_policy_arns   = (known after apply)\n      + max_session_duration  = 3600\n      + name                  = \"Lambda-IAM-Role-For-EC2-Stop-Start\"\n      + name_prefix           = (known after apply)\n      + path                  = \"/lambda/\"\n      + tags_all              = (known after apply)\n      + unique_id             = (known after apply)\n\n      + inline_policy {\n          + name   = \"EC2-Describe-Inline-Policy\"\n          + policy = jsonencode(\n                {\n                  + Statement = [\n                      + {\n                          + Action   = \"ec2:DescribeInstances\"\n                          + Effect   = \"Allow\"\n                          + Resource = \"*\"\n                          + Sid      = \"\"\n                        },\n                    ]\n                  + Version   = \"2012-10-17\"\n                }\n            )\n        }\n      + inline_policy {\n          + name   = \"EC2-Stop-Start-Inline-Policy\"\n          + policy = jsonencode(\n                {\n                  + Statement = [\n                      + {\n                          + Action   = [\n                              + \"ec2:StopInstances\",\n                              + \"ec2:StartInstances\",\n                            ]\n                          + Effect   = \"Allow\"\n                          + Resource = \"arn:aws:ec2:ap-south-1:361738388880:instance/*\"\n                          + Sid      = \"\"\n                        },\n                    ]\n                  + Version   = \"2012-10-17\"\n                }\n            )\n        }\n    }\n\n  # aws_instance.ec2_instance will be created\n  + resource \"aws_instance\" \"ec2_instance\" {\n      + ami                                  = \"ami-0dafa01c8100180f8\"\n      + arn                                  = (known after apply)\n      + associate_public_ip_address          = true\n      + availability_zone                    = \"ap-south-1a\"\n      + cpu_core_count                       = (known after apply)\n      + cpu_threads_per_core                 = (known after apply)\n      + disable_api_termination              = (known after apply)\n      + ebs_optimized                        = (known after apply)\n      + get_password_data                    = false\n      + host_id                              = (known after apply)\n      + id                                   = (known after apply)\n      + instance_initiated_shutdown_behavior = (known after apply)\n      + instance_state                       = (known after apply)\n      + instance_type                        = \"t2.micro\"\n      + ipv6_address_count                   = (known after apply)\n      + ipv6_addresses                       = (known after apply)\n      + key_name                             = (known after apply)\n      + monitoring                           = (known after apply)\n      + outpost_arn                          = (known after apply)\n      + password_data                        = (known after apply)\n      + placement_group                      = (known after apply)\n      + placement_partition_number           = (known after apply)\n      + primary_network_interface_id         = (known after apply)\n      + private_dns                          = (known after apply)\n      + private_ip                           = (known after apply)\n      + public_dns                           = (known after apply)\n      + public_ip                            = (known after apply)\n      + secondary_private_ips                = (known after apply)\n      + security_groups                      = (known after apply)\n      + source_dest_check                    = true\n      + subnet_id                            = \"subnet-0ee7a1d09074c3e0b\"\n      + tags                                 = {\n          + \"Name\" = \"python-terraform\"\n        }\n      + tags_all                             = {\n          + \"Name\" = \"python-terraform\"\n        }\n      + tenancy                              = (known after apply)\n      + user_data                            = \"3f970a9f1a5d611c3764c372fc96f2c681039d94\"\n      + user_data_base64                     = (known after apply)\n      + vpc_security_group_ids               = (known after apply)\n\n      + capacity_reservation_specification {\n          + capacity_reservation_preference = (known after apply)\n\n          + capacity_reservation_target {\n              + capacity_reservation_id = (known after apply)\n            }\n        }\n\n      + ebs_block_device {\n          + delete_on_termination = (known after apply)\n          + device_name           = (known after apply)\n          + encrypted             = (known after apply)\n          + iops                  = (known after apply)\n          + kms_key_id            = (known after apply)\n          + snapshot_id           = (known after apply)\n          + tags                  = (known after apply)\n          + throughput            = (known after apply)\n          + volume_id             = (known after apply)\n          + volume_size           = (known after apply)\n          + volume_type           = (known after apply)\n        }\n\n      + enclave_options {\n          + enabled = (known after apply)\n        }\n\n      + ephemeral_block_device {\n          + device_name  = (known after apply)\n          + no_device    = (known after apply)\n          + virtual_name = (known after apply)\n        }\n\n      + metadata_options {\n          + http_endpoint               = (known after apply)\n          + http_put_response_hop_limit = (known after apply)\n          + http_tokens                 = (known after apply)\n          + instance_metadata_tags      = (known after apply)\n        }\n\n      + network_interface {\n          + delete_on_termination = (known after apply)\n          + device_index          = (known after apply)\n          + network_interface_id  = (known after apply)\n        }\n\n      + root_block_device {\n          + delete_on_termination = true\n          + device_name           = (known after apply)\n          + encrypted             = (known after apply)\n          + iops                  = (known after apply)\n          + kms_key_id            = (known after apply)\n          + throughput            = (known after apply)\n          + volume_id             = (known after apply)\n          + volume_size           = 10\n          + volume_type           = \"gp2\"\n        }\n    }\n\n  # aws_lambda_function.ec2_start_lambda_function will be created\n  + resource \"aws_lambda_function\" \"ec2_start_lambda_function\" {\n      + architectures                  = (known after apply)\n      + arn                            = (known after apply)\n      + description                    = \"This lambda using to start the ec2 instance which we mentioned\"\n      + filename                       = \"tmp/start-lambda-function.zip\"\n      + function_name                  = \"ec2-start-lambda-function\"\n      + handler                        = \"lambda_function.lambda_handler\"\n      + id                             = (known after apply)\n      + invoke_arn                     = (known after apply)\n      + last_modified                  = (known after apply)\n      + memory_size                    = 128\n      + package_type                   = \"Zip\"\n      + publish                        = false\n      + qualified_arn                  = (known after apply)\n      + reserved_concurrent_executions = -1\n      + role                           = (known after apply)\n      + runtime                        = \"python3.9\"\n      + signing_job_arn                = (known after apply)\n      + signing_profile_version_arn    = (known after apply)\n      + source_code_hash               = (known after apply)\n      + source_code_size               = (known after apply)\n      + tags                           = {\n          + \"Name\" = \"ec2 start lambda function\"\n        }\n      + tags_all                       = {\n          + \"Name\" = \"ec2 start lambda function\"\n        }\n      + timeout                        = 60\n      + version                        = (known after apply)\n\n      + environment {\n          + variables = {\n              + \"REGION\" = \"ap-south-1\"\n              + \"TAG\"    = \"python-terraform\"\n            }\n        }\n\n      + tracing_config {\n          + mode = (known after apply)\n        }\n    }\n\n  # aws_lambda_function.ec2_stop_lambda_function will be created\n  + resource \"aws_lambda_function\" \"ec2_stop_lambda_function\" {\n      + architectures                  = (known after apply)\n      + arn                            = (known after apply)\n      + description                    = \"This lambda using to stop the ec2 instance which we mentioned\"\n      + filename                       = \"tmp/stop-lambda-function.zip\"\n      + function_name                  = \"ec2-stop-lambda-function\"\n      + handler                        = \"lambda_function.lambda_handler\"\n      + id                             = (known after apply)\n      + invoke_arn                     = (known after apply)\n      + last_modified                  = (known after apply)\n      + memory_size                    = 128\n      + package_type                   = \"Zip\"\n      + publish                        = false\n      + qualified_arn                  = (known after apply)\n      + reserved_concurrent_executions = -1\n      + role                           = (known after apply)\n      + runtime                        = \"python3.9\"\n      + signing_job_arn                = (known after apply)\n      + signing_profile_version_arn    = (known after apply)\n      + source_code_hash               = (known after apply)\n      + source_code_size               = (known after apply)\n      + tags                           = {\n          + \"Name\" = \"ec2 stop lambda function\"\n        }\n      + tags_all                       = {\n          + \"Name\" = \"ec2 stop lambda function\"\n        }\n      + timeout                        = 60\n      + version                        = (known after apply)\n\n      + environment {\n          + variables = {\n              + \"REGION\" = \"ap-south-1\"\n              + \"TAG\"    = \"python-terraform\"\n            }\n        }\n\n      + tracing_config {\n          + mode = (known after apply)\n        }\n    }\n\n  # aws_lambda_permission.allow_cloudwatch_to_call_start_lambda will be created\n  + resource \"aws_lambda_permission\" \"allow_cloudwatch_to_call_start_lambda\" {\n      + action        = \"lambda:InvokeFunction\"\n      + function_name = \"ec2-start-lambda-function\"\n      + id            = (known after apply)\n      + principal     = \"events.amazonaws.com\"\n      + source_arn    = (known after apply)\n      + statement_id  = \"AllowExecutionFromCloudWatch\"\n    }\n\n  # aws_lambda_permission.allow_cloudwatch_to_call_stop_lambda will be created\n  + resource \"aws_lambda_permission\" \"allow_cloudwatch_to_call_stop_lambda\" {\n      + action        = \"lambda:InvokeFunction\"\n      + function_name = \"ec2-stop-lambda-function\"\n      + id            = (known after apply)\n      + principal     = \"events.amazonaws.com\"\n      + source_arn    = (known after apply)\n      + statement_id  = \"AllowExecutionFromCloudWatch\"\n    }\n\n  # aws_security_group.sg_for_ec2 will be created\n  + resource \"aws_security_group\" \"sg_for_ec2\" {\n      + arn                    = (known after apply)\n      + description            = \"Allow 80,443,22\"\n      + egress                 = [\n          + {\n              + cidr_blocks      = [\n                  + \"0.0.0.0/0\",\n                ]\n              + description      = \"\"\n              + from_port        = 0\n              + ipv6_cidr_blocks = [\n                  + \"::/0\",\n                ]\n              + prefix_list_ids  = []\n              + protocol         = \"-1\"\n              + security_groups  = []\n              + self             = false\n              + to_port          = 0\n            },\n        ]\n      + id                     = (known after apply)\n      + ingress                = [\n          + {\n              + cidr_blocks      = [\n                  + \"0.0.0.0/0\",\n                ]\n              + description      = \"HTTPS\"\n              + from_port        = 443\n              + ipv6_cidr_blocks = [\n                  + \"::/0\",\n                ]\n              + prefix_list_ids  = []\n              + protocol         = \"tcp\"\n              + security_groups  = []\n              + self             = false\n              + to_port          = 443\n            },\n          + {\n              + cidr_blocks      = [\n                  + \"0.0.0.0/0\",\n                ]\n              + description      = \"HTTPS\"\n              + from_port        = 80\n              + ipv6_cidr_blocks = [\n                  + \"::/0\",\n                ]\n              + prefix_list_ids  = []\n              + protocol         = \"tcp\"\n              + security_groups  = []\n              + self             = false\n              + to_port          = 80\n            },\n          + {\n              + cidr_blocks      = [\n                  + \"0.0.0.0/0\",\n                ]\n              + description      = \"SSH\"\n              + from_port        = 22\n              + ipv6_cidr_blocks = [\n                  + \"::/0\",\n                ]\n              + prefix_list_ids  = []\n              + protocol         = \"tcp\"\n              + security_groups  = []\n              + self             = false\n              + to_port          = 22\n            },\n        ]\n      + name                   = \"sgec2\"\n      + name_prefix            = (known after apply)\n      + owner_id               = (known after apply)\n      + revoke_rules_on_delete = false\n      + tags                   = {\n          + \"Name\" = \"sg-for-stop-start-ec2\"\n        }\n      + tags_all               = {\n          + \"Name\" = \"sg-for-stop-start-ec2\"\n        }\n      + vpc_id                 = (known after apply)\n    }\n\nPlan: 11 to add, 0 to change, 0 to destroy.\naws_iam_role.lambda_iam_role_terraform: Creating...\naws_security_group.sg_for_ec2: Creating...\naws_security_group.sg_for_ec2: Creation complete after 4s [id=sg-01e05ef2f174955f7]\naws_instance.ec2_instance: Creating...\naws_iam_role.lambda_iam_role_terraform: Creation complete after 5s [id=Lambda-IAM-Role-For-EC2-Stop-Start]\naws_lambda_function.ec2_start_lambda_function: Creating...\naws_lambda_function.ec2_stop_lambda_function: Creating...\naws_instance.ec2_instance: Still creating... [10s elapsed]\naws_lambda_function.ec2_start_lambda_function: Still creating... [10s elapsed]\naws_lambda_function.ec2_stop_lambda_function: Still creating... [10s elapsed]\naws_lambda_function.ec2_stop_lambda_function: Creation complete after 11s [id=ec2-stop-lambda-function]\naws_cloudwatch_event_rule.trigger_to_stop_ec2_instance: Creating...\naws_cloudwatch_event_rule.trigger_to_stop_ec2_instance: Creation complete after 1s [id=Trigger-stop-ec2-instance-lambda]\naws_lambda_permission.allow_cloudwatch_to_call_stop_lambda: Creating...\naws_cloudwatch_event_target.send_to_stop_lambda_target: Creating...\naws_cloudwatch_event_target.send_to_stop_lambda_target: Creation complete after 0s [id=Trigger-stop-ec2-instance-lambda-SendToLambda]\naws_lambda_permission.allow_cloudwatch_to_call_stop_lambda: Creation complete after 0s [id=AllowExecutionFromCloudWatch]\naws_lambda_function.ec2_start_lambda_function: Creation complete after 16s [id=ec2-start-lambda-function]\naws_cloudwatch_event_rule.trigger_to_start_ec2_instance: Creating...\naws_cloudwatch_event_rule.trigger_to_start_ec2_instance: Creation complete after 1s [id=Trigger-start-ec2-instance-lambda]\naws_lambda_permission.allow_cloudwatch_to_call_start_lambda: Creating...\naws_cloudwatch_event_target.send_to_start_lambda_target: Creating...\naws_cloudwatch_event_target.send_to_start_lambda_target: Creation complete after 0s [id=Trigger-start-ec2-instance-lambda-SendToLambda]\naws_lambda_permission.allow_cloudwatch_to_call_start_lambda: Creation complete after 0s [id=AllowExecutionFromCloudWatch]\naws_instance.ec2_instance: Still creating... [20s elapsed]\naws_instance.ec2_instance: Still creating... [30s elapsed]\naws_instance.ec2_instance: Creation complete after 33s [id=i-07d44771b790189bc]\n\nApply complete! Resources: 11 added, 0 changed, 0 destroyed.\n```\n### _Output Screenshots (at AWS)_\n![](lambda_code/screenshots/1.png)\n![](lambda_code/screenshots/2.png)\n![](lambda_code/screenshots/3.png)\n![](lambda_code/screenshots/4.png)\n\n----\n## Behind the code\n### Terraform code\n_EC2.tf_\n````\n#-----------------------\n# EC2 Instance\n#-----------------------\n\nresource \"aws_instance\" \"ec2_instance\" {\n  ami                         = data.aws_ami.linux.id\n  instance_type               = var.type\n  associate_public_ip_address = true\n  availability_zone           = data.aws_availability_zones.available.names[0]\n#  key_name                    = var.key  #we are using password through userdata once you logged in please change on be half of you!\n  subnet_id                   = tolist(data.aws_subnets.my_vpc.ids)[0]\n  vpc_security_group_ids      = [ aws_security_group.sg_for_ec2.id ]\n  user_data \t\t\t\t           = \u003c\u003cEOF\n#!/bin/bash\necho \"ClientAliveInterval 60\" \u003e\u003e /etc/ssh/sshd_config\necho \"LANG=en_US.utf-8\" \u003e\u003e /etc/environment\necho \"LC_ALL=en_US.utf-8\" \u003e\u003e /etc/environment\necho \"${var.password_for_ec2}\" | passwd root --stdin\nsed  -i 's/#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config\nsed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config\nservice sshd restart\nEOF\n  tags                         = {\n    Name                      = var.ec2_tag\n  }\n\n  root_block_device            {\n  volume_type                   = \"gp2\"\n  volume_size                   = var.vol_size\n  }\n}\n````\n\u003e Userdata including this file due to the password fetching through as a variable. and creating an ec2 instance with your requirements and you can set those variables like \"Instance type, Volume Size, Tag for lambda, Password for the ec2 instance\" so you can choose those strings values as a variable in `terraform.tfvars`.\n\n_SG.tf_\n```\n# -------------------------------------\n# Security Group\n# -------------------------------------\n\nresource \"aws_security_group\" \"sg_for_ec2\" {\n  name        = \"sgec2\"\n  description = \"Allow 80,443,22\"\n  \n  ingress {\n    description      = \"HTTPS\"\n    from_port        = 80\n    to_port          = 80\n    protocol         = \"tcp\"\n    cidr_blocks      = [\"0.0.0.0/0\"]\n    ipv6_cidr_blocks = [\"::/0\"]\n  }\n  ingress {\n    description      = \"HTTPS\"\n    from_port        = 443\n    to_port          = 443\n    protocol         = \"tcp\"\n    cidr_blocks      = [\"0.0.0.0/0\"]\n    ipv6_cidr_blocks = [\"::/0\"]\n  }\n  ingress {\n    description      = \"SSH\"\n    from_port        = 22\n    to_port          = 22\n    protocol         = \"tcp\"\n    cidr_blocks      = [\"0.0.0.0/0\"]\n    ipv6_cidr_blocks = [\"::/0\"]\n  }\n\n  egress {\n    from_port        = 0\n    to_port          = 0\n    protocol         = \"-1\"\n    cidr_blocks      = [\"0.0.0.0/0\"]\n    ipv6_cidr_blocks = [\"::/0\"]\n  }\n\n  tags = {\n    Name = \"sg-for-stop-start-ec2\"\n  }\n    lifecycle {\n    create_before_destroy = true\n  }\n}\n```\n\u003e Security group for EC2 server which we created through the script and this Security group allowed HTTP, HTTPS, SSH.\n\n_Fetch.tf_\n```\n# Fetch Account ID for IAM.\ndata \"aws_caller_identity\" \"current\" {\n}\n\n# Fetch Default VPC \ndata \"aws_vpc\" \"default\" {\n    default = true\n}\n\n# AZ Fetching \ndata \"aws_availability_zones\" \"available\" {\n  state = \"available\"\n}\n\n# Subnet Fetching\ndata \"aws_subnets\" \"my_vpc\" {\n  filter {\n    name   = \"vpc-id\"\n    values = [ data.aws_vpc.default.id ]\n  }\n}\n\n\n#------------------------------------------------------\n# Amazon Linux AMI choosing through data resource\n#------------------------------------------------------\ndata \"aws_ami\" \"linux\" {\n  most_recent = true\n\n   filter {\n   name   = \"owner-alias\"\n   values = [\"amazon\"]\n }\n\n filter {\n   name   = \"name\"\n   values = [\"amzn2-ami-hvm*\"]\n }\nowners = [\"137112412989\"] # Canonical\n}\n```\n\u003e Fetching all the details ie. amazon Linux AMI for all-region, current account ID for creating IAM Role security and we are using default VPC to create the EC2 so which we fetched data for instance creation which of those fetching services like those VPC, Availability zone, Subnet\n\n_IAM.tf_\n```\n# ----------------------------------\n# IAM Role for Lambda Function \n# ----------------------------------\n# Assume Role - For Lambda\ndata \"aws_iam_policy_document\" \"lambda_assume_role\" {\n  statement {\n    effect = \"Allow\"\n    actions = [\n    \"sts:AssumeRole\"]\n    principals {\n      type = \"Service\"\n      identifiers = [\n      \"lambda.amazonaws.com\"]\n    }\n  }\n}\n\n# Inline policy for ec2 stop start for lambda\ndata \"aws_iam_policy_document\" \"ec2_stop_start_inline_policy\" {\n  statement {\n    actions = [\n        \"ec2:StartInstances\",\n        \"ec2:StopInstances\",\n    ]\n    resources = [\n        \"arn:aws:ec2:${var.aws_region}:${data.aws_caller_identity.current.account_id}:instance/*\",\n    ]\n  }\n}\n\ndata \"aws_iam_policy_document\" \"ec2_describe_inline_policy\" {\n  statement {\n    actions = [\n     \"ec2:DescribeInstances\"\n    ]\n    resources = [\n        \"*\"\n      ]\n  }\n}\n\n# Role for Lambda and both assume and inline integrated \nresource \"aws_iam_role\" \"lambda_iam_role_terraform\" {\n  name               = \"Lambda-IAM-Role-For-EC2-Stop-Start\"\n  path               = \"/lambda/\"\n  assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json\n\n  description = \"IAM role for lambda to stop-start that instance which we created\"\n\n  inline_policy {\n    name   = \"EC2-Stop-Start-Inline-Policy\"\n    policy = data.aws_iam_policy_document.ec2_stop_start_inline_policy.json\n  }\n    inline_policy {\n    name   = \"EC2-Describe-Inline-Policy\"\n    policy = data.aws_iam_policy_document.ec2_describe_inline_policy.json\n  }\n}\n```\n\u003e I have created an IAM role for lambda execution and we are using the most secure IAM to run that lambda and lock with the Account ID and Region\n\n_Lambda_Start.tf_\n```\n# ----------------------------------\n# Lambda_Function\n# ----------------------------------\n#archiving py file to zip\ndata \"archive_file\" \"start_lambda_zip\" {\n  type        = \"zip\"\n  source_dir  = \"./lambda_code/start/\"\n  output_path = \"tmp/${local.start_lambda_function}.zip\"\n}\n\nresource \"aws_lambda_function\" \"ec2_start_lambda_function\" {\n  filename      = data.archive_file.start_lambda_zip.output_path\n  function_name = \"ec2-start-lambda-function\"\n  role          = aws_iam_role.lambda_iam_role_terraform.arn\n  description   = \"This lambda using to start the ec2 instance which we mentioned\"\n  handler       = \"lambda_function.lambda_handler\"\n  runtime       = local.runtime_lambda_function\n  timeout       = 60\n  memory_size   = 128\n\n  environment {\n    variables = {\n      REGION = var.aws_region\n      TAG = var.ec2_tag\n    }\n  }\n\n  tags = tomap({\"Name\" = \"ec2 start lambda function\"})\n}\n\n\n#-----------------------\n# CloudWatch Trigger to start ec2 instance\n#-----------------------\nresource \"aws_cloudwatch_event_rule\" \"trigger_to_start_ec2_instance\" {\n  name                  = \"Trigger-start-ec2-instance-lambda\"\n  description           = \"Trigger that moving data lambda\"\n  schedule_expression   = var.start_cron\n  tags = tomap({\"Name\" = \"ec2 start cloudwatch trigger\"})\n\n  depends_on = [aws_lambda_function.ec2_start_lambda_function]\n}\n\nresource \"aws_cloudwatch_event_target\" \"send_to_start_lambda_target\" {\n  rule      = aws_cloudwatch_event_rule.trigger_to_start_ec2_instance.name\n  target_id = \"SendToLambda\"\n  arn       = aws_lambda_function.ec2_start_lambda_function.arn\n\n  depends_on = [aws_lambda_function.ec2_start_lambda_function]\n}\n\nresource \"aws_lambda_permission\" \"allow_cloudwatch_to_call_start_lambda\" {\n    statement_id = \"AllowExecutionFromCloudWatch\"\n    action = \"lambda:InvokeFunction\"\n    function_name = aws_lambda_function.ec2_start_lambda_function.function_name\n    principal = \"events.amazonaws.com\"\n    source_arn = aws_cloudwatch_event_rule.trigger_to_start_ec2_instance.arn\n\n    depends_on = [aws_lambda_function.ec2_start_lambda_function,aws_cloudwatch_event_rule.trigger_to_start_ec2_instance]\n}\n```\n\u003e Creating a lambda function with ec2 instance starting python script and the scheduler cloudwatch (so you can choose the cron time as a variable in `terraform.tfvars`)\n\n_Lambda_Stop.tf_\n```\n# ----------------------------------\n# Lambda_Function\n# ----------------------------------\n#archiving py file to zip\ndata \"archive_file\" \"stop_lambda_zip\" {\n  type        = \"zip\"\n  source_dir  = \"./lambda_code/stop/\"\n  output_path = \"tmp/${local.stop_lambda_function}.zip\"\n}\n\nresource \"aws_lambda_function\" \"ec2_stop_lambda_function\" {\n  filename      = data.archive_file.stop_lambda_zip.output_path\n  function_name = \"ec2-stop-lambda-function\"\n  role          = aws_iam_role.lambda_iam_role_terraform.arn\n  description   = \"This lambda using to stop the ec2 instance which we mentioned\"\n  handler       = \"lambda_function.lambda_handler\"\n  runtime       = local.runtime_lambda_function\n  timeout       = 60\n  memory_size   = 128\n\n  environment {\n    variables = {\n      REGION = var.aws_region\n      TAG = var.ec2_tag\n    }\n  }\n\n  tags = tomap({\"Name\" = \"ec2 stop lambda function\"})\n}\n\n\n#-----------------------\n# CloudWatch Trigger to stop ec2 instance\n#-----------------------\nresource \"aws_cloudwatch_event_rule\" \"trigger_to_stop_ec2_instance\" {\n  name                  = \"Trigger-stop-ec2-instance-lambda\"\n  description           = \"Trigger that moving data lambda\"\n  schedule_expression   = var.stop_cron\n  tags = tomap({\"Name\" = \"ec2 stop cloudwatch trigger\"})\n\n  depends_on = [aws_lambda_function.ec2_stop_lambda_function]\n}\n\nresource \"aws_cloudwatch_event_target\" \"send_to_stop_lambda_target\" {\n  rule      = aws_cloudwatch_event_rule.trigger_to_stop_ec2_instance.name\n  target_id = \"SendToLambda\"\n  arn       = aws_lambda_function.ec2_stop_lambda_function.arn\n\n  depends_on = [aws_lambda_function.ec2_stop_lambda_function]\n}\n\nresource \"aws_lambda_permission\" \"allow_cloudwatch_to_call_stop_lambda\" {\n    statement_id = \"AllowExecutionFromCloudWatch\"\n    action = \"lambda:InvokeFunction\"\n    function_name = aws_lambda_function.ec2_stop_lambda_function.function_name\n    principal = \"events.amazonaws.com\"\n    source_arn = aws_cloudwatch_event_rule.trigger_to_stop_ec2_instance.arn\n\n    depends_on = [aws_lambda_function.ec2_stop_lambda_function,aws_cloudwatch_event_rule.trigger_to_stop_ec2_instance]\n}\n```\n\u003e Creating a lambda function with ec2 instance starting python script and the scheduler cloudwatch (so you can choose the cron time as a variable in `terraform.tfvars`) \n\n_variables.tf_\n```\nvariable \"aws_region\" {\n  type        = string\n  description = \"Which region do you used\"\n  default     = \"\"\n}\n\nvariable \"type\" {\n  type        = string\n  description = \"Which instance type do you need\"\n  default     = \"t2.micro\"\n}\n\nvariable \"vol_size\" {\n  type        = string\n  description = \"Instance volume size do you need\"\n  default     = \"8\"\n}\n\nvariable \"start_cron\" {\n  type        = string\n  description = \"Cron time start the instance which we created\"\n  default     = \"cron(0 9 * * ? *)\"\n}\n\nvariable \"stop_cron\" {\n  type        = string\n  description = \"Cron time stop the instance which we created\"\n  default     = \"cron(0 17 * * ? *)\"\n}\n\nvariable \"ec2_tag\" {\n  type        = string\n  description = \"TAG for ec2 and this tag to take stop start this instance\"\n  default     = \"python-terraform\"\n}\n\nvariable \"password_for_ec2\" {\n  type        = string\n  description = \"Password for EC2 Server\"\n  default     = \"T36r@f06m@YKH\"\n}\n\nlocals {\nstart_lambda_function = \"start-lambda-function\"\nstop_lambda_function = \"stop-lambda-function\"\nruntime_lambda_function = \"python3.9\"\n}\n```\n\u003e Variables name defining here and I have set up some predefined and default values here. you can change all the variable values on `terraform.tfvars`\n\n_terraform.tfvars_\n```\naws_region = \"ap-south-1\"            # mention which region you need here.\ntype = \"t2.micro\"                    # mention which type of instance would you need and mention here.\nvol_size = \"10\"                      # EC2 instance volume size mention here.\nstart_cron = \"cron(0 8 * * ? *)\"     # Which time to start that EC2 instance here.\nstop_cron = \"cron(0 16 * * ? *)\"     # Which time to stop that EC2 instance here.\nec2_tag = \"python-terraform\"         # Tag for EC2 instance here and this tag is using to stop that EC2 instance so please be uniq\npassword_for_ec2 = \"T36r@f06m@YKH\"   # Strong password mentioned here for EC2 because we didn't use key pair if you need please login to the EC2 and do it manually\n```\n\u003e **Please read the side notes and change the values as you need like the left side. if you're not changing it will run with those default values so please change it manually before running `terraform apply`**\n\n### Python Code\n_lambda_code/start/lambda_function.py_\n```\nimport boto3\nimport os\n\nREGION = os.environ['REGION']\nTAG = os.environ['TAG']\n\ndef lambda_handler(event, context):\n    ec2 = boto3.client('ec2',region_name=REGION)\n    all_ec2 = ec2.describe_instances(\n        Filters=[\n        {'Name':'tag:Name', 'Values':[TAG]}\n        ])\n\n    for instance in all_ec2['Reservations'][0]['Instances']:\n        print(\"Starting Ec2 : {} \".format( instance['InstanceId'] ))\n        ec2.start_instances(InstanceIds=[ instance['InstanceId'] ])\n```\n\u003e Using environment variables to fetch that tag and region details from variable and so this is used to start that ec2 instance which we created with this script.\n\n_lambda_code/stop/lambda_function.py_\n```\nimport boto3\nimport os\n\nREGION = os.environ['REGION']\nTAG = os.environ['TAG']\n\ndef lambda_handler(event, context):\n    ec2 = boto3.client('ec2',region_name=REGION)\n    all_ec2 = ec2.describe_instances(\n        Filters=[\n        {'Name':'tag:Name', 'Values':[TAG]}\n        ])\n\n    for instance in all_ec2['Reservations'][0]['Instances']:\n        print(\"Stopping Ec2 : {} \".format( instance['InstanceId'] ))\n        ec2.stop_instances(InstanceIds=[ instance['InstanceId'] ])\n```\n\u003e Using environment variables to fetch that tag and region details from variable and so this is used to stop that ec2 instance which we created with this script.\n\n----\n## Conclusion\nQ: I would like to start and stop an EC2 instance automatically and it's saving cost and time. Also, please create an instance with my wish. So, is it possible?\n\nA: Yeah sure, we can do this with lambda and cloudwatch and you can create an ec2 instance with your required values as you wish. Also, those values can only change through in `terraform.tfvars` so, after it will be automated on rest of time.\n\n### ⚙️ Connect with Me \n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"mailto:yousaf.k.hamza@gmail.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/Gmail-D14836?style=for-the-badge\u0026logo=gmail\u0026logoColor=white\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://www.linkedin.com/in/yousafkhamza\"\u003e\u003cimg src=\"https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge\u0026logo=linkedin\u0026logoColor=white\"/\u003e\u003c/a\u003e \n\u003ca href=\"https://www.instagram.com/yousafkhamza\"\u003e\u003cimg src=\"https://img.shields.io/badge/Instagram-E4405F?style=for-the-badge\u0026logo=instagram\u0026logoColor=white\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://wa.me/%2B917736720639?text=This%20message%20from%20GitHub.\"\u003e\u003cimg src=\"https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge\u0026logo=whatsapp\u0026logoColor=white\"/\u003e\u003c/a\u003e\u003cbr /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyousafkhamza%2Faws-lambda-cost-optimization-with-terraform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyousafkhamza%2Faws-lambda-cost-optimization-with-terraform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyousafkhamza%2Faws-lambda-cost-optimization-with-terraform/lists"}