├── .gitignore ├── README.md ├── ansible.cfg ├── inventory ├── hosts └── terraform-inventory ├── main.tf ├── modules ├── do │ ├── main.tf │ └── variables.tf └── ec2 │ ├── main.tf │ └── variables.tf ├── playbooks ├── example.yml └── roles │ ├── nginx-sites │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── index.html.j2 │ │ └── sites-available.j2 │ ├── nginx │ └── tasks │ │ └── main.yml │ └── ufw │ └── tasks │ └── main.yml └── variables.tf /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform/ 2 | *.tfstate 3 | *.tfstate.backup 4 | terraform.tfvars 5 | *.retry 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Scripts 2 | 3 | ## Install 4 | ``` 5 | brew install terraform 6 | 7 | brew install ansible 8 | brew install terraform-inventory 9 | ``` 10 | 11 | ## Prerequisite 12 | 1. Create ~/.aws/credentials. Obtain keys from Profile -> "My Security Credentials" 13 | ``` 14 | [default] 15 | aws_access_key_id= 16 | aws_secret_access_key= 17 | ``` 18 | 19 | 2. Create or copy a public-private key pair to access instances to `~/.ssh/terraform.pub` 20 | ``` 21 | ssh-keygen -f ~/.ssh/terraform 22 | ``` 23 | 24 | 3. Create `terraform.tfvars` 25 | ``` 26 | cloudflare_email="" 27 | cloudflare_token="" # From My Profile -> API Keys 28 | do_token="" # From Manage -> API -> Tokens 29 | ``` 30 | 31 | ## Usage 32 | 1. `terraform init`. This will download plugins needed. 33 | 2. `terraform apply`. Will create/update/destroy EC2 instances as defined in `main.tf` 34 | 35 | First execution plan will be shown 36 | ``` 37 | An execution plan has been generated and is shown below. 38 | Resource actions are indicated with the following symbols: 39 | + create 40 | 41 | Terraform will perform the following actions: 42 | 43 | + aws_vpc.default 44 | id: 45 | arn: 46 | assign_generated_ipv6_cidr_block: "false" 47 | cidr_block: "10.0.0.0/16" 48 | default_network_acl_id: 49 | default_route_table_id: 50 | default_security_group_id: 51 | dhcp_options_id: 52 | enable_classiclink: 53 | enable_classiclink_dns_support: 54 | enable_dns_hostnames: 55 | enable_dns_support: "true" 56 | instance_tenancy: "default" 57 | ipv6_association_id: 58 | ipv6_cidr_block: 59 | main_route_table_id: 60 | 61 | 62 | Plan: 1 to add, 0 to change, 0 to destroy. 63 | 64 | Do you want to perform these actions? 65 | Terraform will perform the actions described above. 66 | Only 'yes' will be accepted to approve. 67 | 68 | Enter a value: 69 | 70 | ``` 71 | 72 | Then it is applied after keyboard confirmation 73 | 74 | ``` 75 | Enter a value: yes 76 | 77 | aws_vpc.default: Creating... 78 | arn: "" => "" 79 | assign_generated_ipv6_cidr_block: "" => "false" 80 | cidr_block: "" => "10.0.0.0/16" 81 | default_network_acl_id: "" => "" 82 | default_route_table_id: "" => "" 83 | default_security_group_id: "" => "" 84 | dhcp_options_id: "" => "" 85 | enable_classiclink: "" => "" 86 | enable_classiclink_dns_support: "" => "" 87 | enable_dns_hostnames: "" => "" 88 | enable_dns_support: "" => "true" 89 | instance_tenancy: "" => "default" 90 | ipv6_association_id: "" => "" 91 | ipv6_cidr_block: "" => "" 92 | main_route_table_id: "" => "" 93 | [aws_vpc.default: Creation complete after 6s (ID: vpc-080051c8aaca21b68) 94 | 95 | Apply complete! Resources: 1 added, 0 changed, 0 destroyed. 96 | 97 | Outputs: 98 | 99 | example01-ip = 44.252.122.77 100 | ``` 101 | 102 | Outputs we see are what is defined in the `output` block in `main.tf` 103 | 104 | 3. ssh to the instance 105 | 106 | We can query for it or use in the ssh script to the instance, or use DNS entry created by cloudflare. 107 | ``` 108 | ❯❯❯ terraform output example01-ip 109 | 44.252.122.77 110 | ❯❯❯ ssh -i ~/.ssh/terraform ubuntu@`terraform output example01-ip` 111 | 112 | ### DNS should work after a while 113 | ❯❯❯ ssh -i ~/.ssh/terraform ubuntu@example01.varokas.com 114 | 115 | ``` 116 | 117 | 4. State of the execution is kept in `terraform.tfstate.*`. Check this in a repository to share system state with others. 118 | 119 | ## Notes on using Ansible with Terraform 120 | * Ansible dynamic scripts downloaded from https://github.com/adammck/terraform-inventory via brew 121 | * Put it as default inventory source via `ansible.cfg` 122 | * ansible.cfg is configured to read files in inventory/ as inventory file, so we need to symlink from `/usr/local/bin/terraform-inventory` 123 | 124 | ``` 125 | ❯❯❯ ansible all --list-hosts 126 | hosts (1): 127 | 35.165.28.244 128 | 129 | ❯❯❯ ansible role_example --list-hosts 130 | hosts (1): 131 | 35.165.28.244 132 | 133 | ❯❯❯ ansible-playbook playbooks/example.yml 134 | 135 | PLAY [role_example] ********************************* 136 | 137 | TASK [Gathering Facts] ****************************** 138 | ok: [35.162.30.126] 139 | 140 | TASK [ufw : Enable Firewall and allow SSH] ********** 141 | changed: [35.162.30.126] 142 | 143 | PLAY RECAP ****************************************** 144 | 35.162.30.126 : ok=2 changed=1 unreachable=0 failed=0 145 | ``` 146 | 147 | ## Reference 148 | * https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples/two-tier 149 | * https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html 150 | * https://cloud-images.ubuntu.com/locator/ec2/ 151 | * https://github.com/adammck/terraform-inventory 152 | * https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04 153 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=inventory/ 3 | -------------------------------------------------------------------------------- /inventory/hosts: -------------------------------------------------------------------------------- 1 | [all:vars] 2 | ansible_user=ubuntu 3 | ansible_ssh_private_key_file=~/.ssh/terraform 4 | ansible_python_interpreter=/usr/bin/python3 5 | -------------------------------------------------------------------------------- /inventory/terraform-inventory: -------------------------------------------------------------------------------- 1 | /usr/local/bin/terraform-inventory -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | module "varokas_com" { 2 | source = "modules/do" 3 | do_token = "${var.do_token}" 4 | cloudflare_email = "${var.cloudflare_email}" 5 | cloudflare_token = "${var.cloudflare_token}" 6 | terraform_ssh_fingerprint = "${var.terraform_ssh_fingerprint}" 7 | } -------------------------------------------------------------------------------- /modules/do/main.tf: -------------------------------------------------------------------------------- 1 | provider "digitalocean" { 2 | token = "${var.do_token}" 3 | } 4 | 5 | provider "cloudflare" { 6 | email = "${var.cloudflare_email}" 7 | token = "${var.cloudflare_token}" 8 | } 9 | 10 | resource "digitalocean_ssh_key" "terraform" { 11 | name = "terraform" 12 | public_key = "${file(var.public_key_path)}" 13 | } 14 | 15 | resource "digitalocean_droplet" "winter" { 16 | image = "ubuntu-18-04-x64" 17 | name = "winter" 18 | region = "sfo2" 19 | size = "s-1vcpu-1gb" 20 | backups = "true" 21 | ssh_keys = ["${var.terraform_ssh_fingerprint}"] 22 | } 23 | 24 | # Create DNS record on CloudFlare 25 | resource "cloudflare_record" "winter" { 26 | domain = "varokas.com" 27 | name = "winter" 28 | value = "${digitalocean_droplet.winter.ipv4_address}" 29 | type = "A" 30 | ttl = 3600 31 | } -------------------------------------------------------------------------------- /modules/do/variables.tf: -------------------------------------------------------------------------------- 1 | variable "public_key_path" { 2 | description = < 2 | 3 | Welcome to {{domain_name}} 4 | 5 | 6 |

The {{domain_name}} server block is working!

7 | 8 | -------------------------------------------------------------------------------- /playbooks/roles/nginx-sites/templates/sites-available.j2: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | 5 | root /var/www/{{domain_name}}/html; 6 | index index.html index.htm index.nginx-debian.html; 7 | 8 | server_name {{domain_name}}; 9 | 10 | location / { 11 | try_files $uri $uri/ =404; 12 | } 13 | } -------------------------------------------------------------------------------- /playbooks/roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install nginx 3 | become: yes 4 | apt: name=nginx state=present 5 | 6 | - name: Firewall allow both HTTP and HTTPs 7 | become: yes 8 | ufw: rule=allow name="Nginx Full" state=enabled 9 | 10 | - name: Ensure nginx service started 11 | become: yes 12 | service: name=nginx state=started enabled=yes -------------------------------------------------------------------------------- /playbooks/roles/ufw/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Enable Firewall and allow SSH 3 | become: yes 4 | ufw: 5 | rule: allow 6 | name: OpenSSH 7 | state: enabled 8 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "public_key_path" { 2 | description = <