diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ceba02e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,36 @@ +# https://editorconfig.org/ + +root = true + +[*] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +charset = utf-8 + +# Docstrings and comments use max_line_length = 79 +[*.py] +max_line_length = 119 + +# The JSON files contain newlines inconsistently +[*.json] +indent_size = 2 +insert_final_newline = ignore + +# Use 2 spaces for YAML files +[*.yml] +indent_size = 2 + +# Use 2 spaces for Terraform files +[*.tf] +indent_size = 2 + +# Use 2 spaces for Packer files +[packer.pkr.hcl] +indent_size = 2 + +# Use 2 spaces for Nix files +[*.nix] +indent_size = 2 diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..05d4e83 --- /dev/null +++ b/.env.dist @@ -0,0 +1,6 @@ +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-2 +AWS_CLI_AUTO_PROMPT=on + +NIXPKGS_ALLOW_UNFREE=1 \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..1868b33 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,66 @@ +name: Build and Test on Pull Request + +on: [pull_request] + +jobs: + build: + runs-on: ubuntu-latest + env: + ### AWS ### + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + NIXPKGS_ALLOW_UNFREE: 1 + steps: + - uses: actions/checkout@v3 + - run: | + # Create with liberal rights, otherwise cache action will complain + # about permission errors. + sudo mkdir -p /nix/store + sudo chmod -R 777 /nix + - name: Cache nix env take N+1 + id: myCacheStep + uses: actions/cache@v2 + with: + path: | + # See https://github.com/actions/cache/pull/726 + /nix/store/** + # Missing something? + /nix/var/nix/*/* + /nix/var/nix/db/* + /nix/var/nix/db/*/** + !/nix/var/nix/daemon-socket/socket + !/nix/var/nix/userpool/* + !/nix/var/nix/gc.lock + !/nix/var/nix/db/big-lock + !/nix/var/nix/db/reserved + key: ${{ runner.os }}-nix-store + + - uses: cachix/install-nix-action@v18 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: Cache Terraform directory + uses: actions/cache@v2 + with: + path: | + .terraform + key: ${{ runner.os }}-terraform-${{ hashFiles('**/*.tf') }} + restore-keys: | + ${{ runner.os }}-terraform- + + - name: Install custom nix env + if: steps.myCacheStep.outputs.cache-hit != 'true' + run: nix-env -f shell.nix -i '.*' + - name: Packer Format + run: nix-shell --run "task packer.format" + - name: Packer Validate + run: nix-shell --run "task packer.validate" + - name: Packer Build + run: nix-shell --run "task packer.build" + - name: Terraform Format + run: nix-shell --run "task terraform.format" + - name: Terraform Validate + run: nix-shell --run "task terraform.validate" + - name: Terraform Apply + run: nix-shell --run "task terraform.apply" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc30cc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +__pycache__ +.DS_Store +.env +env* +!env.py +.terraform +.terraform.lock.hcl +terraform.tfstate +terraform.tfstate.backup +.venv +.pytest_cache \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1f436d9 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +Terrami Project +============== + +Reliable way to create and provision an AWS AMI with Packer, Ansible & Terraform (others Nix, Taskfile, AWSCLI) + +**Is highly recommended have Nix installed, otherwise you will need manually install: Packer, Ansible, Terraform and Taskfile and AWSCLI** + +# Installation + +1. First, clone this repository: + +```bash +git clone https://github.com/nietzscheson/terrami && cd terrami +``` +2. Export the environment vars: +```bash +export AWS_ACCESS_KEY_ID=your-credentials +export AWS_SECRET_ACCESS_KEY=your-credentials +export AWS_DEFAULT_REGION=us-east-2 +export AWS_CLI_AUTO_PROMPT=on +export NIXPKGS_ALLOW_UNFREE=1 +``` +3. Start the Nix-shell: +```bash +nix-shell +``` +3. Check all the Taskfile commands: +```bash +task --list +task: Available tasks for this project: +* ansible.check: Check the Ansible Playbook +* aws.sts: Who am I in AWS +* packer.build: Build the Packer Image +* packer.format: Format the Packer Template +* packer.validate: Validate the Packer Template +* terraform.apply: Apply the Terraform Deployment +* terraform.destroy: Destroy the Terraform Deployment +* terraform.format: Format the Terraform Code +* terraform.plan: Plan the Terraform Deployment +* terraform.validate: Validate the Terraform Code +``` + + + diff --git a/packer/packer.pkr.hcl b/packer/packer.pkr.hcl new file mode 100644 index 0000000..b6a20c3 --- /dev/null +++ b/packer/packer.pkr.hcl @@ -0,0 +1,45 @@ +packer { + required_plugins { + amazon = { + version = "~> 1" + source = "github.com/hashicorp/amazon" + } + + ansible = { + source = "github.com/hashicorp/ansible" + version = "~> 1" + } + + } +} + +variable "region" { + type = string + default = "us-east-2" +} + +locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") } + +source "amazon-ebs" "default" { + ami_name = "az2-base-${local.timestamp}" + instance_type = "t2.micro" + region = var.region + source_ami_filter { + filters = { + name = "amzn2-ami-hvm-*-x86_64-gp2" + root-device-type = "ebs" + virtualization-type = "hvm" + } + most_recent = true + owners = ["137112412989"] + } + ssh_username = "ec2-user" +} + +build { + sources = ["source.amazon-ebs.default"] + + provisioner "ansible" { + playbook_file = "./playbook.yml" + } +} \ No newline at end of file diff --git a/packer/playbook.yml b/packer/playbook.yml new file mode 100644 index 0000000..65bbe34 --- /dev/null +++ b/packer/playbook.yml @@ -0,0 +1,34 @@ +--- +- name: Basic setup for Amazon Linux 2 + hosts: all + become: yes + + tasks: + - name: Update all packages + yum: + name: "*" + state: latest + + - name: Ensure a list of yum packages are installed + yum: + name: "{{ packages }}" + state: latest + update_cache: yes + vars: + packages: + - python-pip + - yum-utils + - device-mapper-persistent-data + - lvm2 + - amazon-linux-extras + + - name: Add extras repository + shell: yum-config-manager --enable extras + + - name: Install basic packages + yum: + name: + - git + - vim + - htop + state: present diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..898f25f --- /dev/null +++ b/shell.nix @@ -0,0 +1,39 @@ +{ pkgs ? import {} }: + +let + pythonEnv = pkgs.python311.withPackages (ps: [ + ps.pip + ps.debugpy + ps.ipython + ]); +in + +pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + cmake + poetry + jq + tree + ]; + + buildInputs = with pkgs; [ + terraform + packer + pythonEnv + ]; + + packages = with pkgs; [ + git + python311 + awscli + httpie + go-task + ansible + ]; + + shellHook = '' + pyenv global system + export PATH=$PATH:${pythonEnv}/bin + export LC_ALL="C.UTF-8" + ''; +} \ No newline at end of file diff --git a/taskfile.yml b/taskfile.yml new file mode 100644 index 0000000..bf01112 --- /dev/null +++ b/taskfile.yml @@ -0,0 +1,71 @@ +version: "3" + +tasks: + aws.sts: + desc: Who am I in AWS + cmds: + - echo "Getting AWS STS credentials..." + - aws sts get-caller-identity + + packer.format: + desc: Format the Packer Template + dir: ./packer + cmds: + - echo "Formatting Packer template..." + - packer fmt packer.pkr.hcl + + packer.validate: + desc: Validate the Packer Template + dir: ./packer + cmds: + - echo "Validating Packer template..." + - packer validate packer.pkr.hcl + + packer.build: + desc: Build the Packer Image + dir: ./packer + cmds: + - echo "Building Packer image..." + - packer build packer.pkr.hcls + + ansible.check: + desc: Check the Ansible Playbook + dir: ./packer + cmds: + - echo "Checking Ansible playbook..." + - ansible-playbook --check playbook.yml + + terraform.format: + desc: Format the Terraform Code + dir: ./terraform + cmds: + - echo "Formatting Terraform code..." + - terraform fmt + + terraform.validate: + desc: Validate the Terraform Code + dir: ./terraform + cmds: + - echo "Validating Terraform code..." + - terraform validate + + terraform.plan: + desc: Plan the Terraform Deployment + dir: ./terraform + cmds: + - echo "Planning Terraform deployment..." + - terraform plan + + terraform.apply: + desc: Apply the Terraform Deployment + dir: ./terraform + cmds: + - echo "Applying Terraform deployment..." + - terraform apply -auto-approve + + terraform.destroy: + desc: Destroy the Terraform Deployment + dir: ./terraform + cmds: + - echo "Destroying Terraform deployment..." + - terraform destroy -auto-approve \ No newline at end of file diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..5320195 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,33 @@ +provider "aws" { + default_tags { + tags = { + Name = local.name + Environment = local.environment + } + } +} + +terraform { + backend "s3" { + bucket = "terrami-infra" + key = "state.tfstate" + region = "us-east-2" + } + + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.58.0" + } + } +} + +data "aws_ami" "az2_base" { + most_recent = true + owners = ["self"] + + filter { + name = "name" + values = ["az2-base-*"] + } +} \ No newline at end of file diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..276f354 --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,3 @@ +output "image_id" { + value = data.aws_ami.az2_base.id +} \ No newline at end of file diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100755 index 0000000..d570108 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,13 @@ +# core + +locals { + name = "terrami-${terraform.workspace}" + environment = terraform.workspace +} + +data "aws_caller_identity" "current" {} + +variable "region" { + description = "The AWS region to create resources in." + default = "us-east-2" +} \ No newline at end of file